From 097ceb86318246cd38839c049d727d39b33d56dd Mon Sep 17 00:00:00 2001 From: Fabian Vogelsteller Date: Tue, 13 Feb 2018 10:16:51 +0100 Subject: [PATCH] fixes #1340, #1341, 1342 --- .jshintrc | 2 +- packages/web3-core-helpers/src/formatters.js | 61 +- packages/web3-core-method/src/index.js | 4 +- packages/web3-eth-accounts/src/index.js | 117 ++-- packages/web3-utils/src/utils.js | 8 +- test/contract.js | 4 +- test/eth.accounts.signTransaction.js | 559 ++++++++++++++----- 7 files changed, 531 insertions(+), 224 deletions(-) diff --git a/.jshintrc b/.jshintrc index f078444d610..8471c8490ca 100644 --- a/.jshintrc +++ b/.jshintrc @@ -5,7 +5,7 @@ "eqeqeq": true, "freeze": true, "funcscope": false, - "maxcomplexity": 10, + "maxcomplexity": 15, "maxdepth": 4, "maxerr": 50, /*"maxlen": 80*/ /*this should be our goal*/ diff --git a/packages/web3-core-helpers/src/formatters.js b/packages/web3-core-helpers/src/formatters.js index 40a4bdbd230..891b8447378 100644 --- a/packages/web3-core-helpers/src/formatters.js +++ b/packages/web3-core-helpers/src/formatters.js @@ -65,20 +65,27 @@ var inputBlockNumberFormatter = function (blockNumber) { /** * Formats the input of a transaction and converts all values to HEX * - * @method inputCallFormatter + * @method _txInputFormatter * @param {Object} transaction options * @returns object -*/ -var inputCallFormatter = function (options){ + */ +var _txInputFormatter = function (options){ - var from = options.from || (this ? this.defaultAccount : null); + if (options.to) { // it might be contract creation + options.to = inputAddressFormatter(options.to); + } - if (from) { - options.from = inputAddressFormatter(from); + if (options.data && options.input) { + throw new Error('You can\'t have "data" and "input" as properties of transactions at the same time, please use either "data" or "input" instead.'); } - if (options.to) { // it might be contract creation - options.to = inputAddressFormatter(options.to); + if (!options.data && options.input) { + options.data = options.input; + delete options.input; + } + + if(options.data && !utils.isHex(options.data)) { + throw new Error('The data field must be HEX encoded data.'); } // allow both @@ -95,6 +102,27 @@ var inputCallFormatter = function (options){ return options; }; +/** + * Formats the input of a transaction and converts all values to HEX + * + * @method inputCallFormatter + * @param {Object} transaction options + * @returns object +*/ +var inputCallFormatter = function (options){ + + options = _txInputFormatter(options); + + var from = options.from || (this ? this.defaultAccount : null); + + if (from) { + options.from = inputAddressFormatter(from); + } + + + return options; +}; + /** * Formats the input of a transaction and converts all values to HEX * @@ -104,6 +132,8 @@ var inputCallFormatter = function (options){ */ var inputTransactionFormatter = function (options) { + options = _txInputFormatter(options); + // check from, only if not number, or object if (!_.isNumber(options.from) && !_.isObject(options.from)) { options.from = options.from || (this ? this.defaultAccount : null); @@ -115,21 +145,6 @@ var inputTransactionFormatter = function (options) { options.from = inputAddressFormatter(options.from); } - if (options.to) { // it might be contract creation - options.to = inputAddressFormatter(options.to); - } - - // allow both - if (options.gas || options.gasLimit) { - options.gas = options.gas || options.gasLimit; - } - - ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { - return options[key] !== undefined; - }).forEach(function(key){ - options[key] = utils.numberToHex(options[key]); - }); - return options; }; diff --git a/packages/web3-core-method/src/index.js b/packages/web3-core-method/src/index.js index 5ed9b209fe3..7dc285cd518 100644 --- a/packages/web3-core-method/src/index.js +++ b/packages/web3-core-method/src/index.js @@ -513,9 +513,7 @@ Method.prototype.buildCall = function() { // If wallet was found, sign tx, and send using sendRawTransaction if (wallet && wallet.privateKey) { - var signature = method.accounts.signTransaction(_.omit(tx, 'from'), wallet.privateKey); - - return (_.isFunction(signature.then)) ? signature.then(sendSignedTx) : sendSignedTx(signature); + return method.accounts.signTransaction(_.omit(tx, 'from'), wallet.privateKey).then(sendSignedTx); } // ETH_SIGN diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 25fed9590e7..95dfac752eb 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -130,61 +130,88 @@ Accounts.prototype.privateKeyToAccount = function privateKeyToAccount(privateKey }; Accounts.prototype.signTransaction = function signTransaction(tx, privateKey, callback) { - var _this = this; + var _this = this, + error = false, + result; + + callback = callback || function () {}; + + if (!tx) { + error = new Error('No transaction object given!'); + + callback(error); + return Promise.reject(error); + } function signed (tx) { if (!tx.gas && !tx.gasLimit) { - throw new Error('"gas" is missing'); + error = new Error('"gas" is missing'); } - var transaction = { - nonce: utils.numberToHex(tx.nonce), - to: tx.to ? helpers.formatters.inputAddressFormatter(tx.to) : '0x', - data: tx.data || '0x', - value: tx.value ? utils.numberToHex(tx.value) : "0x", - gas: utils.numberToHex(tx.gasLimit || tx.gas), - gasPrice: utils.numberToHex(tx.gasPrice), - chainId: utils.numberToHex(tx.chainId) - }; - - var rlpEncoded = RLP.encode([ - Bytes.fromNat(transaction.nonce), - Bytes.fromNat(transaction.gasPrice), - Bytes.fromNat(transaction.gas), - transaction.to.toLowerCase(), - Bytes.fromNat(transaction.value), - transaction.data, - Bytes.fromNat(transaction.chainId || "0x1"), - "0x", - "0x"]); - - var hash = Hash.keccak256(rlpEncoded); - - var signature = Account.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(Hash.keccak256(rlpEncoded), privateKey); - - var rawTx = RLP.decode(rlpEncoded).slice(0, 6).concat(Account.decodeSignature(signature)); - - rawTx[7] = makeEven(trimLeadingZero(rawTx[7])); - rawTx[8] = makeEven(trimLeadingZero(rawTx[8])); - - var rawTransaction = RLP.encode(rawTx); - - var values = RLP.decode(rawTransaction); - var result = { - messageHash: hash, - v: trimLeadingZero(values[6]), - r: trimLeadingZero(values[7]), - s: trimLeadingZero(values[8]), - rawTransaction: rawTransaction - }; - if (_.isFunction(callback)) { - callback(null, result); + if (tx.nonce < 0 || + tx.gas < 0 || + tx.gasPrice < 0 || + tx.chainId < 0) { + error = new Error('Gas, gasPrice, nonce or chainId is lower than 0'); + } + + if (error) { + callback(error); + return Promise.reject(new Error('"gas" is missing')); + } + + try { + tx = helpers.formatters.inputCallFormatter(tx); + + var transaction = tx; + transaction.to = tx.to || '0x'; + transaction.data = tx.data || '0x'; + transaction.value = tx.value || '0x'; + transaction.chainId = utils.numberToHex(tx.chainId); + + var rlpEncoded = RLP.encode([ + Bytes.fromNat(transaction.nonce), + Bytes.fromNat(transaction.gasPrice), + Bytes.fromNat(transaction.gas), + transaction.to.toLowerCase(), + Bytes.fromNat(transaction.value), + transaction.data, + Bytes.fromNat(transaction.chainId || "0x1"), + "0x", + "0x"]); + + + var hash = Hash.keccak256(rlpEncoded); + + var signature = Account.makeSigner(Nat.toNumber(transaction.chainId || "0x1") * 2 + 35)(Hash.keccak256(rlpEncoded), privateKey); + + var rawTx = RLP.decode(rlpEncoded).slice(0, 6).concat(Account.decodeSignature(signature)); + + rawTx[7] = makeEven(trimLeadingZero(rawTx[7])); + rawTx[8] = makeEven(trimLeadingZero(rawTx[8])); + + var rawTransaction = RLP.encode(rawTx); + + var values = RLP.decode(rawTransaction); + result = { + messageHash: hash, + v: trimLeadingZero(values[6]), + r: trimLeadingZero(values[7]), + s: trimLeadingZero(values[8]), + rawTransaction: rawTransaction + }; + + } catch(e) { + callback(e); + return Promise.reject(e); } + + callback(null, result); return result; } - // Returns synchronously if nonce, chainId and price are provided + // Resolve immediately if nonce, chainId and price are provided if (tx.nonce !== undefined && tx.chainId !== undefined && tx.gasPrice !== undefined) { return Promise.resolve(signed(tx)); } diff --git a/packages/web3-utils/src/utils.js b/packages/web3-utils/src/utils.js index a6f176f2bf8..616cce2902b 100644 --- a/packages/web3-utils/src/utils.js +++ b/packages/web3-utils/src/utils.js @@ -256,10 +256,14 @@ var hexToNumberString = function (value) { * @return {String} */ var numberToHex = function (value) { - if (!isFinite(value) && !_.isString(value)) { + if (_.isNull(value) || _.isUndefined(value)) { return value; } + if (!isFinite(value) && !isHexStrict(value)) { + throw new Error('Given input "'+value+'" is not a number.'); + } + var number = toBN(value); var result = number.toString(16); @@ -369,7 +373,7 @@ var isHexStrict = function (hex) { * @returns {Boolean} */ var isHex = function (hex) { - return ((_.isString(hex) || _.isNumber(hex)) && /^(-0x)?(0x)?[0-9a-f]*$/i.test(hex)); + return ((_.isString(hex) || _.isNumber(hex)) && /^(-0x|0x)?[0-9a-f]*$/i.test(hex)); }; diff --git a/test/contract.js b/test/contract.js index 415e67d987a..455230e5074 100644 --- a/test/contract.js +++ b/test/contract.js @@ -2901,9 +2901,7 @@ describe('typical usage', function() { assert.equal(newContract.options.address, address); assert.isTrue(newContract !== contract, 'contract objects shouldn\'t the same'); - setTimeout(function () { - done(); - }, 1); + done(); }); // .on('error', function (value) { // console.log('error', value); diff --git a/test/eth.accounts.signTransaction.js b/test/eth.accounts.signTransaction.js index c39c91951d2..c2ef1728800 100644 --- a/test/eth.accounts.signTransaction.js +++ b/test/eth.accounts.signTransaction.js @@ -124,7 +124,266 @@ var tests = [ // signature from eth_signTransaction rawTransaction: "0xf8708085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd26a031bb05bd1535150d312dcaa870a4a69c130a51aa80537659c1f308bf1f180ac6a012c938a8e04ac4e279d0b7c29811609031a96e949ad98f1ca74ca6078910bede", oldSignature: "0xf8708085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd1ba081bba037015419ab5ce36e930b987da71b0ed5f0efb1849613223bf72399f598a05d2c1f109ad13f98a7693cfc35291e404ea8795755a176eb58a818de44f3756d" - } + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 10, + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8700a85358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a0496e628e8348a24312ded09ee3d99d85b1b8f947725aa382dcf4003b7389d5aaa00c1b1cfdd66c510fd708d33279a1a61e53dff3c6ced67cf7f7b830862d6e2029", + oldSignature: "0xf8700a85358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a0496e628e8348a24312ded09ee3d99d85b1b8f947725aa382dcf4003b7389d5aaa00c1b1cfdd66c510fd708d33279a1a61e53dff3c6ced67cf7f7b830862d6e2029" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: '0xa', + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8700a85358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a0496e628e8348a24312ded09ee3d99d85b1b8f947725aa382dcf4003b7389d5aaa00c1b1cfdd66c510fd708d33279a1a61e53dff3c6ced67cf7f7b830862d6e2029", + oldSignature: "0xf8700a85358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a0496e628e8348a24312ded09ee3d99d85b1b8f947725aa382dcf4003b7389d5aaa00c1b1cfdd66c510fd708d33279a1a61e53dff3c6ced67cf7f7b830862d6e2029" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: '16', + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8701085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a04ba217e16f62ac277698e8853bcc010db07285b457606e9f3487c70ccc5e6508a05c6cfaa17fc1a52bede0cf25c8bd2e024b4fb89ed205f62cb3e177a83654f29d", + oldSignature: "0xf8701085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a04ba217e16f62ac277698e8853bcc010db07285b457606e9f3487c70ccc5e6508a05c6cfaa17fc1a52bede0cf25c8bd2e024b4fb89ed205f62cb3e177a83654f29d" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 16, + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8701085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a04ba217e16f62ac277698e8853bcc010db07285b457606e9f3487c70ccc5e6508a05c6cfaa17fc1a52bede0cf25c8bd2e024b4fb89ed205f62cb3e177a83654f29d", + oldSignature: "0xf8701085358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd25a04ba217e16f62ac277698e8853bcc010db07285b457606e9f3487c70ccc5e6508a05c6cfaa17fc1a52bede0cf25c8bd2e024b4fb89ed205f62cb3e177a83654f29d" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: '0x16', + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8701685358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd26a0e027ec9e9921975678b73de44f7d2cd6b987a6655b9d0291b2cdff15836c6efba051b4e20835793bf0cdf268339111a24d80a4a7bb141e975a66d0edbcc20542d0", + oldSignature: "0xf8701685358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd26a0e027ec9e9921975678b73de44f7d2cd6b987a6655b9d0291b2cdff15836c6efba051b4e20835793bf0cdf268339111a24d80a4a7bb141e975a66d0edbcc20542d0" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: '0x16', + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + input: "0x0123abcd" + }, + // web3.eth.signTransaction({from: "0xEB014f8c8B418Db6b45774c326A0E64C78914dC0", gasPrice: "230000000000", gas: "50000", to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', value: "1000000000000000000", data: "0x0123abcd"}).then(console.log); + // signature from eth_signTransaction + rawTransaction: "0xf8701685358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd26a0e027ec9e9921975678b73de44f7d2cd6b987a6655b9d0291b2cdff15836c6efba051b4e20835793bf0cdf268339111a24d80a4a7bb141e975a66d0edbcc20542d0", + oldSignature: "0xf8701685358d117c0082c35094fcad0b19bb29d4674531d6f115237e16afce377c880de0b6b3a7640000840123abcd26a0e027ec9e9921975678b73de44f7d2cd6b987a6655b9d0291b2cdff15836c6efba051b4e20835793bf0cdf268339111a24d80a4a7bb141e975a66d0edbcc20542d0" + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 2, + gasPrice: "20000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd", + input: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 2, + gasPrice: "0A", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 2, + gasPrice: "200000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "test" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 2, + gasPrice: "A", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 'a', + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: -1, + nonce: 1, + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: -1, + nonce: 0, + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: -2, + gasPrice: "230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 0, + gasPrice: "-230000000000", + gas: 50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, + { + address: '0xEB014f8c8B418Db6b45774c326A0E64C78914dC0', + privateKey: '0xbe6383dad004f233317e46ddb46ad31b16064d14447a95cc1d8c8d4bc61c3728', + transaction: { + chainId: 1, + nonce: 0, + gasPrice: "230000000000", + gas: -50000, + to: '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c', + toIban: 'XE63TIJX31ZHSLZ6F601ZPKVDKKYHMIK03G', // will be switched to "to" in the test + value: "1000000000000000000", + data: "0x0123abcd" + }, + error: true + }, ]; describe("eth", function () { @@ -132,184 +391,190 @@ describe("eth", function () { // For each test tests.forEach(function (test, i) { - it("signTransaction must compare to eth_signTransaction", function(done) { - var ethAccounts = new Accounts(); + if (test.error) { - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + it("signTransaction must error", function(done) { + var ethAccounts = new Accounts(); - testAccount.signTransaction(test.transaction).then(function (tx) { - assert.equal(tx.rawTransaction, test.rawTransaction); - done(); - }); - }); - }); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); - tests.forEach(function (test, i) { - it("signTransaction using the iban as \"to\" must compare to eth_signTransaction", function(done) { - var ethAccounts = new Accounts(); - - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); - - var transaction = clone(test.transaction); - transaction.to = transaction.toIban; - delete transaction.toIban; - testAccount.signTransaction(transaction).then(function (tx) { - assert.equal(tx.rawTransaction, test.rawTransaction); - done(); - }); - }); - }); - - tests.forEach(function (test, i) { - it("signTransaction will call for nonce", function(done) { - var provider = new FakeHttpProvider(); - var web3 = new Web3(provider); - - provider.injectResult('0xa'); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_getTransactionCount'); - assert.deepEqual(payload.params, [test.address, "latest"]); + testAccount.signTransaction(test.transaction).catch(function (err) { + assert.instanceOf(err, Error); + done(); + }); }); - var ethAccounts = new Accounts(web3); + } else { - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + it("signTransaction must compare to eth_signTransaction", function(done) { + var ethAccounts = new Accounts(); - var transaction = clone(test.transaction); - delete transaction.nonce; - testAccount.signTransaction(transaction) - .then(function (tx) { - assert.isObject(tx); - assert.isString(tx.rawTransaction); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); - done(); + testAccount.signTransaction(test.transaction).then(function (tx) { + assert.equal(tx.rawTransaction, test.rawTransaction); + done(); + }); }); - }); - }); - tests.forEach(function (test, i) { - it("signTransaction will call for gasPrice", function(done) { - var provider = new FakeHttpProvider(); - var web3 = new Web3(provider); - - provider.injectResult('0x5022'); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_gasPrice'); - assert.deepEqual(payload.params, []); + + it("signTransaction using the iban as \"to\" must compare to eth_signTransaction", function(done) { + var ethAccounts = new Accounts(); + + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); + + var transaction = clone(test.transaction); + transaction.to = transaction.toIban; + delete transaction.toIban; + testAccount.signTransaction(transaction).then(function (tx) { + assert.equal(tx.rawTransaction, test.rawTransaction); + done(); + }); }); - var ethAccounts = new Accounts(web3); + it("signTransaction will call for nonce", function(done) { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + provider.injectResult('0xa'); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getTransactionCount'); + assert.deepEqual(payload.params, [test.address, "latest"]); + }); - var transaction = clone(test.transaction); - delete transaction.gasPrice; - testAccount.signTransaction(transaction) - .then(function (tx) { - assert.isObject(tx); - assert.isString(tx.rawTransaction); + var ethAccounts = new Accounts(web3); - done(); - }); - }); - }); - tests.forEach(function (test, i) { - it("signTransaction will call for chainId", function(done) { - var provider = new FakeHttpProvider(); - var web3 = new Web3(provider); - - provider.injectResult(1); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'net_version'); - assert.deepEqual(payload.params, []); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); + + var transaction = clone(test.transaction); + delete transaction.nonce; + testAccount.signTransaction(transaction) + .then(function (tx) { + assert.isObject(tx); + assert.isString(tx.rawTransaction); + + done(); + }); }); - var ethAccounts = new Accounts(web3); + it("signTransaction will call for gasPrice", function(done) { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + provider.injectResult('0x5022'); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_gasPrice'); + assert.deepEqual(payload.params, []); + }); - var transaction = clone(test.transaction); - delete transaction.chainId; - testAccount.signTransaction(transaction) - .then(function (tx) { - assert.isObject(tx); - assert.isString(tx.rawTransaction); + var ethAccounts = new Accounts(web3); - done(); - }); - }); - }); - tests.forEach(function (test, i) { - it("signTransaction will call for nonce, gasPrice and chainId", function(done) { - var provider = new FakeHttpProvider(); - var web3 = new Web3(provider); - - provider.injectResult(1); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'net_version'); - assert.deepEqual(payload.params, []); - }); - provider.injectResult(1); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_gasPrice'); - assert.deepEqual(payload.params, []); - }); - provider.injectResult(1); - provider.injectValidation(function (payload) { - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'eth_getTransactionCount'); - assert.deepEqual(payload.params, [test.address, "latest"]); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); + + var transaction = clone(test.transaction); + delete transaction.gasPrice; + testAccount.signTransaction(transaction) + .then(function (tx) { + assert.isObject(tx); + assert.isString(tx.rawTransaction); + + done(); + }); }); - var ethAccounts = new Accounts(web3); + it("signTransaction will call for chainId", function(done) { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'net_version'); + assert.deepEqual(payload.params, []); + }); + + var ethAccounts = new Accounts(web3); - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); - var transaction = clone(test.transaction); - delete transaction.chainId; - delete transaction.gasPrice; - delete transaction.nonce; - testAccount.signTransaction(transaction) - .then(function (tx) { - assert.isObject(tx); - assert.isString(tx.rawTransaction); + var transaction = clone(test.transaction); + delete transaction.chainId; + testAccount.signTransaction(transaction) + .then(function (tx) { + assert.isObject(tx); + assert.isString(tx.rawTransaction); - done(); + done(); + }); }); - }); - }); - tests.forEach(function (test, i) { - it("recoverTransaction, must recover signature", function() { - var ethAccounts = new Accounts(); + it("signTransaction will call for nonce, gasPrice and chainId", function(done) { + var provider = new FakeHttpProvider(); + var web3 = new Web3(provider); + + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'net_version'); + assert.deepEqual(payload.params, []); + }); + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_gasPrice'); + assert.deepEqual(payload.params, []); + }); + provider.injectResult(1); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, 'eth_getTransactionCount'); + assert.deepEqual(payload.params, [test.address, "latest"]); + }); + + var ethAccounts = new Accounts(web3); + + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); + + var transaction = clone(test.transaction); + delete transaction.chainId; + delete transaction.gasPrice; + delete transaction.nonce; + testAccount.signTransaction(transaction) + .then(function (tx) { + assert.isObject(tx); + assert.isString(tx.rawTransaction); + + done(); + }); + }); + + it("recoverTransaction, must recover signature", function() { + var ethAccounts = new Accounts(); - var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); - assert.equal(testAccount.address, test.address); + var testAccount = ethAccounts.privateKeyToAccount(test.privateKey); + assert.equal(testAccount.address, test.address); - testAccount.signTransaction(test.transaction).then(function (tx) { - assert.equal(ethAccounts.recoverTransaction(tx.rawTransaction), test.address); + testAccount.signTransaction(test.transaction).then(function (tx) { + assert.equal(ethAccounts.recoverTransaction(tx.rawTransaction), test.address); + }); }); - }); - }); - tests.forEach(function (test, i) { - it("recoverTransaction, must also recover old signature from eth-signer", function() { - var ethAccounts = new Accounts(); + it("recoverTransaction, must also recover old signature from eth-signer", function() { + var ethAccounts = new Accounts(); - var oldSignature = ethjsSigner.sign(test.transaction, test.privateKey); + var oldSignature = ethjsSigner.sign(test.transaction, test.privateKey); - assert.equal(ethAccounts.recoverTransaction(oldSignature), test.address); - }); + assert.equal(ethAccounts.recoverTransaction(oldSignature), test.address); + }); + } }); }); });