502 lines
16 KiB
JavaScript
502 lines
16 KiB
JavaScript
'use strict';
|
|
|
|
var fs = require('fs');
|
|
|
|
var utils = require('../utils');
|
|
|
|
var Wallet = require('../wallet/wallet');
|
|
|
|
var providers = require('../providers');
|
|
|
|
var contracts = require('../contracts');
|
|
|
|
var TestContracts = require('./tests/test-contract.json');
|
|
|
|
var TestContract = TestContracts.test;
|
|
var TestContractDeploy = TestContracts.deploy;
|
|
|
|
process.on('unhandledRejection', function(reason, p){
|
|
console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
|
|
console.log(p);
|
|
console.log(reason);
|
|
});
|
|
|
|
var callFallback = (function() {
|
|
var contractInterface = new contracts.Interface(TestContract.interface);
|
|
|
|
return contractInterface.events.callFallback();
|
|
})();
|
|
|
|
var privateKey = null;
|
|
if (fs && fs.readFileSync) {
|
|
try {
|
|
privateKey = fs.readFileSync('.test-account.key').toString();
|
|
console.log('Found privateKey!');
|
|
} catch (error) {
|
|
console.log('Creating new private key!');
|
|
privateKey = utils.hexlify(utils.randomBytes(32));
|
|
fs.writeFileSync('.test-account.key', privateKey);
|
|
}
|
|
|
|
} else {
|
|
privateKey = global.localStorage.getItem('ethers-tests-privateKey');
|
|
if (privateKey) {
|
|
console.log('Found privateKey');
|
|
} else {
|
|
console.log('Creating new private key!');
|
|
privateKey = utils.hexlify(utils.randomBytes(32));
|
|
global.localStorage.setItem('ethers-tests-privateKey', privateKey);
|
|
}
|
|
}
|
|
|
|
var provider = providers.getDefaultProvider(true);
|
|
var wallet = new Wallet(privateKey, provider);
|
|
|
|
console.log('Address: ' + wallet.address);
|
|
|
|
function FailProvider(testnet) {
|
|
if (!(this instanceof FailProvider)) { throw new Error('missing new'); }
|
|
providers.Provider.call(this, testnet);
|
|
}
|
|
providers.Provider.inherits(FailProvider);
|
|
|
|
utils.defineProperty(FailProvider.prototype, 'perform', function (method, params) {
|
|
return new Promise(function(resolve, reject) {
|
|
setTimeout(function() {
|
|
reject(new Error('out of order'));
|
|
}, 1000);
|
|
});
|
|
});
|
|
|
|
|
|
function equal(serialized, object) {
|
|
if (Array.isArray(serialized)) {
|
|
if (!Array.isArray(object) || serialized.length != object.length) { return false; }
|
|
for (var i = 0; i < serialized.length; i++) {
|
|
if (!equal(serialized[i], object[i])) { return false; }
|
|
}
|
|
return true;
|
|
} else if (serialized.type) {
|
|
var result = null;
|
|
switch (serialized.type) {
|
|
case 'null':
|
|
result = (null === object);
|
|
break;
|
|
case 'string':
|
|
case 'number':
|
|
case 'boolean':
|
|
result = (serialized.value === object);
|
|
break;
|
|
case 'bigNumber':
|
|
result = utils.bigNumberify(serialized.value).eq(object);
|
|
break;
|
|
default:
|
|
throw new Error('unknown type - ' + serialized.type);
|
|
}
|
|
if (!result) {
|
|
console.log('Not Equal: ', serialized, object);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
for (var key in serialized) {
|
|
if (!equal(serialized[key], object[key])) { return false; }
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
function testReadOnlyProvider(test, address, provider) {
|
|
return Promise.all([
|
|
provider.getBalance(address),
|
|
provider.getCode(address),
|
|
provider.getStorageAt(address, 0),
|
|
provider.getBlock(TestContract.blockNumber),
|
|
provider.getBlock((provider instanceof providers.EtherscanProvider) ? TestContract.blockNumber: TestContract.blockHash),
|
|
provider.getTransaction(TestContract.transactionHash),
|
|
provider.getTransactionReceipt(TestContract.transactionHash),
|
|
provider.call({to: address, data: '0x' + TestContract.functions['getOwner()']}),
|
|
provider.call({to: address, data: '0x' + TestContract.functions['getStringValue()']}),
|
|
|
|
provider.getBlockNumber(),
|
|
provider.getGasPrice(),
|
|
//provider.estimeGas()
|
|
]).then(function(result) {
|
|
// getBalance
|
|
test.equal(result[0].toString(), '123456789', 'getBalance(contractAddress)');
|
|
|
|
// getCode
|
|
test.equal(result[1], TestContract.runtimeBytecode, 'getCode(contractAddress)');
|
|
|
|
// getStorageAt
|
|
test.ok(utils.bigNumberify(result[2]).eq(42), 'getStorageAt(contractAddress, 0)');
|
|
|
|
// getBlock
|
|
var block = JSON.parse(TestContract.block);
|
|
test.ok(equal(block, result[3]), 'getBlock(blockNumber)');
|
|
test.ok(equal(block, result[4]), 'getBlock(blockHash)');
|
|
|
|
// getTransaction
|
|
var transaction = JSON.parse(TestContract.transaction);
|
|
test.ok(equal(transaction, result[5]), 'getTransaction(transactionHash)');
|
|
|
|
// getTransactionReceipt
|
|
var transactionReceipt = JSON.parse(TestContract.transactionReceipt);
|
|
test.ok(equal(transactionReceipt, result[6]), 'getTransaction(transactionHash)');
|
|
|
|
// call
|
|
test.equal(TestContract.owner, utils.getAddress('0x' + result[7].substring(26)), 'call(getOwner())');
|
|
var thisIsNotAString = '0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001554686973206973206e6f74206120737472696e672e0000000000000000000000';
|
|
test.equal(thisIsNotAString, result[8], 'call(getStringValue())');
|
|
|
|
return {blockNumber: result[9], gasPrice: result[9]}
|
|
});
|
|
}
|
|
|
|
function testWriteProvider(test, address, wallet) {
|
|
|
|
var testTransaction = {
|
|
to: address,
|
|
gasLimit: 0x793e + 42,
|
|
value: 100,
|
|
};
|
|
|
|
return Promise.all([
|
|
wallet.estimateGas(testTransaction),
|
|
wallet.sendTransaction(testTransaction),
|
|
|
|
]).then(function(results) {
|
|
test.ok(results[0].eq(0x793e), 'estimateGas()');
|
|
return wallet.provider.waitForTransaction(results[1].hash);
|
|
|
|
}).then(function(transaction) {
|
|
test.equal(transaction.to, testTransaction.to, 'check toAddress');
|
|
test.equal(transaction.from, wallet.address, 'check fromAddress');
|
|
test.ok(transaction.gasLimit.eq(testTransaction.gasLimit), 'check gasLimit');
|
|
test.ok(transaction.value.eq(testTransaction.value), 'check value');
|
|
|
|
}).catch(function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
});
|
|
}
|
|
|
|
|
|
function getProviders() {
|
|
return [
|
|
new providers.InfuraProvider(true),
|
|
//new providers.EtherscanProvider(true),
|
|
new providers.FallbackProvider([
|
|
new FailProvider(true),
|
|
new providers.InfuraProvider(true),
|
|
]),
|
|
];
|
|
}
|
|
|
|
function testEventsProvider(test, provider) {
|
|
var firstBlockNumber = null;
|
|
var lastBlockNumber = null;
|
|
return Promise.all([
|
|
new Promise(function(resolve, reject) {
|
|
function callback(blockNumber) {
|
|
if (lastBlockNumber === null) {
|
|
firstBlockNumber = blockNumber;
|
|
lastBlockNumber = blockNumber - 1;
|
|
}
|
|
|
|
test.equal(lastBlockNumber + 1, blockNumber, 'increasing block number');
|
|
|
|
lastBlockNumber = blockNumber;
|
|
if (blockNumber > firstBlockNumber + 4) {
|
|
provider.removeListener('block', callback);
|
|
resolve(blockNumber);
|
|
}
|
|
}
|
|
provider.on('block', callback);
|
|
}),
|
|
new Promise(function(resolve, reject) {
|
|
function callback(log) {
|
|
var result = callFallback.parse(log.topics, log.data);
|
|
if (result.sender !== wallet.address || !result.amount.eq(123)) {
|
|
//console.log('someone else is running the test cases');
|
|
return;
|
|
}
|
|
|
|
test.ok(true, 'callFallback triggered');
|
|
|
|
provider.removeListener(callFallback.topics, callback);
|
|
|
|
resolve(result);
|
|
}
|
|
provider.on(callFallback.topics, callback);
|
|
}),
|
|
]);
|
|
}
|
|
|
|
function testReadOnly(test) {
|
|
var promises = [];
|
|
getProviders().forEach(function(provider) {
|
|
promises.push(testReadOnlyProvider(test, TestContract.address, provider));
|
|
});
|
|
|
|
Promise.all(promises).then(function(results) {
|
|
results.forEach(function(result, i) {
|
|
if (i === 0) { return; }
|
|
test.equal(results[0].blockNumber, result.blockNumber, 'blockNumber');
|
|
test.equal(results[0].gasPrice, result.gasPrice, 'blockNumber');
|
|
});
|
|
|
|
test.done();
|
|
}, function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
});
|
|
}
|
|
|
|
function testWrite(test) {
|
|
|
|
var promise = wallet.getBalance().then(function(balance) {
|
|
if (balance.isZero()) {
|
|
console.log('Plese send some testnet ether to: ' + wallet.address);
|
|
throw new Error('insufficient balance');
|
|
}
|
|
});
|
|
|
|
getProviders().forEach(function(provider) {
|
|
promise = promise.then(function() {
|
|
var wallet = new Wallet(privateKey, provider);
|
|
return testWriteProvider(test, TestContract.address, wallet);
|
|
});
|
|
});
|
|
|
|
promise.then(function(result) {
|
|
test.done();
|
|
|
|
}, function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
test.done();
|
|
});
|
|
}
|
|
|
|
function testEvents(test) {
|
|
var promises = [];
|
|
getProviders().forEach(function(provider) {
|
|
promises.push(testEventsProvider(test, provider));
|
|
});
|
|
|
|
Promise.all(promises).then(function(result) {
|
|
test.done()
|
|
}, function (error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
test.done()
|
|
});
|
|
|
|
// Send 123 wei to the contrat to trigger its callFallback event
|
|
wallet.send(TestContract.address, 123).then(function(transaction) {
|
|
console.log('Trigger Transaction: ' + transaction.hash);
|
|
});
|
|
}
|
|
|
|
function testContracts(test) {
|
|
var contract = new contracts.Contract(TestContract.address, TestContract.interface, wallet);
|
|
|
|
var newValue = 'Chicken-' + parseInt((new Date()).getTime());
|
|
|
|
Promise.all([
|
|
contract.getUintValue(),
|
|
contract.getArrayValue(0),
|
|
contract.getArrayValue(1),
|
|
contract.getArrayValue(2),
|
|
contract.getBytes32Value(),
|
|
contract.getStringValue(),
|
|
contract.getOwner(),
|
|
contract.getMappingValue('A'),
|
|
contract.getMappingValue('B'),
|
|
contract.getMappingValue('C'),
|
|
contract.getMappingValue('Nothing'),
|
|
contract.getValue(),
|
|
(new Promise(function(resolve, reject) {
|
|
contract.onvaluechanged = function(author, oldValue, newValue) {
|
|
|
|
test.ok(true, 'contract event oncallfa');
|
|
|
|
contract.onvaluechanged = null;
|
|
|
|
resolve({author: author, oldValue: oldValue, newValue: newValue});
|
|
};
|
|
})),
|
|
contract.setValue(newValue),
|
|
]).then(function(results) {
|
|
|
|
test.ok(results[0][0].eq(42), 'getUintValue()');
|
|
test.equal(results[1][0], 'One', 'getArrayValue(1)');
|
|
test.equal(results[2][0], 'Two', 'getArrayValue(2)');
|
|
test.equal(results[3][0], 'Three', 'getArrayValue(3)');
|
|
test.equal(
|
|
utils.hexlify(results[4][0]),
|
|
utils.keccak256(utils.toUtf8Bytes('TheEmptyString')),
|
|
'getBytes32Value()'
|
|
);
|
|
test.equal(results[5][0], 'This is not a string.', 'getStringValue()');
|
|
test.equal(results[6][0], TestContract.owner, 'getOwner()');
|
|
test.equal(results[7][0], 'Apple', 'getMapping(A)');
|
|
test.equal(results[8][0], 'Banana', 'getMapping(B)');
|
|
test.equal(results[9][0], 'Cherry', 'getMapping(C)');
|
|
test.equal(results[10][0], '', 'getMapping(Nothing)');
|
|
|
|
var getValue = results[11][0];
|
|
var onvaluechanged = results[12];
|
|
|
|
test.equal(onvaluechanged.oldValue, getValue, 'getValue()');
|
|
test.equal(onvaluechanged.author, wallet.address, 'onvaluechanged.author');
|
|
test.equal(onvaluechanged.newValue, newValue, 'onvaluechanged.newValue');
|
|
test.done();
|
|
|
|
}, function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'an error occurred');
|
|
});
|
|
}
|
|
|
|
function testDeploy(test) {
|
|
var valueUint = parseInt((new Date()).getTime());
|
|
var valueString = 'HelloWorld-' + valueUint;
|
|
|
|
/*
|
|
var contractInterface = new contracts.Interface(TestContractDeploy.interface);
|
|
var deployInfo = contractInterface.deployFunction(
|
|
TestContractDeploy.bytecode,
|
|
valueUint,
|
|
valueString
|
|
);
|
|
|
|
var transaction = {
|
|
data: deployInfo.bytecode
|
|
};
|
|
*/
|
|
|
|
var transaction = contracts.Contract.getDeployTransaction(
|
|
TestContractDeploy.bytecode,
|
|
TestContractDeploy.interface,
|
|
valueUint,
|
|
valueString
|
|
);
|
|
|
|
var contract = null;
|
|
|
|
wallet.sendTransaction(transaction).then(function(transaction) {
|
|
return provider.waitForTransaction(transaction.hash);
|
|
|
|
}).then(function(transaction) {
|
|
contract = new contracts.Contract(transaction.creates, TestContractDeploy.interface, wallet);
|
|
return contract.getValues();
|
|
|
|
}).then(function(result) {
|
|
test.ok(result[0].eq(valueUint), 'deployed contract - uint equal');
|
|
test.equal(result[1], valueString, 'deployed contract - string equal');
|
|
return provider.getCode(contract.address);
|
|
|
|
}).then(function(code) {
|
|
test.equal(code, TestContractDeploy.runtimeBytecode, 'getCode() == runtimeBytecode (after deploy)');
|
|
return contract.cleanup();
|
|
|
|
}).then(function(transaction) {
|
|
return provider.waitForTransaction(transaction.hash);
|
|
|
|
}).then(function(transaction) {
|
|
return provider.getCode(contract.address);
|
|
|
|
}).then(function(code) {
|
|
test.equal(code, '0x', 'getCode() == null (after suicide)');
|
|
test.done();
|
|
});
|
|
}
|
|
|
|
function testENSProviderReadOnly(test, provider) {
|
|
var promises = [];
|
|
getProviders().forEach(function(provider) {
|
|
promises.push(testReadOnlyProvider(test, 'test.ricmoose.eth', provider));
|
|
});
|
|
|
|
Promise.all(promises).then(function(results) {
|
|
console.log(results);
|
|
test.done();
|
|
}, function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
});
|
|
|
|
/*
|
|
provider.resolveName('anemone.eth').then(function(result) {
|
|
console.log(result);
|
|
test.done();
|
|
});
|
|
*/
|
|
}
|
|
|
|
|
|
function testENSProviderWrite(test, provider) {
|
|
var promise = wallet.getBalance().then(function(balance) {
|
|
if (balance.isZero()) {
|
|
console.log('Plese send some testnet ether to: ' + wallet.address);
|
|
throw new Error('insufficient balance');
|
|
}
|
|
});
|
|
|
|
getProviders().forEach(function(provider) {
|
|
promise = promise.then(function() {
|
|
var wallet = new Wallet(privateKey, provider);
|
|
return testWriteProvider(test, TestContract.address, wallet);
|
|
});
|
|
});
|
|
|
|
promise.then(function(result) {
|
|
test.done();
|
|
|
|
}, function(error) {
|
|
console.log(error);
|
|
test.ok(false, 'error occurred');
|
|
test.done();
|
|
});
|
|
}
|
|
|
|
function testENSReadOnly(test) {
|
|
testENSProviderReadOnly(test, new providers.InfuraProvider(true));
|
|
}
|
|
|
|
function testENSWrite(test) {
|
|
testENSProviderWrite(test, new providers.InfuraProvider(true));
|
|
}
|
|
|
|
function testENS(test) {
|
|
var provider = providers.getDefaultProvider(true);
|
|
provider.resolveName('ricmoose.eth').then(function(address) {
|
|
test.equal('0x5543707cC4520F3984656e8eDEa6527ca474E77B', address, 'Simple ENS name');
|
|
return provider.resolveName('duck.ricmoose.eth');
|
|
}).then(function(address) {
|
|
test.equal('0xf770358c6F29FAA38186E49c149C87968775B228', address, 'Nested ENS name');
|
|
return provider.resolveName('nothing-here.ricmoose.eth');
|
|
}).then(function(address) {
|
|
test.equal(null, address, 'Non-existing ENS name');
|
|
return provider.resolveName('not-valid');
|
|
}).then(function(address) {
|
|
test.equal(null, address, 'Invalid ENS name');
|
|
test.done();
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
'read-only': testReadOnly,
|
|
'write': testWrite,
|
|
'events': testEvents,
|
|
'contracts': testContracts,
|
|
'deploy': testDeploy,
|
|
'ens': testENS,
|
|
'ens-readonly': testENSReadOnly,
|
|
'ens-write': testENSWrite,
|
|
};
|
|
|