From b0b4d4229b3b80fea0623afc1a729d19c837fded Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sun, 10 Feb 2019 19:57:27 +0100 Subject: [PATCH 01/71] web3 socket provider types fixed in web3-providers module --- packages/web3-providers/types/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web3-providers/types/index.d.ts b/packages/web3-providers/types/index.d.ts index fa4d9a97536..5f211574ef4 100644 --- a/packages/web3-providers/types/index.d.ts +++ b/packages/web3-providers/types/index.d.ts @@ -77,7 +77,7 @@ export class AbstractSocketProvider { sendBatch(methods: AbstractMethod[], moduleInstance: AbstractWeb3Module): Promise; - subscribe(subscribeMethod: string, subscriptionMethod: string, parameters: []): Promise; + subscribe(subscribeMethod: string, subscriptionMethod: string, parameters: any[]): Promise; unsubscribe(subscriptionId: string, unsubscribeMethod: string): Promise; @@ -116,7 +116,7 @@ export class EthereumProvider { sendBatch(methods: AbstractMethod[], moduleInstance: AbstractWeb3Module): Promise; - subscribe(subscribeMethod: string, subscriptionMethod: string, parameters: []): Promise; + subscribe(subscribeMethod: string, subscriptionMethod: string, parameters: any[]): Promise; unsubscribe(subscriptionId: string, unsubscribeMethod: string): Promise; From 6c7cbfe1f97ffb5a6c4a5afd661ac41591a823c8 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sun, 10 Feb 2019 20:51:39 +0100 Subject: [PATCH 02/71] POC eth-accounts module refactoring --- packages/web3-eth-accounts/src/Account.js | 41 ++ packages/web3-eth-accounts/src/Accounts.js | 487 ++---------------- packages/web3-eth-accounts/src/Wallet.js | 291 +++++++++++ .../src/factories/AccountsModuleFactory.js | 30 ++ .../src/signers/TransactionSigner.js | 106 ++++ 5 files changed, 512 insertions(+), 443 deletions(-) create mode 100644 packages/web3-eth-accounts/src/Account.js create mode 100644 packages/web3-eth-accounts/src/Wallet.js create mode 100644 packages/web3-eth-accounts/src/signers/TransactionSigner.js diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js new file mode 100644 index 00000000000..0e735cdd217 --- /dev/null +++ b/packages/web3-eth-accounts/src/Account.js @@ -0,0 +1,41 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ + + +/** + * @file Account.js + * @author Samuel Furter + * @date 2019 + */ + +export default class Account { + + constructor(accountOptions, accounts) { + this.address = accountOptions.address; + this.privateKey = accountOptions.privateKey; + this.accountsModule = accounts; + } + + signTransaction(tx, callback) { + return this.accountsModule.signTransaction(tx, this.privateKey, callback); + } + + sign(data) { + return this.accountsModule.sign(data, this.privateKey); + } + + encrypt(password, options) { + return this.accountsModule.encrypt(this.privateKey, password, options); + } +} diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index dc8dd904f2a..73475f53a3f 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -20,43 +20,17 @@ * @date 2017 */ -import isUndefined from 'lodash/isUndefined'; -import isNull from 'lodash/isNull'; import isObject from 'lodash/isObject'; import isBoolean from 'lodash/isBoolean'; import isString from 'lodash/isString'; -import has from 'lodash/has'; -import extend from 'lodash/extend'; import Account from 'eth-lib/lib/account'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; -import Nat from 'eth-lib/lib/nat'; import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import uuid from 'uuid'; import {AbstractWeb3Module} from 'web3-core'; -const cryp = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); - -const isNot = (value) => { - return isUndefined(value) || isNull(value); -}; - -const trimLeadingZero = (hex) => { - while (hex && hex.startsWith('0x0')) { - hex = `0x${hex.slice(3)}`; - } - return hex; -}; - -const makeEven = (hex) => { - if (hex.length % 2 === 1) { - hex = hex.replace('0x', '0x0'); - } - - return hex; -}; - export default class Accounts extends AbstractWeb3Module { /** * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider @@ -65,42 +39,20 @@ export default class Accounts extends AbstractWeb3Module { * @param {MethodFactory} methodFactory * @param {Utils} utils * @param {Object} formatters + * @param {AccountsModuleFactory} accountsModuleFactory * @param {Object} options * * @constructor */ - constructor(provider, providersModuleFactory, methodModuleFactory, methodFactory, utils, formatters, options) { + constructor(provider, providersModuleFactory, methodModuleFactory, methodFactory, utils, formatters, accountsModuleFactory, crypto, transactionOptionsValidator, options) { super(provider, providersModuleFactory, methodModuleFactory, methodFactory, options); this.utils = utils; this.formatters = formatters; - this.wallet = new Wallet(this); - } - - /** - * Adds the account functions to the given object - * - * @method _addAccountFunctions - * - * @param {Object} account - * - * @returns {Object} - */ - _addAccountFunctions(account) { - // add sign functions - account.signTransaction = (tx, callback) => { - return this.signTransaction(tx, account.privateKey, callback).bind(this); - }; - - account.sign = (data) => { - return this.sign(data, account.privateKey); - }; - - account.encrypt = (password, options) => { - return this.encrypt(account.privateKey, password, options); - }; - - return account; + this.accountsModuleFactory = accountsModuleFactory; + this.wallet = this.accountsModuleFactory.createWallet(this); + this.crypto = crypto; + this.transactionOptionsValidator = transactionOptionsValidator; } /** @@ -110,10 +62,10 @@ export default class Accounts extends AbstractWeb3Module { * * @param {String} entropy * - * @returns {Object} + * @returns {Account} */ create(entropy) { - return this._addAccountFunctions(Account.create(entropy || this.utils.randomHex(32))); + return this.accountsModuleFactory.createAccount(Account.create(entropy || this.utils.randomHex(32)), this); } /** @@ -123,10 +75,10 @@ export default class Accounts extends AbstractWeb3Module { * * @param {String} privateKey * - * @returns {Object} + * @returns {Account} */ privateKeyToAccount(privateKey) { - return this._addAccountFunctions(Account.fromPrivate(privateKey)); + return this.accountsModuleFactory.createAccount(Account.fromPrivate(privateKey), this); } /** @@ -141,109 +93,38 @@ export default class Accounts extends AbstractWeb3Module { * @callback callback callback(error, result) * @returns {Promise} */ - signTransaction(tx, privateKey, callback) { - const _this = this; - let error = false; - let result; - - callback = callback || (() => {}); - - if (!tx) { - error = new Error('No transaction object given!'); - - callback(error); - return Promise.reject(error); + async signTransaction(tx, privateKey, callback) { + if (this.isUndefinedOrNull(tx.chainId)) { + tx.chainId = await this.getId(); } - - function signed(tx) { - if (!tx.gas && !tx.gasLimit) { - error = new Error('gas is missing'); - } - - 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(error); - } - - try { - tx = _this.formatters.inputCallFormatter(tx, _this); - - const transaction = tx; - transaction.to = tx.to || '0x'; - transaction.data = tx.data || '0x'; - transaction.value = tx.value || '0x'; - transaction.chainId = _this.utils.numberToHex(tx.chainId); - - const 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' - ]); - - const hash = Hash.keccak256(rlpEncoded); - - const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || '0x1') * 2 + 35)( - Hash.keccak256(rlpEncoded), - privateKey - ); - - const rawTx = RLP.decode(rlpEncoded) - .slice(0, 6) - .concat(Account.decodeSignature(signature)); - - rawTx[6] = makeEven(trimLeadingZero(rawTx[6])); - rawTx[7] = makeEven(trimLeadingZero(rawTx[7])); - rawTx[8] = makeEven(trimLeadingZero(rawTx[8])); - - const rawTransaction = RLP.encode(rawTx); - - const values = RLP.decode(rawTransaction); - result = { - messageHash: hash, - v: trimLeadingZero(values[6]), - r: trimLeadingZero(values[7]), - s: trimLeadingZero(values[8]), - rawTransaction - }; - } catch (error) { - callback(error); - return Promise.reject(error); - } - - callback(null, result); - - return result; + if (this.isUndefinedOrNull(tx.nonce)) { + tx.nonce = await this.getTransactionCount(this.privateKeyToAccount(privateKey).address); } + if (this.isUndefinedOrNull(tx.gasPrice)) { + tx.gasPrice = await this.getGasPrice(); + } + + const validationResult = this.transactionOptionsValidator.validate(tx); - // Resolve immediately if nonce, chainId and price are provided - if (tx.nonce !== undefined && tx.chainId !== undefined && tx.gasPrice !== undefined) { - return Promise.resolve(signed(tx)); + if (validationResult instanceof Error) { + callback(validationResult); + throw validationResult; } - // Otherwise, get the missing info from the Ethereum Node - return Promise.all([ - isNot(tx.chainId) ? _this.getId() : tx.chainId, - isNot(tx.gasPrice) ? _this.getGasPrice() : tx.gasPrice, - isNot(tx.nonce) ? _this.getTransactionCount(_this.privateKeyToAccount(privateKey).address) : tx.nonce - ]).then((args) => { - if (isNot(args[0]) || isNot(args[1]) || isNot(args[2])) { - throw new Error( - `One of the values 'chainId', 'gasPrice', or 'nonce' couldn't be fetched: ${JSON.stringify(args)}` - ); - } + return this.transactionSigner.sign(tx); + } - return signed(extend(tx, {chainId: args[0], gasPrice: args[1], nonce: args[2]})); - }); + /** + * Checks if the value is not undefined or null + * + * @method isNotUndefinedOrNull + * + * @param {any} value + * + * @returns {Boolean} + */ + isUndefinedOrNull(value) { + return (typeof value === 'undefined' && value === null); } /** @@ -353,7 +234,7 @@ export default class Accounts extends AbstractWeb3Module { * @param {String} password * @param {Boolean} nonStrict * - * @returns {Object} + * @returns {Account} */ decrypt(v3Keystore, password, nonStrict) { if (!isString(password)) { @@ -387,7 +268,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Unsupported parameters to PBKDF2'); } - derivedKey = cryp.pbkdf2Sync( + derivedKey = this.crypto.pbkdf2Sync( Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.c, @@ -405,7 +286,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Key derivation failed - possibly wrong password'); } - const decipher = cryp.createDecipheriv( + const decipher = this.crypto.createDecipheriv( json.crypto.cipher, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipherparams.iv, 'hex') @@ -430,8 +311,8 @@ export default class Accounts extends AbstractWeb3Module { const account = this.privateKeyToAccount(privateKey); options = options || {}; - const salt = options.salt || cryp.randomBytes(32); - const iv = options.iv || cryp.randomBytes(16); + const salt = options.salt || this.crypto.randomBytes(32); + const iv = options.iv || this.crypto.randomBytes(16); let derivedKey; const kdf = options.kdf || 'scrypt'; @@ -443,7 +324,7 @@ export default class Accounts extends AbstractWeb3Module { if (kdf === 'pbkdf2') { kdfparams.c = options.c || 262144; kdfparams.prf = 'hmac-sha256'; - derivedKey = cryp.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); + derivedKey = this.crypto.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); } else if (kdf === 'scrypt') { // FIXME: support progress reporting callback kdfparams.n = options.n || 8192; // 2048 4096 8192 16384 @@ -454,7 +335,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Unsupported kdf'); } - const cipher = cryp.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); + const cipher = this.crypto.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); if (!cipher) { throw new Error('Unsupported cipher'); } @@ -470,7 +351,7 @@ export default class Accounts extends AbstractWeb3Module { return { version: 3, - id: uuid.v4({random: options.uuid || cryp.randomBytes(16)}), + id: uuid.v4({random: options.uuid || this.crypto.randomBytes(16)}), address: account.address.toLowerCase().replace('0x', ''), crypto: { ciphertext: ciphertext.toString('hex'), @@ -485,283 +366,3 @@ export default class Accounts extends AbstractWeb3Module { }; } } - -// Note: this is trying to follow closely the specs on -// http://web3js.readthedocs.io/en/1.0/web3-eth-accounts.html - -/** - * @param {Object} accounts - * - * @constructor - */ -class Wallet { - constructor(accounts) { - this._accounts = accounts; - this.length = 0; - this.defaultKeyName = 'web3js_wallet'; - } - - /** - * Finds the safe index - * - * @method _findSafeIndex - * @private - * - * @param {Number} pointer - * - * @returns {*} - */ - _findSafeIndex(pointer = 0) { - if (has(this, pointer)) { - return this._findSafeIndex(pointer + 1); - } else { - return pointer; - } - } - - /** - * Gets the correntIndexes array - * - * @method _currentIndexes - * @private - * - * @returns {Number[]} - */ - _currentIndexes() { - const keys = Object.keys(this); - const indexes = keys - .map((key) => { - return parseInt(key); - }) - .filter((n) => { - return n < 9e20; - }); - - return indexes; - } - - /** - * Creates new accounts with a given entropy - * - * @method create - * - * @param {Number} numberOfAccounts - * @param {String} entropy - * - * @returns {Wallet} - */ - create(numberOfAccounts, entropy) { - for (let i = 0; i < numberOfAccounts; ++i) { - this.add(this._accounts.create(entropy).privateKey); - } - return this; - } - - /** - * Adds a account to the wallet - * - * @method add - * - * @param {Object} account - * - * @returns {Object} - */ - add(account) { - if (isString(account)) { - account = this._accounts.privateKeyToAccount(account); - } - if (!this[account.address]) { - account = this._accounts.privateKeyToAccount(account.privateKey); - account.index = this._findSafeIndex(); - - this[account.index] = account; - this[account.address] = account; - this[account.address.toLowerCase()] = account; - - this.length++; - - return account; - } else { - return this[account.address]; - } - } - - /** - * Removes a account from the number by his address or index - * - * @method remove - * - * @param {String|Number} addressOrIndex - * - * @returns {boolean} - */ - remove(addressOrIndex) { - const account = this[addressOrIndex]; - - if (account && account.address) { - // address - this[account.address].privateKey = null; - delete this[account.address]; - // address lowercase - this[account.address.toLowerCase()].privateKey = null; - delete this[account.address.toLowerCase()]; - // index - this[account.index].privateKey = null; - delete this[account.index]; - - this.length--; - - return true; - } else { - return false; - } - } - - /** - * Clears the wallet - * - * @method clear - * - * @returns {Wallet} - */ - clear() { - const _this = this; - const indexes = this._currentIndexes(); - - indexes.forEach((index) => { - _this.remove(index); - }); - - return this; - } - - /** - * Encrypts all accounts - * - * @method encrypt - * - * @param {String} password - * @param {Object} options - * - * @returns {any[]} - */ - encrypt(password, options) { - const _this = this; - const indexes = this._currentIndexes(); - - const accounts = indexes.map((index) => { - return _this[index].encrypt(password, options); - }); - - return accounts; - } - - /** - * Decrypts all accounts - * - * @method decrypt - * - * @param {Wallet} encryptedWallet - * @param {String} password - * - * @returns {Wallet} - */ - decrypt(encryptedWallet, password) { - const _this = this; - - encryptedWallet.forEach((keystore) => { - const account = _this._accounts.decrypt(keystore, password); - - if (account) { - _this.add(account); - } else { - throw new Error("Couldn't decrypt accounts. Password wrong?"); - } - }); - - return this; - } - - /** - * Saves the current wallet in the localStorage of the browser - * - * @method save - * - * @param {String} password - * @param {String} keyName - * - * @returns {boolean} - */ - save(password, keyName) { - try { - localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encrypt(password))); - } catch (error) { - // code 18 means trying to use local storage in a iframe - // with third party cookies turned off - // we still want to support using web3 in a iframe - // as by default safari turn these off for all iframes - // so mask the error - if (error.code === 18) { - return true; - } else { - // throw as normal if not - throw new Error(error); - } - } - - return true; - } - - /** - * Loads the stored wallet by his keyName from the localStorage of the browser - * - * @method load - * - * @param {String} password - * @param {String} keyName - * - * @returns {Wallet} - */ - load(password, keyName) { - let keystore; - try { - keystore = localStorage.getItem(keyName || this.defaultKeyName); - - if (keystore) { - try { - keystore = JSON.parse(keystore); - } catch (error) {} - } - } catch (error) { - // code 18 means trying to use local storage in a iframe - // with third party cookies turned off - // we still want to support using web3 in a iframe - // as by default safari turn these off for all iframes - // so mask the error - if (error.code === 18) { - keystore = this.defaultKeyName; - } else { - // throw as normal if not - throw new Error(error); - } - } - - return this.decrypt(keystore || [], password); - } -} - -try { - if (typeof localStorage === 'undefined') { - delete Wallet.prototype.save; - delete Wallet.prototype.load; - } -} catch (error) { - // code 18 means trying to use local storage in a iframe - // with third party cookies turned off - // we still want to support using web3 in a iframe - // as by default safari turn these off for all iframes - // so mask the error - if (error.code !== 18) { - throw new Error(error); - } -} diff --git a/packages/web3-eth-accounts/src/Wallet.js b/packages/web3-eth-accounts/src/Wallet.js new file mode 100644 index 00000000000..328947ae303 --- /dev/null +++ b/packages/web3-eth-accounts/src/Wallet.js @@ -0,0 +1,291 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** + * @file Wallet.js + * @author Samuel Furter + * @date 2019 + */ + +import has from 'lodash/has'; +import isString from 'lodash/isString'; + +class Wallet { + /** + * @param {Accounts} accounts + * + * @constructor + */ + constructor(accounts) { + this._accounts = accounts; + this.length = 0; + this.defaultKeyName = 'web3js_wallet'; + } + + /** + * Finds the safe index + * + * @method _findSafeIndex + * @private + * + * @param {Number} pointer + * + * @returns {*} + */ + _findSafeIndex(pointer = 0) { + if (has(this, pointer)) { + return this._findSafeIndex(pointer + 1); + } else { + return pointer; + } + } + + /** + * Gets the correntIndexes array + * + * @method _currentIndexes + * @private + * + * @returns {Number[]} + */ + _currentIndexes() { + const keys = Object.keys(this); + const indexes = keys + .map((key) => { + return parseInt(key); + }) + .filter((n) => { + return n < 9e20; + }); + + return indexes; + } + + /** + * Creates new accounts with a given entropy + * + * @method create + * + * @param {Number} numberOfAccounts + * @param {String} entropy + * + * @returns {Wallet} + */ + create(numberOfAccounts, entropy) { + for (let i = 0; i < numberOfAccounts; ++i) { + this.add(this._accounts.create(entropy).privateKey); + } + return this; + } + + /** + * Adds a account to the wallet + * + * @method add + * + * @param {Object} account + * + * @returns {Object} + */ + add(account) { + if (isString(account)) { + account = this._accounts.privateKeyToAccount(account); + } + if (!this[account.address]) { + account = this._accounts.privateKeyToAccount(account.privateKey); + account.index = this._findSafeIndex(); + + this[account.index] = account; + this[account.address] = account; + this[account.address.toLowerCase()] = account; + + this.length++; + + return account; + } else { + return this[account.address]; + } + } + + /** + * Removes a account from the number by his address or index + * + * @method remove + * + * @param {String|Number} addressOrIndex + * + * @returns {boolean} + */ + remove(addressOrIndex) { + const account = this[addressOrIndex]; + + if (account && account.address) { + // address + this[account.address].privateKey = null; + delete this[account.address]; + // address lowercase + this[account.address.toLowerCase()].privateKey = null; + delete this[account.address.toLowerCase()]; + // index + this[account.index].privateKey = null; + delete this[account.index]; + + this.length--; + + return true; + } else { + return false; + } + } + + /** + * Clears the wallet + * + * @method clear + * + * @returns {Wallet} + */ + clear() { + const _this = this; + const indexes = this._currentIndexes(); + + indexes.forEach((index) => { + _this.remove(index); + }); + + return this; + } + + /** + * Encrypts all accounts + * + * @method encrypt + * + * @param {String} password + * @param {Object} options + * + * @returns {any[]} + */ + encrypt(password, options) { + const _this = this; + const indexes = this._currentIndexes(); + + const accounts = indexes.map((index) => { + return _this[index].encrypt(password, options); + }); + + return accounts; + } + + /** + * Decrypts all accounts + * + * @method decrypt + * + * @param {Wallet} encryptedWallet + * @param {String} password + * + * @returns {Wallet} + */ + decrypt(encryptedWallet, password) { + const _this = this; + + encryptedWallet.forEach((keystore) => { + const account = _this._accounts.decrypt(keystore, password); + + if (account) { + _this.add(account); + } else { + throw new Error('Couldn\'t decrypt accounts. Password wrong?'); + } + }); + + return this; + } + + /** + * Saves the current wallet in the localStorage of the browser + * + * @method save + * + * @param {String} password + * @param {String} keyName + * + * @returns {boolean} + */ + save(password, keyName) { + if (typeof localStorage === 'undefined') { + throw new Error('window.localStorage is undefined.') + } + + try { + localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encrypt(password))); + } catch (error) { + // code 18 means trying to use local storage in a iframe + // with third party cookies turned off + // we still want to support using web3 in a iframe + // as by default safari turn these off for all iframes + // so mask the error + if (error.code === 18) { + return true; + } else { + // throw as normal if not + throw new Error(error); + } + } + + return true; + } + + /** + * Loads the stored wallet by his keyName from the localStorage of the browser + * + * @method load + * + * @param {String} password + * @param {String} keyName + * + * @returns {Wallet} + */ + load(password, keyName) { + if (typeof localStorage === 'undefined') { + throw new Error('window.localStorage is undefined.') + } + + let keystore; + try { + keystore = localStorage.getItem(keyName || this.defaultKeyName); + + if (keystore) { + try { + keystore = JSON.parse(keystore); + } catch (error) { + } + } + } catch (error) { + // code 18 means trying to use local storage in a iframe + // with third party cookies turned off + // we still want to support using web3 in a iframe + // as by default safari turn these off for all iframes + // so mask the error + if (error.code === 18) { + keystore = this.defaultKeyName; + } else { + // throw as normal if not + throw new Error(error); + } + } + + return this.decrypt(keystore || [], password); + } +} diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index c251ec5c410..9bc71c99e2b 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -22,6 +22,8 @@ import MethodFactory from './MethodFactory'; import Accounts from '../Accounts'; +import Account from '../Account'; +import Wallet from '../Wallet'; export default class AccountsModuleFactory { /** @@ -53,10 +55,38 @@ export default class AccountsModuleFactory { this.createMethodFactory(methodModuleFactory), this.utils, this.formatters, + // const cryp = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); options ); } + /** + * Returns an object of type Wallet + * + * @method createWallet + * + * @param {Accounts} accounts + * + * @returns {Wallet} + */ + createWallet(accounts) { + return new Wallet(accounts); + } + + /** + * Returns an object of type Account + * + * @method createAccount + * + * @param {object} accountOptions + * @param {Accounts} accounts + * + * @returns {Account} + */ + createAccount(accountOptions, accounts) { + return new Account(accountOptions, accounts) + } + /** * Returns an object of type MethodFactory * diff --git a/packages/web3-eth-accounts/src/signers/TransactionSigner.js b/packages/web3-eth-accounts/src/signers/TransactionSigner.js new file mode 100644 index 00000000000..b1d9f129f98 --- /dev/null +++ b/packages/web3-eth-accounts/src/signers/TransactionSigner.js @@ -0,0 +1,106 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +import Nat from 'eth-lib/lib/nat'; +import Bytes from 'eth-lib/lib/bytes'; +import Hash from 'eth-lib/lib/hash'; +import RLP from 'eth-lib/lib/rlp'; +import Account from 'eth-lib/lib/account'; + +/** + * @file TransactionSigner.js + * @author Samuel Furter + * @date 2019 + */ +export default class TransactionSigner { + + constructor(formatters, utils) { + this.formatters = formatters; + this.utils = utils; + } + + sign(tx, moduleInstance, callback) { + let result; + + try { + tx = this.formatters.inputCallFormatter(tx, moduleInstance); + + const transaction = tx; + transaction.to = tx.to || '0x'; + transaction.data = tx.data || '0x'; + transaction.value = tx.value || '0x'; + transaction.chainId = this.utils.numberToHex(tx.chainId); + + const 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' + ]); + + const hash = Hash.keccak256(rlpEncoded); + + const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || '0x1') * 2 + 35)( + Hash.keccak256(rlpEncoded), + privateKey + ); + + const rawTx = RLP.decode(rlpEncoded) + .slice(0, 6) + .concat(Account.decodeSignature(signature)); + + rawTx[6] = this.makeEven(this.trimLeadingZero(rawTx[6])); + rawTx[7] = this.makeEven(this.trimLeadingZero(rawTx[7])); + rawTx[8] = this.makeEven(this.trimLeadingZero(rawTx[8])); + + const rawTransaction = RLP.encode(rawTx); + + const values = RLP.decode(rawTransaction); + result = { + messageHash: hash, + v: this.trimLeadingZero(values[6]), + r: this.trimLeadingZero(values[7]), + s: this.trimLeadingZero(values[8]), + rawTransaction + }; + } catch (error) { + callback(error); + return Promise.reject(error); + } + + callback(null, result); + + return result; + } + + + trimLeadingZero(hex) { + while (hex && hex.startsWith('0x0')) { + hex = `0x${hex.slice(3)}`; + } + return hex; + } + + makeEven(hex) { + if (hex.length % 2 === 1) { + hex = hex.replace('0x', '0x0'); + } + + return hex; + } +} From bb5f07ee762e1cee12c0d117dfe8aa0abada302e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sun, 10 Feb 2019 23:54:32 +0100 Subject: [PATCH 03/71] eth-accounts module simplified and TransactionSigner moved to eth module --- packages/web3-eth-accounts/src/Accounts.js | 64 +++----- packages/web3-eth-accounts/src/Wallet.js | 72 ++++---- .../src/factories/AccountsModuleFactory.js | 1 - .../src/factories/MethodFactory.js | 42 ----- .../src/signers/TransactionSigner.js | 106 ------------ packages/web3-eth/src/Eth.js | 25 +++ .../src/factories/EthModuleFactory.js | 14 ++ .../web3-eth/src/factories/MethodFactory.js | 6 +- .../web3-eth/src/signers/TransactionSigner.js | 154 ++++++++++++++++++ 9 files changed, 249 insertions(+), 235 deletions(-) delete mode 100644 packages/web3-eth-accounts/src/factories/MethodFactory.js delete mode 100644 packages/web3-eth-accounts/src/signers/TransactionSigner.js create mode 100644 packages/web3-eth/src/signers/TransactionSigner.js diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 73475f53a3f..00de692992b 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -30,13 +30,12 @@ import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import uuid from 'uuid'; import {AbstractWeb3Module} from 'web3-core'; +const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); // TODO: This should moved later to the factory method export default class Accounts extends AbstractWeb3Module { /** * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider * @param {ProvidersModuleFactory} providersModuleFactory - * @param {MethodModuleFactory} methodModuleFactory - * @param {MethodFactory} methodFactory * @param {Utils} utils * @param {Object} formatters * @param {AccountsModuleFactory} accountsModuleFactory @@ -44,15 +43,14 @@ export default class Accounts extends AbstractWeb3Module { * * @constructor */ - constructor(provider, providersModuleFactory, methodModuleFactory, methodFactory, utils, formatters, accountsModuleFactory, crypto, transactionOptionsValidator, options) { - super(provider, providersModuleFactory, methodModuleFactory, methodFactory, options); + constructor(provider, providersModuleFactory, utils, formatters, accountsModuleFactory, transactionSigner, options) { + super(provider, providersModuleFactory, null, null, options); this.utils = utils; this.formatters = formatters; this.accountsModuleFactory = accountsModuleFactory; this.wallet = this.accountsModuleFactory.createWallet(this); - this.crypto = crypto; - this.transactionOptionsValidator = transactionOptionsValidator; + this.transactionSigner = transactionSigner; } /** @@ -81,6 +79,7 @@ export default class Accounts extends AbstractWeb3Module { return this.accountsModuleFactory.createAccount(Account.fromPrivate(privateKey), this); } + /** * Signs a transaction object with the given privateKey * @@ -94,37 +93,22 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Promise} */ async signTransaction(tx, privateKey, callback) { - if (this.isUndefinedOrNull(tx.chainId)) { - tx.chainId = await this.getId(); - } - if (this.isUndefinedOrNull(tx.nonce)) { - tx.nonce = await this.getTransactionCount(this.privateKeyToAccount(privateKey).address); - } - if (this.isUndefinedOrNull(tx.gasPrice)) { - tx.gasPrice = await this.getGasPrice(); - } - - const validationResult = this.transactionOptionsValidator.validate(tx); + try { + const transaction = new Transaction(tx); + const signedTransaction = await this.transactionSigner.sign(transaction, privateKey); + } catch (error) { + if (isFunction(callback)) { + callback(error, null); + } - if (validationResult instanceof Error) { - callback(validationResult); - throw validationResult; + throw error; } - return this.transactionSigner.sign(tx); - } + if (isFunction(callback)) { + callback(false, signedTransaction); + } - /** - * Checks if the value is not undefined or null - * - * @method isNotUndefinedOrNull - * - * @param {any} value - * - * @returns {Boolean} - */ - isUndefinedOrNull(value) { - return (typeof value === 'undefined' && value === null); + return signedTransaction; } /** @@ -268,7 +252,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Unsupported parameters to PBKDF2'); } - derivedKey = this.crypto.pbkdf2Sync( + derivedKey = crypto.pbkdf2Sync( Buffer.from(password), Buffer.from(kdfparams.salt, 'hex'), kdfparams.c, @@ -286,7 +270,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Key derivation failed - possibly wrong password'); } - const decipher = this.crypto.createDecipheriv( + const decipher = crypto.createDecipheriv( json.crypto.cipher, derivedKey.slice(0, 16), Buffer.from(json.crypto.cipherparams.iv, 'hex') @@ -311,8 +295,8 @@ export default class Accounts extends AbstractWeb3Module { const account = this.privateKeyToAccount(privateKey); options = options || {}; - const salt = options.salt || this.crypto.randomBytes(32); - const iv = options.iv || this.crypto.randomBytes(16); + const salt = options.salt || crypto.randomBytes(32); + const iv = options.iv || crypto.randomBytes(16); let derivedKey; const kdf = options.kdf || 'scrypt'; @@ -324,7 +308,7 @@ export default class Accounts extends AbstractWeb3Module { if (kdf === 'pbkdf2') { kdfparams.c = options.c || 262144; kdfparams.prf = 'hmac-sha256'; - derivedKey = this.crypto.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); + derivedKey = crypto.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); } else if (kdf === 'scrypt') { // FIXME: support progress reporting callback kdfparams.n = options.n || 8192; // 2048 4096 8192 16384 @@ -335,7 +319,7 @@ export default class Accounts extends AbstractWeb3Module { throw new Error('Unsupported kdf'); } - const cipher = this.crypto.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); + const cipher = crypto.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); if (!cipher) { throw new Error('Unsupported cipher'); } @@ -351,7 +335,7 @@ export default class Accounts extends AbstractWeb3Module { return { version: 3, - id: uuid.v4({random: options.uuid || this.crypto.randomBytes(16)}), + id: uuid.v4({random: options.uuid || crypto.randomBytes(16)}), address: account.address.toLowerCase().replace('0x', ''), crypto: { ciphertext: ciphertext.toString('hex'), diff --git a/packages/web3-eth-accounts/src/Wallet.js b/packages/web3-eth-accounts/src/Wallet.js index 328947ae303..7127a229398 100644 --- a/packages/web3-eth-accounts/src/Wallet.js +++ b/packages/web3-eth-accounts/src/Wallet.js @@ -13,7 +13,7 @@ */ /** * @file Wallet.js - * @author Samuel Furter + * @author Samuel Furter , Fabian Vogelsteller * @date 2019 */ @@ -45,9 +45,9 @@ class Wallet { _findSafeIndex(pointer = 0) { if (has(this, pointer)) { return this._findSafeIndex(pointer + 1); - } else { - return pointer; } + + return pointer; } /** @@ -59,16 +59,11 @@ class Wallet { * @returns {Number[]} */ _currentIndexes() { - const keys = Object.keys(this); - const indexes = keys - .map((key) => { - return parseInt(key); - }) - .filter((n) => { - return n < 9e20; - }); - - return indexes; + return Object.keys(this).map((key) => { + return parseInt(key); + }).filter((n) => { + return n < 9e20; + }); } /** @@ -85,6 +80,7 @@ class Wallet { for (let i = 0; i < numberOfAccounts; ++i) { this.add(this._accounts.create(entropy).privateKey); } + return this; } @@ -101,6 +97,7 @@ class Wallet { if (isString(account)) { account = this._accounts.privateKeyToAccount(account); } + if (!this[account.address]) { account = this._accounts.privateKeyToAccount(account.privateKey); account.index = this._findSafeIndex(); @@ -112,9 +109,9 @@ class Wallet { this.length++; return account; - } else { - return this[account.address]; } + + return this[account.address]; } /** @@ -143,9 +140,9 @@ class Wallet { this.length--; return true; - } else { - return false; } + + return false; } /** @@ -156,11 +153,8 @@ class Wallet { * @returns {Wallet} */ clear() { - const _this = this; - const indexes = this._currentIndexes(); - - indexes.forEach((index) => { - _this.remove(index); + this._currentIndexes().forEach((index) => { + this.remove(index); }); return this; @@ -177,14 +171,9 @@ class Wallet { * @returns {any[]} */ encrypt(password, options) { - const _this = this; - const indexes = this._currentIndexes(); - - const accounts = indexes.map((index) => { - return _this[index].encrypt(password, options); + return this._currentIndexes().map((index) => { + return this[index].encrypt(password, options); }); - - return accounts; } /** @@ -198,16 +187,14 @@ class Wallet { * @returns {Wallet} */ decrypt(encryptedWallet, password) { - const _this = this; - encryptedWallet.forEach((keystore) => { - const account = _this._accounts.decrypt(keystore, password); + const account = this._accounts.decrypt(keystore, password); - if (account) { - _this.add(account); - } else { + if (!account) { throw new Error('Couldn\'t decrypt accounts. Password wrong?'); } + + this.add(account); }); return this; @@ -225,7 +212,7 @@ class Wallet { */ save(password, keyName) { if (typeof localStorage === 'undefined') { - throw new Error('window.localStorage is undefined.') + throw new Error('window.localStorage is undefined.'); } try { @@ -238,10 +225,10 @@ class Wallet { // so mask the error if (error.code === 18) { return true; - } else { - // throw as normal if not - throw new Error(error); } + + // throw as normal if not + throw new Error(error); } return true; @@ -259,7 +246,7 @@ class Wallet { */ load(password, keyName) { if (typeof localStorage === 'undefined') { - throw new Error('window.localStorage is undefined.') + throw new Error('window.localStorage is undefined.'); } let keystore; @@ -267,10 +254,7 @@ class Wallet { keystore = localStorage.getItem(keyName || this.defaultKeyName); if (keystore) { - try { - keystore = JSON.parse(keystore); - } catch (error) { - } + keystore = JSON.parse(keystore); } } catch (error) { // code 18 means trying to use local storage in a iframe diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 9bc71c99e2b..86e534a8ce3 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -20,7 +20,6 @@ * @date 2018 */ -import MethodFactory from './MethodFactory'; import Accounts from '../Accounts'; import Account from '../Account'; import Wallet from '../Wallet'; diff --git a/packages/web3-eth-accounts/src/factories/MethodFactory.js b/packages/web3-eth-accounts/src/factories/MethodFactory.js deleted file mode 100644 index 9696af2e8ab..00000000000 --- a/packages/web3-eth-accounts/src/factories/MethodFactory.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file MethodFactory.js - * @author Samuel Furter - * @date 2018 - */ - -import {AbstractMethodFactory, GetGasPriceMethod, GetTransactionCountMethod, VersionMethod} from 'web3-core-method'; - -export default class MethodFactory extends AbstractMethodFactory { - /** - * @param {MethodModuleFactory} methodModuleFactory - * @param {Utils} utils - * @param {Object} formatters - * - * @constructor - */ - constructor(methodModuleFactory, utils, formatters) { - super(methodModuleFactory, utils, formatters); - - this.methods = { - getGasPrice: GetGasPriceMethod, - getTransactionCount: GetTransactionCountMethod, - getId: VersionMethod - }; - } -} diff --git a/packages/web3-eth-accounts/src/signers/TransactionSigner.js b/packages/web3-eth-accounts/src/signers/TransactionSigner.js deleted file mode 100644 index b1d9f129f98..00000000000 --- a/packages/web3-eth-accounts/src/signers/TransactionSigner.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - This file is part of web3.js. - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -import Nat from 'eth-lib/lib/nat'; -import Bytes from 'eth-lib/lib/bytes'; -import Hash from 'eth-lib/lib/hash'; -import RLP from 'eth-lib/lib/rlp'; -import Account from 'eth-lib/lib/account'; - -/** - * @file TransactionSigner.js - * @author Samuel Furter - * @date 2019 - */ -export default class TransactionSigner { - - constructor(formatters, utils) { - this.formatters = formatters; - this.utils = utils; - } - - sign(tx, moduleInstance, callback) { - let result; - - try { - tx = this.formatters.inputCallFormatter(tx, moduleInstance); - - const transaction = tx; - transaction.to = tx.to || '0x'; - transaction.data = tx.data || '0x'; - transaction.value = tx.value || '0x'; - transaction.chainId = this.utils.numberToHex(tx.chainId); - - const 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' - ]); - - const hash = Hash.keccak256(rlpEncoded); - - const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || '0x1') * 2 + 35)( - Hash.keccak256(rlpEncoded), - privateKey - ); - - const rawTx = RLP.decode(rlpEncoded) - .slice(0, 6) - .concat(Account.decodeSignature(signature)); - - rawTx[6] = this.makeEven(this.trimLeadingZero(rawTx[6])); - rawTx[7] = this.makeEven(this.trimLeadingZero(rawTx[7])); - rawTx[8] = this.makeEven(this.trimLeadingZero(rawTx[8])); - - const rawTransaction = RLP.encode(rawTx); - - const values = RLP.decode(rawTransaction); - result = { - messageHash: hash, - v: this.trimLeadingZero(values[6]), - r: this.trimLeadingZero(values[7]), - s: this.trimLeadingZero(values[8]), - rawTransaction - }; - } catch (error) { - callback(error); - return Promise.reject(error); - } - - callback(null, result); - - return result; - } - - - trimLeadingZero(hex) { - while (hex && hex.startsWith('0x0')) { - hex = `0x${hex.slice(3)}`; - } - return hex; - } - - makeEven(hex) { - if (hex.length % 2 === 1) { - hex = hex.replace('0x', '0x0'); - } - - return hex; - } -} diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index 79c9fe6f9b9..705e61a9cc0 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -58,6 +58,7 @@ export default class Eth extends AbstractWeb3Module { formatters, subscriptionsFactory, contractModuleFactory, + transactionSigner, options ) { super(provider, providersModuleFactory, methodModuleFactory, methodFactory, options); @@ -73,6 +74,7 @@ export default class Eth extends AbstractWeb3Module { this.subscriptionsFactory = subscriptionsFactory; this.contractModuleFactory = contractModuleFactory; this.initiatedContracts = []; + this._transactionSigner = options.transactionSigner || transactionSigner; /** * This wrapper function is required for the "new web3.eth.Contract(...)" call. @@ -101,6 +103,29 @@ export default class Eth extends AbstractWeb3Module { }; } + /** + * Getter for the transactionSigner property + * + * @property transactionSigner + * + * @returns {TransactionSigner} + */ + get transactionSigner() { + return this._transactionSigner; + } + + /** + * Setter for the transactionSigner property + * + * @property transactionSigner + * + * @param {TransactionSigner} signer + */ + set transactionSigner(signer) { + this._transactionSigner = signer; + this.accounts.transactionSigner = signer; + } + /** * Clears all subscriptions and listeners * diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js index 0d1ca2ed65e..de2226406e7 100644 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ b/packages/web3-eth/src/factories/EthModuleFactory.js @@ -22,6 +22,7 @@ import MethodFactory from './MethodFactory'; import Eth from '../Eth'; +import {GetGasPriceMethod} from '../../../web3-core-method/types'; export default class EthModuleFactory { /** @@ -103,4 +104,17 @@ export default class EthModuleFactory { createMethodFactory() { return new MethodFactory(this.methodModuleFactory, this.utils, this.formatters); } + + + createGetGasPriceMethod() { + return new GetGasPriceMethod(this.utils, this.formatters); + } + + createGetTransactionCountMethod() { + return new GetTransactionCountMethod(this.utils, this.formatters); + } + + createVersionMethod() { + return new VersionMethod(this.utils, this.formatters); + } } diff --git a/packages/web3-eth/src/factories/MethodFactory.js b/packages/web3-eth/src/factories/MethodFactory.js index 1d8180590d0..987656ea385 100644 --- a/packages/web3-eth/src/factories/MethodFactory.js +++ b/packages/web3-eth/src/factories/MethodFactory.js @@ -51,7 +51,8 @@ import { SubmitWorkMethod, GetWorkMethod, GetPastLogsMethod, - RequestAccountsMethod + RequestAccountsMethod, + VersionMethod } from 'web3-core-method'; export default class MethodFactory extends AbstractMethodFactory { @@ -95,7 +96,8 @@ export default class MethodFactory extends AbstractMethodFactory { submitWork: SubmitWorkMethod, getWork: GetWorkMethod, getPastLogs: GetPastLogsMethod, - requestAccounts: RequestAccountsMethod + requestAccounts: RequestAccountsMethod, + getId: VersionMethod }; } } diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js new file mode 100644 index 00000000000..3e1d869ede6 --- /dev/null +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -0,0 +1,154 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +import Nat from 'eth-lib/lib/nat'; +import Bytes from 'eth-lib/lib/bytes'; +import Hash from 'eth-lib/lib/hash'; +import RLP from 'eth-lib/lib/rlp'; +import Account from 'eth-lib/lib/account'; + +/** + * @file TransactionSigner.js + * @author Samuel Furter , Fabian Vogelsteller + * @date 2019 + */ +export default class TransactionSigner { + /** + * @param {object} formatters + * @param {Utils} utils + * + * @constructor + */ + constructor(formatters, utils) { + this.formatters = formatters; + this.utils = utils; + } + + /** + * Signs the transaction + * + * @param {object} tx + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Promise} + */ + async sign(tx, moduleInstance) { + let result; + + if (this.isUndefinedOrNull(tx.chainId)) { + tx.chainId = await moduleInstance.getId(); + } + if (this.isUndefinedOrNull(tx.nonce)) { + tx.nonce = await moduleInstance.getTransactionCount(tx.from); + } + if (this.isUndefinedOrNull(tx.gasPrice)) { + tx.gasPrice = await moduleInstance.getGasPrice(); + } + + tx = this.formatters.inputCallFormatter(tx, moduleInstance); + + const transaction = tx; + transaction.to = tx.to || '0x'; + transaction.data = tx.data || '0x'; + transaction.value = tx.value || '0x'; + transaction.chainId = this.utils.numberToHex(tx.chainId); + + const 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' + ]); + + const hash = Hash.keccak256(rlpEncoded); + + const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || '0x1') * 2 + 35)( + Hash.keccak256(rlpEncoded), + privateKey + ); + + const rawTx = RLP.decode(rlpEncoded) + .slice(0, 6) + .concat(Account.decodeSignature(signature)); + + rawTx[6] = this.makeEven(this.trimLeadingZero(rawTx[6])); + rawTx[7] = this.makeEven(this.trimLeadingZero(rawTx[7])); + rawTx[8] = this.makeEven(this.trimLeadingZero(rawTx[8])); + + const rawTransaction = RLP.encode(rawTx); + + const values = RLP.decode(rawTransaction); + result = { + messageHash: hash, + v: this.trimLeadingZero(values[6]), + r: this.trimLeadingZero(values[7]), + s: this.trimLeadingZero(values[8]), + rawTransaction + }; + + return result; + } + + + /** + * Removes the zeros until no zero follows after '0x' + * + * @method trimLeadingZero + * + * @param {String} hex + * + * @returns {String} + */ + trimLeadingZero(hex) { + while (hex && hex.startsWith('0x0')) { + hex = `0x${hex.slice(3)}`; + } + + return hex; + } + + /** + * Maps the hex string starting with '0x' to an even string with adding an additional zero after '0x' if it isn't. + * + * @method makeEven + * + * @param {String} hex + * + * @returns {String} + */ + makeEven(hex) { + if (hex.length % 2 === 1) { + hex = hex.replace('0x', '0x0'); + } + + return hex; + } + + /** + * Checks if the value is not undefined or null + * + * @method isNotUndefinedOrNull + * + * @param {any} value + * + * @returns {Boolean} + */ + isUndefinedOrNull(value) { + return (typeof value === 'undefined' && value === null); + } +} From dff64f0a201571f79d117b5cc33b7f30d9fa45c0 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 11 Feb 2019 01:55:37 +0100 Subject: [PATCH 04/71] eth-accounts module simplified and SendTransactionMethod handlin in core-method module updated. Anything is still in a POC phase --- .../lib/factories/AbstractMethodFactory.js | 2 - .../src/factories/ModuleFactory.js | 12 +- .../transaction/SendTransactionMethod.js | 12 +- .../src/signers/TransactionSigner.js | 1 - packages/web3-eth-accounts/src/Account.js | 150 +++++++++++++++++- packages/web3-eth-accounts/src/Accounts.js | 131 ++------------- packages/web3-eth-accounts/src/Wallet.js | 11 +- .../web3-eth/src/signers/TransactionSigner.js | 7 +- 8 files changed, 174 insertions(+), 152 deletions(-) diff --git a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js index ae72713ee9c..bac3c4fb4d7 100644 --- a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js +++ b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js @@ -109,8 +109,6 @@ export default class AbstractMethodFactory { this.utils, this.formatters, this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.accounts, - this.methodModuleFactory.createTransactionSigner() ); /* eslint-enable new-cap */ } diff --git a/packages/web3-core-method/src/factories/ModuleFactory.js b/packages/web3-core-method/src/factories/ModuleFactory.js index fff82e7d672..f355c815f23 100644 --- a/packages/web3-core-method/src/factories/ModuleFactory.js +++ b/packages/web3-core-method/src/factories/ModuleFactory.js @@ -58,17 +58,6 @@ export default class ModuleFactory { return new MethodProxy(target, methodFactory); } - /** - * Returns the TransactionSigner object - * - * @method createTransactionSigner - * - * @returns {TransactionSigner} - */ - createTransactionSigner() { - return new TransactionSigner(this.accounts); - } - /** * Returns the MessageSigner object * @@ -96,6 +85,7 @@ export default class ModuleFactory { } /** + * TODO: Create TransactionReceipt object e.g.: "TransactionReceipt.from(response)" * Returns the TransactionReceiptValidator object * * @method createTransactionReceiptValidator diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 5c628b442ac..2323e3d21bb 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -28,15 +28,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {Utils} utils * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {Accounts} accounts - * @param {TransactionSigner} transactionSigner * * @constructor */ - constructor(utils, formatters, transactionConfirmationWorkflow, accounts, transactionSigner) { + constructor(utils, formatters, transactionConfirmationWorkflow) { super('eth_sendTransaction', 1, utils, formatters, transactionConfirmationWorkflow); - this.accounts = accounts; - this.transactionSigner = transactionSigner; } /** @@ -81,11 +77,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { return promiEvent; } - if (this.hasWallets()) { + if (moduleInstance.transactionSigner.client) {// TODO: Find a better name for having a boolean to check if the transaction should be signed locally or not. this.rpcMethod = 'eth_sendRawTransaction'; - this.transactionSigner - .sign(this.parameters[0]) + moduleInstance.transactionSigner + .sign(this.parameters[0])) .then((response) => { this.parameters = [response.rawTransaction]; super.execute(moduleInstance, promiEvent); diff --git a/packages/web3-core-method/src/signers/TransactionSigner.js b/packages/web3-core-method/src/signers/TransactionSigner.js index e934fcfc4d0..fe796dff832 100644 --- a/packages/web3-core-method/src/signers/TransactionSigner.js +++ b/packages/web3-core-method/src/signers/TransactionSigner.js @@ -45,7 +45,6 @@ export default class TransactionSigner extends AbstractSigner { const wallet = this.getWallet(transaction.from); if (wallet && wallet.privateKey) { - delete transaction.from; try { return await this.accounts.signTransaction(transaction, wallet.privateKey); } catch (error) { diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js index 0e735cdd217..52aba005e5f 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/Account.js @@ -13,6 +13,12 @@ */ +import scryptsy from 'scrypt.js'; +import isString from 'lodash/isString'; +import isObject from 'lodash/isObject'; +import {Account as EthAccount} from 'eth-lib/lib/account'; +import uuid from 'uuid'; + /** * @file Account.js * @author Samuel Furter @@ -21,8 +27,8 @@ export default class Account { - constructor(accountOptions, accounts) { - this.address = accountOptions.address; + constructor(accountOptions) { + this.address = accountOptions.address; // TODO: Add address validation here (if enough time create a Address VO) this.privateKey = accountOptions.privateKey; this.accountsModule = accounts; } @@ -32,10 +38,148 @@ export default class Account { } sign(data) { - return this.accountsModule.sign(data, this.privateKey); + return Account.sign(hash, this.privateKey); } encrypt(password, options) { return this.accountsModule.encrypt(this.privateKey, password, options); } + + static from(entropy) { + return new Account(EthAccount.create(entropy || this.utils.randomHex(32))); + } + + static fromPrivateKey(privateKey) { + return new Account(EthAccount.fromPrivate(privateKey)); + } + + toV3Keystore(password, options) { + options = options || {}; + const salt = options.salt || crypto.randomBytes(32); + const iv = options.iv || crypto.randomBytes(16); + + let derivedKey; + const kdf = options.kdf || 'scrypt'; + const kdfparams = { + dklen: options.dklen || 32, + salt: salt.toString('hex') + }; + + if (kdf === 'pbkdf2') { + kdfparams.c = options.c || 262144; + kdfparams.prf = 'hmac-sha256'; + derivedKey = crypto.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); + } else if (kdf === 'scrypt') { + // FIXME: support progress reporting callback + kdfparams.n = options.n || 8192; // 2048 4096 8192 16384 + kdfparams.r = options.r || 8; + kdfparams.p = options.p || 1; + derivedKey = scryptsy(Buffer.from(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); + } else { + throw new Error('Unsupported kdf'); + } + + const cipher = crypto.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); + if (!cipher) { + throw new Error('Unsupported cipher'); + } + + const ciphertext = Buffer.concat([ + cipher.update(Buffer.from(this.privateKey.replace('0x', ''), 'hex')), + cipher.final() + ]); + + const mac = this.utils + .sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])) + .replace('0x', ''); + + return { + version: 3, + id: uuid.v4({random: options.uuid || crypto.randomBytes(16)}), + address: this.address.toLowerCase().replace('0x', ''), + crypto: { + ciphertext: ciphertext.toString('hex'), + cipherparams: { + iv: iv.toString('hex') + }, + cipher: options.cipher || 'aes-128-ctr', + kdf, + kdfparams, + mac: mac.toString('hex') + } + }; + } + + /** + * Decrypts account + * + * Note: Taken from https://github.com/ethereumjs/ethereumjs-wallet + * + * @method decrypt + * + * @param {Object|String} v3Keystore + * @param {String} password + * @param {Boolean} nonStrict + * + * @returns {Account} + */ + static fromV3Keystore(v3Keystore, password, nonStrict) { + if (!isString(password)) { + throw new Error('No password given.'); + } + + const json = isObject(v3Keystore) ? v3Keystore : JSON.parse(nonStrict ? v3Keystore.toLowerCase() : v3Keystore); + + if (json.version !== 3) { + throw new Error('Not a valid V3 wallet'); + } + + let derivedKey; + let kdfparams; + if (json.crypto.kdf === 'scrypt') { + kdfparams = json.crypto.kdfparams; + + // FIXME: support progress reporting callback + derivedKey = scryptsy( + Buffer.from(password), + Buffer.from(kdfparams.salt, 'hex'), + kdfparams.n, + kdfparams.r, + kdfparams.p, + kdfparams.dklen + ); + } else if (json.crypto.kdf === 'pbkdf2') { + kdfparams = json.crypto.kdfparams; + + if (kdfparams.prf !== 'hmac-sha256') { + throw new Error('Unsupported parameters to PBKDF2'); + } + + derivedKey = crypto.pbkdf2Sync( + Buffer.from(password), + Buffer.from(kdfparams.salt, 'hex'), + kdfparams.c, + kdfparams.dklen, + 'sha256' + ); + } else { + throw new Error('Unsupported key derivation scheme'); + } + + const ciphertext = Buffer.from(json.crypto.ciphertext, 'hex'); + + const mac = this.utils.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', ''); + if (mac !== json.crypto.mac) { + throw new Error('Key derivation failed - possibly wrong password'); + } + + const decipher = crypto.createDecipheriv( + json.crypto.cipher, + derivedKey.slice(0, 16), + Buffer.from(json.crypto.cipherparams.iv, 'hex') + ); + const seed = `0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`; + + return this.fromPrivateKey(seed); + } } diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 00de692992b..c02caaf469b 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -23,7 +23,6 @@ import isObject from 'lodash/isObject'; import isBoolean from 'lodash/isBoolean'; import isString from 'lodash/isString'; -import Account from 'eth-lib/lib/account'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; @@ -63,7 +62,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Account} */ create(entropy) { - return this.accountsModuleFactory.createAccount(Account.create(entropy || this.utils.randomHex(32)), this); + return Account.from(entropy); } /** @@ -76,11 +75,13 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Account} */ privateKeyToAccount(privateKey) { - return this.accountsModuleFactory.createAccount(Account.fromPrivate(privateKey), this); + return Account.fromPrivateKey(privateKey)); } /** + * TODO: Add deprecation message and extend the signTransaction method in the eth module + * * Signs a transaction object with the given privateKey * * @method signTransaction @@ -93,6 +94,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Promise} */ async signTransaction(tx, privateKey, callback) { + try { const transaction = new Transaction(tx); const signedTransaction = await this.transactionSigner.sign(transaction, privateKey); @@ -162,8 +164,8 @@ export default class Accounts extends AbstractWeb3Module { */ sign(data, privateKey) { const hash = this.hashMessage(data); - const signature = Account.sign(hash, privateKey); - const vrs = Account.decodeSignature(signature); + const account = Account.fromPrivateKey(privateKey); + const vrs = account.decodeSignature(account.sign(hash)); return { message: data, @@ -176,7 +178,7 @@ export default class Accounts extends AbstractWeb3Module { } /** - * Recovers + * Recovers the Ethereum address which was used to sign the given data. * * @method recover * @@ -184,7 +186,7 @@ export default class Accounts extends AbstractWeb3Module { * @param {String} signature * @param {Boolean} preFixed * - * @returns {*} + * @returns {String} */ recover(message, signature, preFixed) { const args = [].slice.apply(arguments); @@ -221,63 +223,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Account} */ decrypt(v3Keystore, password, nonStrict) { - if (!isString(password)) { - throw new Error('No password given.'); - } - - const json = isObject(v3Keystore) ? v3Keystore : JSON.parse(nonStrict ? v3Keystore.toLowerCase() : v3Keystore); - - if (json.version !== 3) { - throw new Error('Not a valid V3 wallet'); - } - - let derivedKey; - let kdfparams; - if (json.crypto.kdf === 'scrypt') { - kdfparams = json.crypto.kdfparams; - - // FIXME: support progress reporting callback - derivedKey = scryptsy( - Buffer.from(password), - Buffer.from(kdfparams.salt, 'hex'), - kdfparams.n, - kdfparams.r, - kdfparams.p, - kdfparams.dklen - ); - } else if (json.crypto.kdf === 'pbkdf2') { - kdfparams = json.crypto.kdfparams; - - if (kdfparams.prf !== 'hmac-sha256') { - throw new Error('Unsupported parameters to PBKDF2'); - } - - derivedKey = crypto.pbkdf2Sync( - Buffer.from(password), - Buffer.from(kdfparams.salt, 'hex'), - kdfparams.c, - kdfparams.dklen, - 'sha256' - ); - } else { - throw new Error('Unsupported key derivation scheme'); - } - - const ciphertext = Buffer.from(json.crypto.ciphertext, 'hex'); - - const mac = this.utils.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', ''); - if (mac !== json.crypto.mac) { - throw new Error('Key derivation failed - possibly wrong password'); - } - - const decipher = crypto.createDecipheriv( - json.crypto.cipher, - derivedKey.slice(0, 16), - Buffer.from(json.crypto.cipherparams.iv, 'hex') - ); - const seed = `0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`; - - return this.privateKeyToAccount(seed); + return Account.fromV3Keystore(v3Keystore, password, nonStrict); } /** @@ -292,61 +238,6 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Object} */ encrypt(privateKey, password, options) { - const account = this.privateKeyToAccount(privateKey); - - options = options || {}; - const salt = options.salt || crypto.randomBytes(32); - const iv = options.iv || crypto.randomBytes(16); - - let derivedKey; - const kdf = options.kdf || 'scrypt'; - const kdfparams = { - dklen: options.dklen || 32, - salt: salt.toString('hex') - }; - - if (kdf === 'pbkdf2') { - kdfparams.c = options.c || 262144; - kdfparams.prf = 'hmac-sha256'; - derivedKey = crypto.pbkdf2Sync(Buffer.from(password), salt, kdfparams.c, kdfparams.dklen, 'sha256'); - } else if (kdf === 'scrypt') { - // FIXME: support progress reporting callback - kdfparams.n = options.n || 8192; // 2048 4096 8192 16384 - kdfparams.r = options.r || 8; - kdfparams.p = options.p || 1; - derivedKey = scryptsy(Buffer.from(password), salt, kdfparams.n, kdfparams.r, kdfparams.p, kdfparams.dklen); - } else { - throw new Error('Unsupported kdf'); - } - - const cipher = crypto.createCipheriv(options.cipher || 'aes-128-ctr', derivedKey.slice(0, 16), iv); - if (!cipher) { - throw new Error('Unsupported cipher'); - } - - const ciphertext = Buffer.concat([ - cipher.update(Buffer.from(account.privateKey.replace('0x', ''), 'hex')), - cipher.final() - ]); - - const mac = this.utils - .sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])) - .replace('0x', ''); - - return { - version: 3, - id: uuid.v4({random: options.uuid || crypto.randomBytes(16)}), - address: account.address.toLowerCase().replace('0x', ''), - crypto: { - ciphertext: ciphertext.toString('hex'), - cipherparams: { - iv: iv.toString('hex') - }, - cipher: options.cipher || 'aes-128-ctr', - kdf, - kdfparams, - mac: mac.toString('hex') - } - }; + return Account.fromPrivateKey(privateKey).toV3Keystore(password, option) } } diff --git a/packages/web3-eth-accounts/src/Wallet.js b/packages/web3-eth-accounts/src/Wallet.js index 7127a229398..7a2f8aad9bd 100644 --- a/packages/web3-eth-accounts/src/Wallet.js +++ b/packages/web3-eth-accounts/src/Wallet.js @@ -26,8 +26,8 @@ class Wallet { * * @constructor */ - constructor(accounts) { - this._accounts = accounts; + constructor(accountsModuleFacotry, utils) { + this.utils = utils; this.length = 0; this.defaultKeyName = 'web3js_wallet'; } @@ -77,8 +77,10 @@ class Wallet { * @returns {Wallet} */ create(numberOfAccounts, entropy) { + const account = Account.from(entropy || this.utils.randomHex(32))); + for (let i = 0; i < numberOfAccounts; ++i) { - this.add(this._accounts.create(entropy).privateKey); + this.add(account.privateKey); } return this; @@ -95,11 +97,10 @@ class Wallet { */ add(account) { if (isString(account)) { - account = this._accounts.privateKeyToAccount(account); + account = Account.fromPrivateKey(account); } if (!this[account.address]) { - account = this._accounts.privateKeyToAccount(account.privateKey); account.index = this._findSafeIndex(); this[account.index] = account; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 3e1d869ede6..77c05a6cd68 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -29,21 +29,23 @@ export default class TransactionSigner { * * @constructor */ - constructor(formatters, utils) { + constructor(formatters, utils, accounts) { this.formatters = formatters; this.utils = utils; + this.accounts = accounts; } /** * Signs the transaction * - * @param {object} tx + * @param {Transaction} tx * @param {AbstractWeb3Module} moduleInstance * * @returns {Promise} */ async sign(tx, moduleInstance) { let result; + const privateKey = this.accounts.wallet[from]; if (this.isUndefinedOrNull(tx.chainId)) { tx.chainId = await moduleInstance.getId(); @@ -55,6 +57,7 @@ export default class TransactionSigner { tx.gasPrice = await moduleInstance.getGasPrice(); } + // delete tx.from; tx = this.formatters.inputCallFormatter(tx, moduleInstance); const transaction = tx; From bb3c21cab2208eddd9bcc56339e07b7e89b5f7ed Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 18 Feb 2019 17:40:08 +0100 Subject: [PATCH 05/71] eth_chainId method implemented --- .../src/methods/network/ChainIdMethod.js | 48 +++++++++++++++++++ .../src/methods/network/ChainIdMethodTest.js | 37 ++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 packages/web3-core-method/src/methods/network/ChainIdMethod.js create mode 100644 packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js diff --git a/packages/web3-core-method/src/methods/network/ChainIdMethod.js b/packages/web3-core-method/src/methods/network/ChainIdMethod.js new file mode 100644 index 00000000000..d2a972defbe --- /dev/null +++ b/packages/web3-core-method/src/methods/network/ChainIdMethod.js @@ -0,0 +1,48 @@ +/* + This file is part of web3.js. + + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** + * @file ListeningMethod.js + * @author Samuel Furter + * @date 2018 + */ + +import AbstractCallMethod from '../../../lib/methods/AbstractCallMethod'; + +export default class ChainIdMethod extends AbstractCallMethod { + /** + * @param {Utils} utils + * @param {Object} formatters + * + * @constructor + */ + constructor(utils, formatters) { + super('eth_chainId', 0, utils, formatters); + } + + /** + * This method will be executed after the RPC request. + * + * @method afterExecution + * + * @param {Object} response + * + * @returns {Number} + */ + afterExecution(response) { + return this.utils.hexToNumber(response); + } +} diff --git a/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js b/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js new file mode 100644 index 00000000000..8787b47c36b --- /dev/null +++ b/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js @@ -0,0 +1,37 @@ +import * as Utils from 'web3-utils'; +import AbstractCallMethod from '../../../../lib/methods/AbstractCallMethod'; +import ChainIdMethod from '../../../../src/methods/network/ChainIdMethod'; + +// Mocks +jest.mock('Utils'); + +/** + * PeerCountMethod test + */ +describe('PeerCountMethodTest', () => { + let method; + + beforeEach(() => { + method = new ChainIdMethod(Utils, null); + }); + + it('constructor check', () => { + expect(method).toBeInstanceOf(AbstractCallMethod); + + expect(method.rpcMethod).toEqual('eth_chainId'); + + expect(method.parametersAmount).toEqual(0); + + expect(method.utils).toEqual(Utils); + + expect(method.formatters).toEqual(null); + }); + + it('afterExecution should map the response', () => { + Utils.hexToNumber.mockReturnValueOnce(61); + + expect(method.afterExecution('0x0')).toEqual(61); + + expect(Utils.hexToNumber).toHaveBeenCalledWith('0x0'); + }); +}); From d98cef205047c100f49229550c0acc109be7d8b3 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 18 Feb 2019 17:48:13 +0100 Subject: [PATCH 06/71] MethodFactory and TransactionSigner updated with ChainIdMethod in the eth module --- packages/web3-eth/src/factories/MethodFactory.js | 6 ++++-- packages/web3-eth/src/signers/TransactionSigner.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/web3-eth/src/factories/MethodFactory.js b/packages/web3-eth/src/factories/MethodFactory.js index 987656ea385..7021652f126 100644 --- a/packages/web3-eth/src/factories/MethodFactory.js +++ b/packages/web3-eth/src/factories/MethodFactory.js @@ -52,7 +52,8 @@ import { GetWorkMethod, GetPastLogsMethod, RequestAccountsMethod, - VersionMethod + VersionMethod, + ChainIdMethod } from 'web3-core-method'; export default class MethodFactory extends AbstractMethodFactory { @@ -97,7 +98,8 @@ export default class MethodFactory extends AbstractMethodFactory { getWork: GetWorkMethod, getPastLogs: GetPastLogsMethod, requestAccounts: RequestAccountsMethod, - getId: VersionMethod + getId: VersionMethod, + getChainId: ChainIdMethod }; } } diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 77c05a6cd68..d10c18d9b70 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -48,7 +48,7 @@ export default class TransactionSigner { const privateKey = this.accounts.wallet[from]; if (this.isUndefinedOrNull(tx.chainId)) { - tx.chainId = await moduleInstance.getId(); + tx.chainId = await moduleInstance.getChainId(); } if (this.isUndefinedOrNull(tx.nonce)) { tx.nonce = await moduleInstance.getTransactionCount(tx.from); From 4b174ed5a682ff29f34debf4264a452ec154250e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 19 Feb 2019 13:13:26 +0100 Subject: [PATCH 07/71] AllEventsLogDecoder fixed --- .../web3-eth-contract/src/decoders/AllEventsLogDecoder.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js b/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js index 944b9d9fb7a..53e0efc5bd6 100644 --- a/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js +++ b/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js @@ -43,6 +43,12 @@ export default class AllEventsLogDecoder extends EventLogDecoder { * @returns {Object} */ decode(abiModel, response) { - return super.decode(abiModel.getEventBySignature(response.topics[0]), response); + let abiItemModel = abiModel.getEventBySignature(response.topics[0]); + + if (abiItemModel) { + return super.decode(abiItemModel, response); + } + + return response; } } From f4ef0fa491527b3fa445be95dee364116fafbbc9 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 19 Feb 2019 13:15:03 +0100 Subject: [PATCH 08/71] Revert "AllEventsLogDecoder fixed" This reverts commit 4b174ed5a682ff29f34debf4264a452ec154250e. --- .../web3-eth-contract/src/decoders/AllEventsLogDecoder.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js b/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js index 53e0efc5bd6..944b9d9fb7a 100644 --- a/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js +++ b/packages/web3-eth-contract/src/decoders/AllEventsLogDecoder.js @@ -43,12 +43,6 @@ export default class AllEventsLogDecoder extends EventLogDecoder { * @returns {Object} */ decode(abiModel, response) { - let abiItemModel = abiModel.getEventBySignature(response.topics[0]); - - if (abiItemModel) { - return super.decode(abiItemModel, response); - } - - return response; + return super.decode(abiModel.getEventBySignature(response.topics[0]), response); } } From b1127421c881b24c0fdc1d2c54d17045aafc932f Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 20 Feb 2019 17:04:31 +0100 Subject: [PATCH 09/71] throIfMissing removed because it isn't required --- packages/web3-core/src/AbstractWeb3Module.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/web3-core/src/AbstractWeb3Module.js b/packages/web3-core/src/AbstractWeb3Module.js index c2d15caa421..12ebb49c05b 100644 --- a/packages/web3-core/src/AbstractWeb3Module.js +++ b/packages/web3-core/src/AbstractWeb3Module.js @@ -35,8 +35,8 @@ export default class AbstractWeb3Module { * @constructor */ constructor( - provider = AbstractWeb3Module.throwIfMissing('provider'), - providersModuleFactory = AbstractWeb3Module.throwIfMissing('ProvidersModuleFactory'), + provider, + providersModuleFactory, methodModuleFactory = null, methodFactory = null, options = {} @@ -320,13 +320,4 @@ export default class AbstractWeb3Module { return Promise.resolve(true); } - - /** - * Throws an error if the parameter is missing - * - * @param {String} name - */ - static throwIfMissing(name) { - throw new Error(`Missing parameter: ${name}`); - } } From 0827f583f8bc20ba4e7b25db1bc1c3a199b02d5e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 14:31:58 +0100 Subject: [PATCH 10/71] Dependency handling updated, funcDocs added and todo's added --- packages/web3-eth-accounts/src/Account.js | 95 +++++++++++++++---- packages/web3-eth-accounts/src/Accounts.js | 46 +++------ packages/web3-eth-accounts/src/Wallet.js | 12 +-- .../src/factories/AccountsModuleFactory.js | 16 ++-- 4 files changed, 103 insertions(+), 66 deletions(-) diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js index 52aba005e5f..4ca5a10111e 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/Account.js @@ -11,48 +11,103 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ - - -import scryptsy from 'scrypt.js'; -import isString from 'lodash/isString'; -import isObject from 'lodash/isObject'; -import {Account as EthAccount} from 'eth-lib/lib/account'; -import uuid from 'uuid'; - /** * @file Account.js * @author Samuel Furter * @date 2019 */ -export default class Account { +import scryptsy from 'scrypt.js'; +import isString from 'lodash/isString'; +import isObject from 'lodash/isObject'; +import * as EthAccount from 'eth-lib/lib/account';// TODO: Remove this dependency +import uuid from 'uuid'; - constructor(accountOptions) { - this.address = accountOptions.address; // TODO: Add address validation here (if enough time create a Address VO) - this.privateKey = accountOptions.privateKey; - this.accountsModule = accounts; +export default class Account { + /** + * @param {Accounts} accounts + * @param {Object} options + * + * @constructor + */ + constructor(accounts, options) { + this.address = options.address; // TODO: Add address validation here (if enough time create a Address VO) + this.privateKey = options.privateKey; + this.accounts = accounts; } + /** + * This method does sign the given transaction with the current account + * + * @method signTransaction + * + * @param {Object} tx + * @param {Function} callback + * + * @callback callback callback(error, result) + * @returns {Promise | *} + */ signTransaction(tx, callback) { - return this.accountsModule.signTransaction(tx, this.privateKey, callback); + return this.accounts.signTransaction(tx, this.privateKey, callback); } + /** + * This method does sign a given string with the current account. + * + * @method sign + * + * @param {String} data + * + * @returns {String} + */ sign(data) { - return Account.sign(hash, this.privateKey); + return EthAccount.sign(hash, this.privateKey); } + /** + * This methods returns the EncryptedKeystoreV3Json object from the current account. + * + * @param {String} password + * @param {Object} options + * + * @returns {EncryptedKeystoreV3Json | {version, id, address, crypto}} + */ encrypt(password, options) { - return this.accountsModule.encrypt(this.privateKey, password, options); + return Account.fromPrivateKey(this.privateKey).toV3Keystore(password, option); } + /** + * This static methods gives us the possibility to create a new account. + * + * @param {String} entropy + * + * @returns {Account} + */ static from(entropy) { return new Account(EthAccount.create(entropy || this.utils.randomHex(32))); } + /** + * This static method gived us the possibility to create a Account object from a private key. + * + * @param {String} privateKey + * + * @returns {Account} + */ static fromPrivateKey(privateKey) { return new Account(EthAccount.fromPrivate(privateKey)); } + /** + * This method will map the current Account object to V3Keystore object. + * + * @method toV3Keystore + * + * @param {String} password + * @param {Object} options + * + * @returns {{version, id, address, crypto}} + */ toV3Keystore(password, options) { options = options || {}; const salt = options.salt || crypto.randomBytes(32); @@ -111,11 +166,13 @@ export default class Account { } /** - * Decrypts account + * TODO: Clean up this method + * + * Returns an Account object by the given V3Keystore object. * * Note: Taken from https://github.com/ethereumjs/ethereumjs-wallet * - * @method decrypt + * @method fromV3Keystore * * @param {Object|String} v3Keystore * @param {String} password @@ -123,7 +180,7 @@ export default class Account { * * @returns {Account} */ - static fromV3Keystore(v3Keystore, password, nonStrict) { + static fromV3Keystore(v3Keystore, password, nonStrict = false) { if (!isString(password)) { throw new Error('No password given.'); } diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index c02caaf469b..baed7da0472 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -16,7 +16,7 @@ */ /** * @file Accounts.js - * @author Fabian Vogelsteller + * @author Samuel Furter , Fabian Vogelsteller * @date 2017 */ @@ -28,27 +28,23 @@ import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import uuid from 'uuid'; -import {AbstractWeb3Module} from 'web3-core'; const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); // TODO: This should moved later to the factory method -export default class Accounts extends AbstractWeb3Module { +//TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. +export default class Accounts { /** - * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @param {ProvidersModuleFactory} providersModuleFactory * @param {Utils} utils * @param {Object} formatters - * @param {AccountsModuleFactory} accountsModuleFactory + * @param {TransactionSigner} transactionSigner + * @param {Wallet} wallet * @param {Object} options * * @constructor */ - constructor(provider, providersModuleFactory, utils, formatters, accountsModuleFactory, transactionSigner, options) { - super(provider, providersModuleFactory, null, null, options); - + constructor(utils, formatters, transactionSigner, wallet, options) { this.utils = utils; this.formatters = formatters; - this.accountsModuleFactory = accountsModuleFactory; - this.wallet = this.accountsModuleFactory.createWallet(this); + this.wallet = wallet; this.transactionSigner = transactionSigner; } @@ -75,7 +71,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Account} */ privateKeyToAccount(privateKey) { - return Account.fromPrivateKey(privateKey)); + return Account.fromPrivateKey(privateKey); } @@ -94,10 +90,15 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Promise} */ async signTransaction(tx, privateKey, callback) { - try { const transaction = new Transaction(tx); const signedTransaction = await this.transactionSigner.sign(transaction, privateKey); + + if (isFunction(callback)) { + callback(false, signedTransaction); + } + + return signedTransaction; } catch (error) { if (isFunction(callback)) { callback(error, null); @@ -105,12 +106,6 @@ export default class Accounts extends AbstractWeb3Module { throw error; } - - if (isFunction(callback)) { - callback(false, signedTransaction); - } - - return signedTransaction; } /** @@ -163,18 +158,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Object} */ sign(data, privateKey) { - const hash = this.hashMessage(data); - const account = Account.fromPrivateKey(privateKey); - const vrs = account.decodeSignature(account.sign(hash)); - - return { - message: data, - messageHash: hash, - v: vrs[0], - r: vrs[1], - s: vrs[2], - signature - }; + return Account.fromPrivateKey(privateKey).sign(data); } /** diff --git a/packages/web3-eth-accounts/src/Wallet.js b/packages/web3-eth-accounts/src/Wallet.js index 7a2f8aad9bd..5399cf19a1f 100644 --- a/packages/web3-eth-accounts/src/Wallet.js +++ b/packages/web3-eth-accounts/src/Wallet.js @@ -22,11 +22,9 @@ import isString from 'lodash/isString'; class Wallet { /** - * @param {Accounts} accounts - * * @constructor */ - constructor(accountsModuleFacotry, utils) { + constructor() { this.utils = utils; this.length = 0; this.defaultKeyName = 'web3js_wallet'; @@ -77,7 +75,7 @@ class Wallet { * @returns {Wallet} */ create(numberOfAccounts, entropy) { - const account = Account.from(entropy || this.utils.randomHex(32))); + const account = Account.from(entropy || this.utils.randomHex(32)); for (let i = 0; i < numberOfAccounts; ++i) { this.add(account.privateKey); @@ -91,7 +89,7 @@ class Wallet { * * @method add * - * @param {Object} account + * @param {Account} account * * @returns {Object} */ @@ -122,7 +120,7 @@ class Wallet { * * @param {String|Number} addressOrIndex * - * @returns {boolean} + * @returns {Boolean} */ remove(addressOrIndex) { const account = this[addressOrIndex]; @@ -189,7 +187,7 @@ class Wallet { */ decrypt(encryptedWallet, password) { encryptedWallet.forEach((keystore) => { - const account = this._accounts.decrypt(keystore, password); + const account = Account.fromV3Keystore(keystore, password); if (!account) { throw new Error('Couldn\'t decrypt accounts. Password wrong?'); diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 86e534a8ce3..14bf203ef89 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -50,10 +50,10 @@ export default class AccountsModuleFactory { return new Accounts( provider, providersModuleFactory, - methodModuleFactory, - this.createMethodFactory(methodModuleFactory), this.utils, this.formatters, + transactionSigner, + this.createWallet(), // const cryp = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); options ); @@ -64,12 +64,10 @@ export default class AccountsModuleFactory { * * @method createWallet * - * @param {Accounts} accounts - * * @returns {Wallet} */ - createWallet(accounts) { - return new Wallet(accounts); + createWallet() { + return new Wallet(); } /** @@ -77,13 +75,13 @@ export default class AccountsModuleFactory { * * @method createAccount * - * @param {object} accountOptions + * @param {Object} options * @param {Accounts} accounts * * @returns {Account} */ - createAccount(accountOptions, accounts) { - return new Account(accountOptions, accounts) + createAccount(accounts, options) { + return new Account(accounts, options) } /** From 86242dbba9211d1d875cd6a1bc65b0cbe662a3cd Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 14:41:35 +0100 Subject: [PATCH 11/71] Proxy added in Accounts constructor for security reasons. --- packages/web3-eth-accounts/src/Accounts.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index baed7da0472..42d92cf92ce 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -46,6 +46,12 @@ export default class Accounts { this.formatters = formatters; this.wallet = wallet; this.transactionSigner = transactionSigner; + + return new Proxy(this, { + get: (target, name) => { + return target[name]; + } + }); } /** From f9048c79b91827844a41ec544903ee8e354a1062 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 15:22:05 +0100 Subject: [PATCH 12/71] TransactionSigner updated and hasWallets removed ffrom the AbstractMethod class --- .../lib/methods/AbstractMethod.js | 11 ----- packages/web3-eth-accounts/src/Account.js | 15 ++++-- packages/web3-eth-accounts/src/Accounts.js | 4 +- .../web3-eth/src/signers/TransactionSigner.js | 48 +++++++++++++++++-- 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/packages/web3-core-method/lib/methods/AbstractMethod.js b/packages/web3-core-method/lib/methods/AbstractMethod.js index 926065fb9b1..fe7cdba9445 100644 --- a/packages/web3-core-method/lib/methods/AbstractMethod.js +++ b/packages/web3-core-method/lib/methods/AbstractMethod.js @@ -214,15 +214,4 @@ export default class AbstractMethod { isHash(parameter) { return isString(parameter) && parameter.indexOf('0x') === 0; } - - /** - * Checks if accounts is defined and if wallet is not empty - * - * @method hasWallet - * - * @returns {Boolean} - */ - hasWallets() { - return this.accounts && this.accounts.wallet.length > 0; - } } diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js index 4ca5a10111e..325b7cc54ee 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/Account.js @@ -30,14 +30,21 @@ export default class Account { * * @constructor */ - constructor(accounts, options) { + constructor(options) { this.address = options.address; // TODO: Add address validation here (if enough time create a Address VO) this.privateKey = options.privateKey; - this.accounts = accounts; + + return new Proxy(this, { + get: (target, name) => { + return target[name]; + } + }); } /** - * This method does sign the given transaction with the current account + * TODO: Add deprecation message and extend the signTransaction method in the eth module + * + * Signs a transaction object with the given privateKey * * @method signTransaction * @@ -45,7 +52,7 @@ export default class Account { * @param {Function} callback * * @callback callback callback(error, result) - * @returns {Promise | *} + * @returns {Promise} */ signTransaction(tx, callback) { return this.accounts.signTransaction(tx, this.privateKey, callback); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 42d92cf92ce..3b7d8f67760 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -26,6 +26,7 @@ import isString from 'lodash/isString'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; +import Account from './Account'; import scryptsy from 'scrypt.js'; import uuid from 'uuid'; const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); // TODO: This should moved later to the factory method @@ -80,7 +81,6 @@ export default class Accounts { return Account.fromPrivateKey(privateKey); } - /** * TODO: Add deprecation message and extend the signTransaction method in the eth module * @@ -97,7 +97,7 @@ export default class Accounts { */ async signTransaction(tx, privateKey, callback) { try { - const transaction = new Transaction(tx); + const transaction = new Transaction(tx);// TODO: Create Transaction VO or add validation here. const signedTransaction = await this.transactionSigner.sign(transaction, privateKey); if (isFunction(callback)) { diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index d10c18d9b70..5894daae7a1 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -24,15 +24,18 @@ import Account from 'eth-lib/lib/account'; */ export default class TransactionSigner { /** - * @param {object} formatters + * @param {Wallet} wallet + * @param {SignMethod} signMethod + * @param {Object} formatters * @param {Utils} utils * * @constructor */ - constructor(formatters, utils, accounts) { + constructor(wallet, signMethod, formatters, utils) { + this.wallet = wallet; + this.signMethod = signMethod; this.formatters = formatters; this.utils = utils; - this.accounts = accounts; } /** @@ -43,9 +46,44 @@ export default class TransactionSigner { * * @returns {Promise} */ - async sign(tx, moduleInstance) { + sign(tx, moduleInstance) { + if (this.wallet.length > 0) { + return this.signLocal(tx, moduleInstance); + } + + return this.signRemote(tx, moduleInstance); + + } + + /** + * This method signs the transaction remotely on the node. + * + * @method signLocal + * + * @param {Object} tx + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Promise<{messageHash: *, v: String, r: String, s: String, rawTransaction: *}>} + */ + signRemote(tx, moduleInstance) { + this.signMethod.parameters = [tx]; + + return this.signMethod.execute(moduleInstance); + } + + /** + * This method signs the transaction with the local decrypted account. + * + * @method signLocal + * + * @param {Object} tx + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Promise<{messageHash: *, v: String, r: String, s: String, rawTransaction: *}>} + */ + async signLocal(tx, moduleInstance) { let result; - const privateKey = this.accounts.wallet[from]; + const privateKey = this.wallet[from]; if (this.isUndefinedOrNull(tx.chainId)) { tx.chainId = await moduleInstance.getChainId(); From 7ba1ee0144d05ad72e86f955e2ef45e7118ec574 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 15:55:09 +0100 Subject: [PATCH 13/71] TransactionSigner export added in index.js --- packages/web3-eth-accounts/src/Account.js | 3 +- .../src/factories/EthModuleFactory.js | 75 +++++++++---------- packages/web3-eth/src/index.js | 28 ++++--- .../web3-eth/src/signers/TransactionSigner.js | 1 - 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js index 325b7cc54ee..26e23549906 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/Account.js @@ -25,7 +25,6 @@ import uuid from 'uuid'; export default class Account { /** - * @param {Accounts} accounts * @param {Object} options * * @constructor @@ -55,7 +54,7 @@ export default class Account { * @returns {Promise} */ signTransaction(tx, callback) { - return this.accounts.signTransaction(tx, this.privateKey, callback); + return this.signTransaction(tx, this.privateKey, callback); } /** diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js index de2226406e7..f4b5bb69659 100644 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ b/packages/web3-eth/src/factories/EthModuleFactory.js @@ -23,41 +23,21 @@ import MethodFactory from './MethodFactory'; import Eth from '../Eth'; import {GetGasPriceMethod} from '../../../web3-core-method/types'; +import TransactionSigner from '../signers/TransactionSigner'; export default class EthModuleFactory { /** - * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @param {ProvidersModuleFactory} providersModuleFactory - * @param {MethodModuleFactory} methodModuleFactory - * @param {Accounts} accounts - * @param {PromiEvent} PromiEvent * @param {Utils} utils * @param {Object} formatters - * @param {ContractModuleFactory} contractModuleFactory - * @param {AbiCoder} abiCoder * * @constructor */ constructor( - provider, - providersModuleFactory, - methodModuleFactory, - accounts, - PromiEvent, utils, formatters, - contractModuleFactory, - abiCoder ) { - this.provider = provider; - this.providersModuleFactory = providersModuleFactory; - this.methodModuleFactory = methodModuleFactory; - this.accounts = accounts; this.utils = utils; this.formatters = formatters; - this.contractModuleFactory = contractModuleFactory; - this.PromiEvent = PromiEvent; - this.abiCoder = abiCoder; } /** @@ -65,31 +45,49 @@ export default class EthModuleFactory { * * @method createEthModule * + * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @param {ProvidersModuleFactory} providersModuleFactory + * @param {MethodModuleFactory} methodModuleFactory * @param {Network} net + * @param {Accounts} accounts * @param {Personal} personal * @param {Iban} iban + * @param {AbiCoder} abiCoder * @param {Ens} ens * @param {SubscriptionsFactory} subscriptionsFactory + * @param {ContractModuleFactory} contractModuleFactory * @param {Object} options * * @returns {Eth} */ - createEthModule(net, personal, iban, ens, subscriptionsFactory, options) { + createEthModule( + provider, + providersModuleFactory, + methodModuleFactory, + net, + accounts, + personal, + iban, + abiCoder, + ens, + subscriptionsFactory, + contractModuleFactory, + options + ) { return new Eth( - this.provider, - this.providersModuleFactory, - this.methodModuleFactory, + providersModuleFactory, + methodModuleFactory, this.createMethodFactory(), net, - this.accounts, + accounts, personal, iban, - this.abiCoder, + abiCoder, ens, this.utils, this.formatters, subscriptionsFactory, - this.contractModuleFactory, + contractModuleFactory, options ); } @@ -105,16 +103,15 @@ export default class EthModuleFactory { return new MethodFactory(this.methodModuleFactory, this.utils, this.formatters); } - - createGetGasPriceMethod() { - return new GetGasPriceMethod(this.utils, this.formatters); - } - - createGetTransactionCountMethod() { - return new GetTransactionCountMethod(this.utils, this.formatters); - } - - createVersionMethod() { - return new VersionMethod(this.utils, this.formatters); + /** + * Returns an object of type TransactionSigner + * + * @param {Wallet} wallet + * @param {SignMethod} signMethod + * + * @returns {TransactionSigner} + */ + createTransactionSigner(wallet, signMethod) { + return new TransactionSigner(wallet, signMethod, this.formatters, this.utils); } } diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 9874ad9d981..0dcc7228986 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -20,9 +20,8 @@ * @date 2018 */ -import {MethodModuleFactory} from 'web3-core-method'; +import {MethodModuleFactory, SignMethod} from 'web3-core-method'; import {formatters} from 'web3-core-helpers'; -import {PromiEvent} from 'web3-core-promievent'; import {SubscriptionsFactory} from 'web3-core-subscriptions'; import {Accounts} from 'web3-eth-accounts'; import {Ens} from 'web3-eth-ens'; @@ -47,27 +46,32 @@ import EthModuleFactory from './factories/EthModuleFactory'; */ export const Eth = (provider, options) => { const accounts = new Accounts(provider, options); - const abiCoder = new AbiCoder(); - const methodModuleFactory = new MethodModuleFactory(accounts); return new EthModuleFactory( - provider, - new ProvidersModuleFactory(), - methodModuleFactory, - accounts, - PromiEvent, Utils, formatters, - new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), - abiCoder ).createEthModule( + provider, + new ProvidersModuleFactory(), + methodModuleFactory, new Network(provider, options), + accounts, new Personal(provider, accounts, options), Iban, - new Ens(provider, accounts), + abiCoder, + new Ens(provider, accounts, options), new SubscriptionsFactory(), + new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), options ); }; + + +export const TransactionSigner = (wallet) => { + return new EthModuleFactory( + Utils, + formatters, + ).createTransactionSigner(wallet, new SignMethod()); +}; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 5894daae7a1..f3ae9f03ba2 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -52,7 +52,6 @@ export default class TransactionSigner { } return this.signRemote(tx, moduleInstance); - } /** From 67fb030e6b3ae76b6764099d9d77282f71fa0665 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 16:07:26 +0100 Subject: [PATCH 14/71] signTransaction in Account and Accounts class updated --- packages/web3-eth-accounts/src/Account.js | 31 +++++++++++++--------- packages/web3-eth-accounts/src/Accounts.js | 9 +++---- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/Account.js index 26e23549906..f25d9dfca16 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/Account.js @@ -20,18 +20,20 @@ import scryptsy from 'scrypt.js'; import isString from 'lodash/isString'; import isObject from 'lodash/isObject'; -import * as EthAccount from 'eth-lib/lib/account';// TODO: Remove this dependency +import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency import uuid from 'uuid'; export default class Account { /** * @param {Object} options + * @param {TransactionSigner} transactionSigner * * @constructor */ - constructor(options) { + constructor(options, transactionSigner) { this.address = options.address; // TODO: Add address validation here (if enough time create a Address VO) this.privateKey = options.privateKey; + this.transactionSinger = transactionSigner; return new Proxy(this, { get: (target, name) => { @@ -41,8 +43,8 @@ export default class Account { } /** - * TODO: Add deprecation message and extend the signTransaction method in the eth module - * + * TODO: Add deprecation message, remove TransactionSigner dependency and extend the signTransaction method in the eth module. + * TODO: Create Transaction VO or add validation here. * Signs a transaction object with the given privateKey * * @method signTransaction @@ -53,8 +55,8 @@ export default class Account { * @callback callback callback(error, result) * @returns {Promise} */ - signTransaction(tx, callback) { - return this.signTransaction(tx, this.privateKey, callback); + async signTransaction(tx) { + return await this.transactionSigner.sign(new Transaction(tx), this.privateKey); } /** @@ -79,29 +81,31 @@ export default class Account { * @returns {EncryptedKeystoreV3Json | {version, id, address, crypto}} */ encrypt(password, options) { - return Account.fromPrivateKey(this.privateKey).toV3Keystore(password, option); + return Account.fromPrivateKey(this.privateKey, this.transactionSinger).toV3Keystore(password, option); } /** * This static methods gives us the possibility to create a new account. * * @param {String} entropy + * @param {TransactionSigner} transactionSigner * * @returns {Account} */ - static from(entropy) { - return new Account(EthAccount.create(entropy || this.utils.randomHex(32))); + static from(entropy, transactionSigner) { + return new Account(EthAccount.create(entropy || this.utils.randomHex(32)), transactionSigner); } /** * This static method gived us the possibility to create a Account object from a private key. * * @param {String} privateKey + * @param {TransactionSigner} transactionSigner * * @returns {Account} */ - static fromPrivateKey(privateKey) { - return new Account(EthAccount.fromPrivate(privateKey)); + static fromPrivateKey(privateKey, transactionSigner) { + return new Account(EthAccount.fromPrivate(privateKey), transactionSigner); } /** @@ -183,10 +187,11 @@ export default class Account { * @param {Object|String} v3Keystore * @param {String} password * @param {Boolean} nonStrict + * @param {TransactionSigner} transactionSigner * * @returns {Account} */ - static fromV3Keystore(v3Keystore, password, nonStrict = false) { + static fromV3Keystore(v3Keystore, password, nonStrict = false, transactionSigner) { if (!isString(password)) { throw new Error('No password given.'); } @@ -243,6 +248,6 @@ export default class Account { ); const seed = `0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`; - return this.fromPrivateKey(seed); + return this.fromPrivateKey(seed, transactionSigner); } } diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 3b7d8f67760..8d57ecb96b2 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -22,13 +22,11 @@ import isObject from 'lodash/isObject'; import isBoolean from 'lodash/isBoolean'; -import isString from 'lodash/isString'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import Account from './Account'; -import scryptsy from 'scrypt.js'; -import uuid from 'uuid'; + const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); // TODO: This should moved later to the factory method //TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. @@ -97,8 +95,7 @@ export default class Accounts { */ async signTransaction(tx, privateKey, callback) { try { - const transaction = new Transaction(tx);// TODO: Create Transaction VO or add validation here. - const signedTransaction = await this.transactionSigner.sign(transaction, privateKey); + const signedTransaction = Account.fromPrivateKey(privateKey, this.transactionSigner).signTransaction(tx); if (isFunction(callback)) { callback(false, signedTransaction); @@ -228,6 +225,6 @@ export default class Accounts { * @returns {Object} */ encrypt(privateKey, password, options) { - return Account.fromPrivateKey(privateKey).toV3Keystore(password, option) + return Account.fromPrivateKey(privateKey).toV3Keystore(password, option); } } From 7d2b67594b2c45219379462d9acb01f94b3f1813 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 16:18:17 +0100 Subject: [PATCH 15/71] models folder created and AccountsModuleFactory updated --- packages/web3-eth-accounts/src/Accounts.js | 7 +-- .../src/factories/AccountsModuleFactory.js | 45 ++++--------------- .../src/{ => models}/Account.js | 5 +-- .../src/{ => models}/Wallet.js | 0 4 files changed, 12 insertions(+), 45 deletions(-) rename packages/web3-eth-accounts/src/{ => models}/Account.js (97%) rename packages/web3-eth-accounts/src/{ => models}/Wallet.js (100%) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 8d57ecb96b2..e44a30770e3 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -25,9 +25,7 @@ import isBoolean from 'lodash/isBoolean'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; -import Account from './Account'; - -const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); // TODO: This should moved later to the factory method +import Account from './models/Account'; //TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. export default class Accounts { @@ -36,11 +34,10 @@ export default class Accounts { * @param {Object} formatters * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet - * @param {Object} options * * @constructor */ - constructor(utils, formatters, transactionSigner, wallet, options) { + constructor(utils, formatters, transactionSigner, wallet) { this.utils = utils; this.formatters = formatters; this.wallet = wallet; diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 14bf203ef89..44f881e8144 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -21,8 +21,8 @@ */ import Accounts from '../Accounts'; -import Account from '../Account'; -import Wallet from '../Wallet'; +import Account from '../models/Account'; +import Wallet from '../models/Wallet'; export default class AccountsModuleFactory { /** @@ -39,51 +39,22 @@ export default class AccountsModuleFactory { /** * Returns an object of type Accounts * - * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @param {ProvidersModuleFactory} providersModuleFactory - * @param {MethodModuleFactory} methodModuleFactory - * @param {Object} options + * @method createAccounts + * + * @param {TransactionSigner} transactionSigner + * @param {Wallet} wallet * * @returns {Accounts} */ - createAccounts(provider, providersModuleFactory, methodModuleFactory, options) { + createAccounts(transactionSigner, wallet) { return new Accounts( - provider, - providersModuleFactory, this.utils, this.formatters, transactionSigner, - this.createWallet(), - // const cryp = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); - options + wallet ); } - /** - * Returns an object of type Wallet - * - * @method createWallet - * - * @returns {Wallet} - */ - createWallet() { - return new Wallet(); - } - - /** - * Returns an object of type Account - * - * @method createAccount - * - * @param {Object} options - * @param {Accounts} accounts - * - * @returns {Account} - */ - createAccount(accounts, options) { - return new Account(accounts, options) - } - /** * Returns an object of type MethodFactory * diff --git a/packages/web3-eth-accounts/src/Account.js b/packages/web3-eth-accounts/src/models/Account.js similarity index 97% rename from packages/web3-eth-accounts/src/Account.js rename to packages/web3-eth-accounts/src/models/Account.js index f25d9dfca16..c2d4b72d8c9 100644 --- a/packages/web3-eth-accounts/src/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -13,10 +13,11 @@ */ /** * @file Account.js - * @author Samuel Furter + * @author Samuel Furter , Fabian Vogelsteller * @date 2019 */ +const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); import scryptsy from 'scrypt.js'; import isString from 'lodash/isString'; import isObject from 'lodash/isObject'; @@ -50,9 +51,7 @@ export default class Account { * @method signTransaction * * @param {Object} tx - * @param {Function} callback * - * @callback callback callback(error, result) * @returns {Promise} */ async signTransaction(tx) { diff --git a/packages/web3-eth-accounts/src/Wallet.js b/packages/web3-eth-accounts/src/models/Wallet.js similarity index 100% rename from packages/web3-eth-accounts/src/Wallet.js rename to packages/web3-eth-accounts/src/models/Wallet.js From 5f8447903d8ed2c5786f9fb60bacfc5d4a0b4ed8 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 16:55:38 +0100 Subject: [PATCH 16/71] SendTransactionMethod updated, Account factory method parameters updated in Accounts module and TransactionSigner simplified --- .../transaction/SendTransactionMethod.js | 22 ++++++--- packages/web3-eth-accounts/src/Accounts.js | 7 +-- .../src/factories/AccountsModuleFactory.js | 1 - .../src/factories/EthModuleFactory.js | 7 +-- packages/web3-eth/src/index.js | 4 +- .../web3-eth/src/signers/TransactionSigner.js | 45 ++----------------- 6 files changed, 26 insertions(+), 60 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index e9b501a3092..8306449f866 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -80,17 +80,25 @@ export default class SendTransactionMethod extends AbstractSendMethod { } if (!this.isGasPriceDefined() && !this.hasDefaultGasPrice(moduleInstance)) { - moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { - this.parameters[0]['gasPrice'] = gasPrice; - this.execute(moduleInstance, promiEvent); - }); + moduleInstance.currentProvider + .send('eth_gasPrice', []) + .then((gasPrice) => { + this.parameters[0]['gasPrice'] = gasPrice; + this.execute(moduleInstance, promiEvent); + }); return promiEvent; } - if (this.hasWallets()) { - moduleInstance.transactionSigner - .sign(this.parameters[0]) + let wallet; + + if (moduleInstance.accounts) { + wallet = moduleInstance.accounts.wallet; + } + + if (wallet.length > 0) { + moduleInstance.transactionSigner + .sign(this.parameters[0], moduleInstance, moduleInstance.accounts.wallet[this.parameters[0].from]) .then((response) => { this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index e44a30770e3..994216aff0f 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -28,6 +28,7 @@ import Bytes from 'eth-lib/lib/bytes'; import Account from './models/Account'; //TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. +//TODO: After this refactoring will it be possible to move the wallet class to the eth module and to remove the accounts module. export default class Accounts { /** * @param {Utils} utils @@ -60,7 +61,7 @@ export default class Accounts { * @returns {Account} */ create(entropy) { - return Account.from(entropy); + return Account.from(entropy, this.transactionSigner); } /** @@ -73,7 +74,7 @@ export default class Accounts { * @returns {Account} */ privateKeyToAccount(privateKey) { - return Account.fromPrivateKey(privateKey); + return Account.fromPrivateKey(privateKey, this.transactionSigner); } /** @@ -222,6 +223,6 @@ export default class Accounts { * @returns {Object} */ encrypt(privateKey, password, options) { - return Account.fromPrivateKey(privateKey).toV3Keystore(password, option); + return Account.fromPrivateKey(privateKey, this.transactionSigner).toV3Keystore(password, option); } } diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 44f881e8144..00bf1eb5f63 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -21,7 +21,6 @@ */ import Accounts from '../Accounts'; -import Account from '../models/Account'; import Wallet from '../models/Wallet'; export default class AccountsModuleFactory { diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js index f4b5bb69659..8b8977e9488 100644 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ b/packages/web3-eth/src/factories/EthModuleFactory.js @@ -106,12 +106,9 @@ export default class EthModuleFactory { /** * Returns an object of type TransactionSigner * - * @param {Wallet} wallet - * @param {SignMethod} signMethod - * * @returns {TransactionSigner} */ - createTransactionSigner(wallet, signMethod) { - return new TransactionSigner(wallet, signMethod, this.formatters, this.utils); + createTransactionSigner() { + return new TransactionSigner(this.formatters, this.utils); } } diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 0dcc7228986..5a67e1349c3 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -69,9 +69,9 @@ export const Eth = (provider, options) => { }; -export const TransactionSigner = (wallet) => { +export const TransactionSigner = () => { return new EthModuleFactory( Utils, formatters, - ).createTransactionSigner(wallet, new SignMethod()); + ).createTransactionSigner(); }; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index f3ae9f03ba2..b8e7d0540f8 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -24,16 +24,12 @@ import Account from 'eth-lib/lib/account'; */ export default class TransactionSigner { /** - * @param {Wallet} wallet - * @param {SignMethod} signMethod * @param {Object} formatters * @param {Utils} utils * * @constructor */ - constructor(wallet, signMethod, formatters, utils) { - this.wallet = wallet; - this.signMethod = signMethod; + constructor(formatters, utils) { this.formatters = formatters; this.utils = utils; } @@ -43,46 +39,12 @@ export default class TransactionSigner { * * @param {Transaction} tx * @param {AbstractWeb3Module} moduleInstance + * @param {String} privateKey * * @returns {Promise} */ - sign(tx, moduleInstance) { - if (this.wallet.length > 0) { - return this.signLocal(tx, moduleInstance); - } - - return this.signRemote(tx, moduleInstance); - } - - /** - * This method signs the transaction remotely on the node. - * - * @method signLocal - * - * @param {Object} tx - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Promise<{messageHash: *, v: String, r: String, s: String, rawTransaction: *}>} - */ - signRemote(tx, moduleInstance) { - this.signMethod.parameters = [tx]; - - return this.signMethod.execute(moduleInstance); - } - - /** - * This method signs the transaction with the local decrypted account. - * - * @method signLocal - * - * @param {Object} tx - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Promise<{messageHash: *, v: String, r: String, s: String, rawTransaction: *}>} - */ - async signLocal(tx, moduleInstance) { + async sign(tx, moduleInstance, privateKey) { let result; - const privateKey = this.wallet[from]; if (this.isUndefinedOrNull(tx.chainId)) { tx.chainId = await moduleInstance.getChainId(); @@ -144,7 +106,6 @@ export default class TransactionSigner { return result; } - /** * Removes the zeros until no zero follows after '0x' * From 82967cf92465e25e9f7e752fff1f5357b722d12d Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 17:18:42 +0100 Subject: [PATCH 17/71] Dependency handling updated in eth-accounts module --- .../transaction/SendTransactionMethod.js | 4 +-- .../src/factories/AccountsModuleFactory.js | 28 ++----------------- packages/web3-eth-accounts/src/index.js | 15 +++------- .../web3-eth-accounts/src/models/Wallet.js | 4 ++- .../web3-eth/src/signers/TransactionSigner.js | 4 +-- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 8306449f866..eb376d41d92 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -23,7 +23,7 @@ import isObject from 'lodash/isObject'; import AbstractSendMethod from '../../../lib/methods/AbstractSendMethod'; -// TODO: Clean up this method and move the signing logic etc. to the eth module +// TODO: Clean up this method and move the signing and observing logic to the eth module export default class SendTransactionMethod extends AbstractSendMethod { /** * @param {Utils} utils @@ -98,7 +98,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (wallet.length > 0) { moduleInstance.transactionSigner - .sign(this.parameters[0], moduleInstance, moduleInstance.accounts.wallet[this.parameters[0].from]) + .sign(this.parameters[0], moduleInstance.accounts.wallet[this.parameters[0].from], moduleInstance) .then((response) => { this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 00bf1eb5f63..cb37f409921 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -24,17 +24,6 @@ import Accounts from '../Accounts'; import Wallet from '../models/Wallet'; export default class AccountsModuleFactory { - /** - * @param {Utils} utils - * @param {Object} formatters - * - * @constructor - */ - constructor(utils, formatters) { - this.utils = utils; - this.formatters = formatters; - } - /** * Returns an object of type Accounts * @@ -42,10 +31,12 @@ export default class AccountsModuleFactory { * * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet + * @param {Utils} utils + * @param {Object}formatters * * @returns {Accounts} */ - createAccounts(transactionSigner, wallet) { + createAccounts(transactionSigner, wallet, utils, formatters) { return new Accounts( this.utils, this.formatters, @@ -53,17 +44,4 @@ export default class AccountsModuleFactory { wallet ); } - - /** - * Returns an object of type MethodFactory - * - * @method createMethodFactory - * - * @param {MethodModuleFactory} methodModuleFactory - * - * @returns {MethodFactory} - */ - createMethodFactory(methodModuleFactory) { - return new MethodFactory(methodModuleFactory, this.utils, this.formatters); - } } diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index e9f4432fa4b..516291136f0 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -20,10 +20,9 @@ * @date 2018 */ -import {MethodModuleFactory} from 'web3-core-method'; -import {ProvidersModuleFactory} from 'web3-providers'; import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; +import Wallet from './models/Wallet'; import AccountsModuleFactory from './factories/AccountsModuleFactory'; /** @@ -31,16 +30,10 @@ import AccountsModuleFactory from './factories/AccountsModuleFactory'; * * @method Accounts * - * @params {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @params {Object} options + * @params {TransactionSigner} transactionSigner * * @returns {Accounts} */ -export const Accounts = (provider, options) => { - return new AccountsModuleFactory(Utils, formatters).createAccounts( - provider, - new ProvidersModuleFactory(), - new MethodModuleFactory(), - options - ); +export const Accounts = (transactionSigner) => { + return new AccountsModuleFactory().createAccounts(Utils, formatters, transactionSigner, new Wallet(Utils)); }; diff --git a/packages/web3-eth-accounts/src/models/Wallet.js b/packages/web3-eth-accounts/src/models/Wallet.js index 5399cf19a1f..10e32082392 100644 --- a/packages/web3-eth-accounts/src/models/Wallet.js +++ b/packages/web3-eth-accounts/src/models/Wallet.js @@ -22,9 +22,11 @@ import isString from 'lodash/isString'; class Wallet { /** + * @param {Utils} utils + * * @constructor */ - constructor() { + constructor(utils) { this.utils = utils; this.length = 0; this.defaultKeyName = 'web3js_wallet'; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index b8e7d0540f8..79726174475 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -38,12 +38,12 @@ export default class TransactionSigner { * Signs the transaction * * @param {Transaction} tx - * @param {AbstractWeb3Module} moduleInstance * @param {String} privateKey + * @param {AbstractWeb3Module} moduleInstance * * @returns {Promise} */ - async sign(tx, moduleInstance, privateKey) { + async sign(tx, privateKey, moduleInstance) { let result; if (this.isUndefinedOrNull(tx.chainId)) { From 56efe5cb7e75fe2dfce2980ba07989ceaae0f13a Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 18:48:56 +0100 Subject: [PATCH 18/71] Tranasaction validation from TransactionSigner moved to SendTransactionmethod. --- .../transaction/SendTransactionMethod.js | 104 ++++++++++++------ .../src/models/Transaction.js | 51 +++++++++ .../web3-eth/src/signers/TransactionSigner.js | 33 +----- 3 files changed, 121 insertions(+), 67 deletions(-) create mode 100644 packages/web3-eth-accounts/src/models/Transaction.js diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index eb376d41d92..4657fbb6aad 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -69,56 +69,90 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @returns {PromiEvent} */ execute(moduleInstance, promiEvent) { - if (!this.isGasLimitDefined()) { - if (this.hasDefaultGasLimit(moduleInstance)) { - this.parameters[0]['gas'] = moduleInstance.defaultGas; - } + if (!this.isGasLimitDefined() && this.hasDefaultGasLimit(moduleInstance)) { + this.parameters[0]['gas'] = moduleInstance.defaultGas; } - if (!this.isGasPriceDefined() && this.hasDefaultGasPrice(moduleInstance)) { + if (!this.isGasPriceDefined()) { + if (!this.hasDefaultGasPrice(moduleInstance)) { + moduleInstance.currentProvider + .send('eth_gasPrice', []) + .then((gasPrice) => { + this.parameters[0]['gasPrice'] = gasPrice; + this.execute(moduleInstance, promiEvent); + }); + + return promiEvent; + } + this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (!this.isGasPriceDefined() && !this.hasDefaultGasPrice(moduleInstance)) { - moduleInstance.currentProvider - .send('eth_gasPrice', []) - .then((gasPrice) => { - this.parameters[0]['gasPrice'] = gasPrice; - this.execute(moduleInstance, promiEvent); - }); + if (moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0) { + this.sendRawTransaction(this.parameters[0], promiEvent, moduleInstance); return promiEvent; } - let wallet; + super.execute(moduleInstance, promiEvent); - if (moduleInstance.accounts) { - wallet = moduleInstance.accounts.wallet; - } + return promiEvent; + } + + /** + * Signs the transaction and executes the SendRawTransaction method. + * + * @method sendRawTransaction + * + * @param {Object} tx + * @param {PromiEvent} promiEvent + * @param {AbstractWeb3Module} moduleInstance + */ + sendRawTransaction(tx, promiEvent, moduleInstance) { + let missingTxProperties = []; - if (wallet.length > 0) { - moduleInstance.transactionSigner - .sign(this.parameters[0], moduleInstance.accounts.wallet[this.parameters[0].from], moduleInstance) - .then((response) => { - this.sendRawTransactionMethod.parameters = [response.rawTransaction]; - this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); - }) - .catch((error) => { - if (this.callback) { - this.callback(error, null); - } - - promiEvent.reject(error); - promiEvent.emit('error', error); - promiEvent.removeAllListeners(); - }); + if (tx.chainId) { + missingTxProperties.push(moduleInstance.getChainId()); + } - return promiEvent; + if (tx.nonce) { + missingTxProperties.push(moduleInstance.getTransactionCount()); } - super.execute(moduleInstance, promiEvent); + Promise.all(missingTxProperties).then((txProperties) => { + if (txProperties[0]) { + tx.chainId = txProperties[0]; + } - return promiEvent; + if (txProperties[1]) { + tx.nonce = txProperties[1]; + } + + }); + + const transaction = this.formatters.txInputFormatter(tx); + transaction.to = tx.to || '0x'; + transaction.data = tx.data || '0x'; + transaction.value = tx.value || '0x'; + transaction.chainId = this.utils.numberToHex(tx.chainId); + + moduleInstance.transactionSigner + .sign(this.parameters[0], moduleInstance.accounts.wallet[tx.from]) + .then((response) => { + this.sendRawTransactionMethod.parameters = [response.rawTransaction]; + this.sendRawTransactionMethod.callback = this.callback; + + this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); + }) + .catch((error) => { + if (this.callback) { + this.callback(error, null); + } + + promiEvent.reject(error); + promiEvent.emit('error', error); + promiEvent.removeAllListeners(); + }); } /** diff --git a/packages/web3-eth-accounts/src/models/Transaction.js b/packages/web3-eth-accounts/src/models/Transaction.js new file mode 100644 index 00000000000..8f9dbf77bff --- /dev/null +++ b/packages/web3-eth-accounts/src/models/Transaction.js @@ -0,0 +1,51 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** + * @file Transaction.js + * @author Samuel Furter + * @date 2019 + */ + +export default class Transaction { + + constructor(options) { + this.options = options; + } + + set options(value) { + this._options = this.validate(value); + } + + validate() { + + if (this.isUndefinedOrNull(tx.chainId)) { + tx.chainId = await moduleInstance.getChainId(); + } + if (this.isUndefinedOrNull(tx.nonce)) { + tx.nonce = await moduleInstance.getTransactionCount(tx.from); + } + if (this.isUndefinedOrNull(tx.gasPrice)) { + tx.gasPrice = await moduleInstance.getGasPrice(); + } + + // delete tx.from; + tx = this.formatters.txInputFormatter(tx); + + const transaction = tx; + transaction.to = tx.to || '0x'; + transaction.data = tx.data || '0x'; + transaction.value = tx.value || '0x'; + transaction.chainId = this.utils.numberToHex(tx.chainId); + } +} diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 79726174475..f2fdac269c9 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -23,48 +23,17 @@ import Account from 'eth-lib/lib/account'; * @date 2019 */ export default class TransactionSigner { - /** - * @param {Object} formatters - * @param {Utils} utils - * - * @constructor - */ - constructor(formatters, utils) { - this.formatters = formatters; - this.utils = utils; - } - /** * Signs the transaction * * @param {Transaction} tx * @param {String} privateKey - * @param {AbstractWeb3Module} moduleInstance * * @returns {Promise} */ - async sign(tx, privateKey, moduleInstance) { + async sign(tx, privateKey) { let result; - if (this.isUndefinedOrNull(tx.chainId)) { - tx.chainId = await moduleInstance.getChainId(); - } - if (this.isUndefinedOrNull(tx.nonce)) { - tx.nonce = await moduleInstance.getTransactionCount(tx.from); - } - if (this.isUndefinedOrNull(tx.gasPrice)) { - tx.gasPrice = await moduleInstance.getGasPrice(); - } - - // delete tx.from; - tx = this.formatters.inputCallFormatter(tx, moduleInstance); - - const transaction = tx; - transaction.to = tx.to || '0x'; - transaction.data = tx.data || '0x'; - transaction.value = tx.value || '0x'; - transaction.chainId = this.utils.numberToHex(tx.chainId); - const rlpEncoded = RLP.encode([ Bytes.fromNat(transaction.nonce), Bytes.fromNat(transaction.gasPrice), From 051a87d0967a9d846226d8725699aa44cbb490fd Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 19:09:20 +0100 Subject: [PATCH 19/71] setting of a custom transaction signer in the eth module constructor updated --- .../web3-eth-accounts/src/models/Account.js | 4 +- .../src/models/Transaction.js | 51 ------------------- packages/web3-eth/src/Eth.js | 16 ++++-- .../src/factories/EthModuleFactory.js | 18 ++----- packages/web3-eth/src/index.js | 12 ++--- .../web3-eth/src/signers/TransactionSigner.js | 10 ++-- 6 files changed, 26 insertions(+), 85 deletions(-) delete mode 100644 packages/web3-eth-accounts/src/models/Transaction.js diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index c2d4b72d8c9..04b9a874d78 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -54,8 +54,8 @@ export default class Account { * * @returns {Promise} */ - async signTransaction(tx) { - return await this.transactionSigner.sign(new Transaction(tx), this.privateKey); + signTransaction(tx) { + return this.transactionSigner.sign(new Transaction(tx), this.privateKey); } /** diff --git a/packages/web3-eth-accounts/src/models/Transaction.js b/packages/web3-eth-accounts/src/models/Transaction.js deleted file mode 100644 index 8f9dbf77bff..00000000000 --- a/packages/web3-eth-accounts/src/models/Transaction.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - This file is part of web3.js. - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file Transaction.js - * @author Samuel Furter - * @date 2019 - */ - -export default class Transaction { - - constructor(options) { - this.options = options; - } - - set options(value) { - this._options = this.validate(value); - } - - validate() { - - if (this.isUndefinedOrNull(tx.chainId)) { - tx.chainId = await moduleInstance.getChainId(); - } - if (this.isUndefinedOrNull(tx.nonce)) { - tx.nonce = await moduleInstance.getTransactionCount(tx.from); - } - if (this.isUndefinedOrNull(tx.gasPrice)) { - tx.gasPrice = await moduleInstance.getGasPrice(); - } - - // delete tx.from; - tx = this.formatters.txInputFormatter(tx); - - const transaction = tx; - transaction.to = tx.to || '0x'; - transaction.data = tx.data || '0x'; - transaction.value = tx.value || '0x'; - transaction.chainId = this.utils.numberToHex(tx.chainId); - } -} diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index 705e61a9cc0..549323ab8b6 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -39,6 +39,7 @@ export default class Eth extends AbstractWeb3Module { * @param {Object} formatters * @param {SubscriptionsFactory} subscriptionsFactory * @param {ContractModuleFactory} contractModuleFactory + * @param {TransactionSigner} transactionSigner * @param {Object} options * * @constructor @@ -74,7 +75,12 @@ export default class Eth extends AbstractWeb3Module { this.subscriptionsFactory = subscriptionsFactory; this.contractModuleFactory = contractModuleFactory; this.initiatedContracts = []; - this._transactionSigner = options.transactionSigner || transactionSigner; + this._transactionSigner = transactionSigner; + + if (options.transactionSigner) { + this._transactionSigner = options.transactionSigner; + this.accounts.transactionSigner = options.transactionSigner; + } /** * This wrapper function is required for the "new web3.eth.Contract(...)" call. @@ -119,11 +125,11 @@ export default class Eth extends AbstractWeb3Module { * * @property transactionSigner * - * @param {TransactionSigner} signer + * @param {TransactionSigner} transactionSigner */ - set transactionSigner(signer) { - this._transactionSigner = signer; - this.accounts.transactionSigner = signer; + set transactionSigner(transactionSigner) { + this._transactionSigner = transactionSigner; + this.accounts.transactionSigner = transactionSigner; } /** diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js index 8b8977e9488..450a66a7bd6 100644 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ b/packages/web3-eth/src/factories/EthModuleFactory.js @@ -22,7 +22,6 @@ import MethodFactory from './MethodFactory'; import Eth from '../Eth'; -import {GetGasPriceMethod} from '../../../web3-core-method/types'; import TransactionSigner from '../signers/TransactionSigner'; export default class EthModuleFactory { @@ -75,9 +74,10 @@ export default class EthModuleFactory { options ) { return new Eth( + provider, providersModuleFactory, methodModuleFactory, - this.createMethodFactory(), + this.createMethodFactory(methodModuleFactory), net, accounts, personal, @@ -88,6 +88,7 @@ export default class EthModuleFactory { this.formatters, subscriptionsFactory, contractModuleFactory, + new TransactionSigner(), options ); } @@ -99,16 +100,7 @@ export default class EthModuleFactory { * * @returns {MethodFactory} */ - createMethodFactory() { - return new MethodFactory(this.methodModuleFactory, this.utils, this.formatters); - } - - /** - * Returns an object of type TransactionSigner - * - * @returns {TransactionSigner} - */ - createTransactionSigner() { - return new TransactionSigner(this.formatters, this.utils); + createMethodFactory(methodModuleFactory) { + return new MethodFactory(methodModuleFactory, this.utils, this.formatters); } } diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 5a67e1349c3..36be59e1900 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -34,6 +34,8 @@ import {Network} from 'web3-net'; import * as Utils from 'web3-utils'; import EthModuleFactory from './factories/EthModuleFactory'; +export TransactionSigner from './signers/TransactionSigner'; + /** * Creates the Eth object * @@ -47,7 +49,7 @@ import EthModuleFactory from './factories/EthModuleFactory'; export const Eth = (provider, options) => { const accounts = new Accounts(provider, options); const abiCoder = new AbiCoder(); - const methodModuleFactory = new MethodModuleFactory(accounts); + const methodModuleFactory = new MethodModuleFactory(); return new EthModuleFactory( Utils, @@ -67,11 +69,3 @@ export const Eth = (provider, options) => { options ); }; - - -export const TransactionSigner = () => { - return new EthModuleFactory( - Utils, - formatters, - ).createTransactionSigner(); -}; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index f2fdac269c9..cf053787bbd 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -11,17 +11,17 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/** + * @file TransactionSigner.js + * @author Samuel Furter , Fabian Vogelsteller + * @date 2019 + */ import Nat from 'eth-lib/lib/nat'; import Bytes from 'eth-lib/lib/bytes'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Account from 'eth-lib/lib/account'; -/** - * @file TransactionSigner.js - * @author Samuel Furter , Fabian Vogelsteller - * @date 2019 - */ export default class TransactionSigner { /** * Signs the transaction From 6cf0b43ecbe17179ef6e8ca2c090c2ec12b36180 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 19:46:45 +0100 Subject: [PATCH 20/71] SignMethod updated, signers removed , SendTransactionMethod updated and dependency handling updated in the core-method module. --- .../lib/factories/AbstractMethodFactory.js | 10 ---- .../lib/signers/AbstractSigner.js | 48 ---------------- .../src/factories/ModuleFactory.js | 17 +----- .../src/methods/SignMethod.js | 19 ++++--- .../transaction/SendTransactionMethod.js | 3 - .../src/signers/MessageSigner.js | 53 ----------------- .../src/signers/TransactionSigner.js | 57 ------------------- packages/web3-eth-accounts/src/index.js | 1 + 8 files changed, 12 insertions(+), 196 deletions(-) delete mode 100644 packages/web3-core-method/lib/signers/AbstractSigner.js delete mode 100644 packages/web3-core-method/src/signers/MessageSigner.js delete mode 100644 packages/web3-core-method/src/signers/TransactionSigner.js diff --git a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js index 6586c0036f8..98e6a958a6e 100644 --- a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js +++ b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js @@ -89,15 +89,6 @@ export default class AbstractMethodFactory { /* eslint-disable new-cap */ switch (method.Type) { case 'CALL': - if (method.name === 'SignMethod') { - return new method( - this.utils, - this.formatters, - this.methodModuleFactory.accounts, - this.methodModuleFactory.createMessageSigner() - ); - } - return new method(this.utils, this.formatters); case 'SEND': if (method.name === 'SendTransactionMethod') { @@ -105,7 +96,6 @@ export default class AbstractMethodFactory { this.utils, this.formatters, this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.createTransactionSigner(), this.methodModuleFactory.createSendRawTransactionMethod() ); } diff --git a/packages/web3-core-method/lib/signers/AbstractSigner.js b/packages/web3-core-method/lib/signers/AbstractSigner.js deleted file mode 100644 index 3ff678cec1a..00000000000 --- a/packages/web3-core-method/lib/signers/AbstractSigner.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file AbstractSigner.js - * @author Samuel Furter - * @date 2018 - */ - -export default class AbstractSigner { - /** - * @param {Accounts} accounts - */ - constructor(accounts) { - this.accounts = accounts; - } - - /** - * Get wallet for address with accounts package - * - * @method getWallet - * - * @param {String} from - * - * @returns {Account} - */ - getWallet(from) { - const account = this.accounts.wallet[from]; - if (account) { - return account; - } - - return null; - } -} diff --git a/packages/web3-core-method/src/factories/ModuleFactory.js b/packages/web3-core-method/src/factories/ModuleFactory.js index 8874ff45dfb..d35fb4b6791 100644 --- a/packages/web3-core-method/src/factories/ModuleFactory.js +++ b/packages/web3-core-method/src/factories/ModuleFactory.js @@ -24,22 +24,18 @@ import TransactionConfirmationWorkflow from '../workflows/TransactionConfirmatio import TransactionReceiptValidator from '../validators/TransactionReceiptValidator'; import NewHeadsWatcher from '../watchers/NewHeadsWatcher'; import MethodProxy from '../proxy/MethodProxy'; -import MessageSigner from '../signers/MessageSigner'; -import TransactionSigner from '../signers/TransactionSigner'; import GetTransactionReceiptMethod from '../methods/transaction/GetTransactionReceiptMethod'; import SendRawTransactionMethod from '../methods/transaction/SendRawTransactionMethod'; export default class ModuleFactory { /** - * @param {Accounts} accounts * @param {SubscriptionsFactory} subscriptionsFactory * @param {Utils} utils * @param {Object} formatters * * @constructor */ - constructor(accounts, subscriptionsFactory, utils, formatters) { - this.accounts = accounts || {}; + constructor(subscriptionsFactory, utils, formatters) { this.subscriptionsFactory = subscriptionsFactory; this.formatters = formatters; this.utils = utils; @@ -59,17 +55,6 @@ export default class ModuleFactory { return new MethodProxy(target, methodFactory); } - /** - * Returns the MessageSigner object - * - * @method createMessageSigner - * - * @returns {MessageSigner} - */ - createMessageSigner() { - return new MessageSigner(this.accounts); - } - /** * Returns the TransactionConfirmationWorkflow object * diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 46a5cb6b816..9602190727c 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -21,20 +21,17 @@ */ import AbstractCallMethod from '../../lib/methods/AbstractCallMethod'; +import Account from '../../../web3-eth-accounts/src/models/Account'; export default class SignMethod extends AbstractCallMethod { /** * @param {Utils} utils * @param {Object} formatters - * @param {Accounts} accounts - * @param {MessageSigner} messageSigner * * @constructor */ - constructor(utils, formatters, accounts, messageSigner) { + constructor(utils, formatters) { super('eth_sign', 2, utils, formatters); - this.accounts = accounts; - this.messageSigner = messageSigner; } /** @@ -48,10 +45,10 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Promise} */ execute(moduleInstance) { - if (this.hasWallets()) { + if (moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0) { this.beforeExecution(moduleInstance); - return this.signOnClient(); + return this.signOnClient(moduleInstance); } return super.execute(moduleInstance); @@ -62,13 +59,17 @@ export default class SignMethod extends AbstractCallMethod { * * @method signOnClient * + * @param {AbstractWeb3Module} moduleInstance + * * @returns {Promise} */ - signOnClient() { + signOnClient(moduleInstance) { let signedMessage; try { - signedMessage = this.afterExecution(this.messageSigner.sign(this.parameters[0], this.parameters[1])); + signedMessage = Account.fromPrivateKey( + moduleInstance.accounts.wallet[this.parameters[1]] + ).sign(this.parameters[0]); } catch (error) { if (this.callback) { this.callback(error, null); diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 4657fbb6aad..6ecd58c9215 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -29,7 +29,6 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {Utils} utils * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {TransactionSigner} transactionSigner * @param {SendRawTransactionMethod} sendRawTransactionMethod * * @constructor @@ -38,11 +37,9 @@ export default class SendTransactionMethod extends AbstractSendMethod { utils, formatters, transactionConfirmationWorkflow, - transactionSigner, sendRawTransactionMethod ) { super('eth_sendTransaction', 1, utils, formatters, transactionConfirmationWorkflow); - this.transactionSigner = transactionSigner; this.sendRawTransactionMethod = sendRawTransactionMethod; } diff --git a/packages/web3-core-method/src/signers/MessageSigner.js b/packages/web3-core-method/src/signers/MessageSigner.js deleted file mode 100644 index 2caa8541544..00000000000 --- a/packages/web3-core-method/src/signers/MessageSigner.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file MessageSigner.js - * @author Samuel Furter - * @date 2018 - */ - -import AbstractSigner from '../../lib/signers/AbstractSigner'; - -export default class MessageSigner extends AbstractSigner { - /** - * @param {Accounts} accounts - * - * @constructor - */ - constructor(accounts) { - super(accounts); - } - - /** - * Signs a given message - * - * @method sign - * - * @param {String} data - * @param {String} address - * - * @returns {String|Error} - */ - sign(data, address) { - const wallet = this.getWallet(address); - if (wallet && wallet.privateKey) { - return this.accounts.sign(data, wallet.privateKey).signature; - } - - throw new Error('Wallet or privateKey in wallet is not set!'); - } -} diff --git a/packages/web3-core-method/src/signers/TransactionSigner.js b/packages/web3-core-method/src/signers/TransactionSigner.js deleted file mode 100644 index fe796dff832..00000000000 --- a/packages/web3-core-method/src/signers/TransactionSigner.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file TransactionSigner.js - * @author Samuel Furter - * @date 2018 - */ - -import AbstractSigner from '../../lib/signers/AbstractSigner'; - -export default class TransactionSigner extends AbstractSigner { - /** - * @param {Accounts} accounts - * - * @constructor - */ - constructor(accounts) { - super(accounts); - } - - /** - * Signs the given transaction - * - * @method sign - * - * @param {Object} transaction - * - * @returns {Promise} - */ - async sign(transaction) { - const wallet = this.getWallet(transaction.from); - - if (wallet && wallet.privateKey) { - try { - return await this.accounts.signTransaction(transaction, wallet.privateKey); - } catch (error) { - throw error; - } - } - - throw new Error('Wallet or privateKey in wallet is not set!'); - } -} diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 516291136f0..acb37bf4090 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -37,3 +37,4 @@ import AccountsModuleFactory from './factories/AccountsModuleFactory'; export const Accounts = (transactionSigner) => { return new AccountsModuleFactory().createAccounts(Utils, formatters, transactionSigner, new Wallet(Utils)); }; + From 6bfeb959a4ef47264146d6489f9c463919337dc4 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 20:43:43 +0100 Subject: [PATCH 21/71] eslint executed --- packages/web3-core-method/src/index.js | 6 ++--- .../src/methods/SignMethod.js | 6 ++--- .../transaction/SendTransactionMethod.js | 20 +++++----------- .../src/methods/network/ChainIdMethodTest.js | 4 ++-- packages/web3-core/src/AbstractWeb3Module.js | 8 +------ packages/web3-eth-accounts/src/Accounts.js | 7 +++--- .../src/factories/AccountsModuleFactory.js | 8 +------ packages/web3-eth-accounts/src/index.js | 1 - .../web3-eth-accounts/src/models/Account.js | 8 +++---- .../web3-eth-accounts/src/models/Wallet.js | 23 +++++++++++-------- packages/web3-eth/src/Eth.js | 1 - .../src/factories/EthModuleFactory.js | 5 +--- packages/web3-eth/src/index.js | 5 +--- .../web3-eth/src/signers/TransactionSigner.js | 6 ++--- 14 files changed, 41 insertions(+), 67 deletions(-) diff --git a/packages/web3-core-method/src/index.js b/packages/web3-core-method/src/index.js index 184245e78a1..3a3d308ff1f 100644 --- a/packages/web3-core-method/src/index.js +++ b/packages/web3-core-method/src/index.js @@ -31,14 +31,12 @@ import * as Utils from 'web3-utils'; /** * Returns the ModuleFactory of the method module * - * @param {Accounts} accounts - * * @returns {ModuleFactory} * * @constructor */ -export const MethodModuleFactory = (accounts) => { - return new ModuleFactory(accounts, new SubscriptionsFactory(), Utils, formatters); +export const MethodModuleFactory = () => { + return new ModuleFactory(new SubscriptionsFactory(), Utils, formatters); }; export AbstractMethod from '../lib/methods/AbstractMethod'; diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 9602190727c..41bd46d7830 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -67,9 +67,9 @@ export default class SignMethod extends AbstractCallMethod { let signedMessage; try { - signedMessage = Account.fromPrivateKey( - moduleInstance.accounts.wallet[this.parameters[1]] - ).sign(this.parameters[0]); + signedMessage = Account.fromPrivateKey(moduleInstance.accounts.wallet[this.parameters[1]]).sign( + this.parameters[0] + ); } catch (error) { if (this.callback) { this.callback(error, null); diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 6ecd58c9215..4554b545cbd 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -33,12 +33,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * * @constructor */ - constructor( - utils, - formatters, - transactionConfirmationWorkflow, - sendRawTransactionMethod - ) { + constructor(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod) { super('eth_sendTransaction', 1, utils, formatters, transactionConfirmationWorkflow); this.sendRawTransactionMethod = sendRawTransactionMethod; } @@ -72,12 +67,10 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (!this.isGasPriceDefined()) { if (!this.hasDefaultGasPrice(moduleInstance)) { - moduleInstance.currentProvider - .send('eth_gasPrice', []) - .then((gasPrice) => { - this.parameters[0]['gasPrice'] = gasPrice; - this.execute(moduleInstance, promiEvent); - }); + moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { + this.parameters[0]['gasPrice'] = gasPrice; + this.execute(moduleInstance, promiEvent); + }); return promiEvent; } @@ -85,7 +78,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0) { + if (moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[0].from]) { this.sendRawTransaction(this.parameters[0], promiEvent, moduleInstance); return promiEvent; @@ -124,7 +117,6 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (txProperties[1]) { tx.nonce = txProperties[1]; } - }); const transaction = this.formatters.txInputFormatter(tx); diff --git a/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js b/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js index 8787b47c36b..cd51ef802b6 100644 --- a/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/network/ChainIdMethodTest.js @@ -6,9 +6,9 @@ import ChainIdMethod from '../../../../src/methods/network/ChainIdMethod'; jest.mock('Utils'); /** - * PeerCountMethod test + * ChainIdMethod test */ -describe('PeerCountMethodTest', () => { +describe('ChainIdMethodTest', () => { let method; beforeEach(() => { diff --git a/packages/web3-core/src/AbstractWeb3Module.js b/packages/web3-core/src/AbstractWeb3Module.js index 12ebb49c05b..93ce82d3b9a 100644 --- a/packages/web3-core/src/AbstractWeb3Module.js +++ b/packages/web3-core/src/AbstractWeb3Module.js @@ -34,13 +34,7 @@ export default class AbstractWeb3Module { * * @constructor */ - constructor( - provider, - providersModuleFactory, - methodModuleFactory = null, - methodFactory = null, - options = {} - ) { + constructor(provider, providersModuleFactory, methodModuleFactory = null, methodFactory = null, options = {}) { this.providersModuleFactory = providersModuleFactory; this.providerDetector = providersModuleFactory.createProviderDetector(); // TODO: detection of an provider and setting of givenProvider could be removed. this.providerResolver = providersModuleFactory.createProviderResolver(); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 994216aff0f..450a01db1ff 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -20,6 +20,7 @@ * @date 2017 */ +import isFunction from 'lodash/isFunction'; import isObject from 'lodash/isObject'; import isBoolean from 'lodash/isBoolean'; import Hash from 'eth-lib/lib/hash'; @@ -27,8 +28,8 @@ import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import Account from './models/Account'; -//TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. -//TODO: After this refactoring will it be possible to move the wallet class to the eth module and to remove the accounts module. +// TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. +// TODO: After this refactoring will it be possible to move the wallet class to the eth module and to remove the accounts module. export default class Accounts { /** * @param {Utils} utils @@ -223,6 +224,6 @@ export default class Accounts { * @returns {Object} */ encrypt(privateKey, password, options) { - return Account.fromPrivateKey(privateKey, this.transactionSigner).toV3Keystore(password, option); + return Account.fromPrivateKey(privateKey, this.transactionSigner).toV3Keystore(password, options); } } diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index cb37f409921..9cf4dba84c7 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -21,7 +21,6 @@ */ import Accounts from '../Accounts'; -import Wallet from '../models/Wallet'; export default class AccountsModuleFactory { /** @@ -37,11 +36,6 @@ export default class AccountsModuleFactory { * @returns {Accounts} */ createAccounts(transactionSigner, wallet, utils, formatters) { - return new Accounts( - this.utils, - this.formatters, - transactionSigner, - wallet - ); + return new Accounts(this.utils, this.formatters, transactionSigner, wallet); } } diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index acb37bf4090..516291136f0 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -37,4 +37,3 @@ import AccountsModuleFactory from './factories/AccountsModuleFactory'; export const Accounts = (transactionSigner) => { return new AccountsModuleFactory().createAccounts(Utils, formatters, transactionSigner, new Wallet(Utils)); }; - diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 04b9a874d78..145956de2d6 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -17,12 +17,12 @@ * @date 2019 */ -const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); import scryptsy from 'scrypt.js'; import isString from 'lodash/isString'; import isObject from 'lodash/isObject'; import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency import uuid from 'uuid'; +const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); export default class Account { /** @@ -55,7 +55,7 @@ export default class Account { * @returns {Promise} */ signTransaction(tx) { - return this.transactionSigner.sign(new Transaction(tx), this.privateKey); + return this.transactionSigner.sign(tx, this.privateKey); } /** @@ -68,7 +68,7 @@ export default class Account { * @returns {String} */ sign(data) { - return EthAccount.sign(hash, this.privateKey); + return EthAccount.sign(data, this.privateKey); } /** @@ -80,7 +80,7 @@ export default class Account { * @returns {EncryptedKeystoreV3Json | {version, id, address, crypto}} */ encrypt(password, options) { - return Account.fromPrivateKey(this.privateKey, this.transactionSinger).toV3Keystore(password, option); + return Account.fromPrivateKey(this.privateKey, this.transactionSinger).toV3Keystore(password, options); } /** diff --git a/packages/web3-eth-accounts/src/models/Wallet.js b/packages/web3-eth-accounts/src/models/Wallet.js index 10e32082392..81b222316a8 100644 --- a/packages/web3-eth-accounts/src/models/Wallet.js +++ b/packages/web3-eth-accounts/src/models/Wallet.js @@ -19,8 +19,9 @@ import has from 'lodash/has'; import isString from 'lodash/isString'; +import Account from './Account'; -class Wallet { +export default class Wallet { /** * @param {Utils} utils * @@ -59,11 +60,13 @@ class Wallet { * @returns {Number[]} */ _currentIndexes() { - return Object.keys(this).map((key) => { - return parseInt(key); - }).filter((n) => { - return n < 9e20; - }); + return Object.keys(this) + .map((key) => { + return parseInt(key); + }) + .filter((n) => { + return n < 9e20; + }); } /** @@ -91,7 +94,7 @@ class Wallet { * * @method add * - * @param {Account} account + * @param {Account|String} account * * @returns {Object} */ @@ -192,7 +195,7 @@ class Wallet { const account = Account.fromV3Keystore(keystore, password); if (!account) { - throw new Error('Couldn\'t decrypt accounts. Password wrong?'); + throw new Error("Couldn't decrypt accounts. Password wrong?"); } this.add(account); @@ -213,7 +216,7 @@ class Wallet { */ save(password, keyName) { if (typeof localStorage === 'undefined') { - throw new Error('window.localStorage is undefined.'); + throw new TypeError('window.localStorage is undefined.'); } try { @@ -247,7 +250,7 @@ class Wallet { */ load(password, keyName) { if (typeof localStorage === 'undefined') { - throw new Error('window.localStorage is undefined.'); + throw new TypeError('window.localStorage is undefined.'); } let keystore; diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index 549323ab8b6..83f629ff9fb 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -396,7 +396,6 @@ export default class Eth extends AbstractWeb3Module { return ( this.net.setProvider(provider, net) && this.personal.setProvider(provider, net) && - this.accounts.setProvider(provider, net) && super.setProvider(provider, net) && setContractProviders ); diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js index 450a66a7bd6..d7334cdad28 100644 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ b/packages/web3-eth/src/factories/EthModuleFactory.js @@ -31,10 +31,7 @@ export default class EthModuleFactory { * * @constructor */ - constructor( - utils, - formatters, - ) { + constructor(utils, formatters) { this.utils = utils; this.formatters = formatters; } diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 36be59e1900..2c9fa1464ec 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -51,10 +51,7 @@ export const Eth = (provider, options) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); - return new EthModuleFactory( - Utils, - formatters, - ).createEthModule( + return new EthModuleFactory(Utils, formatters).createEthModule( provider, new ProvidersModuleFactory(), methodModuleFactory, diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index cf053787bbd..a463e488906 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -26,12 +26,12 @@ export default class TransactionSigner { /** * Signs the transaction * - * @param {Transaction} tx + * @param {Transaction} transaction * @param {String} privateKey * * @returns {Promise} */ - async sign(tx, privateKey) { + async sign(transaction, privateKey) { let result; const rlpEncoded = RLP.encode([ @@ -119,6 +119,6 @@ export default class TransactionSigner { * @returns {Boolean} */ isUndefinedOrNull(value) { - return (typeof value === 'undefined' && value === null); + return typeof value === 'undefined' && value === null; } } From 243f44b366d9e4e8b7752ea7e8dae1af842ae3fc Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 21:19:09 +0100 Subject: [PATCH 22/71] short sentence added to the signTransaction method because this method just works if you're connected to a Parity node --- docs/web3-eth.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/web3-eth.rst b/docs/web3-eth.rst index a5f94713f67..0b6b18b02e4 100644 --- a/docs/web3-eth.rst +++ b/docs/web3-eth.rst @@ -1174,7 +1174,8 @@ signTransaction web3.eth.signTransaction(transactionObject [, address] [, callback]) -Signs a transaction. This account needs to be unlocked. +The method ``signTransaction`` signs a transaction with the private key of the given address. +This method does only work if you're connected to a Parity node. ---------- Parameters From adf8b800bf0449b4cdd030498a54b5e7231de275 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 21:24:27 +0100 Subject: [PATCH 23/71] unnecessary dependency removed in SignMethod --- packages/web3-core-method/src/methods/SignMethod.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 41bd46d7830..0cf04bd5442 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -21,8 +21,8 @@ */ import AbstractCallMethod from '../../lib/methods/AbstractCallMethod'; -import Account from '../../../web3-eth-accounts/src/models/Account'; +// TODO: Move local signing logic to the eth module export default class SignMethod extends AbstractCallMethod { /** * @param {Utils} utils @@ -67,7 +67,9 @@ export default class SignMethod extends AbstractCallMethod { let signedMessage; try { - signedMessage = Account.fromPrivateKey(moduleInstance.accounts.wallet[this.parameters[1]]).sign( + signedMessage = moduleInstance.accounts.privateKeyToAccount( + moduleInstance.accounts.wallet[this.parameters[1]] + ).sign( this.parameters[0] ); } catch (error) { From 1819c5acc07f90b17ce7671bb198233f3db14eeb Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 21:34:12 +0100 Subject: [PATCH 24/71] SendTransactionMethod updated if any custom signer got defined which doesn't have the name TransactionSigner it will sign and send it as raw transaction to the node --- .../transaction/SendTransactionMethod.js | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 4554b545cbd..9b1a623c94e 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -78,8 +78,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[0].from]) { - this.sendRawTransaction(this.parameters[0], promiEvent, moduleInstance); + if ( + moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[0].from] || + moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner' + ) { + this.sendRawTransaction(promiEvent, moduleInstance); return promiEvent; } @@ -94,39 +97,39 @@ export default class SendTransactionMethod extends AbstractSendMethod { * * @method sendRawTransaction * - * @param {Object} tx * @param {PromiEvent} promiEvent * @param {AbstractWeb3Module} moduleInstance */ - sendRawTransaction(tx, promiEvent, moduleInstance) { - let missingTxProperties = []; + sendRawTransaction(promiEvent, moduleInstance) { + let missingTxProperties = [], + transaction = this.parameters[0]; - if (tx.chainId) { + if (transaction.chainId) { missingTxProperties.push(moduleInstance.getChainId()); } - if (tx.nonce) { + if (transaction.nonce) { missingTxProperties.push(moduleInstance.getTransactionCount()); } Promise.all(missingTxProperties).then((txProperties) => { if (txProperties[0]) { - tx.chainId = txProperties[0]; + transaction.chainId = txProperties[0]; } if (txProperties[1]) { - tx.nonce = txProperties[1]; + transaction.nonce = txProperties[1]; } }); - const transaction = this.formatters.txInputFormatter(tx); + transaction = this.formatters.txInputFormatter(transaction); transaction.to = tx.to || '0x'; transaction.data = tx.data || '0x'; transaction.value = tx.value || '0x'; - transaction.chainId = this.utils.numberToHex(tx.chainId); + transaction.chainId = this.utils.numberToHex(transaction.chainId); moduleInstance.transactionSigner - .sign(this.parameters[0], moduleInstance.accounts.wallet[tx.from]) + .sign(transaction, moduleInstance.accounts.wallet[this.parameters[0].from]) .then((response) => { this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.callback = this.callback; From b78ae98b9dfc9469250b1b83914d7a8a0fd51cd9 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 22:40:46 +0100 Subject: [PATCH 25/71] SendTransactionMethod signing workflow improved --- .../transaction/SendTransactionMethod.js | 129 +++++++----------- 1 file changed, 50 insertions(+), 79 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 9b1a623c94e..e836a116c90 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -61,14 +61,14 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @returns {PromiEvent} */ execute(moduleInstance, promiEvent) { - if (!this.isGasLimitDefined() && this.hasDefaultGasLimit(moduleInstance)) { + if (!this.parameters[0].gas && moduleInstance.defaultGas) { this.parameters[0]['gas'] = moduleInstance.defaultGas; } - if (!this.isGasPriceDefined()) { - if (!this.hasDefaultGasPrice(moduleInstance)) { + if (!this.parameters[0].gasPrice) { + if (!moduleInstance.defaultGasPrice) { moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { - this.parameters[0]['gasPrice'] = gasPrice; + this.parameters[0].gasPrice = gasPrice; this.execute(moduleInstance, promiEvent); }); @@ -78,58 +78,69 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if ( - moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[0].from] || - moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner' - ) { - this.sendRawTransaction(promiEvent, moduleInstance); + if (!this.parameters[0].nonce) { + moduleInstance.getTransactionCount().then((count) => { + this.parameters[0].nonce = count; + + this.execute(moduleInstance, promiEvent); + }); + + return promiEvent + } + + if (this.isWeb3Signing(moduleInstance)) { + this.sendRawTransaction( + this.formatTransactionForSigning(transaction), + moduleInstance.accounts.wallet[this.parameters[0].from], + promiEvent, + moduleInstance + ); return promiEvent; } + if (this.hasCustomSigner(moduleInstance)) { + this.sendRawTransaction(this.formatTransactionForSigning(transaction), null, promiEvent, moduleInstance); + } + super.execute(moduleInstance, promiEvent); return promiEvent; } - /** - * Signs the transaction and executes the SendRawTransaction method. - * - * @method sendRawTransaction - * - * @param {PromiEvent} promiEvent - * @param {AbstractWeb3Module} moduleInstance - */ - sendRawTransaction(promiEvent, moduleInstance) { - let missingTxProperties = [], - transaction = this.parameters[0]; + formatTransactionForSigning(transaction) { + let transaction = this.parameters[0]; if (transaction.chainId) { - missingTxProperties.push(moduleInstance.getChainId()); - } + moduleInstance.getChainId().then((chainId) => { + this.parameters[0].chainId = chainId; - if (transaction.nonce) { - missingTxProperties.push(moduleInstance.getTransactionCount()); + this.execute(moduleInstance, promiEvent); + }); } - Promise.all(missingTxProperties).then((txProperties) => { - if (txProperties[0]) { - transaction.chainId = txProperties[0]; - } - - if (txProperties[1]) { - transaction.nonce = txProperties[1]; - } - }); - transaction = this.formatters.txInputFormatter(transaction); transaction.to = tx.to || '0x'; transaction.data = tx.data || '0x'; transaction.value = tx.value || '0x'; transaction.chainId = this.utils.numberToHex(transaction.chainId); + return transaction; + } + + /** + * Signs the transaction and executes the SendRawTransaction method. + * + * @method sendRawTransaction + * + * @param {Object} transaction + * @param {String} privateKey + * @param {PromiEvent} promiEvent + * @param {AbstractWeb3Module} moduleInstance + */ + sendRawTransaction(transactiom, privateKey, promiEvent, moduleInstance) { moduleInstance.transactionSigner - .sign(transaction, moduleInstance.accounts.wallet[this.parameters[0].from]) + .sign(transaction, privateKey) .then((response) => { this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.callback = this.callback; @@ -147,51 +158,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { }); } - /** - * Checks if the given Web3Module has an default gasPrice defined - * - * @method hasDefaultGasPrice - * - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Boolean} - */ - hasDefaultGasPrice(moduleInstance) { - return moduleInstance.defaultGasPrice !== null && typeof moduleInstance.defaultGasPrice !== 'undefined'; + isWeb3Signing(moduleInstance) { + return moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0; } - /** - * Checks if gasPrice is defined in the method options - * - * @method isGasPriceDefined - * - * @returns {Boolean} - */ - isGasPriceDefined() { - return isObject(this.parameters[0]) && typeof this.parameters[0].gasPrice !== 'undefined'; - } - - /** - * Checks if the given Web3Module has an default gas limit defined - * - * @method hasDefaultGasLimit - * - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Boolean} - */ - hasDefaultGasLimit(moduleInstance) { - return moduleInstance.defaultGas !== null && typeof moduleInstance.defaultGas !== 'undefined'; - } - - /** - * Checks if a gas limit is defined - * - * @method isGasLimitDefined - * - * @returns {Boolean} - */ - isGasLimitDefined() { - return isObject(this.parameters[0]) && typeof this.parameters[0].gas !== 'undefined'; + hasCustomSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; } } From 78994b3fd9fe97981dc5f4435f716be533ef7e92 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Thu, 21 Feb 2019 22:48:17 +0100 Subject: [PATCH 26/71] codestyle improvements --- .../transaction/SendTransactionMethod.js | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index e836a116c90..cbc96c09aff 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -69,6 +69,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (!moduleInstance.defaultGasPrice) { moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { this.parameters[0].gasPrice = gasPrice; + this.execute(moduleInstance, promiEvent); }); @@ -81,11 +82,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (!this.parameters[0].nonce) { moduleInstance.getTransactionCount().then((count) => { this.parameters[0].nonce = count; - + this.execute(moduleInstance, promiEvent); }); - return promiEvent + return promiEvent; } if (this.isWeb3Signing(moduleInstance)) { @@ -101,6 +102,8 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (this.hasCustomSigner(moduleInstance)) { this.sendRawTransaction(this.formatTransactionForSigning(transaction), null, promiEvent, moduleInstance); + + return promiEvent; } super.execute(moduleInstance, promiEvent); @@ -108,6 +111,13 @@ export default class SendTransactionMethod extends AbstractSendMethod { return promiEvent; } + /** + * Formats the transaction options object + * + * @param {Object} transaction + * + * @returns {Object} + */ formatTransactionForSigning(transaction) { let transaction = this.parameters[0]; @@ -158,11 +168,31 @@ export default class SendTransactionMethod extends AbstractSendMethod { }); } + /** + * Checks if the current module has decrypted accounts + * + * @method isWeb3Signing + * + * @param moduleInstance + * + * @returns {Boolean} + */ isWeb3Signing(moduleInstance) { - return moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0; + return moduleInstance.accounts && + moduleInstance.accounts.wallet.length > 0 && + moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; } + /** + * Checks if a custom signer is given. + * + * @method hasCustomerSigner + * + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ hasCustomSigner(moduleInstance) { - return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; + return moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner'; } } From 9129509524c6c6e42cdfac56b4a00bcafbd4983e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 14:07:19 +0100 Subject: [PATCH 27/71] AccountsTest updated and not required test cases moved to new test files --- packages/web3-eth-accounts/src/Accounts.js | 27 +- .../tests/__mocks__/TransactionSigner.js | 22 + .../tests/src/AccountsTest.js | 1179 ++--------------- .../tests/src/models/AccountTest.js | 530 ++++++++ .../src/signers/TransactionSignerTest.js | 17 + 5 files changed, 699 insertions(+), 1076 deletions(-) create mode 100644 packages/web3-eth-accounts/tests/__mocks__/TransactionSigner.js create mode 100644 packages/web3-eth-accounts/tests/src/models/AccountTest.js create mode 100644 packages/web3-eth/tests/src/signers/TransactionSignerTest.js diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 450a01db1ff..270e569d1e5 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -27,23 +27,24 @@ import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import Account from './models/Account'; +import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency // TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. // TODO: After this refactoring will it be possible to move the wallet class to the eth module and to remove the accounts module. export default class Accounts { /** - * @param {Utils} utils - * @param {Object} formatters * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet + * @param {Utils} utils + * @param {Object} formatters * * @constructor */ - constructor(utils, formatters, transactionSigner, wallet) { - this.utils = utils; - this.formatters = formatters; + constructor(transactionSigner, wallet, utils, formatters) { this.wallet = wallet; this.transactionSigner = transactionSigner; + this.utils = utils; + this.formatters = formatters; return new Proxy(this, { get: (target, name) => { @@ -94,7 +95,7 @@ export default class Accounts { */ async signTransaction(tx, privateKey, callback) { try { - const signedTransaction = Account.fromPrivateKey(privateKey, this.transactionSigner).signTransaction(tx); + const signedTransaction = await Account.fromPrivateKey(privateKey, this.transactionSigner).signTransaction(tx); if (isFunction(callback)) { callback(false, signedTransaction); @@ -121,13 +122,13 @@ export default class Accounts { */ recoverTransaction(rawTx) { const values = RLP.decode(rawTx); - const signature = Account.encodeSignature(values.slice(6, 9)); + const signature = EthAccount.encodeSignature(values.slice(6, 9)); const recovery = Bytes.toNumber(values[6]); const extraData = recovery < 35 ? [] : [Bytes.fromNumber((recovery - 35) >> 1), '0x', '0x']; const signingData = values.slice(0, 6).concat(extraData); const signingDataHex = RLP.encode(signingData); - return Account.recover(Hash.keccak256(signingDataHex), signature); + return EthAccount.recover(Hash.keccak256(signingDataHex), signature); } /** @@ -160,7 +161,7 @@ export default class Accounts { * @returns {Object} */ sign(data, privateKey) { - return Account.fromPrivateKey(privateKey).sign(data); + return Account.fromPrivateKey(privateKey, this.transactionSigner).sign(data); } /** @@ -178,7 +179,7 @@ export default class Accounts { const args = [].slice.apply(arguments); if (isObject(message)) { - return this.recover(message.messageHash, Account.encodeSignature([message.v, message.r, message.s]), true); + return this.recover(message.messageHash, EthAccount.encodeSignature([message.v, message.r, message.s]), true); } if (!preFixed) { @@ -189,10 +190,10 @@ export default class Accounts { preFixed = args.slice(-1)[0]; preFixed = isBoolean(preFixed) ? preFixed : false; - return this.recover(message, Account.encodeSignature(args.slice(1, 4)), preFixed); // v, r, s + return this.recover(message, EthAccount.encodeSignature(args.slice(1, 4)), preFixed); // v, r, s } - return Account.recover(message, signature); + return EthAccount.recover(message, signature); } /** @@ -209,7 +210,7 @@ export default class Accounts { * @returns {Account} */ decrypt(v3Keystore, password, nonStrict) { - return Account.fromV3Keystore(v3Keystore, password, nonStrict); + return Account.fromV3Keystore(v3Keystore, password, nonStrict, this.transactionSigner); } /** diff --git a/packages/web3-eth-accounts/tests/__mocks__/TransactionSigner.js b/packages/web3-eth-accounts/tests/__mocks__/TransactionSigner.js new file mode 100644 index 00000000000..c88cae6f7f8 --- /dev/null +++ b/packages/web3-eth-accounts/tests/__mocks__/TransactionSigner.js @@ -0,0 +1,22 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** + * @file TransactionSigner.js + * @author Samuel Furter + * @date 2019 + */ + +export default class TransactionSigner { + sign() {} +} diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index 9b8b9ddbb7c..daf214b5e8f 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,84 +1,47 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; -import {GetGasPriceMethod, GetTransactionCountMethod, MethodModuleFactory, VersionMethod} from 'web3-core-method'; -import {AbstractWeb3Module} from 'web3-core'; -import Account from 'eth-lib/lib/account'; +import {GetGasPriceMethod, GetTransactionCountMethod, VersionMethod} from 'web3-core-method'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; -import Nat from 'eth-lib/lib/nat'; import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import crypto from 'crypto'; import uuid from 'uuid'; -import MethodFactory from '../../src/factories/MethodFactory'; +import TransactionSigner from '../__mocks__/TransactionSigner'; +import Wallet from '../../src/models/Wallet'; import Accounts from '../../src/Accounts'; +import Account from '../../src/models/Account'; +import * as EthAccount from 'eth-lib/lib/account'; // Mocks jest.mock('Utils'); jest.mock('formatters'); -jest.mock('HttpProvider'); -jest.mock('ProvidersModuleFactory'); -jest.mock('MethodModuleFactory'); -jest.mock('eth-lib/lib/account'); jest.mock('eth-lib/lib/rlp'); jest.mock('eth-lib/lib/nat'); jest.mock('eth-lib/lib/bytes'); jest.mock('eth-lib/lib/hash'); +jest.mock('eth-lib/lib/account'); jest.mock('scryptsy'); jest.mock('crypto'); jest.mock('uuid'); +jest.mock('../../src/models/Wallet'); +jest.mock('../../src/models/Account'); /** * Accounts test */ describe('AccountsTest', () => { let accounts, - methodFactory, - methodModuleFactoryMock, - providerMock, - providersModuleFactoryMock, - providerDetectorMock, - providerResolverMock; + transactionSignerMock, + walletMock; beforeEach(() => { - new HttpProvider(); - providerMock = HttpProvider.mock.instances[0]; - - new ProvidersModuleFactory(); - providersModuleFactoryMock = ProvidersModuleFactory.mock.instances[0]; - - new ProviderDetector(); - providerDetectorMock = ProviderDetector.mock.instances[0]; - providerDetectorMock.detect = jest.fn(() => { - return null; - }); - - new ProviderResolver(); - providerResolverMock = ProviderResolver.mock.instances[0]; - providerResolverMock.resolve = jest.fn(() => { - return providerMock; - }); - - providersModuleFactoryMock.createProviderDetector.mockReturnValueOnce(providerDetectorMock); - - providersModuleFactoryMock.createProviderResolver.mockReturnValueOnce(providerResolverMock); - - new MethodModuleFactory(); - methodModuleFactoryMock = MethodModuleFactory.mock.instances[0]; - methodModuleFactoryMock.createMethodProxy = jest.fn(); - - methodFactory = new MethodFactory(methodModuleFactoryMock, Utils, formatters); - - accounts = new Accounts( - providerMock, - providersModuleFactoryMock, - methodModuleFactoryMock, - methodFactory, - Utils, - formatters, - {} - ); + transactionSignerMock = new TransactionSigner(); + + new Wallet(Utils); + walletMock = Wallet.mock.instances[0]; + + accounts = new Accounts(transactionSignerMock, walletMock, Utils, formatters); }); it('constructor check', () => { @@ -86,625 +49,172 @@ describe('AccountsTest', () => { expect(accounts.formatters).toEqual(formatters); - expect(accounts.wallet.defaultKeyName).toEqual('web3js_wallet'); - - expect(accounts).toBeInstanceOf(AbstractWeb3Module); - }); - - it('JSON-RPC methods check', () => { - expect(accounts.methodFactory.methods).toEqual({ - getGasPrice: GetGasPriceMethod, - getTransactionCount: GetTransactionCountMethod, - getId: VersionMethod - }); - }); - - it('calls addAccountFunctions and returns the expected object', () => { - const object = {}; + expect(accounts.wallet).toEqual(walletMock); - expect(accounts._addAccountFunctions(object)).toBeInstanceOf(Object); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); + expect(accounts.transactionSigner).toEqual(transactionSignerMock); }); it('calls create with the entropy parameter and returns the expected object', () => { - const object = {}; - - Account.create = jest.fn((entropy) => { - expect(entropy).toEqual('entropy'); - - return object; - }); - - expect(accounts.create('entropy')).toBeInstanceOf(Object); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); - }); - - it('calls create without the entropy parameter and returns the expected object', () => { - const object = {}; - - Utils.randomHex = jest.fn(() => { - return '0x0'; - }); - - Account.create = jest.fn((entropy) => { - expect(entropy).toEqual('0x0'); - - return object; - }); + Account.from.mockReturnValueOnce(true); - expect(accounts.create()).toBeInstanceOf(Object); + expect(accounts.create('entropy')).toEqual(true); - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); - - expect(Utils.randomHex).toHaveBeenCalledWith(32); + expect(Account.from).toHaveBeenCalledWith('entropy', transactionSignerMock); }); it('calls privateKeyToAccount with the privateKey parameter and returns the expected object', () => { - const object = {}; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return object; - }); - - expect(accounts.privateKeyToAccount('pk')).toBeInstanceOf(Object); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); - }); - - it('calls signTransaction and returns a resolved promise', async () => { - const callback = jest.fn(); - - const tx = { - gas: 1, - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - RLP.encode = jest.fn(); - RLP.decode = jest.fn(); - Hash.keccak256 = jest.fn(); - Account.makeSigner = jest.fn(); - Account.decodeSignature = jest.fn(); - Nat.toNumber = jest.fn(); - Bytes.fromNat = jest.fn(); - - formatters.inputCallFormatter.mockReturnValueOnce(tx); - - Utils.numberToHex.mockReturnValueOnce(1); - - RLP.encode.mockReturnValue('encoded'); - - Bytes.fromNat.mockReturnValue(1); - - Hash.keccak256.mockReturnValue('hash'); - - const signer = jest.fn(); - - Account.makeSigner.mockReturnValueOnce(signer); - - signer.mockReturnValueOnce('signature'); - - Nat.toNumber.mockReturnValueOnce(1); - - Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); - - RLP.decode - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); - - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(callback).toHaveBeenCalledWith(null, { - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); - - expect(Utils.numberToHex).toHaveBeenCalledWith(4); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(1, 2); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(2, 3); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(3, 1); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(4, 5); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(5, 1); - - expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); - - expect(RLP.encode).toHaveBeenNthCalledWith(2, [ - 'zero', - 'one', - 'two', - 'three', - 'four', - 'five', - 'seven', - 'eight', - 'nine' - ]); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); - - expect(Nat.toNumber).toHaveBeenCalledWith(1); - - expect(Account.makeSigner).toHaveBeenCalledWith(37); - - expect(signer).toHaveBeenCalledWith('hash', 'pk'); - - expect(RLP.decode).toHaveBeenCalledWith('encoded'); - - expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); - }); - - it('calls signTransaction without chainId, gasPrice, nonce and returns a resolved promise', async () => { - const callback = jest.fn(); - - const tx = { - gas: 1, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - RLP.encode = jest.fn(); - RLP.decode = jest.fn(); - Hash.keccak256 = jest.fn(); - Account.makeSigner = jest.fn(); - Account.decodeSignature = jest.fn(); - Nat.toNumber = jest.fn(); - Bytes.fromNat = jest.fn(); - accounts.getId = jest.fn(); - accounts.getGasPrice = jest.fn(); - accounts.getTransactionCount = jest.fn(); + Account.fromPrivateKey.mockReturnValueOnce(true); - formatters.inputCallFormatter.mockReturnValueOnce(tx); + expect(accounts.privateKeyToAccount('pk')).toEqual(true); - Utils.numberToHex.mockReturnValueOnce(1); - - RLP.encode.mockReturnValue('encoded'); - - Bytes.fromNat.mockReturnValue(1); - - Hash.keccak256.mockReturnValue('hash'); - - const signer = jest.fn(); - - Account.makeSigner.mockReturnValueOnce(signer); - - signer.mockReturnValueOnce('signature'); - - Nat.toNumber.mockReturnValueOnce(1); - - Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); - - RLP.decode - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); - - accounts.getId.mockReturnValueOnce(Promise.resolve(4)); - - accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(3)); - - accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(2)); - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return {address: '0x0'}; - }); - - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(callback).toHaveBeenCalledWith(null, { - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); - - expect(Utils.numberToHex).toHaveBeenCalledWith(4); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(1, 2); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(2, 3); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(3, 1); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(4, 5); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(5, 1); - - expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); - - expect(RLP.encode).toHaveBeenNthCalledWith(2, [ - 'zero', - 'one', - 'two', - 'three', - 'four', - 'five', - 'seven', - 'eight', - 'nine' - ]); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); - - expect(Nat.toNumber).toHaveBeenCalledWith(1); - - expect(Account.makeSigner).toHaveBeenCalledWith(37); - - expect(signer).toHaveBeenCalledWith('hash', 'pk'); - - expect(RLP.decode).toHaveBeenCalledWith('encoded'); - - expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); - - expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); - - expect(accounts.getId).toHaveBeenCalled(); - - expect(accounts.getGasPrice).toHaveBeenCalled(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); }); - it('calls singTransaction and returns a rejected promise because it could not fetch the missing properties', async () => { - accounts.getId = jest.fn(); - accounts.getGasPrice = jest.fn(); - accounts.getTransactionCount = jest.fn(); - - accounts.getId.mockReturnValueOnce(Promise.resolve(null)); + it('calls signTransaction and resolves with a promise', async () => { + const callback = jest.fn(), + signTransaction = jest.fn(); - accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(null)); + signTransaction.mockReturnValueOnce(Promise.resolve('signed-transaction')); - accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(null)); + Account.fromPrivateKey.mockReturnValueOnce({signTransaction: signTransaction}); - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); + await expect(accounts.signTransaction({}, 'pk', callback)).resolves.toEqual('signed-transaction'); - return {address: '0x0'}; - }); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); - await expect(accounts.signTransaction({}, 'pk', () => {})).rejects.toThrow( - `One of the values 'chainId', 'gasPrice', or 'nonce' couldn't be fetched: ${JSON.stringify([ - null, - null, - null - ])}` - ); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); - - expect(accounts.getId).toHaveBeenCalled(); - - expect(accounts.getGasPrice).toHaveBeenCalled(); + expect(signTransaction).toHaveBeenCalledWith({}); }); - it('calls singTransaction and returns a rejected promise because of invalid values in the TX', async () => { - const tx = { - gas: -1, - nonce: -2, - gasPrice: -3, - chainId: -4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow( - 'Gas, gasPrice, nonce or chainId is lower than 0' - ); - }); - - it('calls singTransaction and returns a rejected promise because the gas limit property is missing', async () => { - const tx = { - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow('gas is missing'); - }); - - it('calls singTransaction and returns a rejected promise because of the inputCallFormatter', async () => { - const tx = { - gas: 1, - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; + it('calls signTransaction and rejects with a promise', async () => { + const signTransaction = jest.fn(); + signTransaction.mockReturnValueOnce(Promise.reject('ERROR')); const callback = jest.fn(); - formatters.inputCallFormatter = jest.fn(() => { - throw new Error('ERROR'); - }); - - await expect(accounts.signTransaction(tx, 'pk', callback)).rejects.toThrow('ERROR'); + Account.fromPrivateKey.mockReturnValueOnce({signTransaction: signTransaction}); - expect(callback).toHaveBeenCalledWith(new Error('ERROR')); - }); + await expect(accounts.signTransaction({}, 'pk', callback)).rejects.toEqual('ERROR'); - it('calls singTransaction and returns a rejected promise because of the missing TX parameter', async () => { - const callback = jest.fn(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); - await expect(accounts.signTransaction(undefined, 'pk', callback)).rejects.toThrow( - 'No transaction object given!' - ); + expect(callback).toHaveBeenCalledWith('ERROR', null); - expect(callback).toHaveBeenCalledWith(new Error('No transaction object given!')); + expect(signTransaction).toHaveBeenCalledWith({}); }); it('calls recoverTransaction and returns the expected string', () => { - RLP.decode = jest.fn((rawTransaction) => { - expect(rawTransaction).toEqual('rawTransaction'); + RLP.decode.mockReturnValueOnce([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - }); + EthAccount.encodeSignature.mockReturnValueOnce('signature'); - Account.encodeSignature = jest.fn((values) => { - expect(values).toEqual([6, 7, 8]); + Bytes.toNumber.mockReturnValueOnce(40); - return 'signature'; - }); + Bytes.fromNumber.mockReturnValueOnce(1); - Bytes.toNumber = jest.fn((value) => { - expect(value).toEqual(6); + RLP.encode.mockReturnValueOnce('encoded'); - return 40; - }); + Hash.keccak256.mockReturnValueOnce('hash'); - Bytes.fromNumber = jest.fn((recovery) => { - expect(recovery).toEqual(2); + EthAccount.recover.mockReturnValueOnce('recovered'); - return 1; - }); - - RLP.encode = jest.fn((signingData) => { - expect(signingData).toEqual([0, 1, 2, 3, 4, 5, 1, '0x', '0x']); - - return 'encoded'; - }); - - Hash.keccak256 = jest.fn((signingDataHex) => { - expect(signingDataHex).toEqual('encoded'); - - return 'hash'; - }); - - Account.recover = jest.fn((hash, signature) => { - expect(hash).toEqual('hash'); - - expect(signature).toEqual('signature'); - - return 'recovered'; - }); expect(accounts.recoverTransaction('rawTransaction')).toEqual('recovered'); - expect(Account.recover).toHaveBeenCalled(); - expect(Hash.keccak256).toHaveBeenCalled(); + expect(EthAccount.recover).toHaveBeenCalledWith('hash', 'signature'); - expect(RLP.encode).toHaveBeenCalled(); + expect(Hash.keccak256).toHaveBeenCalledWith('encoded'); - expect(Bytes.fromNumber).toHaveBeenCalled(); + expect(RLP.encode).toHaveBeenCalledWith([0, 1, 2, 3, 4, 5, 1, '0x', '0x']); - expect(Bytes.toNumber).toHaveBeenCalled(); + expect(Bytes.fromNumber).toHaveBeenCalledWith(2); - expect(Account.encodeSignature).toHaveBeenCalled(); + expect(Bytes.toNumber).toHaveBeenCalledWith(6); - expect(RLP.decode).toHaveBeenCalled(); + expect(EthAccount.encodeSignature).toHaveBeenCalledWith([6, 7, 8]); + + expect(RLP.decode).toHaveBeenCalledWith('rawTransaction'); }); it('calls hashMessage with strict hex and returns the expected string', () => { - Utils.isHexStrict = jest.fn((data) => { - expect(data).toEqual('data'); - - return true; - }); + Utils.isHexStrict.mockReturnValueOnce(true); - Utils.hexToBytes = jest.fn((data) => { - expect(data).toEqual('data'); + Utils.hexToBytes.mockReturnValueOnce('message'); - return 'message'; - }); - - Hash.keccak256s = jest.fn((ethMessage) => { - const messageBuffer = Buffer.from('message'); - const preamble = `\u0019Ethereum Signed Message:\n${'message'.length}`; - const preambleBuffer = Buffer.from(preamble); - const message = Buffer.concat([preambleBuffer, messageBuffer]); - - expect(ethMessage).toEqual(message); - - return 'keccak'; - }); + Hash.keccak256s.mockReturnValueOnce('keccak'); expect(accounts.hashMessage('data')).toEqual('keccak'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(Utils.isHexStrict).toHaveBeenCalledWith('data'); - expect(Utils.hexToBytes).toHaveBeenCalled(); + expect(Utils.hexToBytes).toHaveBeenCalledWith('data'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); }); it('calls hashMessage with non-strict hex and returns the expected string', () => { - Utils.isHexStrict = jest.fn((data) => { - expect(data).toEqual('message'); - - return false; - }); - - Hash.keccak256s = jest.fn((ethMessage) => { - const messageBuffer = Buffer.from('message'); - const preamble = `\u0019Ethereum Signed Message:\n${'message'.length}`; - const preambleBuffer = Buffer.from(preamble); - const message = Buffer.concat([preambleBuffer, messageBuffer]); + Utils.isHexStrict.mockReturnValueOnce(false); - expect(ethMessage).toEqual(message); - - return 'keccak'; - }); + Hash.keccak256s.mockReturnValueOnce('keccak'); expect(accounts.hashMessage('message')).toEqual('keccak'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); }); - it('calls sign with non-strict hex and returns the expected string', () => { - Utils.isHexStrict = jest.fn((data) => { - expect(data).toEqual('message'); - - return false; - }); - - Hash.keccak256s = jest.fn((ethMessage) => { - const messageBuffer = Buffer.from('message'); - const preamble = `\u0019Ethereum Signed Message:\n${'message'.length}`; - const preambleBuffer = Buffer.from(preamble); - const message = Buffer.concat([preambleBuffer, messageBuffer]); - - expect(ethMessage).toEqual(message); + it('calls sign and returns the expected value', () => { + const sign = jest.fn(); - return 'keccak'; - }); + sign.mockReturnValueOnce(true); - Account.sign = jest.fn((hash, privateKey) => { - expect(hash).toEqual('keccak'); + Account.fromPrivateKey.mockReturnValueOnce({sign: sign}); - expect(privateKey).toEqual('pk'); + expect(accounts.sign('data', 'pk')).toEqual(true); - return 'signed'; - }); + expect(sign).toHaveBeenCalledWith('data'); - Account.decodeSignature = jest.fn((signature) => { - expect(signature).toEqual('signed'); - - return ['v', 'r', 's']; - }); - - expect(accounts.sign('message', 'pk')).toEqual({ - message: 'message', - messageHash: 'keccak', - v: 'v', - r: 'r', - s: 's', - signature: 'signed' - }); - - expect(Utils.isHexStrict).toHaveBeenCalled(); - - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); }); it('calls recover with a string as message and returns the expected value', () => { - Utils.isHexStrict = jest.fn((data) => { - expect(data).toEqual('message'); - - return false; - }); - - Hash.keccak256s = jest.fn((ethMessage) => { - const messageBuffer = Buffer.from('message'); - const preamble = `\u0019Ethereum Signed Message:\n${'message'.length}`; - const preambleBuffer = Buffer.from(preamble); - const message = Buffer.concat([preambleBuffer, messageBuffer]); - - expect(ethMessage).toEqual(message); - - return 'keccak'; - }); + Utils.isHexStrict.mockReturnValueOnce(false); - Account.recover = jest.fn((message, signature) => { - expect(message).toEqual('keccak'); + Hash.keccak256s.mockReturnValueOnce('keccak'); - expect(signature).toEqual('signature'); - - return 'recovered'; - }); + EthAccount.recover.mockReturnValueOnce('recovered'); expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); - expect(Account.recover).toHaveBeenCalled(); + expect(EthAccount.recover).toHaveBeenCalledWith('keccak', 'signature'); }); it('calls recover with a object as message and returns the expected value', () => { - Account.recover = jest.fn((message, signature) => { - expect(message).toEqual('message'); - - expect(signature).toEqual('signature'); - - return 'recovered'; - }); + EthAccount.recover.mockReturnValueOnce('recovered'); - Account.encodeSignature = jest.fn((vrs) => { - expect(vrs).toEqual(['v', 'r', 's']); - - return 'signature'; - }); + EthAccount.encodeSignature.mockReturnValueOnce('signature'); expect( accounts.recover( @@ -719,500 +229,43 @@ describe('AccountsTest', () => { ) ).toEqual('recovered'); - expect(Account.recover).toHaveBeenCalled(); + expect(EthAccount.recover).toHaveBeenCalledWith('message', 'signature'); + + expect(EthAccount.encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); }); it('calls recover with a string as message, preFixed is true and it returns the expected value', () => { - Account.recover = jest.fn((message, signature) => { - expect(message).toEqual('message'); + EthAccount.recover.mockReturnValueOnce('recovered'); - expect(signature).toEqual('signature'); - - return 'recovered'; - }); - - Account.encodeSignature = jest.fn((vrs) => { - expect(vrs).toEqual(['v', 'r', 's']); - - return 'signature'; - }); + EthAccount.encodeSignature.mockReturnValueOnce('signature'); expect(accounts.recover('message', 'v', 'r', 's', true)).toEqual('recovered'); - expect(Account.recover).toHaveBeenCalled(); - }); - - it('calls decrypt and returns the expected object', () => { - const json = { - version: 3, - crypto: { - kdf: 'scrypt', - mac: 'mac', - ciphertext: 'xx', - cipher: 'cipher', - cipherparams: { - iv: ['0x0'] - }, - kdfparams: { - n: 'n', - r: 'r', - p: 'p', - dklen: 'dklen', - salt: 'salt' - } - } - }; - - const object = {}; - - Account.fromPrivate = jest.fn((seed) => { - expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); - - return object; - }); - - scryptsy.mockReturnValueOnce(Buffer.from('00000000000000000000000000000000')); - - Utils.sha3.mockReturnValueOnce('0xmac'); - - const decipher = { - update: jest.fn(), - final: jest.fn() - }; + expect(EthAccount.recover).toHaveBeenCalledWith('message', 'signature'); - decipher.update.mockReturnValueOnce(Buffer.from('0')); - - decipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { - expect(cipher).toEqual('cipher'); - - expect(derivedKey).toEqual(Buffer.from('0000000000000000')); - - expect(buffer).toEqual(Buffer.from(['0x0'], 'hex')); - - return decipher; - }); - - expect(accounts.decrypt(json, 'password', false)).toEqual(object); - - expect(scryptsy).toHaveBeenCalledWith( - Buffer.from('password'), - Buffer.from('salt', 'hex'), - 'n', - 'r', - 'p', - 'dklen' - ); - - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) - ); - - expect(crypto.createDecipheriv).toHaveBeenCalled(); - - expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); - - expect(decipher.final).toHaveBeenCalled(); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); + expect(EthAccount.encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); }); - it('calls decrypt with pbkdf2 and returns the expected object', () => { - const json = { - version: 3, - crypto: { - kdf: 'pbkdf2', - mac: 'mac', - ciphertext: 'xx', - cipher: 'cipher', - cipherparams: { - iv: ['0x0'] - }, - kdfparams: { - c: 1, - dklen: 'dklen', - salt: 'salt', - prf: 'hmac-sha256' - } - } - }; - - const object = {}; - - Account.fromPrivate = jest.fn((seed) => { - expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); - - return object; - }); + it('calls decrypt and returns the expected value', () => { + Account.fromV3Keystore.mockReturnValueOnce(true); - Utils.sha3.mockReturnValueOnce('0xmac'); + expect(accounts.decrypt('v3Keystore', 'password', false)).toEqual(true); - const decipher = { - update: jest.fn(), - final: jest.fn() - }; - - decipher.update.mockReturnValueOnce(Buffer.from('0')); - - decipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { - expect(cipher).toEqual('cipher'); - - expect(derivedKey).toEqual(Buffer.from('0000000000000000')); - - expect(buffer).toEqual(Buffer.from(['0x0'], 'hex')); - - return decipher; - }); - - crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { - expect(password).toEqual(Buffer.from(password)); - - expect(salt).toEqual(Buffer.from('salt', 'hex')); - - expect(c).toEqual(1); - - expect(dklen).toEqual('dklen'); - - expect(sha256).toEqual('sha256'); - - return Buffer.from('00000000000000000000000000000000'); - }); - - expect(accounts.decrypt(json, 'password', false)).toEqual(object); - - expect(crypto.pbkdf2Sync).toHaveBeenCalled(); - - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) - ); - - expect(crypto.createDecipheriv).toHaveBeenCalled(); - - expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); - - expect(decipher.final).toHaveBeenCalled(); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); - }); - - it('calls decrypt and throws an error because of the missing password paramerter', () => { - expect(() => { - accounts.decrypt(''); - }).toThrow('No password given.'); - }); - - it('calls decrypt and throws an error because of a wrong keystore version', () => { - expect(() => { - accounts.decrypt({version: 0}, 'password', false); - }).toThrow('Not a valid V3 wallet'); - }); - - it('calls decrypt with pbkdf2 and throws an error because of a wrong PRF property', () => { - expect(() => { - accounts.decrypt({version: 3, crypto: {kdf: 'pbkdf2', kdfparams: {prf: 'nope'}}}, 'password', false); - }).toThrow('Unsupported parameters to PBKDF2'); + expect(Account.fromV3Keystore).toHaveBeenCalledWith('v3Keystore', 'password', false, transactionSignerMock); }); - it('calls decrypt with unsupported scheme and throws an error', () => { - expect(() => { - accounts.decrypt({version: 3, crypto: {kdf: 'asdf'}}, 'password', false); - }).toThrow('Unsupported key derivation scheme'); - }); - - it('calls decrypt and the key derivation failed and throws an error', () => { - const json = { - version: 3, - crypto: { - kdf: 'pbkdf2', - mac: 'macs', - ciphertext: 'xx', - cipher: 'cipher', - cipherparams: { - iv: ['0x0'] - }, - kdfparams: { - c: 1, - dklen: 'dklen', - salt: 'salt', - prf: 'hmac-sha256' - } - } - }; - - Utils.sha3.mockReturnValueOnce('0xmac'); - - crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { - expect(password).toEqual(Buffer.from(password)); - - expect(salt).toEqual(Buffer.from('salt', 'hex')); - - expect(c).toEqual(1); - - expect(dklen).toEqual('dklen'); - - expect(sha256).toEqual('sha256'); - - return Buffer.from('00000000000000000000000000000000'); - }); - - expect(() => { - accounts.decrypt(json, 'password', false); - }).toThrow('Key derivation failed - possibly wrong password'); - - expect(crypto.pbkdf2Sync).toHaveBeenCalled(); - - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) - ); - }); - - it('calls encrypt and returns the expected object', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - - const options = {}; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; - }); - - crypto.randomBytes.mockReturnValue(Buffer.from('random')); - - const cipher = { - update: jest.fn(), - final: jest.fn() - }; - - cipher.update.mockReturnValueOnce(Buffer.from('0')); - - cipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createCipheriv.mockReturnValue(cipher); - - scryptsy.mockReturnValueOnce(Buffer.from('0000000000000000')); - - Utils.sha3.mockReturnValueOnce('0xmac'); - - uuid.v4.mockReturnValueOnce(0); - - expect(accounts.encrypt('pk', 'password', options)).toEqual({ - version: 3, - id: 0, - address: 'a', - crypto: { - ciphertext: '3030', - cipherparams: {iv: '72616e646f6d'}, - cipher: 'aes-128-ctr', - kdf: 'scrypt', - kdfparams: { - dklen: 32, - salt: '72616e646f6d', - n: 8192, - p: 1, - r: 8 - }, - mac: 'mac' - } - }); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(3, 16); - - expect(scryptsy).toHaveBeenCalledWith(Buffer.from('password'), Buffer.from('random'), 8192, 8, 1, 32); - - expect(crypto.createCipheriv).toHaveBeenCalledWith( - 'aes-128-ctr', - Buffer.from('0000000000000000').slice(0, 16), - Buffer.from('random') - ); - - expect(cipher.update).toHaveBeenCalledWith(Buffer.from(account.privateKey.replace('0x', ''), 'hex')); - - expect(cipher.final).toHaveBeenCalled(); - - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([ - Buffer.from('0000000000000000').slice(16, 32), - Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') - ]) - ); - - expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); - }); - - it('calls encrypt with the pbkdf2 sheme and returns the expected object', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - - const options = {kdf: 'pbkdf2'}; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; - }); - - crypto.randomBytes.mockReturnValue(Buffer.from('random')); - - const cipher = { - update: jest.fn(), - final: jest.fn() - }; - - cipher.update.mockReturnValueOnce(Buffer.from('0')); - - cipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createCipheriv.mockReturnValue(cipher); - - crypto.pbkdf2Sync = jest.fn(() => { - return Buffer.from('0000000000000000'); - }); - - Utils.sha3.mockReturnValueOnce('0xmac'); - - uuid.v4.mockReturnValueOnce(0); - - expect(accounts.encrypt('pk', 'password', options)).toEqual({ - version: 3, - id: 0, - address: 'a', - crypto: { - ciphertext: '3030', - cipherparams: {iv: '72616e646f6d'}, - cipher: 'aes-128-ctr', - kdf: 'pbkdf2', - kdfparams: { - dklen: 32, - salt: '72616e646f6d', - c: 262144, - prf: 'hmac-sha256' - }, - mac: 'mac' - } - }); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(3, 16); - - expect(crypto.pbkdf2Sync).toHaveBeenCalledWith( - Buffer.from('password'), - Buffer.from('random'), - 262144, - 32, - 'sha256' - ); - - expect(crypto.createCipheriv).toHaveBeenCalledWith( - 'aes-128-ctr', - Buffer.from('0000000000000000').slice(0, 16), - Buffer.from('random') - ); - - expect(cipher.update).toHaveBeenCalledWith(Buffer.from(account.privateKey.replace('0x', ''), 'hex')); - - expect(cipher.final).toHaveBeenCalled(); - - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([ - Buffer.from('0000000000000000').slice(16, 32), - Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') - ]) - ); - - expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); - }); - - it('calls encrypt with a unsupported sheme', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; - }); - - crypto.randomBytes.mockReturnValue(Buffer.from('random')); - - expect(() => { - accounts.encrypt('pk', 'password', {kdf: 'nope'}); - }).toThrow('Unsupported kdf'); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); - }); - - it('calls encrypt with a unsupported cipher', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - - const options = {kdf: 'pbkdf2'}; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; - }); - - crypto.randomBytes.mockReturnValue(Buffer.from('random')); - - crypto.createCipheriv.mockReturnValue(false); - - crypto.pbkdf2Sync = jest.fn(() => { - return Buffer.from('0000000000000000'); - }); - - Utils.sha3.mockReturnValueOnce('0xmac'); + it('calls encrypt and returns the expected value', () => { + const toV3Keystore = jest.fn(); - expect(() => { - accounts.encrypt('pk', 'password', options); - }).toThrow('Unsupported cipher'); + toV3Keystore.mockReturnValueOnce(true); - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + Account.fromPrivateKey.mockReturnValueOnce({toV3Keystore: toV3Keystore}); - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + expect(accounts.encrypt('pk', 'password', {})).toEqual(true); - expect(crypto.pbkdf2Sync).toHaveBeenCalledWith( - Buffer.from('password'), - Buffer.from('random'), - 262144, - 32, - 'sha256' - ); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); - expect(crypto.createCipheriv).toHaveBeenCalledWith( - 'aes-128-ctr', - Buffer.from('0000000000000000').slice(0, 16), - Buffer.from('random') - ); + expect(toV3Keystore).toHaveBeenCalledWith('password', {}); }); -}); +}) +; diff --git a/packages/web3-eth-accounts/tests/src/models/AccountTest.js b/packages/web3-eth-accounts/tests/src/models/AccountTest.js new file mode 100644 index 00000000000..b044a6ebafe --- /dev/null +++ b/packages/web3-eth-accounts/tests/src/models/AccountTest.js @@ -0,0 +1,530 @@ +// Mocks +import Account from '../../../src/models/Account'; +import scryptsy from 'scrypt.js'; +import crypto from "crypto"; +import uuid from 'uuid'; +import Hash from 'eth-lib/lib/hash'; + +jest.mock(''); + +/** + * AccountTest test + */ +describe('AccountTestTest', () => { + let AccountTest; + + beforeEach(() => { + AccountTest = new AccountTest(); + }); + + it('constructor check', () => { + + }); + + it('calls sign with non-strict hex and returns the expected string', () => { + Utils.isHexStrict.mockReturnValueOnce(false); + + Hash.keccak256s.mockReturnValueOnce('keccak'); + + Account.sign.mockReturnValueOnce('signed'); + + Account.decodeSignature.mockReturnValueOnce(['v', 'r', 's']); + + expect(accounts.sign('message', 'pk')).toEqual({ + message: 'message', + messageHash: 'keccak', + v: 'v', + r: 'r', + s: 's', + signature: 'signed' + }); + + expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); + + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); + + expect(Account.sign).toHaveBeenCalledWith('keccak', 'pk'); + + expect(Account.decodeSignature).toHaveBeenCalledWith('signed'); + }); + + it('calls decrypt and returns the expected object', () => { + const json = { + version: 3, + crypto: { + kdf: 'scrypt', + mac: 'mac', + ciphertext: 'xx', + cipher: 'cipher', + cipherparams: { + iv: ['0x0'] + }, + kdfparams: { + n: 'n', + r: 'r', + p: 'p', + dklen: 'dklen', + salt: 'salt' + } + } + }; + + const object = {}; + + Account.fromPrivate = jest.fn((seed) => { + expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); + + return object; + }); + + scryptsy.mockReturnValueOnce(Buffer.from('00000000000000000000000000000000')); + + Utils.sha3.mockReturnValueOnce('0xmac'); + + const decipher = { + update: jest.fn(), + final: jest.fn() + }; + + decipher.update.mockReturnValueOnce(Buffer.from('0')); + + decipher.final.mockReturnValueOnce(Buffer.from('0')); + + crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { + expect(cipher).toEqual('cipher'); + + expect(derivedKey).toEqual(Buffer.from('0000000000000000')); + + expect(buffer).toEqual(Buffer.from(['0x0'], 'hex')); + + return decipher; + }); + + expect(accounts.decrypt(json, 'password', false)).toEqual(object); + + expect(scryptsy).toHaveBeenCalledWith( + Buffer.from('password'), + Buffer.from('salt', 'hex'), + 'n', + 'r', + 'p', + 'dklen' + ); + + expect(Utils.sha3).toHaveBeenCalledWith( + Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) + ); + + expect(crypto.createDecipheriv).toHaveBeenCalled(); + + expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); + + expect(decipher.final).toHaveBeenCalled(); + + expect(object.signTransaction).toBeInstanceOf(Function); + + expect(object.sign).toBeInstanceOf(Function); + + expect(object.encrypt).toBeInstanceOf(Function); + }); + + it('calls decrypt with pbkdf2 and returns the expected object', () => { + const json = { + version: 3, + crypto: { + kdf: 'pbkdf2', + mac: 'mac', + ciphertext: 'xx', + cipher: 'cipher', + cipherparams: { + iv: ['0x0'] + }, + kdfparams: { + c: 1, + dklen: 'dklen', + salt: 'salt', + prf: 'hmac-sha256' + } + } + }; + + const object = {}; + + Account.fromPrivate = jest.fn((seed) => { + expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); + + return object; + }); + + Utils.sha3.mockReturnValueOnce('0xmac'); + + const decipher = { + update: jest.fn(), + final: jest.fn() + }; + + decipher.update.mockReturnValueOnce(Buffer.from('0')); + + decipher.final.mockReturnValueOnce(Buffer.from('0')); + + crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { + expect(cipher).toEqual('cipher'); + + expect(derivedKey).toEqual(Buffer.from('0000000000000000')); + + expect(buffer).toEqual(Buffer.from(['0x0'], 'hex')); + + return decipher; + }); + + crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { + expect(password).toEqual(Buffer.from(password)); + + expect(salt).toEqual(Buffer.from('salt', 'hex')); + + expect(c).toEqual(1); + + expect(dklen).toEqual('dklen'); + + expect(sha256).toEqual('sha256'); + + return Buffer.from('00000000000000000000000000000000'); + }); + + expect(accounts.decrypt(json, 'password', false)).toEqual(object); + + expect(crypto.pbkdf2Sync).toHaveBeenCalled(); + + expect(Utils.sha3).toHaveBeenCalledWith( + Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) + ); + + expect(crypto.createDecipheriv).toHaveBeenCalled(); + + expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); + + expect(decipher.final).toHaveBeenCalled(); + + expect(object.signTransaction).toBeInstanceOf(Function); + + expect(object.sign).toBeInstanceOf(Function); + + expect(object.encrypt).toBeInstanceOf(Function); + }); + + it('calls decrypt and throws an error because of the missing password paramerter', () => { + expect(() => { + accounts.decrypt(''); + }).toThrow('No password given.'); + }); + + it('calls decrypt and throws an error because of a wrong keystore version', () => { + expect(() => { + accounts.decrypt({version: 0}, 'password', false); + }).toThrow('Not a valid V3 wallet'); + }); + + it('calls decrypt with pbkdf2 and throws an error because of a wrong PRF property', () => { + expect(() => { + accounts.decrypt({version: 3, crypto: {kdf: 'pbkdf2', kdfparams: {prf: 'nope'}}}, 'password', false); + }).toThrow('Unsupported parameters to PBKDF2'); + }); + + it('calls decrypt with unsupported scheme and throws an error', () => { + expect(() => { + accounts.decrypt({version: 3, crypto: {kdf: 'asdf'}}, 'password', false); + }).toThrow('Unsupported key derivation scheme'); + }); + + it('calls decrypt and the key derivation failed and throws an error', () => { + const json = { + version: 3, + crypto: { + kdf: 'pbkdf2', + mac: 'macs', + ciphertext: 'xx', + cipher: 'cipher', + cipherparams: { + iv: ['0x0'] + }, + kdfparams: { + c: 1, + dklen: 'dklen', + salt: 'salt', + prf: 'hmac-sha256' + } + } + }; + + Utils.sha3.mockReturnValueOnce('0xmac'); + + crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { + expect(password).toEqual(Buffer.from(password)); + + expect(salt).toEqual(Buffer.from('salt', 'hex')); + + expect(c).toEqual(1); + + expect(dklen).toEqual('dklen'); + + expect(sha256).toEqual('sha256'); + + return Buffer.from('00000000000000000000000000000000'); + }); + + expect(() => { + accounts.decrypt(json, 'password', false); + }).toThrow('Key derivation failed - possibly wrong password'); + + expect(crypto.pbkdf2Sync).toHaveBeenCalled(); + + expect(Utils.sha3).toHaveBeenCalledWith( + Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) + ); + }); + + + it('calls encrypt and returns the expected object', () => { + const account = { + privateKey: '0xxx', + address: '0xA' + }; + + const options = {}; + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return account; + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + const cipher = { + update: jest.fn(), + final: jest.fn() + }; + + cipher.update.mockReturnValueOnce(Buffer.from('0')); + + cipher.final.mockReturnValueOnce(Buffer.from('0')); + + crypto.createCipheriv.mockReturnValue(cipher); + + scryptsy.mockReturnValueOnce(Buffer.from('0000000000000000')); + + Utils.sha3.mockReturnValueOnce('0xmac'); + + uuid.v4.mockReturnValueOnce(0); + + expect(accounts.encrypt('pk', 'password', options)).toEqual({ + version: 3, + id: 0, + address: 'a', + crypto: { + ciphertext: '3030', + cipherparams: {iv: '72616e646f6d'}, + cipher: 'aes-128-ctr', + kdf: 'scrypt', + kdfparams: { + dklen: 32, + salt: '72616e646f6d', + n: 8192, + p: 1, + r: 8 + }, + mac: 'mac' + } + }); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(3, 16); + + expect(scryptsy).toHaveBeenCalledWith(Buffer.from('password'), Buffer.from('random'), 8192, 8, 1, 32); + + expect(crypto.createCipheriv).toHaveBeenCalledWith( + 'aes-128-ctr', + Buffer.from('0000000000000000').slice(0, 16), + Buffer.from('random') + ); + + expect(cipher.update).toHaveBeenCalledWith(Buffer.from(account.privateKey.replace('0x', ''), 'hex')); + + expect(cipher.final).toHaveBeenCalled(); + + expect(Utils.sha3).toHaveBeenCalledWith( + Buffer.concat([ + Buffer.from('0000000000000000').slice(16, 32), + Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') + ]) + ); + + expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); + }); + + it('calls encrypt with the pbkdf2 sheme and returns the expected object', () => { + const account = { + privateKey: '0xxx', + address: '0xA' + }; + + const options = {kdf: 'pbkdf2'}; + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return account; + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + const cipher = { + update: jest.fn(), + final: jest.fn() + }; + + cipher.update.mockReturnValueOnce(Buffer.from('0')); + + cipher.final.mockReturnValueOnce(Buffer.from('0')); + + crypto.createCipheriv.mockReturnValue(cipher); + + crypto.pbkdf2Sync = jest.fn(() => { + return Buffer.from('0000000000000000'); + }); + + Utils.sha3.mockReturnValueOnce('0xmac'); + + uuid.v4.mockReturnValueOnce(0); + + expect(accounts.encrypt('pk', 'password', options)).toEqual({ + version: 3, + id: 0, + address: 'a', + crypto: { + ciphertext: '3030', + cipherparams: {iv: '72616e646f6d'}, + cipher: 'aes-128-ctr', + kdf: 'pbkdf2', + kdfparams: { + dklen: 32, + salt: '72616e646f6d', + c: 262144, + prf: 'hmac-sha256' + }, + mac: 'mac' + } + }); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(3, 16); + + expect(crypto.pbkdf2Sync).toHaveBeenCalledWith( + Buffer.from('password'), + Buffer.from('random'), + 262144, + 32, + 'sha256' + ); + + expect(crypto.createCipheriv).toHaveBeenCalledWith( + 'aes-128-ctr', + Buffer.from('0000000000000000').slice(0, 16), + Buffer.from('random') + ); + + expect(cipher.update).toHaveBeenCalledWith(Buffer.from(account.privateKey.replace('0x', ''), 'hex')); + + expect(cipher.final).toHaveBeenCalled(); + + expect(Utils.sha3).toHaveBeenCalledWith( + Buffer.concat([ + Buffer.from('0000000000000000').slice(16, 32), + Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') + ]) + ); + + expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); + }); + + it('calls encrypt with a unsupported sheme', () => { + const account = { + privateKey: '0xxx', + address: '0xA' + }; + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return account; + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + expect(() => { + accounts.encrypt('pk', 'password', {kdf: 'nope'}); + }).toThrow('Unsupported kdf'); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + }); + + it('calls encrypt with a unsupported cipher', () => { + const account = { + privateKey: '0xxx', + address: '0xA' + }; + + const options = {kdf: 'pbkdf2'}; + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return account; + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + crypto.createCipheriv.mockReturnValue(false); + + crypto.pbkdf2Sync = jest.fn(() => { + return Buffer.from('0000000000000000'); + }); + + Utils.sha3.mockReturnValueOnce('0xmac'); + + expect(() => { + accounts.encrypt('pk', 'password', options); + }).toThrow('Unsupported cipher'); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + + expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + + expect(crypto.pbkdf2Sync).toHaveBeenCalledWith( + Buffer.from('password'), + Buffer.from('random'), + 262144, + 32, + 'sha256' + ); + + expect(crypto.createCipheriv).toHaveBeenCalledWith( + 'aes-128-ctr', + Buffer.from('0000000000000000').slice(0, 16), + Buffer.from('random') + ); + }); +}); diff --git a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js new file mode 100644 index 00000000000..069f8f601d7 --- /dev/null +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -0,0 +1,17 @@ +// Mocks +jest.mock(''); + +/** + * TransactionSignerTest test + */ +describe('TransactionSignerTestTest', () => { + let TransactionSignerTest; + + beforeEach(() => { + TransactionSignerTest = new TransactionSignerTest(); + }); + + it('constructor check', () => { + + }); +}); From 6b770d569d919756b1289db96e38940d7da8ec35 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 14:07:36 +0100 Subject: [PATCH 28/71] TransactionSignerTest template created --- .../src/signers/TransactionSignerTest.js | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) diff --git a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js index 069f8f601d7..aa227d8f3f5 100644 --- a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -1,4 +1,7 @@ // Mocks +import Account from 'web3-eth-accounts/src/models/Account'; +import {formatters} from 'web3-core-helpers'; + jest.mock(''); /** @@ -14,4 +17,323 @@ describe('TransactionSignerTestTest', () => { it('constructor check', () => { }); + + it('calls signTransaction and returns a resolved promise', async () => { + const callback = jest.fn(); + + const tx = { + gas: 1, + nonce: 2, + gasPrice: 3, + chainId: 4, + value: 5, + to: 'LOWERCASE', + data: 'data' + }; + + RLP.encode = jest.fn(); + RLP.decode = jest.fn(); + Hash.keccak256 = jest.fn(); + Account.makeSigner = jest.fn(); + Account.decodeSignature = jest.fn(); + Nat.toNumber = jest.fn(); + Bytes.fromNat = jest.fn(); + + formatters.inputCallFormatter.mockReturnValueOnce(tx); + + Utils.numberToHex.mockReturnValueOnce(1); + + RLP.encode.mockReturnValue('encoded'); + + Bytes.fromNat.mockReturnValue(1); + + Hash.keccak256.mockReturnValue('hash'); + + const signer = jest.fn(); + + Account.makeSigner.mockReturnValueOnce(signer); + + signer.mockReturnValueOnce('signature'); + + Nat.toNumber.mockReturnValueOnce(1); + + Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); + + RLP.decode + .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) + .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); + + await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ + messageHash: 'hash', + v: 'six', + r: 'seven', + s: 'eight', + rawTransaction: 'encoded' + }); + + expect(callback).toHaveBeenCalledWith(null, { + messageHash: 'hash', + v: 'six', + r: 'seven', + s: 'eight', + rawTransaction: 'encoded' + }); + + expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); + + expect(Utils.numberToHex).toHaveBeenCalledWith(4); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(1, 2); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(2, 3); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(3, 1); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(4, 5); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(5, 1); + + expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); + + expect(RLP.encode).toHaveBeenNthCalledWith(2, [ + 'zero', + 'one', + 'two', + 'three', + 'four', + 'five', + 'seven', + 'eight', + 'nine' + ]); + + expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); + + expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); + + expect(Nat.toNumber).toHaveBeenCalledWith(1); + + expect(Account.makeSigner).toHaveBeenCalledWith(37); + + expect(signer).toHaveBeenCalledWith('hash', 'pk'); + + expect(RLP.decode).toHaveBeenCalledWith('encoded'); + + expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); + }); + + it('calls signTransaction without chainId, gasPrice, nonce and returns a resolved promise', async () => { + const callback = jest.fn(); + + const tx = { + gas: 1, + value: 5, + to: 'LOWERCASE', + data: 'data' + }; + + RLP.encode = jest.fn(); + RLP.decode = jest.fn(); + Hash.keccak256 = jest.fn(); + Account.makeSigner = jest.fn(); + Account.decodeSignature = jest.fn(); + Nat.toNumber = jest.fn(); + Bytes.fromNat = jest.fn(); + accounts.getId = jest.fn(); + accounts.getGasPrice = jest.fn(); + accounts.getTransactionCount = jest.fn(); + + formatters.inputCallFormatter.mockReturnValueOnce(tx); + + Utils.numberToHex.mockReturnValueOnce(1); + + RLP.encode.mockReturnValue('encoded'); + + Bytes.fromNat.mockReturnValue(1); + + Hash.keccak256.mockReturnValue('hash'); + + const signer = jest.fn(); + + Account.makeSigner.mockReturnValueOnce(signer); + + signer.mockReturnValueOnce('signature'); + + Nat.toNumber.mockReturnValueOnce(1); + + Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); + + RLP.decode + .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) + .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); + + accounts.getId.mockReturnValueOnce(Promise.resolve(4)); + + accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(3)); + + accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(2)); + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return {address: '0x0'}; + }); + + await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ + messageHash: 'hash', + v: 'six', + r: 'seven', + s: 'eight', + rawTransaction: 'encoded' + }); + + expect(callback).toHaveBeenCalledWith(null, { + messageHash: 'hash', + v: 'six', + r: 'seven', + s: 'eight', + rawTransaction: 'encoded' + }); + + expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); + + expect(Utils.numberToHex).toHaveBeenCalledWith(4); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(1, 2); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(2, 3); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(3, 1); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(4, 5); + + expect(Bytes.fromNat).toHaveBeenNthCalledWith(5, 1); + + expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); + + expect(RLP.encode).toHaveBeenNthCalledWith(2, [ + 'zero', + 'one', + 'two', + 'three', + 'four', + 'five', + 'seven', + 'eight', + 'nine' + ]); + + expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); + + expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); + + expect(Nat.toNumber).toHaveBeenCalledWith(1); + + expect(Account.makeSigner).toHaveBeenCalledWith(37); + + expect(signer).toHaveBeenCalledWith('hash', 'pk'); + + expect(RLP.decode).toHaveBeenCalledWith('encoded'); + + expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); + + expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); + + expect(accounts.getId).toHaveBeenCalled(); + + expect(accounts.getGasPrice).toHaveBeenCalled(); + }); + + it('calls singTransaction and returns a rejected promise because it could not fetch the missing properties', async () => { + accounts.getId = jest.fn(); + accounts.getGasPrice = jest.fn(); + accounts.getTransactionCount = jest.fn(); + + accounts.getId.mockReturnValueOnce(Promise.resolve(null)); + + accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(null)); + + accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(null)); + + Account.fromPrivate = jest.fn((pk) => { + expect(pk).toEqual('pk'); + + return {address: '0x0'}; + }); + + await expect(accounts.signTransaction({}, 'pk', () => {})).rejects.toThrow( + `One of the values 'chainId', 'gasPrice', or 'nonce' couldn't be fetched: ${JSON.stringify([ + null, + null, + null + ])}` + ); + + expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); + + expect(accounts.getId).toHaveBeenCalled(); + + expect(accounts.getGasPrice).toHaveBeenCalled(); + }); + + it('calls singTransaction and returns a rejected promise because of invalid values in the TX', async () => { + const tx = { + gas: -1, + nonce: -2, + gasPrice: -3, + chainId: -4, + value: 5, + to: 'LOWERCASE', + data: 'data' + }; + + await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow( + 'Gas, gasPrice, nonce or chainId is lower than 0' + ); + }); + + it('calls singTransaction and returns a rejected promise because the gas limit property is missing', async () => { + const tx = { + nonce: 2, + gasPrice: 3, + chainId: 4, + value: 5, + to: 'LOWERCASE', + data: 'data' + }; + + await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow('gas is missing'); + }); + + it('calls singTransaction and returns a rejected promise because of the inputCallFormatter', async () => { + const tx = { + gas: 1, + nonce: 2, + gasPrice: 3, + chainId: 4, + value: 5, + to: 'LOWERCASE', + data: 'data' + }; + + const callback = jest.fn(); + + formatters.inputCallFormatter = jest.fn(() => { + throw new Error('ERROR'); + }); + + await expect(accounts.signTransaction(tx, 'pk', callback)).rejects.toThrow('ERROR'); + + expect(callback).toHaveBeenCalledWith(new Error('ERROR')); + }); + + it('calls singTransaction and returns a rejected promise because of the missing TX parameter', async () => { + const callback = jest.fn(); + + await expect(accounts.signTransaction(undefined, 'pk', callback)).rejects.toThrow( + 'No transaction object given!' + ); + + expect(callback).toHaveBeenCalledWith(new Error('No transaction object given!')); + }); }); From 800cc3ddd4faac6db7b8000d9f0731cadc938c04 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 17:15:05 +0100 Subject: [PATCH 29/71] Account, Accounts and AccountsModuleFactory updated --- packages/web3-eth-accounts/src/Accounts.js | 45 +++++------- .../src/factories/AccountsModuleFactory.js | 5 +- .../web3-eth-accounts/src/models/Account.js | 37 +++++++--- .../tests/src/AccountsTest.js | 38 ---------- .../tests/src/models/AccountTest.js | 69 ++++++++++++++++--- 5 files changed, 109 insertions(+), 85 deletions(-) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 270e569d1e5..70ac38f55e1 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -28,22 +28,21 @@ import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import Account from './models/Account'; import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency +import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. // TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. -// TODO: After this refactoring will it be possible to move the wallet class to the eth module and to remove the accounts module. +// TODO: After this refactoring is it possible to move the wallet class to the eth module and to remove the accounts module. export default class Accounts { /** * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet - * @param {Utils} utils * @param {Object} formatters * * @constructor */ - constructor(transactionSigner, wallet, utils, formatters) { - this.wallet = wallet; + constructor(transactionSigner, wallet, formatters) { this.transactionSigner = transactionSigner; - this.utils = utils; + this.wallet = wallet; this.formatters = formatters; return new Proxy(this, { @@ -131,25 +130,6 @@ export default class Accounts { return EthAccount.recover(Hash.keccak256(signingDataHex), signature); } - /** - * Hashes a given message - * - * @method hashMessage - * - * @param {String} data - * - * @returns {String} - */ - hashMessage(data) { - const message = this.utils.isHexStrict(data) ? this.utils.hexToBytes(data) : data; - const messageBuffer = Buffer.from(message); - const preamble = `\u0019Ethereum Signed Message:\n${message.length}`; - const preambleBuffer = Buffer.from(preamble); - const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); - - return Hash.keccak256s(ethMessage); - } - /** * Signs a string with the given privateKey * @@ -161,7 +141,11 @@ export default class Accounts { * @returns {Object} */ sign(data, privateKey) { - return Account.fromPrivateKey(privateKey, this.transactionSigner).sign(data); + if (isHexStrict(data)) { + data = hexToBytes(data); + } + + return Account.fromPrivateKey(privateKey).sign(data); } /** @@ -183,7 +167,16 @@ export default class Accounts { } if (!preFixed) { - message = this.hashMessage(message); + if (isHexStrict(message)) { + message = hexToBytes(message); + } + + const messageBuffer = Buffer.from(message); + const preamble = `\u0019Ethereum Signed Message:\n${message.length}`; + const preambleBuffer = Buffer.from(preamble); + const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); + + message = Hash.keccak256s(ethMessage); } if (args.length >= 4) { diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js index 9cf4dba84c7..d91cbfba5ec 100644 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js @@ -30,12 +30,11 @@ export default class AccountsModuleFactory { * * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet - * @param {Utils} utils * @param {Object}formatters * * @returns {Accounts} */ - createAccounts(transactionSigner, wallet, utils, formatters) { - return new Accounts(this.utils, this.formatters, transactionSigner, wallet); + createAccounts(transactionSigner, wallet, formatters) { + return new Accounts(transactionSigner, wallet, formatters); } } diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 145956de2d6..27d6f7b1a74 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -22,17 +22,19 @@ import isString from 'lodash/isString'; import isObject from 'lodash/isObject'; import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency import uuid from 'uuid'; +import Hash from 'eth-lib/lib/hash'; +import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); export default class Account { /** - * @param {Object} options + * @param {Object} options TODO: Pass a Address VO in the options * @param {TransactionSigner} transactionSigner * * @constructor */ - constructor(options, transactionSigner) { - this.address = options.address; // TODO: Add address validation here (if enough time create a Address VO) + constructor(options, transactionSigner = null) { + this.address = options.address; this.privateKey = options.privateKey; this.transactionSinger = transactionSigner; @@ -68,7 +70,26 @@ export default class Account { * @returns {String} */ sign(data) { - return EthAccount.sign(data, this.privateKey); + if (isHexStrict(data)) { + data = hexToBytes(data); + } + + const messageBuffer = Buffer.from(data); + const preamble = `\u0019Ethereum Signed Message:\n${message.length}`; + const preambleBuffer = Buffer.from(preamble); + const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); + const hash = Hash.keccak256s(ethMessage); + const signature = EthAccount.sign(hash, this.privateKey); + const vrs = EthAccount.decodeSignature(signature); + + return { + message: data, + messageHash: hash, + v: vrs[0], + r: vrs[1], + s: vrs[2], + signature + }; } /** @@ -91,7 +112,7 @@ export default class Account { * * @returns {Account} */ - static from(entropy, transactionSigner) { + static from(entropy, transactionSigner = null) { return new Account(EthAccount.create(entropy || this.utils.randomHex(32)), transactionSigner); } @@ -103,8 +124,8 @@ export default class Account { * * @returns {Account} */ - static fromPrivateKey(privateKey, transactionSigner) { - return new Account(EthAccount.fromPrivate(privateKey), transactionSigner); + static fromPrivateKey(privateKey, transactionSigner = null) { + return new Account(EthAccount.fromPrivate(privateKey), transactionSigner = null); } /** @@ -190,7 +211,7 @@ export default class Account { * * @returns {Account} */ - static fromV3Keystore(v3Keystore, password, nonStrict = false, transactionSigner) { + static fromV3Keystore(v3Keystore, password, nonStrict = false, transactionSigner = null) { if (!isString(password)) { throw new Error('No password given.'); } diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index daf214b5e8f..08f75217396 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -138,44 +138,6 @@ describe('AccountsTest', () => { expect(RLP.decode).toHaveBeenCalledWith('rawTransaction'); }); - it('calls hashMessage with strict hex and returns the expected string', () => { - Utils.isHexStrict.mockReturnValueOnce(true); - - Utils.hexToBytes.mockReturnValueOnce('message'); - - Hash.keccak256s.mockReturnValueOnce('keccak'); - - expect(accounts.hashMessage('data')).toEqual('keccak'); - - expect(Utils.isHexStrict).toHaveBeenCalledWith('data'); - - expect(Utils.hexToBytes).toHaveBeenCalledWith('data'); - - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); - }); - - it('calls hashMessage with non-strict hex and returns the expected string', () => { - Utils.isHexStrict.mockReturnValueOnce(false); - - Hash.keccak256s.mockReturnValueOnce('keccak'); - - expect(accounts.hashMessage('message')).toEqual('keccak'); - - expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); - - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); - }); - it('calls sign and returns the expected value', () => { const sign = jest.fn(); diff --git a/packages/web3-eth-accounts/tests/src/models/AccountTest.js b/packages/web3-eth-accounts/tests/src/models/AccountTest.js index b044a6ebafe..9dbb0d6304e 100644 --- a/packages/web3-eth-accounts/tests/src/models/AccountTest.js +++ b/packages/web3-eth-accounts/tests/src/models/AccountTest.js @@ -1,36 +1,49 @@ -// Mocks -import Account from '../../../src/models/Account'; import scryptsy from 'scrypt.js'; -import crypto from "crypto"; +import crypto from 'crypto'; import uuid from 'uuid'; import Hash from 'eth-lib/lib/hash'; +import TransactionSigner from '../../__mocks__/TransactionSigner'; +import Account from '../../../src/models/Account'; +// Mocks jest.mock(''); /** * AccountTest test */ describe('AccountTestTest', () => { - let AccountTest; + let account, transactionSignerMock; beforeEach(() => { - AccountTest = new AccountTest(); + transactionSignerMock = new TransactionSigner(); + + account = new Account({address: 'address', privateKey: 'pk'}, transactionSignerMock); }); it('constructor check', () => { + expect(account.address).toEqual('address'); + + expect(account.privateKey).toEqual('pk'); + expect(account.transactionSigner).toEqual(transactionSignerMock); }); - it('calls sign with non-strict hex and returns the expected string', () => { - Utils.isHexStrict.mockReturnValueOnce(false); + it('calls signTransaction and returns the expected value', () => { + transactionSignerMock.sign.mockReturnValueOnce(true); + + expect(account.sign({})).toEqual(true); + + expect(transactionSignerMock.sign).toHaveBeenCalledWith({}, 'pk'); + }); + it('calls sign with non-strict hex and returns the expected string', () => { Hash.keccak256s.mockReturnValueOnce('keccak'); Account.sign.mockReturnValueOnce('signed'); Account.decodeSignature.mockReturnValueOnce(['v', 'r', 's']); - expect(accounts.sign('message', 'pk')).toEqual({ + expect(account.sign('message')).toEqual({ message: 'message', messageHash: 'keccak', v: 'v', @@ -39,8 +52,6 @@ describe('AccountTestTest', () => { signature: 'signed' }); - expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s) .toHaveBeenCalledWith( Buffer.concat( @@ -53,6 +64,44 @@ describe('AccountTestTest', () => { expect(Account.decodeSignature).toHaveBeenCalledWith('signed'); }); + it('calls hashMessage with strict hex and returns the expected string', () => { + Utils.isHexStrict.mockReturnValueOnce(true); + + Utils.hexToBytes.mockReturnValueOnce('message'); + + Hash.keccak256s.mockReturnValueOnce('keccak'); + + expect(accounts.hashMessage('data')).toEqual('keccak'); + + expect(Utils.isHexStrict).toHaveBeenCalledWith('data'); + + expect(Utils.hexToBytes).toHaveBeenCalledWith('data'); + + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); + }); + + it('calls hashMessage with non-strict hex and returns the expected string', () => { + Utils.isHexStrict.mockReturnValueOnce(false); + + Hash.keccak256s.mockReturnValueOnce('keccak'); + + expect(accounts.hashMessage('message')).toEqual('keccak'); + + expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); + + expect(Hash.keccak256s) + .toHaveBeenCalledWith( + Buffer.concat( + [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] + ) + ); + }); + it('calls decrypt and returns the expected object', () => { const json = { version: 3, From 8533bd4e2c50ef6bd8d6d54b1498f5c3e7da2432 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 17:41:39 +0100 Subject: [PATCH 30/71] SendTransactionMeethod updated and signTransaction in eth-accounts updated --- .../transaction/SendTransactionMethod.js | 19 +++---- packages/web3-eth-accounts/src/Accounts.js | 57 +++++++++++++++---- .../web3-eth-accounts/src/models/Account.js | 26 +++++---- 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index cbc96c09aff..31cd88d75b8 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -79,8 +79,8 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (!this.parameters[0].nonce) { - moduleInstance.getTransactionCount().then((count) => { + if (moduleInstance.accounts.wallet[this.parameters[0].from]) { + moduleInstance.getTransactionCount(this.parameters[0].from).then((count) => { this.parameters[0].nonce = count; this.execute(moduleInstance, promiEvent); @@ -91,7 +91,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (this.isWeb3Signing(moduleInstance)) { this.sendRawTransaction( - this.formatTransactionForSigning(transaction), + this.formatTransactionForSigning(), moduleInstance.accounts.wallet[this.parameters[0].from], promiEvent, moduleInstance @@ -101,7 +101,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { } if (this.hasCustomSigner(moduleInstance)) { - this.sendRawTransaction(this.formatTransactionForSigning(transaction), null, promiEvent, moduleInstance); + this.sendRawTransaction(this.formatTransactionForSigning(), null, promiEvent, moduleInstance); return promiEvent; } @@ -114,14 +114,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { /** * Formats the transaction options object * - * @param {Object} transaction * * @returns {Object} */ - formatTransactionForSigning(transaction) { - let transaction = this.parameters[0]; - - if (transaction.chainId) { + formatTransactionForSigning() { + if (this.parameters[0].chainId) { moduleInstance.getChainId().then((chainId) => { this.parameters[0].chainId = chainId; @@ -129,7 +126,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { }); } - transaction = this.formatters.txInputFormatter(transaction); + let transaction = this.formatters.txInputFormatter(this.parameters[0]); transaction.to = tx.to || '0x'; transaction.data = tx.data || '0x'; transaction.value = tx.value || '0x'; @@ -148,7 +145,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {PromiEvent} promiEvent * @param {AbstractWeb3Module} moduleInstance */ - sendRawTransaction(transactiom, privateKey, promiEvent, moduleInstance) { + sendRawTransaction(transaction, privateKey, promiEvent, moduleInstance) { moduleInstance.transactionSigner .sign(transaction, privateKey) .then((response) => { diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 70ac38f55e1..9a0ad5ede5f 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -26,24 +26,45 @@ import isBoolean from 'lodash/isBoolean'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; -import Account from './models/Account'; import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. +import {AbstractWeb3Module} from 'web3-core'; +import Account from './models/Account'; // TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. // TODO: After this refactoring is it possible to move the wallet class to the eth module and to remove the accounts module. -export default class Accounts { +export default class Accounts extends AbstractWeb3Module { /** + * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @param {ProvidersModuleFactory} providersModuleFactory * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet * @param {Object} formatters + * @param {GetChainIdMethod} getChainIdMethod + * @param {GetGasPriceMethod} getGasPriceMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod + * @param options * * @constructor */ - constructor(transactionSigner, wallet, formatters) { - this.transactionSigner = transactionSigner; + constructor( + provider, + providersModuleFactory, + transactionSigner, + wallet, + formatters, + getChainIdMethod, + getGasPriceMethod, + getTransactionCountMethod, + options + ) { + super(provider, providersModuleFactory, null, null, options); + this.transactionSigner = options.transactionSigner || transactionSigner; this.wallet = wallet; this.formatters = formatters; + this.getChainIdMethod = getChainIdMethod; + this.getGasPriceMethod = getGasPriceMethod; + this.getTransactionCountMethod = getTransactionCountMethod; return new Proxy(this, { get: (target, name) => { @@ -62,7 +83,7 @@ export default class Accounts { * @returns {Account} */ create(entropy) { - return Account.from(entropy, this.transactionSigner); + return Account.from(entropy, this); } /** @@ -75,7 +96,7 @@ export default class Accounts { * @returns {Account} */ privateKeyToAccount(privateKey) { - return Account.fromPrivateKey(privateKey, this.transactionSigner); + return Account.fromPrivateKey(privateKey, this); } /** @@ -93,8 +114,24 @@ export default class Accounts { * @returns {Promise} */ async signTransaction(tx, privateKey, callback) { + const account = Account.fromPrivateKey(privateKey, this); + + if (!tx.chainId) { + tx.chainId = await this.getChainIdMethod.execute(this); + } + + if (!tx.getGasPrice) { + tx.getGasPrice = await this.getGasPriceMethod.execute(this); + } + + if (!tx.nonce) { + this.getTransactionCountMethod.parameters = [account.address]; + + tx.nonce = await this.getTransactionCountMethod.execute(this); + } + try { - const signedTransaction = await Account.fromPrivateKey(privateKey, this.transactionSigner).signTransaction(tx); + const signedTransaction = await account.signTransaction(tx); if (isFunction(callback)) { callback(false, signedTransaction); @@ -145,7 +182,7 @@ export default class Accounts { data = hexToBytes(data); } - return Account.fromPrivateKey(privateKey).sign(data); + return Account.fromPrivateKey(privateKey, this).sign(data); } /** @@ -203,7 +240,7 @@ export default class Accounts { * @returns {Account} */ decrypt(v3Keystore, password, nonStrict) { - return Account.fromV3Keystore(v3Keystore, password, nonStrict, this.transactionSigner); + return Account.fromV3Keystore(v3Keystore, password, nonStrict, this); } /** @@ -218,6 +255,6 @@ export default class Accounts { * @returns {Object} */ encrypt(privateKey, password, options) { - return Account.fromPrivateKey(privateKey, this.transactionSigner).toV3Keystore(password, options); + return Account.fromPrivateKey(privateKey, this).toV3Keystore(password, options); } } diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 27d6f7b1a74..102242683dd 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -23,20 +23,20 @@ import isObject from 'lodash/isObject'; import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency import uuid from 'uuid'; import Hash from 'eth-lib/lib/hash'; -import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. +import {isHexStrict, hexToBytes, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); export default class Account { /** * @param {Object} options TODO: Pass a Address VO in the options - * @param {TransactionSigner} transactionSigner + * @param {Accounts} accounts * * @constructor */ - constructor(options, transactionSigner = null) { + constructor(options, accounts = null) { this.address = options.address; this.privateKey = options.privateKey; - this.transactionSinger = transactionSigner; + this.accounts = accounts; return new Proxy(this, { get: (target, name) => { @@ -46,18 +46,20 @@ export default class Account { } /** - * TODO: Add deprecation message, remove TransactionSigner dependency and extend the signTransaction method in the eth module. - * TODO: Create Transaction VO or add validation here. + * TODO: Add deprecation message, remove accounts dependency and extend the signTransaction method in the eth module. * Signs a transaction object with the given privateKey * * @method signTransaction * * @param {Object} tx + * @param {String} privateKey + * @param {Function }callback * + * @callback callback callback(error, result) * @returns {Promise} */ - signTransaction(tx) { - return this.transactionSigner.sign(tx, this.privateKey); + signTransaction(tx, privateKey, callback) { + return this.accounts.signTransaction(tx, this.privateKey, callback); } /** @@ -101,7 +103,7 @@ export default class Account { * @returns {EncryptedKeystoreV3Json | {version, id, address, crypto}} */ encrypt(password, options) { - return Account.fromPrivateKey(this.privateKey, this.transactionSinger).toV3Keystore(password, options); + return Account.fromPrivateKey(this.privateKey, this.accounts.transactionSinger).toV3Keystore(password, options); } /** @@ -113,7 +115,7 @@ export default class Account { * @returns {Account} */ static from(entropy, transactionSigner = null) { - return new Account(EthAccount.create(entropy || this.utils.randomHex(32)), transactionSigner); + return new Account(EthAccount.create(entropy || randomHex(32)), this.accounts.transactionSigner); } /** @@ -125,7 +127,7 @@ export default class Account { * @returns {Account} */ static fromPrivateKey(privateKey, transactionSigner = null) { - return new Account(EthAccount.fromPrivate(privateKey), transactionSigner = null); + return new Account(EthAccount.fromPrivate(privateKey), this.accounts.transactionSigner); } /** @@ -268,6 +270,6 @@ export default class Account { ); const seed = `0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`; - return this.fromPrivateKey(seed, transactionSigner); + return this.fromPrivateKey(seed, this.accounts.transactionSigner); } } From ffe399082735dc2ef39310ad97a45b2e327ac65d Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 18:04:55 +0100 Subject: [PATCH 31/71] index.js updated and factory removed in eth-accounts module --- packages/web3-core-method/src/index.js | 1 + packages/web3-eth-accounts/src/Accounts.js | 12 +++--- .../src/factories/AccountsModuleFactory.js | 40 ------------------- packages/web3-eth-accounts/src/index.js | 23 ++++++++--- .../web3-eth-accounts/src/models/Account.js | 5 +-- 5 files changed, 25 insertions(+), 56 deletions(-) delete mode 100644 packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js diff --git a/packages/web3-core-method/src/index.js b/packages/web3-core-method/src/index.js index 3a3d308ff1f..b50db0f8497 100644 --- a/packages/web3-core-method/src/index.js +++ b/packages/web3-core-method/src/index.js @@ -47,6 +47,7 @@ export GetProtocolVersionMethod from './methods/network/GetProtocolVersionMethod export VersionMethod from './methods/network/VersionMethod'; export ListeningMethod from './methods/network/ListeningMethod'; export PeerCountMethod from './methods/network/PeerCountMethod'; +export ChainIdMethod from './methods/network/ChainIdMethod'; // Node export GetNodeInfoMethod from './methods/node/GetNodeInfoMethod'; diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 9a0ad5ede5f..d5c5b1410cd 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -37,10 +37,9 @@ export default class Accounts extends AbstractWeb3Module { /** * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider * @param {ProvidersModuleFactory} providersModuleFactory - * @param {TransactionSigner} transactionSigner * @param {Wallet} wallet * @param {Object} formatters - * @param {GetChainIdMethod} getChainIdMethod + * @param {ChainIdMethod} chainIdMethod * @param {GetGasPriceMethod} getGasPriceMethod * @param {GetTransactionCountMethod} getTransactionCountMethod * @param options @@ -50,19 +49,18 @@ export default class Accounts extends AbstractWeb3Module { constructor( provider, providersModuleFactory, - transactionSigner, wallet, formatters, - getChainIdMethod, + chainIdMethod, getGasPriceMethod, getTransactionCountMethod, options ) { super(provider, providersModuleFactory, null, null, options); - this.transactionSigner = options.transactionSigner || transactionSigner; + this.transactionSigner = options.transactionSigner; this.wallet = wallet; this.formatters = formatters; - this.getChainIdMethod = getChainIdMethod; + this.chainIdMethod = chainIdMethod; this.getGasPriceMethod = getGasPriceMethod; this.getTransactionCountMethod = getTransactionCountMethod; @@ -117,7 +115,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.fromPrivateKey(privateKey, this); if (!tx.chainId) { - tx.chainId = await this.getChainIdMethod.execute(this); + tx.chainId = await this.chainIdMethod.execute(this); } if (!tx.getGasPrice) { diff --git a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js b/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js deleted file mode 100644 index d91cbfba5ec..00000000000 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file AccountsModuleFactory.js - * @author Samuel Furter - * @date 2018 - */ - -import Accounts from '../Accounts'; - -export default class AccountsModuleFactory { - /** - * Returns an object of type Accounts - * - * @method createAccounts - * - * @param {TransactionSigner} transactionSigner - * @param {Wallet} wallet - * @param {Object}formatters - * - * @returns {Accounts} - */ - createAccounts(transactionSigner, wallet, formatters) { - return new Accounts(transactionSigner, wallet, formatters); - } -} diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 516291136f0..880461e5eae 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -23,17 +23,28 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; import Wallet from './models/Wallet'; -import AccountsModuleFactory from './factories/AccountsModuleFactory'; +import {Accounts as AccountsModule} from './Accounts'; +import {ProvidersModuleFactory} from 'web3-providers'; +import {GetGasPriceMethod, GetChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; /** * Returns the Accounts object * - * @method Accounts - * - * @params {TransactionSigner} transactionSigner + * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @params {Object} options * * @returns {Accounts} + * @constructor */ -export const Accounts = (transactionSigner) => { - return new AccountsModuleFactory().createAccounts(Utils, formatters, transactionSigner, new Wallet(Utils)); +export const Accounts = (provider, options) => { + return new AccountsModule( + provider, + new ProvidersModuleFactory(), + new Wallet(Utils), + formatters, + new GetChainIdMethod(Utils, formatters), + new GetGasPriceMethod(Utils, formatters), + new GetTransactionCountMethod(Utils, formatters), + options + ); }; diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 102242683dd..96cb7f51f1e 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -52,13 +52,12 @@ export default class Account { * @method signTransaction * * @param {Object} tx - * @param {String} privateKey - * @param {Function }callback + * @param {Function} callback * * @callback callback callback(error, result) * @returns {Promise} */ - signTransaction(tx, privateKey, callback) { + signTransaction(tx, callback) { return this.accounts.signTransaction(tx, this.privateKey, callback); } From 00218c29ffc7a8dc61d77d4f6e35e9d553ec4389 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 19:07:27 +0100 Subject: [PATCH 32/71] Proxy added to Wallet --- packages/web3-eth-accounts/src/models/Wallet.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/web3-eth-accounts/src/models/Wallet.js b/packages/web3-eth-accounts/src/models/Wallet.js index 81b222316a8..6cadd4d222e 100644 --- a/packages/web3-eth-accounts/src/models/Wallet.js +++ b/packages/web3-eth-accounts/src/models/Wallet.js @@ -31,6 +31,12 @@ export default class Wallet { this.utils = utils; this.length = 0; this.defaultKeyName = 'web3js_wallet'; + + return new Proxy(this, { + get: (target, name) => { + return target[name]; + } + }); } /** From 14f1c931324b47a74c7277605b50083e5beab376 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 20:11:37 +0100 Subject: [PATCH 33/71] AccountsTest updated --- packages/web3-eth-accounts/jest.config.js | 19 ++-- .../web3-eth-accounts/src/models/Account.js | 18 ++-- .../tests/src/AccountsTest.js | 96 +++++++++++++++---- 3 files changed, 99 insertions(+), 34 deletions(-) diff --git a/packages/web3-eth-accounts/jest.config.js b/packages/web3-eth-accounts/jest.config.js index 2d3e15221af..5dd3461c3ec 100644 --- a/packages/web3-eth-accounts/jest.config.js +++ b/packages/web3-eth-accounts/jest.config.js @@ -1,12 +1,15 @@ const jestConfig = require('../../jest.config'); module.exports = jestConfig({ - Utils: 'web3-utils', - formatters: 'web3-core-helpers', - HttpProvider: 'web3-providers', - ProvidersModuleFactory: 'web3-providers', - ProviderDetector: 'web3-providers', - ProviderResolver: 'web3-providers', - MethodModuleFactory: 'web3-core-method', - scryptsy: 'scrypt.js' + 'Utils': 'web3-utils', + 'formatters': 'web3-core-helpers', + 'HttpProvider': 'web3-providers', + 'ProvidersModuleFactory': 'web3-providers', + 'ProviderDetector': 'web3-providers', + 'ProviderResolver': 'web3-providers', + 'GetGasPriceMethod': 'web3-core-method', + 'ChainIdMethod': 'web3-core-method', + 'GetTransactionCountMethod': 'web3-core-method', + 'MethodModuleFactory': 'web3-core-method', + 'scryptsy': 'scrypt.js' }); diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 96cb7f51f1e..b4601117909 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -109,24 +109,24 @@ export default class Account { * This static methods gives us the possibility to create a new account. * * @param {String} entropy - * @param {TransactionSigner} transactionSigner + * @param {Accounts} accounts * * @returns {Account} */ - static from(entropy, transactionSigner = null) { - return new Account(EthAccount.create(entropy || randomHex(32)), this.accounts.transactionSigner); + static from(entropy, accounts = null) { + return new Account(EthAccount.create(entropy || randomHex(32)), accounts.transactionSigner); } /** * This static method gived us the possibility to create a Account object from a private key. * * @param {String} privateKey - * @param {TransactionSigner} transactionSigner + * @param {Accounts} accounts * * @returns {Account} */ - static fromPrivateKey(privateKey, transactionSigner = null) { - return new Account(EthAccount.fromPrivate(privateKey), this.accounts.transactionSigner); + static fromPrivateKey(privateKey, accounts = null) { + return new Account(EthAccount.fromPrivate(privateKey), accounts.transactionSigner); } /** @@ -208,11 +208,11 @@ export default class Account { * @param {Object|String} v3Keystore * @param {String} password * @param {Boolean} nonStrict - * @param {TransactionSigner} transactionSigner + * @param {Accounts} accounts * * @returns {Account} */ - static fromV3Keystore(v3Keystore, password, nonStrict = false, transactionSigner = null) { + static fromV3Keystore(v3Keystore, password, nonStrict = false, accounts = null) { if (!isString(password)) { throw new Error('No password given.'); } @@ -269,6 +269,6 @@ export default class Account { ); const seed = `0x${Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('hex')}`; - return this.fromPrivateKey(seed, this.accounts.transactionSigner); + return this.fromPrivateKey(seed, accounts); } } diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index 08f75217396..1939f4a762b 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,21 +1,30 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {GetGasPriceMethod, GetTransactionCountMethod, VersionMethod} from 'web3-core-method'; +import {GetGasPriceMethod, GetTransactionCountMethod, ChainIdMethod} from 'web3-core-method'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import crypto from 'crypto'; import uuid from 'uuid'; +import * as EthAccount from 'eth-lib/lib/account'; +import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; import TransactionSigner from '../__mocks__/TransactionSigner'; import Wallet from '../../src/models/Wallet'; import Accounts from '../../src/Accounts'; import Account from '../../src/models/Account'; -import * as EthAccount from 'eth-lib/lib/account'; +import {AbstractWeb3Module} from 'web3-core'; // Mocks jest.mock('Utils'); jest.mock('formatters'); +jest.mock('HttpProvider'); +jest.mock('ProviderDetector'); +jest.mock('ProviderResolver'); +jest.mock('ProvidersModuleFactory'); +jest.mock('GetGasPriceMethod'); +jest.mock('GetTransactionCountMethod'); +jest.mock('ChainIdMethod'); jest.mock('eth-lib/lib/rlp'); jest.mock('eth-lib/lib/nat'); jest.mock('eth-lib/lib/bytes'); @@ -32,26 +41,79 @@ jest.mock('../../src/models/Account'); */ describe('AccountsTest', () => { let accounts, - transactionSignerMock, - walletMock; + providerMock, + providersModuleFactoryMock, + providerDetectorMock, + providerResolverMock, + walletMock, + chainIdMethodMock, + getGasPriceMethodMock, + getTransactionCountMethodMock, + options; beforeEach(() => { - transactionSignerMock = new TransactionSigner(); + new HttpProvider(); + providerMock = HttpProvider.mock.instances[0]; + + new ProvidersModuleFactory(); + providersModuleFactoryMock = ProvidersModuleFactory.mock.instances[0]; + + new ProviderDetector(); + providerDetectorMock = ProviderDetector.mock.instances[0]; + providerDetectorMock.detect = jest.fn(() => { + return null; + }); - new Wallet(Utils); + new ProviderResolver(); + providerResolverMock = ProviderResolver.mock.instances[0]; + providerResolverMock.resolve = jest.fn(() => { + return providerMock; + }); + + providersModuleFactoryMock.createProviderDetector.mockReturnValueOnce(providerDetectorMock); + + providersModuleFactoryMock.createProviderResolver.mockReturnValueOnce(providerResolverMock); + + new Wallet(); walletMock = Wallet.mock.instances[0]; - accounts = new Accounts(transactionSignerMock, walletMock, Utils, formatters); + new ChainIdMethod(); + chainIdMethodMock = ChainIdMethod.mock.instances[0]; + + new GetGasPriceMethod(); + getGasPriceMethodMock = GetGasPriceMethod.mock.instances[0]; + + new GetTransactionCountMethod(); + getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; + + options = {transactionSigner: new TransactionSigner()}; + + accounts = new Accounts( + providerMock, + providersModuleFactoryMock, + walletMock, + formatters, + chainIdMethodMock, + getGasPriceMethodMock, + getTransactionCountMethodMock, + options + ); }); it('constructor check', () => { - expect(accounts.utils).toEqual(Utils); + expect(accounts.wallet).toEqual(walletMock); expect(accounts.formatters).toEqual(formatters); - expect(accounts.wallet).toEqual(walletMock); + expect(accounts.chainIdMethod).toEqual(chainIdMethodMock); + + expect(accounts.getGasPriceMethod).toEqual(getGasPriceMethodMock); + + expect(accounts.getTransactionCountMethod).toEqual(getTransactionCountMethodMock); + + expect(accounts.transactionSigner).toEqual(options.transactionSigner); - expect(accounts.transactionSigner).toEqual(transactionSignerMock); + expect(accounts).toBeInstanceOf(AbstractWeb3Module); }); it('calls create with the entropy parameter and returns the expected object', () => { @@ -59,7 +121,7 @@ describe('AccountsTest', () => { expect(accounts.create('entropy')).toEqual(true); - expect(Account.from).toHaveBeenCalledWith('entropy', transactionSignerMock); + expect(Account.from).toHaveBeenCalledWith('entropy', accounts); }); it('calls privateKeyToAccount with the privateKey parameter and returns the expected object', () => { @@ -67,7 +129,7 @@ describe('AccountsTest', () => { expect(accounts.privateKeyToAccount('pk')).toEqual(true); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); it('calls signTransaction and resolves with a promise', async () => { @@ -80,7 +142,7 @@ describe('AccountsTest', () => { await expect(accounts.signTransaction({}, 'pk', callback)).resolves.toEqual('signed-transaction'); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); @@ -97,7 +159,7 @@ describe('AccountsTest', () => { await expect(accounts.signTransaction({}, 'pk', callback)).rejects.toEqual('ERROR'); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); expect(callback).toHaveBeenCalledWith('ERROR', null); @@ -149,7 +211,7 @@ describe('AccountsTest', () => { expect(sign).toHaveBeenCalledWith('data'); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); it('calls recover with a string as message and returns the expected value', () => { @@ -213,7 +275,7 @@ describe('AccountsTest', () => { expect(accounts.decrypt('v3Keystore', 'password', false)).toEqual(true); - expect(Account.fromV3Keystore).toHaveBeenCalledWith('v3Keystore', 'password', false, transactionSignerMock); + expect(Account.fromV3Keystore).toHaveBeenCalledWith('v3Keystore', 'password', false, accounts); }); it('calls encrypt and returns the expected value', () => { @@ -225,7 +287,7 @@ describe('AccountsTest', () => { expect(accounts.encrypt('pk', 'password', {})).toEqual(true); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', transactionSignerMock); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); expect(toV3Keystore).toHaveBeenCalledWith('password', {}); }); From 3e5515bcc440e4edda505072a467041dca1a13cd Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 20:13:28 +0100 Subject: [PATCH 34/71] utils method mocks fixed in AccountsTest --- packages/web3-eth-accounts/jest.config.js | 3 ++- packages/web3-eth-accounts/tests/src/AccountsTest.js | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/web3-eth-accounts/jest.config.js b/packages/web3-eth-accounts/jest.config.js index 5dd3461c3ec..13ac0d30567 100644 --- a/packages/web3-eth-accounts/jest.config.js +++ b/packages/web3-eth-accounts/jest.config.js @@ -1,7 +1,8 @@ const jestConfig = require('../../jest.config'); module.exports = jestConfig({ - 'Utils': 'web3-utils', + 'hexToBytes': 'web3-utils', + 'isHexStrict': 'web3-utils', 'formatters': 'web3-core-helpers', 'HttpProvider': 'web3-providers', 'ProvidersModuleFactory': 'web3-providers', diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index 1939f4a762b..e843864ebd9 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,4 +1,4 @@ -import * as Utils from 'web3-utils'; +import {isHexStrict, hexToBytes} from 'web3-utils'; import {formatters} from 'web3-core-helpers'; import {GetGasPriceMethod, GetTransactionCountMethod, ChainIdMethod} from 'web3-core-method'; import Hash from 'eth-lib/lib/hash'; @@ -16,7 +16,8 @@ import Account from '../../src/models/Account'; import {AbstractWeb3Module} from 'web3-core'; // Mocks -jest.mock('Utils'); +jest.mock('isHexStrict'); +jest.mock('hexToBytes'); jest.mock('formatters'); jest.mock('HttpProvider'); jest.mock('ProviderDetector'); @@ -215,7 +216,7 @@ describe('AccountsTest', () => { }); it('calls recover with a string as message and returns the expected value', () => { - Utils.isHexStrict.mockReturnValueOnce(false); + isHexStrict.mockReturnValueOnce(false); Hash.keccak256s.mockReturnValueOnce('keccak'); @@ -223,7 +224,7 @@ describe('AccountsTest', () => { expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); - expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); + expect(isHexStrict).toHaveBeenCalledWith('message'); expect(Hash.keccak256s) .toHaveBeenCalledWith( From a785dae559658a842b417cc095d15e46e4fe2ca0 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 21:26:49 +0100 Subject: [PATCH 35/71] AccountsTest and AccountTest fixed --- packages/web3-eth-accounts/jest.config.js | 1 + packages/web3-eth-accounts/src/Accounts.js | 12 +- .../web3-eth-accounts/src/models/Account.js | 30 +-- .../tests/src/AccountsTest.js | 30 +-- .../factories/AccountsModuleFactoryTest.js | 35 --- .../tests/src/models/AccountTest.js | 222 +++++++++--------- 6 files changed, 144 insertions(+), 186 deletions(-) delete mode 100644 packages/web3-eth-accounts/tests/src/factories/AccountsModuleFactoryTest.js diff --git a/packages/web3-eth-accounts/jest.config.js b/packages/web3-eth-accounts/jest.config.js index 13ac0d30567..2a398143d0d 100644 --- a/packages/web3-eth-accounts/jest.config.js +++ b/packages/web3-eth-accounts/jest.config.js @@ -12,5 +12,6 @@ module.exports = jestConfig({ 'ChainIdMethod': 'web3-core-method', 'GetTransactionCountMethod': 'web3-core-method', 'MethodModuleFactory': 'web3-core-method', + 'EthAccount': 'eth-lib/lib/account', 'scryptsy': 'scrypt.js' }); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index d5c5b1410cd..da48334e140 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -26,7 +26,7 @@ import isBoolean from 'lodash/isBoolean'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; -import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency +import {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove this dependency import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. import {AbstractWeb3Module} from 'web3-core'; import Account from './models/Account'; @@ -156,13 +156,13 @@ export default class Accounts extends AbstractWeb3Module { */ recoverTransaction(rawTx) { const values = RLP.decode(rawTx); - const signature = EthAccount.encodeSignature(values.slice(6, 9)); + const signature = encodeSignature(values.slice(6, 9)); const recovery = Bytes.toNumber(values[6]); const extraData = recovery < 35 ? [] : [Bytes.fromNumber((recovery - 35) >> 1), '0x', '0x']; const signingData = values.slice(0, 6).concat(extraData); const signingDataHex = RLP.encode(signingData); - return EthAccount.recover(Hash.keccak256(signingDataHex), signature); + return recover(Hash.keccak256(signingDataHex), signature); } /** @@ -198,7 +198,7 @@ export default class Accounts extends AbstractWeb3Module { const args = [].slice.apply(arguments); if (isObject(message)) { - return this.recover(message.messageHash, EthAccount.encodeSignature([message.v, message.r, message.s]), true); + return this.recover(message.messageHash, encodeSignature([message.v, message.r, message.s]), true); } if (!preFixed) { @@ -218,10 +218,10 @@ export default class Accounts extends AbstractWeb3Module { preFixed = args.slice(-1)[0]; preFixed = isBoolean(preFixed) ? preFixed : false; - return this.recover(message, EthAccount.encodeSignature(args.slice(1, 4)), preFixed); // v, r, s + return this.recover(message, encodeSignature(args.slice(1, 4)), preFixed); // v, r, s } - return EthAccount.recover(message, signature); + return recover(message, signature); } /** diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index b4601117909..00603098925 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -20,10 +20,10 @@ import scryptsy from 'scrypt.js'; import isString from 'lodash/isString'; import isObject from 'lodash/isObject'; -import * as EthAccount from 'eth-lib/lib/account'; // TODO: Remove this dependency +import {fromPrivate, create, sign, decodeSignature} from 'eth-lib/lib/account'; // TODO: Remove this dependency import uuid from 'uuid'; import Hash from 'eth-lib/lib/hash'; -import {isHexStrict, hexToBytes, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. +import {isHexStrict, hexToBytes, randomHex, sha3} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. const crypto = typeof global === 'undefined' ? require('crypto-browserify') : require('crypto'); export default class Account { @@ -76,12 +76,12 @@ export default class Account { } const messageBuffer = Buffer.from(data); - const preamble = `\u0019Ethereum Signed Message:\n${message.length}`; + const preamble = `\u0019Ethereum Signed Message:\n${data.length}`; const preambleBuffer = Buffer.from(preamble); const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); const hash = Hash.keccak256s(ethMessage); - const signature = EthAccount.sign(hash, this.privateKey); - const vrs = EthAccount.decodeSignature(signature); + const signature = sign(hash, this.privateKey); + const vrs = decodeSignature(signature); return { message: data, @@ -113,8 +113,8 @@ export default class Account { * * @returns {Account} */ - static from(entropy, accounts = null) { - return new Account(EthAccount.create(entropy || randomHex(32)), accounts.transactionSigner); + static from(entropy, accounts = {}) { + return new Account(create(entropy || randomHex(32)), accounts['transactionSigner']); } /** @@ -125,8 +125,8 @@ export default class Account { * * @returns {Account} */ - static fromPrivateKey(privateKey, accounts = null) { - return new Account(EthAccount.fromPrivate(privateKey), accounts.transactionSigner); + static fromPrivateKey(privateKey, accounts = {}) { + return new Account(fromPrivate(privateKey), accounts['transactionSigner']); } /** @@ -175,9 +175,11 @@ export default class Account { cipher.final() ]); - const mac = this.utils - .sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])) - .replace('0x', ''); + const mac = sha3( + Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')]) + ).replace( + '0x', '' + ); return { version: 3, @@ -212,7 +214,7 @@ export default class Account { * * @returns {Account} */ - static fromV3Keystore(v3Keystore, password, nonStrict = false, accounts = null) { + static fromV3Keystore(v3Keystore, password, nonStrict = false, accounts = {}) { if (!isString(password)) { throw new Error('No password given.'); } @@ -257,7 +259,7 @@ export default class Account { const ciphertext = Buffer.from(json.crypto.ciphertext, 'hex'); - const mac = this.utils.sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', ''); + const mac = sha3(Buffer.concat([derivedKey.slice(16, 32), ciphertext])).replace('0x', ''); if (mac !== json.crypto.mac) { throw new Error('Key derivation failed - possibly wrong password'); } diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index e843864ebd9..b968b98960a 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -7,7 +7,7 @@ import Bytes from 'eth-lib/lib/bytes'; import scryptsy from 'scrypt.js'; import crypto from 'crypto'; import uuid from 'uuid'; -import * as EthAccount from 'eth-lib/lib/account'; +import {encodeSignature, recover} from 'eth-lib/lib/account'; import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; import TransactionSigner from '../__mocks__/TransactionSigner'; import Wallet from '../../src/models/Wallet'; @@ -170,7 +170,7 @@ describe('AccountsTest', () => { it('calls recoverTransaction and returns the expected string', () => { RLP.decode.mockReturnValueOnce([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - EthAccount.encodeSignature.mockReturnValueOnce('signature'); + encodeSignature.mockReturnValueOnce('signature'); Bytes.toNumber.mockReturnValueOnce(40); @@ -180,13 +180,13 @@ describe('AccountsTest', () => { Hash.keccak256.mockReturnValueOnce('hash'); - EthAccount.recover.mockReturnValueOnce('recovered'); + recover.mockReturnValueOnce('recovered'); expect(accounts.recoverTransaction('rawTransaction')).toEqual('recovered'); - expect(EthAccount.recover).toHaveBeenCalledWith('hash', 'signature'); + expect(recover).toHaveBeenCalledWith('hash', 'signature'); expect(Hash.keccak256).toHaveBeenCalledWith('encoded'); @@ -196,7 +196,7 @@ describe('AccountsTest', () => { expect(Bytes.toNumber).toHaveBeenCalledWith(6); - expect(EthAccount.encodeSignature).toHaveBeenCalledWith([6, 7, 8]); + expect(encodeSignature).toHaveBeenCalledWith([6, 7, 8]); expect(RLP.decode).toHaveBeenCalledWith('rawTransaction'); }); @@ -220,7 +220,7 @@ describe('AccountsTest', () => { Hash.keccak256s.mockReturnValueOnce('keccak'); - EthAccount.recover.mockReturnValueOnce('recovered'); + recover.mockReturnValueOnce('recovered'); expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); @@ -233,13 +233,13 @@ describe('AccountsTest', () => { ) ); - expect(EthAccount.recover).toHaveBeenCalledWith('keccak', 'signature'); + expect(recover).toHaveBeenCalledWith('keccak', 'signature'); }); it('calls recover with a object as message and returns the expected value', () => { - EthAccount.recover.mockReturnValueOnce('recovered'); + recover.mockReturnValueOnce('recovered'); - EthAccount.encodeSignature.mockReturnValueOnce('signature'); + encodeSignature.mockReturnValueOnce('signature'); expect( accounts.recover( @@ -254,21 +254,21 @@ describe('AccountsTest', () => { ) ).toEqual('recovered'); - expect(EthAccount.recover).toHaveBeenCalledWith('message', 'signature'); + expect(recover).toHaveBeenCalledWith('message', 'signature'); - expect(EthAccount.encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); + expect(encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); }); it('calls recover with a string as message, preFixed is true and it returns the expected value', () => { - EthAccount.recover.mockReturnValueOnce('recovered'); + recover.mockReturnValueOnce('recovered'); - EthAccount.encodeSignature.mockReturnValueOnce('signature'); + encodeSignature.mockReturnValueOnce('signature'); expect(accounts.recover('message', 'v', 'r', 's', true)).toEqual('recovered'); - expect(EthAccount.recover).toHaveBeenCalledWith('message', 'signature'); + expect(recover).toHaveBeenCalledWith('message', 'signature'); - expect(EthAccount.encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); + expect(encodeSignature).toHaveBeenCalledWith(['v', 'r', 's']); }); it('calls decrypt and returns the expected value', () => { diff --git a/packages/web3-eth-accounts/tests/src/factories/AccountsModuleFactoryTest.js b/packages/web3-eth-accounts/tests/src/factories/AccountsModuleFactoryTest.js deleted file mode 100644 index dfac3bea095..00000000000 --- a/packages/web3-eth-accounts/tests/src/factories/AccountsModuleFactoryTest.js +++ /dev/null @@ -1,35 +0,0 @@ -import * as Utils from 'web3-utils'; -import {formatters} from 'web3-core-helpers'; -import Accounts from '../../../src/Accounts'; -import AccountsModuleFactory from '../../../src/factories/AccountsModuleFactory'; -import MethodFactory from '../../../src/factories/MethodFactory'; - -// Mocks -jest.mock('Utils'); -jest.mock('formatters'); -jest.mock('../../../src/Accounts'); - -/** - * AccountsModuleFactory test - */ -describe('AccountsModuleFactoryTest', () => { - let accountsModuleFactory; - - beforeEach(() => { - accountsModuleFactory = new AccountsModuleFactory(Utils, formatters); - }); - - it('constructor check', () => { - expect(accountsModuleFactory.utils).toEqual(Utils); - - expect(accountsModuleFactory.formatters).toEqual(formatters); - }); - - it('calls createAccounts and returns a object of type Accounts', () => { - expect(accountsModuleFactory.createAccounts({}, {}, {}, {})).toBeInstanceOf(Accounts); - }); - - it('calls createMethodFactory and returns a object of type MethodFactory', () => { - expect(accountsModuleFactory.createMethodFactory({})).toBeInstanceOf(MethodFactory); - }); -}); diff --git a/packages/web3-eth-accounts/tests/src/models/AccountTest.js b/packages/web3-eth-accounts/tests/src/models/AccountTest.js index 9dbb0d6304e..2a3fee428fa 100644 --- a/packages/web3-eth-accounts/tests/src/models/AccountTest.js +++ b/packages/web3-eth-accounts/tests/src/models/AccountTest.js @@ -2,22 +2,37 @@ import scryptsy from 'scrypt.js'; import crypto from 'crypto'; import uuid from 'uuid'; import Hash from 'eth-lib/lib/hash'; +import {fromPrivate, create, sign, decodeSignature} from 'eth-lib/lib/account'; +import {hexToBytes, isHexStrict, sha3} from 'web3-utils'; import TransactionSigner from '../../__mocks__/TransactionSigner'; +import Accounts from '../../../src/Accounts'; import Account from '../../../src/models/Account'; // Mocks -jest.mock(''); +jest.mock('eth-lib/lib/account'); +jest.mock('eth-lib/lib/hash'); +jest.mock('isHexStrict'); +jest.mock('hexToBytes'); +jest.mock('uuid'); +jest.mock('crypto'); +jest.mock('scryptsy'); +jest.mock('EthAccount'); +jest.mock('../../../src/Accounts'); /** * AccountTest test */ -describe('AccountTestTest', () => { - let account, transactionSignerMock; +describe('AccountTest', () => { + let account, accountsMock, transactionSignerMock; beforeEach(() => { transactionSignerMock = new TransactionSigner(); - account = new Account({address: 'address', privateKey: 'pk'}, transactionSignerMock); + new Accounts(); + accountsMock = Accounts.mock.instances[0]; + accountsMock.transactionSigner = transactionSignerMock; + + account = new Account({address: 'address', privateKey: 'pk'}, accountsMock); }); it('constructor check', () => { @@ -25,23 +40,27 @@ describe('AccountTestTest', () => { expect(account.privateKey).toEqual('pk'); - expect(account.transactionSigner).toEqual(transactionSignerMock); + expect(account.accounts).toEqual(accountsMock); }); it('calls signTransaction and returns the expected value', () => { - transactionSignerMock.sign.mockReturnValueOnce(true); + const callback = jest.fn(); + + accountsMock.signTransaction.mockReturnValueOnce(true); - expect(account.sign({})).toEqual(true); + expect(account.signTransaction({}, callback)).toEqual(true); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({}, 'pk'); + expect(accountsMock.signTransaction).toHaveBeenCalledWith({}, 'pk', callback); }); it('calls sign with non-strict hex and returns the expected string', () => { + isHexStrict.mockReturnValue(false); + Hash.keccak256s.mockReturnValueOnce('keccak'); - Account.sign.mockReturnValueOnce('signed'); + sign.mockReturnValueOnce('signed'); - Account.decodeSignature.mockReturnValueOnce(['v', 'r', 's']); + decodeSignature.mockReturnValueOnce(['v', 'r', 's']); expect(account.sign('message')).toEqual({ message: 'message', @@ -59,23 +78,32 @@ describe('AccountTestTest', () => { ) ); - expect(Account.sign).toHaveBeenCalledWith('keccak', 'pk'); + expect(sign).toHaveBeenCalledWith('keccak', 'pk'); + + expect(decodeSignature).toHaveBeenCalledWith('signed'); - expect(Account.decodeSignature).toHaveBeenCalledWith('signed'); + expect(isHexStrict).toHaveBeenCalledWith('message'); }); - it('calls hashMessage with strict hex and returns the expected string', () => { - Utils.isHexStrict.mockReturnValueOnce(true); + it('calls sign with strict hex and returns the expected string', () => { + isHexStrict.mockReturnValue(true); - Utils.hexToBytes.mockReturnValueOnce('message'); + hexToBytes.mockReturnValue('message'); Hash.keccak256s.mockReturnValueOnce('keccak'); - expect(accounts.hashMessage('data')).toEqual('keccak'); + sign.mockReturnValueOnce('signed'); - expect(Utils.isHexStrict).toHaveBeenCalledWith('data'); + decodeSignature.mockReturnValueOnce(['v', 'r', 's']); - expect(Utils.hexToBytes).toHaveBeenCalledWith('data'); + expect(account.sign('message')).toEqual({ + message: 'message', + messageHash: 'keccak', + v: 'v', + r: 'r', + s: 's', + signature: 'signed' + }); expect(Hash.keccak256s) .toHaveBeenCalledWith( @@ -83,26 +111,17 @@ describe('AccountTestTest', () => { [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] ) ); - }); - - it('calls hashMessage with non-strict hex and returns the expected string', () => { - Utils.isHexStrict.mockReturnValueOnce(false); - Hash.keccak256s.mockReturnValueOnce('keccak'); + expect(sign).toHaveBeenCalledWith('keccak', 'pk'); - expect(accounts.hashMessage('message')).toEqual('keccak'); + expect(decodeSignature).toHaveBeenCalledWith('signed'); - expect(Utils.isHexStrict).toHaveBeenCalledWith('message'); + expect(hexToBytes).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); + expect(isHexStrict).toHaveBeenCalledWith('message'); }); - it('calls decrypt and returns the expected object', () => { + it('calls the factory method fromV3Keystore and returns the expected Account class', () => { const json = { version: 3, crypto: { @@ -123,17 +142,14 @@ describe('AccountTestTest', () => { } }; - const object = {}; - - Account.fromPrivate = jest.fn((seed) => { - expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); - - return object; + fromPrivate.mockReturnValueOnce({ + address: '0x0', + privateKey: '0x0' }); scryptsy.mockReturnValueOnce(Buffer.from('00000000000000000000000000000000')); - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); const decipher = { update: jest.fn(), @@ -154,7 +170,9 @@ describe('AccountTestTest', () => { return decipher; }); - expect(accounts.decrypt(json, 'password', false)).toEqual(object); + expect(Account.fromV3Keystore(json, 'password', false)).toBeInstanceOf(Account); + + expect(fromPrivate).toHaveBeenLastCalledWith(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); expect(scryptsy).toHaveBeenCalledWith( Buffer.from('password'), @@ -165,7 +183,7 @@ describe('AccountTestTest', () => { 'dklen' ); - expect(Utils.sha3).toHaveBeenCalledWith( + expect(sha3).toHaveBeenCalledWith( Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) ); @@ -174,15 +192,9 @@ describe('AccountTestTest', () => { expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); expect(decipher.final).toHaveBeenCalled(); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); }); - it('calls decrypt with pbkdf2 and returns the expected object', () => { + it('calls the factory method fromV3Keystore with pbkdf2 and returns the expected object', () => { const json = { version: 3, crypto: { @@ -202,15 +214,12 @@ describe('AccountTestTest', () => { } }; - const object = {}; - - Account.fromPrivate = jest.fn((seed) => { - expect(seed).toEqual(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); - - return object; + fromPrivate.mockReturnValueOnce({ + address: '0x0', + privateKey: '0x0' }); - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); const decipher = { update: jest.fn(), @@ -245,11 +254,13 @@ describe('AccountTestTest', () => { return Buffer.from('00000000000000000000000000000000'); }); - expect(accounts.decrypt(json, 'password', false)).toEqual(object); + expect(Account.fromV3Keystore(json, 'password', false)).toBeInstanceOf(Account); + + expect(fromPrivate).toHaveBeenCalledWith(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); expect(crypto.pbkdf2Sync).toHaveBeenCalled(); - expect(Utils.sha3).toHaveBeenCalledWith( + expect(sha3).toHaveBeenCalledWith( Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) ); @@ -258,35 +269,29 @@ describe('AccountTestTest', () => { expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); expect(decipher.final).toHaveBeenCalled(); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); }); it('calls decrypt and throws an error because of the missing password paramerter', () => { expect(() => { - accounts.decrypt(''); + Account.fromV3Keystore(''); }).toThrow('No password given.'); }); it('calls decrypt and throws an error because of a wrong keystore version', () => { expect(() => { - accounts.decrypt({version: 0}, 'password', false); + Account.fromV3Keystore({version: 0}, 'password', false); }).toThrow('Not a valid V3 wallet'); }); it('calls decrypt with pbkdf2 and throws an error because of a wrong PRF property', () => { expect(() => { - accounts.decrypt({version: 3, crypto: {kdf: 'pbkdf2', kdfparams: {prf: 'nope'}}}, 'password', false); + Account.fromV3Keystore({version: 3, crypto: {kdf: 'pbkdf2', kdfparams: {prf: 'nope'}}}, 'password', false); }).toThrow('Unsupported parameters to PBKDF2'); }); it('calls decrypt with unsupported scheme and throws an error', () => { expect(() => { - accounts.decrypt({version: 3, crypto: {kdf: 'asdf'}}, 'password', false); + Account.fromV3Keystore({version: 3, crypto: {kdf: 'asdf'}}, 'password', false); }).toThrow('Unsupported key derivation scheme'); }); @@ -310,7 +315,7 @@ describe('AccountTestTest', () => { } }; - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { expect(password).toEqual(Buffer.from(password)); @@ -327,29 +332,22 @@ describe('AccountTestTest', () => { }); expect(() => { - accounts.decrypt(json, 'password', false); + Account.fromV3Keystore(json, 'password', false); }).toThrow('Key derivation failed - possibly wrong password'); expect(crypto.pbkdf2Sync).toHaveBeenCalled(); - expect(Utils.sha3).toHaveBeenCalledWith( + expect(sha3).toHaveBeenCalledWith( Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) ); }); + it('calls toV3Keystore and returns the expected object', () => { + const options = {}; - it('calls encrypt and returns the expected object', () => { - const account = { + fromPrivate.mockReturnValueOnce({ privateKey: '0xxx', address: '0xA' - }; - - const options = {}; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; }); crypto.randomBytes.mockReturnValue(Buffer.from('random')); @@ -367,11 +365,11 @@ describe('AccountTestTest', () => { scryptsy.mockReturnValueOnce(Buffer.from('0000000000000000')); - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); uuid.v4.mockReturnValueOnce(0); - expect(accounts.encrypt('pk', 'password', options)).toEqual({ + expect(Account.fromPrivateKey('pk').toV3Keystore('password', options)).toEqual({ version: 3, id: 0, address: 'a', @@ -391,6 +389,8 @@ describe('AccountTestTest', () => { } }); + expect(fromPrivate).toHaveBeenCalledWith('pk'); + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); @@ -409,7 +409,7 @@ describe('AccountTestTest', () => { expect(cipher.final).toHaveBeenCalled(); - expect(Utils.sha3).toHaveBeenCalledWith( + expect(sha3).toHaveBeenCalledWith( Buffer.concat([ Buffer.from('0000000000000000').slice(16, 32), Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') @@ -419,19 +419,15 @@ describe('AccountTestTest', () => { expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); }); - it('calls encrypt with the pbkdf2 sheme and returns the expected object', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - + it('calls toV3Keystore with the pbkdf2 sheme and returns the expected object', () => { const options = {kdf: 'pbkdf2'}; - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; - }); + fromPrivate.mockReturnValueOnce( + { + privateKey: '0xxx', + address: '0xA' + } + ); crypto.randomBytes.mockReturnValue(Buffer.from('random')); @@ -450,11 +446,11 @@ describe('AccountTestTest', () => { return Buffer.from('0000000000000000'); }); - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); uuid.v4.mockReturnValueOnce(0); - expect(accounts.encrypt('pk', 'password', options)).toEqual({ + expect(Account.fromPrivateKey('pk').toV3Keystore('password', options)).toEqual({ version: 3, id: 0, address: 'a', @@ -473,6 +469,8 @@ describe('AccountTestTest', () => { } }); + expect(fromPrivate).toHaveBeenCalledWith('pk'); + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); @@ -497,7 +495,7 @@ describe('AccountTestTest', () => { expect(cipher.final).toHaveBeenCalled(); - expect(Utils.sha3).toHaveBeenCalledWith( + expect(sha3).toHaveBeenCalledWith( Buffer.concat([ Buffer.from('0000000000000000').slice(16, 32), Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') @@ -508,40 +506,30 @@ describe('AccountTestTest', () => { }); it('calls encrypt with a unsupported sheme', () => { - const account = { + fromPrivate.mockReturnValueOnce({ privateKey: '0xxx', address: '0xA' - }; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; }); crypto.randomBytes.mockReturnValue(Buffer.from('random')); expect(() => { - accounts.encrypt('pk', 'password', {kdf: 'nope'}); + Account.fromPrivateKey('pk').toV3Keystore('password', {kdf: 'nope'}); }).toThrow('Unsupported kdf'); + expect(fromPrivate).toHaveBeenCalledWith('pk'); + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); }); it('calls encrypt with a unsupported cipher', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - const options = {kdf: 'pbkdf2'}; - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return account; + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' }); crypto.randomBytes.mockReturnValue(Buffer.from('random')); @@ -552,12 +540,14 @@ describe('AccountTestTest', () => { return Buffer.from('0000000000000000'); }); - Utils.sha3.mockReturnValueOnce('0xmac'); + sha3.mockReturnValueOnce('0xmac'); expect(() => { - accounts.encrypt('pk', 'password', options); + Account.fromPrivateKey('pk').toV3Keystore('password', options); }).toThrow('Unsupported cipher'); + expect(fromPrivate).toHaveBeenCalledWith('pk'); + expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); From 72a48b47dff2bb44e9cf42b704bfc0853a7034d7 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 21:55:33 +0100 Subject: [PATCH 36/71] Wallet class removed and logic moved to the Accounts module. Proxy implemented for the wallet property in the Accounts module to not break any public API --- packages/web3-eth-accounts/src/Accounts.js | 268 +++++++++++++++- .../web3-eth-accounts/src/models/Wallet.js | 285 ------------------ .../tests/src/models/WalletTest.js | 25 ++ 3 files changed, 292 insertions(+), 286 deletions(-) delete mode 100644 packages/web3-eth-accounts/src/models/Wallet.js create mode 100644 packages/web3-eth-accounts/tests/src/models/WalletTest.js diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index da48334e140..e487ceccfcb 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -30,6 +30,8 @@ import {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove th import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. import {AbstractWeb3Module} from 'web3-core'; import Account from './models/Account'; +import has from 'lodash/has'; +import isString from 'lodash/isString'; // TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. // TODO: After this refactoring is it possible to move the wallet class to the eth module and to remove the accounts module. @@ -58,12 +60,33 @@ export default class Accounts extends AbstractWeb3Module { ) { super(provider, providersModuleFactory, null, null, options); this.transactionSigner = options.transactionSigner; - this.wallet = wallet; this.formatters = formatters; this.chainIdMethod = chainIdMethod; this.getGasPriceMethod = getGasPriceMethod; this.getTransactionCountMethod = getTransactionCountMethod; + /** + * This is for compatibility reasons and will be removed later when it got added to the eth-module + */ + new Proxy(this.wallet, { + get: (target, name) => { + switch (name) { + case 'create': + return this.addGeneratedAccountsToWallet; + case 'encrypt': + return this.encrypt; + case 'decrypt': + return this.decrypt; + default: + if (this[name]) { + return this[name]; + } + + return target[name]; + } + } + }); + return new Proxy(this, { get: (target, name) => { return target[name]; @@ -71,6 +94,249 @@ export default class Accounts extends AbstractWeb3Module { }); } + + /** + * Finds the safe index + * + * @method findSafeIndex + * @private + * + * @param {Number} pointer + * + * @returns {*} + */ + findSafeIndexWallet(pointer = 0) { + if (has(this, pointer)) { + return this.findSafeIndex(pointer + 1); + } + + return pointer; + } + + /** + * Gets the correntIndexes array + * + * @method currentIndexes + * @private + * + * @returns {Number[]} + */ + currentIndexesWallet() { + return Object.keys(this) + .map((key) => { + return parseInt(key); + }) + .filter((n) => { + return n < 9e20; + }); + } + + /** + * Creates new accounts with a given entropy + * + * @method create + * + * @param {Number} numberOfAccounts + * @param {String} entropy + * + * @returns {Wallet} + */ + addGeneratedAccountsToWallet(numberOfAccounts, entropy) { + const account = Account.from(entropy || randomHex(32)); + + for (let i = 0; i < numberOfAccounts; ++i) { + this.add(account.privateKey); + } + + return this; + } + + /** + * Adds a account to the wallet + * + * @method add + * + * @param {Account|String} account + * + * @returns {Object} + */ + add(account) { + if (isString(account)) { + account = Account.fromPrivateKey(account); + } + + if (!this[account.address]) { + account.index = this.findSafeIndex(); + + this[account.index] = account; + this[account.address] = account; + this[account.address.toLowerCase()] = account; + + this.length++; + + return account; + } + + return this[account.address]; + } + + /** + * Removes a account from the number by his address or index + * + * @method remove + * + * @param {String|Number} addressOrIndex + * + * @returns {Boolean} + */ + remove(addressOrIndex) { + const account = this[addressOrIndex]; + + if (account && account.address) { + // address + this[account.address].privateKey = null; + delete this[account.address]; + // address lowercase + this[account.address.toLowerCase()].privateKey = null; + delete this[account.address.toLowerCase()]; + // index + this[account.index].privateKey = null; + delete this[account.index]; + + this.length--; + + return true; + } + + return false; + } + + /** + * Clears the wallet + * + * @method clear + * + * @returns {Wallet} + */ + clear() { + this.accounts = []; + + return this; + } + + /** + * Encrypts all accounts + * + * @method encrypt + * + * @param {String} password + * @param {Object} options + * + * @returns {any[]} + */ + encryptWallet(password, options) { + return this.accounts.map((account) => { + return account.encrypt(password, options); + }); + } + + /** + * Decrypts all accounts + * + * @method decrypt + * + * @param {Wallet} encryptedWallet + * @param {String} password + * + * @returns {Wallet} + */ + decryptWallet(encryptedWallet, password) { + encryptedWallet.accounts.forEach((keystore) => { + const account = Account.fromV3Keystore(keystore, password); + + if (!account) { + throw new Error("Couldn't decrypt accounts. Password wrong?"); + } + + this.add(account); + }); + + return this; + } + + /** + * Saves the current wallet in the localStorage of the browser + * + * @method save + * + * @param {String} password + * @param {String} keyName + * + * @returns {boolean} + */ + save(password, keyName) { + if (typeof localStorage === 'undefined') { + throw new TypeError('window.localStorage is undefined.'); + } + + try { + localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encrypt(password))); + } catch (error) { + // code 18 means trying to use local storage in a iframe + // with third party cookies turned off + // we still want to support using web3 in a iframe + // as by default safari turn these off for all iframes + // so mask the error + if (error.code === 18) { + return true; + } + + // throw as normal if not + throw new Error(error); + } + + return true; + } + + /** + * Loads the stored wallet by his keyName from the localStorage of the browser + * + * @method load + * + * @param {String} password + * @param {String} keyName + * + * @returns {Wallet} + */ + load(password, keyName) { + if (typeof localStorage === 'undefined') { + throw new TypeError('window.localStorage is undefined.'); + } + + let keystore; + try { + keystore = localStorage.getItem(keyName || this.defaultKeyName); + + if (keystore) { + keystore = JSON.parse(keystore).map(item => Account.fromV3Keystore(item, password, false)); + } + } catch (error) { + // code 18 means trying to use local storage in a iframe + // with third party cookies turned off + // we still want to support using web3 in a iframe + // as by default safari turn these off for all iframes + // so mask the error + if (error.code === 18) { + keystore = this.defaultKeyName; + } else { + // throw as normal if not + throw new Error(error); + } + } + + return this.decrypt(keystore || [], password); + } + /** * Creates an account with a given entropy * diff --git a/packages/web3-eth-accounts/src/models/Wallet.js b/packages/web3-eth-accounts/src/models/Wallet.js deleted file mode 100644 index 6cadd4d222e..00000000000 --- a/packages/web3-eth-accounts/src/models/Wallet.js +++ /dev/null @@ -1,285 +0,0 @@ -/* - This file is part of web3.js. - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file Wallet.js - * @author Samuel Furter , Fabian Vogelsteller - * @date 2019 - */ - -import has from 'lodash/has'; -import isString from 'lodash/isString'; -import Account from './Account'; - -export default class Wallet { - /** - * @param {Utils} utils - * - * @constructor - */ - constructor(utils) { - this.utils = utils; - this.length = 0; - this.defaultKeyName = 'web3js_wallet'; - - return new Proxy(this, { - get: (target, name) => { - return target[name]; - } - }); - } - - /** - * Finds the safe index - * - * @method _findSafeIndex - * @private - * - * @param {Number} pointer - * - * @returns {*} - */ - _findSafeIndex(pointer = 0) { - if (has(this, pointer)) { - return this._findSafeIndex(pointer + 1); - } - - return pointer; - } - - /** - * Gets the correntIndexes array - * - * @method _currentIndexes - * @private - * - * @returns {Number[]} - */ - _currentIndexes() { - return Object.keys(this) - .map((key) => { - return parseInt(key); - }) - .filter((n) => { - return n < 9e20; - }); - } - - /** - * Creates new accounts with a given entropy - * - * @method create - * - * @param {Number} numberOfAccounts - * @param {String} entropy - * - * @returns {Wallet} - */ - create(numberOfAccounts, entropy) { - const account = Account.from(entropy || this.utils.randomHex(32)); - - for (let i = 0; i < numberOfAccounts; ++i) { - this.add(account.privateKey); - } - - return this; - } - - /** - * Adds a account to the wallet - * - * @method add - * - * @param {Account|String} account - * - * @returns {Object} - */ - add(account) { - if (isString(account)) { - account = Account.fromPrivateKey(account); - } - - if (!this[account.address]) { - account.index = this._findSafeIndex(); - - this[account.index] = account; - this[account.address] = account; - this[account.address.toLowerCase()] = account; - - this.length++; - - return account; - } - - return this[account.address]; - } - - /** - * Removes a account from the number by his address or index - * - * @method remove - * - * @param {String|Number} addressOrIndex - * - * @returns {Boolean} - */ - remove(addressOrIndex) { - const account = this[addressOrIndex]; - - if (account && account.address) { - // address - this[account.address].privateKey = null; - delete this[account.address]; - // address lowercase - this[account.address.toLowerCase()].privateKey = null; - delete this[account.address.toLowerCase()]; - // index - this[account.index].privateKey = null; - delete this[account.index]; - - this.length--; - - return true; - } - - return false; - } - - /** - * Clears the wallet - * - * @method clear - * - * @returns {Wallet} - */ - clear() { - this._currentIndexes().forEach((index) => { - this.remove(index); - }); - - return this; - } - - /** - * Encrypts all accounts - * - * @method encrypt - * - * @param {String} password - * @param {Object} options - * - * @returns {any[]} - */ - encrypt(password, options) { - return this._currentIndexes().map((index) => { - return this[index].encrypt(password, options); - }); - } - - /** - * Decrypts all accounts - * - * @method decrypt - * - * @param {Wallet} encryptedWallet - * @param {String} password - * - * @returns {Wallet} - */ - decrypt(encryptedWallet, password) { - encryptedWallet.forEach((keystore) => { - const account = Account.fromV3Keystore(keystore, password); - - if (!account) { - throw new Error("Couldn't decrypt accounts. Password wrong?"); - } - - this.add(account); - }); - - return this; - } - - /** - * Saves the current wallet in the localStorage of the browser - * - * @method save - * - * @param {String} password - * @param {String} keyName - * - * @returns {boolean} - */ - save(password, keyName) { - if (typeof localStorage === 'undefined') { - throw new TypeError('window.localStorage is undefined.'); - } - - try { - localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encrypt(password))); - } catch (error) { - // code 18 means trying to use local storage in a iframe - // with third party cookies turned off - // we still want to support using web3 in a iframe - // as by default safari turn these off for all iframes - // so mask the error - if (error.code === 18) { - return true; - } - - // throw as normal if not - throw new Error(error); - } - - return true; - } - - /** - * Loads the stored wallet by his keyName from the localStorage of the browser - * - * @method load - * - * @param {String} password - * @param {String} keyName - * - * @returns {Wallet} - */ - load(password, keyName) { - if (typeof localStorage === 'undefined') { - throw new TypeError('window.localStorage is undefined.'); - } - - let keystore; - try { - keystore = localStorage.getItem(keyName || this.defaultKeyName); - - if (keystore) { - keystore = JSON.parse(keystore); - } - } catch (error) { - // code 18 means trying to use local storage in a iframe - // with third party cookies turned off - // we still want to support using web3 in a iframe - // as by default safari turn these off for all iframes - // so mask the error - if (error.code === 18) { - keystore = this.defaultKeyName; - } else { - // throw as normal if not - throw new Error(error); - } - } - - return this.decrypt(keystore || [], password); - } -} diff --git a/packages/web3-eth-accounts/tests/src/models/WalletTest.js b/packages/web3-eth-accounts/tests/src/models/WalletTest.js new file mode 100644 index 00000000000..72df416829f --- /dev/null +++ b/packages/web3-eth-accounts/tests/src/models/WalletTest.js @@ -0,0 +1,25 @@ +import Wallet from '../../../src/models/Wallet'; + +// Mocks +jest.mock(''); + +/** + * Wallet test + */ +describe('WalletTest', () => { + let wallet; + + beforeEach(() => { + wallet = new Wallet(); + }); + + it('constructor check', () => { + expect(wallet.length).toEqual(0); + + expect(wallet.defaultKeyName).toEqual('web3js_wallet'); + }); + + it('calls findSafeIndex and returns the expected pointer', () =< { + + }) +}); From 77374ac57750bbe25a735848fdd7d3fe7158d3c3 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 22:11:25 +0100 Subject: [PATCH 37/71] Accounts updated --- packages/web3-eth-accounts/src/Accounts.js | 89 ++++++---------------- 1 file changed, 22 insertions(+), 67 deletions(-) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index e487ceccfcb..c08492c2025 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -27,14 +27,13 @@ import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove this dependency -import {isHexStrict, hexToBytes} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. +import {isHexStrict, hexToBytes, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. import {AbstractWeb3Module} from 'web3-core'; import Account from './models/Account'; import has from 'lodash/has'; import isString from 'lodash/isString'; -// TODO: Rename Accounts module to Wallet and add the functionalities of the current Wallet class. -// TODO: After this refactoring is it possible to move the wallet class to the eth module and to remove the accounts module. +// TODO: Rename Accounts module to Wallet and move the Wallet class to the eth module. export default class Accounts extends AbstractWeb3Module { /** * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider @@ -64,6 +63,8 @@ export default class Accounts extends AbstractWeb3Module { this.chainIdMethod = chainIdMethod; this.getGasPriceMethod = getGasPriceMethod; this.getTransactionCountMethod = getTransactionCountMethod; + this.defaultKeyName = 'web3js_wallet'; + this.accounts = []; /** * This is for compatibility reasons and will be removed later when it got added to the eth-module @@ -94,43 +95,6 @@ export default class Accounts extends AbstractWeb3Module { }); } - - /** - * Finds the safe index - * - * @method findSafeIndex - * @private - * - * @param {Number} pointer - * - * @returns {*} - */ - findSafeIndexWallet(pointer = 0) { - if (has(this, pointer)) { - return this.findSafeIndex(pointer + 1); - } - - return pointer; - } - - /** - * Gets the correntIndexes array - * - * @method currentIndexes - * @private - * - * @returns {Number[]} - */ - currentIndexesWallet() { - return Object.keys(this) - .map((key) => { - return parseInt(key); - }) - .filter((n) => { - return n < 9e20; - }); - } - /** * Creates new accounts with a given entropy * @@ -142,7 +106,7 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Wallet} */ addGeneratedAccountsToWallet(numberOfAccounts, entropy) { - const account = Account.from(entropy || randomHex(32)); + const account = Account.from(entropy || randomHex(32), this); for (let i = 0; i < numberOfAccounts; ++i) { this.add(account.privateKey); @@ -158,21 +122,17 @@ export default class Accounts extends AbstractWeb3Module { * * @param {Account|String} account * - * @returns {Object} + * @returns {Wallet} */ add(account) { if (isString(account)) { - account = Account.fromPrivateKey(account); + account = Account.fromPrivateKey(account, this); } if (!this[account.address]) { - account.index = this.findSafeIndex(); - - this[account.index] = account; - this[account.address] = account; - this[account.address.toLowerCase()] = account; - - this.length++; + this.accounts.push(account); + this.accounts[account.address] = account; + this.accounts[account.address.toLowerCase()] = account; return account; } @@ -190,20 +150,15 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Boolean} */ remove(addressOrIndex) { - const account = this[addressOrIndex]; + const account = this.accounts[addressOrIndex]; if (account && account.address) { - // address - this[account.address].privateKey = null; - delete this[account.address]; - // address lowercase - this[account.address.toLowerCase()].privateKey = null; - delete this[account.address.toLowerCase()]; - // index - this[account.index].privateKey = null; - delete this[account.index]; - - this.length--; + delete this.accounts[account.address]; + delete this.accounts[account.address.toLowerCase()]; + + const index = this.accounts.findIndex(item => item.address === account.address); + + delete this.accounts[index]; return true; } @@ -251,8 +206,8 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Wallet} */ decryptWallet(encryptedWallet, password) { - encryptedWallet.accounts.forEach((keystore) => { - const account = Account.fromV3Keystore(keystore, password); + encryptedWallet.forEach((keystore) => { + const account = Account.fromV3Keystore(keystore, password, false, this); if (!account) { throw new Error("Couldn't decrypt accounts. Password wrong?"); @@ -280,7 +235,7 @@ export default class Accounts extends AbstractWeb3Module { } try { - localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encrypt(password))); + localStorage.setItem(keyName || this.defaultKeyName, JSON.stringify(this.encryptWallet(password))); } catch (error) { // code 18 means trying to use local storage in a iframe // with third party cookies turned off @@ -318,7 +273,7 @@ export default class Accounts extends AbstractWeb3Module { keystore = localStorage.getItem(keyName || this.defaultKeyName); if (keystore) { - keystore = JSON.parse(keystore).map(item => Account.fromV3Keystore(item, password, false)); + keystore = JSON.parse(keystore).map(item => Account.fromV3Keystore(item, password, false, this)); } } catch (error) { // code 18 means trying to use local storage in a iframe @@ -334,7 +289,7 @@ export default class Accounts extends AbstractWeb3Module { } } - return this.decrypt(keystore || [], password); + return this.decryptWallet(keystore || [], password); } /** From 06bfe7b7fd41c80d889072967a1fe9f5df3f460f Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 23:52:57 +0100 Subject: [PATCH 38/71] Accounts and AccountsTest updated --- packages/web3-eth-accounts/src/Accounts.js | 87 ++++++----- .../tests/src/AccountsTest.js | 144 ++++++++++++++++-- 2 files changed, 178 insertions(+), 53 deletions(-) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index c08492c2025..a8412eca9c1 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -23,6 +23,7 @@ import isFunction from 'lodash/isFunction'; import isObject from 'lodash/isObject'; import isBoolean from 'lodash/isBoolean'; +import isString from 'lodash/isString'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; @@ -30,15 +31,12 @@ import {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove th import {isHexStrict, hexToBytes, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. import {AbstractWeb3Module} from 'web3-core'; import Account from './models/Account'; -import has from 'lodash/has'; -import isString from 'lodash/isString'; // TODO: Rename Accounts module to Wallet and move the Wallet class to the eth module. export default class Accounts extends AbstractWeb3Module { /** * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider * @param {ProvidersModuleFactory} providersModuleFactory - * @param {Wallet} wallet * @param {Object} formatters * @param {ChainIdMethod} chainIdMethod * @param {GetGasPriceMethod} getGasPriceMethod @@ -50,7 +48,6 @@ export default class Accounts extends AbstractWeb3Module { constructor( provider, providersModuleFactory, - wallet, formatters, chainIdMethod, getGasPriceMethod, @@ -64,35 +61,41 @@ export default class Accounts extends AbstractWeb3Module { this.getGasPriceMethod = getGasPriceMethod; this.getTransactionCountMethod = getTransactionCountMethod; this.defaultKeyName = 'web3js_wallet'; - this.accounts = []; + this.accounts = {}; + this.accountsIndex = 0; + this.wallet = this.createWalletProxy(); - /** - * This is for compatibility reasons and will be removed later when it got added to the eth-module - */ - new Proxy(this.wallet, { + return new Proxy(this, { + get: (target, name) => { + return target[name]; + } + }); + } + + /** + * This is for compatibility reasons and will be removed later when it got added to the eth-module + * + * @method createWalletProxy + * + * @returns {Accounts} + */ + createWalletProxy() { + return new Proxy(this, { get: (target, name) => { switch (name) { case 'create': - return this.addGeneratedAccountsToWallet; + return target.addGeneratedAccountsToWallet; case 'encrypt': - return this.encrypt; + return target.encryptWallet; case 'decrypt': - return this.decrypt; + return target.decryptWallet; + case 'clear': + return target.clear; default: - if (this[name]) { - return this[name]; - } - return target[name]; } } }); - - return new Proxy(this, { - get: (target, name) => { - return target[name]; - } - }); } /** @@ -109,7 +112,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.from(entropy || randomHex(32), this); for (let i = 0; i < numberOfAccounts; ++i) { - this.add(account.privateKey); + this.add(account); } return this; @@ -120,9 +123,9 @@ export default class Accounts extends AbstractWeb3Module { * * @method add * - * @param {Account|String} account + * @param {Account|String} account - A Account object or privateKey * - * @returns {Wallet} + * @returns {Account} */ add(account) { if (isString(account)) { @@ -130,14 +133,16 @@ export default class Accounts extends AbstractWeb3Module { } if (!this[account.address]) { - this.accounts.push(account); + this.accounts[this.accountsIndex] = account; this.accounts[account.address] = account; this.accounts[account.address.toLowerCase()] = account; + this.accountsIndex++; + return account; } - return this[account.address]; + return this.accounts[account.address]; } /** @@ -150,15 +155,14 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Boolean} */ remove(addressOrIndex) { - const account = this.accounts[addressOrIndex]; - - if (account && account.address) { - delete this.accounts[account.address]; - delete this.accounts[account.address.toLowerCase()]; - - const index = this.accounts.findIndex(item => item.address === account.address); + if (this.accounts[addressOrIndex]) { + Object.keys(this.accounts).forEach((key) => { + if (this.accounts[key].address === addressOrIndex || key === addressOrIndex) { + delete this.accounts[key]; - delete this.accounts[index]; + this.accountsIndex--; + } + }); return true; } @@ -174,7 +178,8 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Wallet} */ clear() { - this.accounts = []; + this.accounts = {}; + this.accountsIndex = 0; return this; } @@ -190,9 +195,13 @@ export default class Accounts extends AbstractWeb3Module { * @returns {any[]} */ encryptWallet(password, options) { - return this.accounts.map((account) => { - return account.encrypt(password, options); + let encryptedAccounts = []; + + Object.keys(this.accounts).forEach((key) => { + return encryptedAccounts.push(this.accounts[key].encrypt(password, options)); }); + + return encryptedAccounts; } /** @@ -210,7 +219,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.fromV3Keystore(keystore, password, false, this); if (!account) { - throw new Error("Couldn't decrypt accounts. Password wrong?"); + throw new Error('Couldn\'t decrypt accounts. Password wrong?'); } this.add(account); diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index b968b98960a..bfe6a0c2cbb 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,6 +1,6 @@ -import {isHexStrict, hexToBytes} from 'web3-utils'; +import {isHexStrict, randomHex} from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {GetGasPriceMethod, GetTransactionCountMethod, ChainIdMethod} from 'web3-core-method'; +import {ChainIdMethod, GetGasPriceMethod, GetTransactionCountMethod} from 'web3-core-method'; import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; @@ -10,7 +10,6 @@ import uuid from 'uuid'; import {encodeSignature, recover} from 'eth-lib/lib/account'; import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; import TransactionSigner from '../__mocks__/TransactionSigner'; -import Wallet from '../../src/models/Wallet'; import Accounts from '../../src/Accounts'; import Account from '../../src/models/Account'; import {AbstractWeb3Module} from 'web3-core'; @@ -34,7 +33,6 @@ jest.mock('eth-lib/lib/account'); jest.mock('scryptsy'); jest.mock('crypto'); jest.mock('uuid'); -jest.mock('../../src/models/Wallet'); jest.mock('../../src/models/Account'); /** @@ -46,7 +44,6 @@ describe('AccountsTest', () => { providersModuleFactoryMock, providerDetectorMock, providerResolverMock, - walletMock, chainIdMethodMock, getGasPriceMethodMock, getTransactionCountMethodMock, @@ -75,9 +72,6 @@ describe('AccountsTest', () => { providersModuleFactoryMock.createProviderResolver.mockReturnValueOnce(providerResolverMock); - new Wallet(); - walletMock = Wallet.mock.instances[0]; - new ChainIdMethod(); chainIdMethodMock = ChainIdMethod.mock.instances[0]; @@ -87,12 +81,11 @@ describe('AccountsTest', () => { new GetTransactionCountMethod(); getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; - options = {transactionSigner: new TransactionSigner()}; + options = {transactionSigner: new TransactionSigner()}; accounts = new Accounts( providerMock, providersModuleFactoryMock, - walletMock, formatters, chainIdMethodMock, getGasPriceMethodMock, @@ -102,8 +95,6 @@ describe('AccountsTest', () => { }); it('constructor check', () => { - expect(accounts.wallet).toEqual(walletMock); - expect(accounts.formatters).toEqual(formatters); expect(accounts.chainIdMethod).toEqual(chainIdMethodMock); @@ -292,5 +283,130 @@ describe('AccountsTest', () => { expect(toV3Keystore).toHaveBeenCalledWith('password', {}); }); -}) -; + + it('calls wallet.create and returns the expected value', () => { + randomHex.mockReturnValueOnce('asdf'); + + Account.from.mockReturnValueOnce({address: '0x0', privateKey: '0x0'}); + + expect(accounts.wallet.create(1)).toEqual(accounts); + + expect(randomHex).toHaveBeenCalledWith(32); + + expect(Account.from).toHaveBeenCalledWith('asdf', accounts); + + expect(accounts.accountsIndex).toEqual(1); + }); + + it('calls wallet.add with a Account object and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + expect(accounts.wallet.add(accountMock)).toEqual(accountMock); + + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); + + expect(accounts.accounts[0]).toEqual(accountMock); + + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); + }); + + it('calls wallet.add with a privateKey and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + Account.fromPrivateKey.mockReturnValueOnce(accountMock); + + expect(accounts.wallet.add('0x0')).toEqual(accountMock); + + expect(Account.fromPrivateKey).toHaveBeenCalledWith('0x0', accounts); + + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); + + expect(accounts.accounts[0]).toEqual(accountMock); + + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); + }); + + it('calls wallet.remove and returns true', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + accounts.accounts = {0: accountMock}; + + expect(accounts.wallet.remove(0)).toEqual(true); + + expect(accounts.accountsIndex).toEqual(0); + }); + + it('calls wallet.remove and returns false', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + delete accountMock.address; + + accounts.accounts = {}; + + expect(accounts.wallet.remove(0)).toEqual(false); + + expect(accounts.accountsIndex).toEqual(0); + }); + + it('calls wallet.clear and returns the expect value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + accounts.accounts = {0: accountMock}; + + expect(accounts.wallet.clear()).toEqual(accounts); + + expect(accounts.accountsIndex).toEqual(0); + }); + + it('calls wallet.encrypt and returns the expect value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + accountMock.encrypt.mockReturnValueOnce(true); + + accounts.accounts = {0: accountMock}; + + expect(accounts.wallet.encrypt('pw', {})).toEqual([true]); + + expect(accountMock.encrypt).toHaveBeenCalledWith('pw', {}); + + expect(accounts.accountsIndex).toEqual(0); + }); + + it('calls wallet.decrypt and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + + Account.fromV3Keystore.mockReturnValueOnce(accountMock); + + expect(accounts.wallet.decrypt([true], 'pw')).toEqual(accounts); + + expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); + + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); + + expect(accounts.accounts[0]).toEqual(accountMock); + + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); + }); + + it('calls wallet.decrypt and throws an error', () => { + Account.fromV3Keystore.mockReturnValueOnce(false); + + expect(() => { + accounts.wallet.decrypt([true], 'pw'); + }).toThrow('Couldn\'t decrypt accounts. Password wrong?'); + + expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); + }); +}); From 3b604ce1b82e9a27a00faa5f93b7e7aa4279c3d2 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Fri, 22 Feb 2019 23:58:10 +0100 Subject: [PATCH 39/71] code style improvements --- .../src/methods/SignMethod.js | 8 ++-- .../transaction/SendTransactionMethod.js | 23 ++++++----- packages/web3-core-subscriptions/src/index.js | 1 - packages/web3-eth-accounts/src/Accounts.js | 4 +- .../web3-eth-accounts/src/models/Account.js | 6 +-- .../tests/src/AccountsTest.js | 27 +++++-------- .../tests/src/models/AccountTest.js | 38 +++++++++---------- .../tests/src/models/WalletTest.js | 25 ------------ packages/web3-eth/src/index.js | 2 +- .../src/signers/TransactionSignerTest.js | 4 +- 10 files changed, 48 insertions(+), 90 deletions(-) delete mode 100644 packages/web3-eth-accounts/tests/src/models/WalletTest.js diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 0cf04bd5442..825b67409df 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -67,11 +67,9 @@ export default class SignMethod extends AbstractCallMethod { let signedMessage; try { - signedMessage = moduleInstance.accounts.privateKeyToAccount( - moduleInstance.accounts.wallet[this.parameters[1]] - ).sign( - this.parameters[0] - ); + signedMessage = moduleInstance.accounts + .privateKeyToAccount(moduleInstance.accounts.wallet[this.parameters[1]]) + .sign(this.parameters[0]); } catch (error) { if (this.callback) { this.callback(error, null); diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 31cd88d75b8..9e46fe6d2e0 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -20,7 +20,6 @@ * @date 2018 */ -import isObject from 'lodash/isObject'; import AbstractSendMethod from '../../../lib/methods/AbstractSendMethod'; // TODO: Clean up this method and move the signing and observing logic to the eth module @@ -91,7 +90,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { if (this.isWeb3Signing(moduleInstance)) { this.sendRawTransaction( - this.formatTransactionForSigning(), + this.formatTransactionForSigning(moduleInstance, promiEvent), moduleInstance.accounts.wallet[this.parameters[0].from], promiEvent, moduleInstance @@ -101,7 +100,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { } if (this.hasCustomSigner(moduleInstance)) { - this.sendRawTransaction(this.formatTransactionForSigning(), null, promiEvent, moduleInstance); + this.sendRawTransaction(this.formatTransactionForSigning(moduleInstance, promiEvent), null, promiEvent, moduleInstance); return promiEvent; } @@ -114,10 +113,12 @@ export default class SendTransactionMethod extends AbstractSendMethod { /** * Formats the transaction options object * + * @param {Eth} moduleInstance + * @param {PromiEvent} promiEvent * * @returns {Object} */ - formatTransactionForSigning() { + formatTransactionForSigning(moduleInstance, promiEvent) { if (this.parameters[0].chainId) { moduleInstance.getChainId().then((chainId) => { this.parameters[0].chainId = chainId; @@ -127,9 +128,9 @@ export default class SendTransactionMethod extends AbstractSendMethod { } let transaction = this.formatters.txInputFormatter(this.parameters[0]); - transaction.to = tx.to || '0x'; - transaction.data = tx.data || '0x'; - transaction.value = tx.value || '0x'; + transaction.to = transaction.to || '0x'; + transaction.data = transaction.data || '0x'; + transaction.value = transaction.value || '0x'; transaction.chainId = this.utils.numberToHex(transaction.chainId); return transaction; @@ -175,9 +176,11 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @returns {Boolean} */ isWeb3Signing(moduleInstance) { - return moduleInstance.accounts && - moduleInstance.accounts.wallet.length > 0 && - moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; + return ( + moduleInstance.accounts && + moduleInstance.accounts.wallet.length > 0 && + moduleInstance.transactionSigner.constructor.name === 'TransactionSigner' + ); } /** diff --git a/packages/web3-core-subscriptions/src/index.js b/packages/web3-core-subscriptions/src/index.js index a9d4c232bac..737904a13e8 100644 --- a/packages/web3-core-subscriptions/src/index.js +++ b/packages/web3-core-subscriptions/src/index.js @@ -45,4 +45,3 @@ export SyncingSubscription from './subscriptions/eth/SyncingSubscription'; // Shh export MessagesSubscription from './subscriptions/shh/MessagesSubscription'; - diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index a8412eca9c1..bc19dd88bc8 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -219,7 +219,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.fromV3Keystore(keystore, password, false, this); if (!account) { - throw new Error('Couldn\'t decrypt accounts. Password wrong?'); + throw new Error("Couldn't decrypt accounts. Password wrong?"); } this.add(account); @@ -282,7 +282,7 @@ export default class Accounts extends AbstractWeb3Module { keystore = localStorage.getItem(keyName || this.defaultKeyName); if (keystore) { - keystore = JSON.parse(keystore).map(item => Account.fromV3Keystore(item, password, false, this)); + keystore = JSON.parse(keystore).map((item) => Account.fromV3Keystore(item, password, false, this)); } } catch (error) { // code 18 means trying to use local storage in a iframe diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 00603098925..7b8c4fdd332 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -175,11 +175,7 @@ export default class Account { cipher.final() ]); - const mac = sha3( - Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')]) - ).replace( - '0x', '' - ); + const mac = sha3(Buffer.concat([derivedKey.slice(16, 32), Buffer.from(ciphertext, 'hex')])).replace('0x', ''); return { version: 3, diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index bfe6a0c2cbb..29bb391bb8e 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -4,9 +4,6 @@ import {ChainIdMethod, GetGasPriceMethod, GetTransactionCountMethod} from 'web3- import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; -import scryptsy from 'scrypt.js'; -import crypto from 'crypto'; -import uuid from 'uuid'; import {encodeSignature, recover} from 'eth-lib/lib/account'; import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; import TransactionSigner from '../__mocks__/TransactionSigner'; @@ -125,8 +122,9 @@ describe('AccountsTest', () => { }); it('calls signTransaction and resolves with a promise', async () => { - const callback = jest.fn(), - signTransaction = jest.fn(); + const callback = jest.fn(); + + const signTransaction = jest.fn(); signTransaction.mockReturnValueOnce(Promise.resolve('signed-transaction')); @@ -143,17 +141,17 @@ describe('AccountsTest', () => { it('calls signTransaction and rejects with a promise', async () => { const signTransaction = jest.fn(); - signTransaction.mockReturnValueOnce(Promise.reject('ERROR')); + signTransaction.mockReturnValueOnce(Promise.reject(new Error('ERROR'))); const callback = jest.fn(); Account.fromPrivateKey.mockReturnValueOnce({signTransaction: signTransaction}); - await expect(accounts.signTransaction({}, 'pk', callback)).rejects.toEqual('ERROR'); + await expect(accounts.signTransaction({}, 'pk', callback)).rejects.toEqual(new Error('ERROR')); expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - expect(callback).toHaveBeenCalledWith('ERROR', null); + expect(callback).toHaveBeenCalledWith(new Error('ERROR'), null); expect(signTransaction).toHaveBeenCalledWith({}); }); @@ -173,10 +171,8 @@ describe('AccountsTest', () => { recover.mockReturnValueOnce('recovered'); - expect(accounts.recoverTransaction('rawTransaction')).toEqual('recovered'); - expect(recover).toHaveBeenCalledWith('hash', 'signature'); expect(Hash.keccak256).toHaveBeenCalledWith('encoded'); @@ -217,12 +213,9 @@ describe('AccountsTest', () => { expect(isHexStrict).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); expect(recover).toHaveBeenCalledWith('keccak', 'signature'); }); @@ -405,7 +398,7 @@ describe('AccountsTest', () => { expect(() => { accounts.wallet.decrypt([true], 'pw'); - }).toThrow('Couldn\'t decrypt accounts. Password wrong?'); + }).toThrow("Couldn't decrypt accounts. Password wrong?"); expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); }); diff --git a/packages/web3-eth-accounts/tests/src/models/AccountTest.js b/packages/web3-eth-accounts/tests/src/models/AccountTest.js index 2a3fee428fa..d822436a0d7 100644 --- a/packages/web3-eth-accounts/tests/src/models/AccountTest.js +++ b/packages/web3-eth-accounts/tests/src/models/AccountTest.js @@ -2,7 +2,7 @@ import scryptsy from 'scrypt.js'; import crypto from 'crypto'; import uuid from 'uuid'; import Hash from 'eth-lib/lib/hash'; -import {fromPrivate, create, sign, decodeSignature} from 'eth-lib/lib/account'; +import {fromPrivate, sign, decodeSignature} from 'eth-lib/lib/account'; import {hexToBytes, isHexStrict, sha3} from 'web3-utils'; import TransactionSigner from '../../__mocks__/TransactionSigner'; import Accounts from '../../../src/Accounts'; @@ -71,12 +71,9 @@ describe('AccountTest', () => { signature: 'signed' }); - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); expect(sign).toHaveBeenCalledWith('keccak', 'pk'); @@ -105,12 +102,9 @@ describe('AccountTest', () => { signature: 'signed' }); - expect(Hash.keccak256s) - .toHaveBeenCalledWith( - Buffer.concat( - [Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')] - ) - ); + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); expect(sign).toHaveBeenCalledWith('keccak', 'pk'); @@ -172,7 +166,9 @@ describe('AccountTest', () => { expect(Account.fromV3Keystore(json, 'password', false)).toBeInstanceOf(Account); - expect(fromPrivate).toHaveBeenLastCalledWith(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); + expect(fromPrivate).toHaveBeenLastCalledWith( + `0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}` + ); expect(scryptsy).toHaveBeenCalledWith( Buffer.from('password'), @@ -256,7 +252,9 @@ describe('AccountTest', () => { expect(Account.fromV3Keystore(json, 'password', false)).toBeInstanceOf(Account); - expect(fromPrivate).toHaveBeenCalledWith(`0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}`); + expect(fromPrivate).toHaveBeenCalledWith( + `0x${Buffer.concat([Buffer.from('0'), Buffer.from('0')]).toString('hex')}` + ); expect(crypto.pbkdf2Sync).toHaveBeenCalled(); @@ -422,12 +420,10 @@ describe('AccountTest', () => { it('calls toV3Keystore with the pbkdf2 sheme and returns the expected object', () => { const options = {kdf: 'pbkdf2'}; - fromPrivate.mockReturnValueOnce( - { - privateKey: '0xxx', - address: '0xA' - } - ); + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' + }); crypto.randomBytes.mockReturnValue(Buffer.from('random')); diff --git a/packages/web3-eth-accounts/tests/src/models/WalletTest.js b/packages/web3-eth-accounts/tests/src/models/WalletTest.js deleted file mode 100644 index 72df416829f..00000000000 --- a/packages/web3-eth-accounts/tests/src/models/WalletTest.js +++ /dev/null @@ -1,25 +0,0 @@ -import Wallet from '../../../src/models/Wallet'; - -// Mocks -jest.mock(''); - -/** - * Wallet test - */ -describe('WalletTest', () => { - let wallet; - - beforeEach(() => { - wallet = new Wallet(); - }); - - it('constructor check', () => { - expect(wallet.length).toEqual(0); - - expect(wallet.defaultKeyName).toEqual('web3js_wallet'); - }); - - it('calls findSafeIndex and returns the expected pointer', () =< { - - }) -}); diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 2c9fa1464ec..f4c8d57068d 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -20,7 +20,7 @@ * @date 2018 */ -import {MethodModuleFactory, SignMethod} from 'web3-core-method'; +import {MethodModuleFactory} from 'web3-core-method'; import {formatters} from 'web3-core-helpers'; import {SubscriptionsFactory} from 'web3-core-subscriptions'; import {Accounts} from 'web3-eth-accounts'; diff --git a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js index aa227d8f3f5..e0bd3330469 100644 --- a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -14,9 +14,7 @@ describe('TransactionSignerTestTest', () => { TransactionSignerTest = new TransactionSignerTest(); }); - it('constructor check', () => { - - }); + it('constructor check', () => {}); it('calls signTransaction and returns a resolved promise', async () => { const callback = jest.fn(); From a6c24f909e1c1f8494ef2a32dcb1dea69d182fbb Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sat, 23 Feb 2019 00:03:03 +0100 Subject: [PATCH 40/71] possibility added for using the API of the wallet like this: accounts.wallet['0x0'] --- packages/web3-eth-accounts/src/Accounts.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index bc19dd88bc8..ad539a96670 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -92,6 +92,10 @@ export default class Accounts extends AbstractWeb3Module { case 'clear': return target.clear; default: + if(target.accounts[name]) { + return target.accounts[name]; + } + return target[name]; } } From 24f33d616e0bda65287bb5f654e585f9b4d14e39 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sat, 23 Feb 2019 01:03:50 +0100 Subject: [PATCH 41/71] SendTransactionMethod updated and started with updating the regarding test --- .../transaction/SendTransactionMethod.js | 23 +- .../tests/__mocks__/TransactionSigner.js | 22 ++ .../transaction/SendTransactionMethodTest.js | 365 ++++++++++++++---- packages/web3-eth-accounts/src/Accounts.js | 2 +- 4 files changed, 315 insertions(+), 97 deletions(-) create mode 100644 packages/web3-core-method/tests/__mocks__/TransactionSigner.js diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 9e46fe6d2e0..67796f569a2 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -20,6 +20,7 @@ * @date 2018 */ +import {cloneDeep} from 'lodash/cloneDeep'; import AbstractSendMethod from '../../../lib/methods/AbstractSendMethod'; // TODO: Clean up this method and move the signing and observing logic to the eth module @@ -78,16 +79,6 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (moduleInstance.accounts.wallet[this.parameters[0].from]) { - moduleInstance.getTransactionCount(this.parameters[0].from).then((count) => { - this.parameters[0].nonce = count; - - this.execute(moduleInstance, promiEvent); - }); - - return promiEvent; - } - if (this.isWeb3Signing(moduleInstance)) { this.sendRawTransaction( this.formatTransactionForSigning(moduleInstance, promiEvent), @@ -127,7 +118,15 @@ export default class SendTransactionMethod extends AbstractSendMethod { }); } - let transaction = this.formatters.txInputFormatter(this.parameters[0]); + if (!this.parameters[0].nonce && this.parameters[0].nonce !== 0) { + moduleInstance.getTransactionCount(this.parameters[0].from).then((count) => { + this.parameters[0].nonce = count; + + this.execute(moduleInstance, promiEvent); + }); + } + + let transaction = this.formatters.txInputFormatter(cloneDeep(this.parameters[0])); transaction.to = transaction.to || '0x'; transaction.data = transaction.data || '0x'; transaction.value = transaction.value || '0x'; @@ -178,7 +177,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { isWeb3Signing(moduleInstance) { return ( moduleInstance.accounts && - moduleInstance.accounts.wallet.length > 0 && + Object.keys(moduleInstance.accounts.wallet).length > 0 && moduleInstance.transactionSigner.constructor.name === 'TransactionSigner' ); } diff --git a/packages/web3-core-method/tests/__mocks__/TransactionSigner.js b/packages/web3-core-method/tests/__mocks__/TransactionSigner.js new file mode 100644 index 00000000000..c88cae6f7f8 --- /dev/null +++ b/packages/web3-core-method/tests/__mocks__/TransactionSigner.js @@ -0,0 +1,22 @@ +/* + This file is part of web3.js. + web3.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + web3.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public License + along with web3.js. If not, see . +*/ +/** + * @file TransactionSigner.js + * @author Samuel Furter + * @date 2019 + */ + +export default class TransactionSigner { + sign() {} +} diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 1c5e0997f16..38df9407c8c 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -4,16 +4,16 @@ import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; import Accounts from '../../../__mocks__/Accounts'; import SendRawTransactionMethod from '../../../../src/methods/transaction/SendRawTransactionMethod'; -import TransactionSigner from '../../../../src/signers/TransactionSigner'; +import TransactionSigner from '../../../__mocks__/TransactionSigner'; import TransactionConfirmationWorkflow from '../../../../src/workflows/TransactionConfirmationWorkflow'; import SendTransactionMethod from '../../../../src/methods/transaction/SendTransactionMethod'; +import AbstractSendMethod from '../../../../lib/methods/AbstractSendMethod'; // Mocks jest.mock('formatters'); jest.mock('WebsocketProvider'); jest.mock('AbstractWeb3Module'); jest.mock('../../../../src/workflows/TransactionConfirmationWorkflow'); -jest.mock('../../../../src/signers/TransactionSigner'); jest.mock('../../../../src/methods/transaction/SendRawTransactionMethod'); /** @@ -39,8 +39,7 @@ describe('SendTransactionMethodTest', () => { accountsMock = new Accounts(); - new TransactionSigner(accountsMock); - transactionSignerMock = TransactionSigner.mock.instances[0]; + transactionSignerMock = new TransactionSigner(); promiEvent = new PromiEvent(); @@ -54,8 +53,6 @@ describe('SendTransactionMethodTest', () => { {}, formatters, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, sendRawTransactionMethodMock ); @@ -64,144 +61,344 @@ describe('SendTransactionMethodTest', () => { }); it('constructor check', () => { - expect(SendTransactionMethod.Type).toEqual('SEND'); - expect(method.rpcMethod).toEqual('eth_sendTransaction'); expect(method.parametersAmount).toEqual(1); - expect(method.accounts).toEqual(accountsMock); + expect(method.sendRawTransactionMethod).toEqual(sendRawTransactionMethodMock); + + expect(method).toBeInstanceOf(AbstractSendMethod); + }); + + it('calls execute with wallets defined and returns with a resolved promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + sendRawTransactionMethodMock.parameters = [transaction]; + + formatters.txInputFormatter.mockReturnValueOnce(transaction); + + Utils.numberToHex.mockReturnValueOnce('0x0'); + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; + + const response = await method.execute(moduleInstanceMock, promiEvent); + + expect(response).toEqual(true); + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(method.transactionConfirmationWorkflow).toEqual(transactionConfirmationWorkflowMock); + expect(Utils.numberToHex).toHaveBeenCalledWith(1); - expect(method.transactionSigner).toEqual(transactionSignerMock); + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute with wallets defined', async () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; + it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { + const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; - transactionSignerMock.sign = jest.fn(() => { - return Promise.resolve('0x0'); - }); + customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); - }); + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.transactionSigner = customSigner; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + sendRawTransactionMethodMock.parameters = [transaction]; - sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, givenPromiEvent) => { - expect(moduleInstance).toEqual(moduleInstanceMock); + formatters.txInputFormatter.mockReturnValueOnce(transaction); - expect(givenPromiEvent).toEqual(promiEvent); + Utils.numberToHex.mockReturnValueOnce('0x0'); - givenPromiEvent.resolve(true); - }); + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; const response = await method.execute(moduleInstanceMock, promiEvent); expect(response).toEqual(true); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: '0x0'}); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute with wallets defined and uses the module default gas properties', async () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; + it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.defaultGas = 10; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + sendRawTransactionMethodMock.parameters = [transaction]; + + formatters.txInputFormatter.mockReturnValueOnce(transaction); + + Utils.numberToHex.mockReturnValueOnce('0x0'); + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; + + const response = await method.execute(moduleInstanceMock, promiEvent); + + expect(response).toEqual(true); + + const mappedTransaction = { + from: 0, + gas: 10, + gasPrice: 1, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); + }); - transactionSignerMock.sign = jest.fn(() => { - return Promise.resolve('0x0'); - }); + it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); - }); + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.defaultGas = 100; - moduleInstanceMock.defaultGasPrice = 100; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.defaultGasPrice = 10; - sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, givenPromiEvent) => { - expect(moduleInstance).toEqual(moduleInstanceMock); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - expect(givenPromiEvent).toEqual(promiEvent); + sendRawTransactionMethodMock.parameters = [transaction]; - givenPromiEvent.resolve(true); - }); + formatters.txInputFormatter.mockReturnValueOnce(transaction); + + Utils.numberToHex.mockReturnValueOnce('0x0'); + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; const response = await method.execute(moduleInstanceMock, promiEvent); expect(response).toEqual(true); - expect(method.parameters[0].gas).toEqual(100); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - expect(method.parameters[0].gasPrice).toEqual(100); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: 100, gas: 100}); + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute and TransactionSigner throws error', async (done) => { - accountsMock.wallet[0] = {privateKey: '0x0'}; + it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); - }); + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - const error = new Error('SIGN ERROR'); - transactionSignerMock.sign = jest.fn(() => { - return new Promise((resolve, reject) => { - reject(error); - }); - }); + providerMock.send.mockReturnValueOnce(Promise.resolve(10)); moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.defaultGasPrice = false; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - promiEvent.on('error', (e) => { - expect(e).toEqual(error); + sendRawTransactionMethodMock.parameters = [transaction]; - expect(providerMock.send).toHaveBeenCalledWith('eth_gasPrice', []); + formatters.txInputFormatter.mockReturnValueOnce(transaction); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: '0x0'}); + Utils.numberToHex.mockReturnValueOnce('0x0'); - done(); - }); + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); - try { - await method.execute(moduleInstanceMock, promiEvent); - } catch (error2) { - expect(error2).toEqual(error); + const callback = jest.fn(); + method.callback = callback; + + const response = await method.execute(moduleInstanceMock, promiEvent); - expect(method.callback).toHaveBeenCalledWith(error, null); - } + expect(response).toEqual(true); + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + + expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute without wallets defined', async (done) => { - method.parameters = [{gasPrice: false}]; + it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); - }); + providerMock.send.mockReturnValueOnce(Promise.resolve(10)); moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.defaultGasPrice = false; - promiEvent.on('transactionHash', (response) => { - expect(response).toEqual('0x0'); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( - method, - moduleInstanceMock, - '0x0', - promiEvent - ); + sendRawTransactionMethodMock.parameters = [transaction]; - expect(providerMock.send).toHaveBeenCalledWith(method.rpcMethod, method.parameters); + formatters.txInputFormatter.mockReturnValueOnce(transaction); - done(); - }); + Utils.numberToHex.mockReturnValueOnce('0x0'); + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; const response = await method.execute(moduleInstanceMock, promiEvent); - expect(response).toEqual('0x0'); + expect(response).toEqual(true); + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + + expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); - expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); }); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index ad539a96670..3d4473784cf 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -95,7 +95,7 @@ export default class Accounts extends AbstractWeb3Module { if(target.accounts[name]) { return target.accounts[name]; } - + return target[name]; } } From 16422d9dc82e61455ab1c67f3e9ad9af2d76e245 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Sat, 23 Feb 2019 01:44:35 +0100 Subject: [PATCH 42/71] Readability of the SendTransactionMethod class improved --- .../transaction/SendTransactionMethod.js | 58 +++++++++---------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 67796f569a2..d24a7c2a5b0 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -79,9 +79,8 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (this.isWeb3Signing(moduleInstance)) { + if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { this.sendRawTransaction( - this.formatTransactionForSigning(moduleInstance, promiEvent), moduleInstance.accounts.wallet[this.parameters[0].from], promiEvent, moduleInstance @@ -91,7 +90,10 @@ export default class SendTransactionMethod extends AbstractSendMethod { } if (this.hasCustomSigner(moduleInstance)) { - this.sendRawTransaction(this.formatTransactionForSigning(moduleInstance, promiEvent), null, promiEvent, moduleInstance); + this.sendRawTransaction(null, + promiEvent, + moduleInstance + ); return promiEvent; } @@ -102,14 +104,15 @@ export default class SendTransactionMethod extends AbstractSendMethod { } /** - * Formats the transaction options object + * Signs the transaction and executes the SendRawTransaction method. * - * @param {Eth} moduleInstance - * @param {PromiEvent} promiEvent + * @method sendRawTransaction * - * @returns {Object} + * @param {String} privateKey + * @param {PromiEvent} promiEvent + * @param {AbstractWeb3Module} moduleInstance */ - formatTransactionForSigning(moduleInstance, promiEvent) { + sendRawTransaction(privateKey, promiEvent, moduleInstance) { if (this.parameters[0].chainId) { moduleInstance.getChainId().then((chainId) => { this.parameters[0].chainId = chainId; @@ -132,20 +135,6 @@ export default class SendTransactionMethod extends AbstractSendMethod { transaction.value = transaction.value || '0x'; transaction.chainId = this.utils.numberToHex(transaction.chainId); - return transaction; - } - - /** - * Signs the transaction and executes the SendRawTransaction method. - * - * @method sendRawTransaction - * - * @param {Object} transaction - * @param {String} privateKey - * @param {PromiEvent} promiEvent - * @param {AbstractWeb3Module} moduleInstance - */ - sendRawTransaction(transaction, privateKey, promiEvent, moduleInstance) { moduleInstance.transactionSigner .sign(transaction, privateKey) .then((response) => { @@ -168,18 +157,27 @@ export default class SendTransactionMethod extends AbstractSendMethod { /** * Checks if the current module has decrypted accounts * - * @method isWeb3Signing + * @method isDefaultSigner * - * @param moduleInstance + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ + isDefaultSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; + } + + /** + * Checks if the current module has decrypted accounts + * + * @method hasAccounts + * + * @param {AbstractWeb3Module} moduleInstance * * @returns {Boolean} */ - isWeb3Signing(moduleInstance) { - return ( - moduleInstance.accounts && - Object.keys(moduleInstance.accounts.wallet).length > 0 && - moduleInstance.transactionSigner.constructor.name === 'TransactionSigner' - ); + hasAccounts(moduleInstance) { + return moduleInstance.accounts && Object.keys(moduleInstance.accounts.wallet).length > 0; } /** From ae1a7f2a616cb8b5cc7013809e839181b636b1ed Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 25 Feb 2019 15:13:46 +0100 Subject: [PATCH 43/71] ongoing work of test and SendTransactionMethod improved --- .../transaction/SendTransactionMethod.js | 54 ++----- .../transaction/SendTransactionMethodTest.js | 141 ++++++++---------- 2 files changed, 77 insertions(+), 118 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index d24a7c2a5b0..faa773e37bb 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -79,21 +79,20 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { + if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance) || this.hasCustomSigner(moduleInstance)) { this.sendRawTransaction( moduleInstance.accounts.wallet[this.parameters[0].from], promiEvent, moduleInstance - ); - - return promiEvent; - } + ).catch((error) => { + if (this.callback) { + this.callback(error, null); + } - if (this.hasCustomSigner(moduleInstance)) { - this.sendRawTransaction(null, - promiEvent, - moduleInstance - ); + promiEvent.reject(error); + promiEvent.emit('error', error); + promiEvent.removeAllListeners(); + }); return promiEvent; } @@ -112,21 +111,13 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {PromiEvent} promiEvent * @param {AbstractWeb3Module} moduleInstance */ - sendRawTransaction(privateKey, promiEvent, moduleInstance) { + async sendRawTransaction(privateKey, promiEvent, moduleInstance) { if (this.parameters[0].chainId) { - moduleInstance.getChainId().then((chainId) => { - this.parameters[0].chainId = chainId; - - this.execute(moduleInstance, promiEvent); - }); + this.parameters[0].chainId = await moduleInstance.getChainId(); } if (!this.parameters[0].nonce && this.parameters[0].nonce !== 0) { - moduleInstance.getTransactionCount(this.parameters[0].from).then((count) => { - this.parameters[0].nonce = count; - - this.execute(moduleInstance, promiEvent); - }); + this.parameters[0].nonce = await moduleInstance.getTransactionCount(this.parameters[0].from); } let transaction = this.formatters.txInputFormatter(cloneDeep(this.parameters[0])); @@ -135,23 +126,10 @@ export default class SendTransactionMethod extends AbstractSendMethod { transaction.value = transaction.value || '0x'; transaction.chainId = this.utils.numberToHex(transaction.chainId); - moduleInstance.transactionSigner - .sign(transaction, privateKey) - .then((response) => { - this.sendRawTransactionMethod.parameters = [response.rawTransaction]; - this.sendRawTransactionMethod.callback = this.callback; - - this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); - }) - .catch((error) => { - if (this.callback) { - this.callback(error, null); - } - - promiEvent.reject(error); - promiEvent.emit('error', error); - promiEvent.removeAllListeners(); - }); + const response = await moduleInstance.transactionSigner.sign(transaction, privateKey); + this.sendRawTransactionMethod.parameters = [response.rawTransaction]; + this.sendRawTransactionMethod.callback = this.callback; + this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); } /** diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 38df9407c8c..0c76766f2d7 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -178,15 +178,16 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + it('calls execute signs locally but doesnt have chainId defined and returns with a resolved promise', async () => { + const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; + + customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; - moduleInstanceMock.transactionSigner = transactionSignerMock; - moduleInstanceMock.defaultGas = 10; + moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.transactionSigner = customSigner; const transaction = { from: 0, @@ -213,7 +214,7 @@ describe('SendTransactionMethodTest', () => { const mappedTransaction = { from: 0, - gas: 10, + gas: 1, gasPrice: 1, nonce: 1, chainId: '0x0' @@ -232,34 +233,34 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); - it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - + it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async (done) => { providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { + promiEvent.resolve(true); + }); + moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; - moduleInstanceMock.transactionSigner = transactionSignerMock; - moduleInstanceMock.defaultGasPrice = 10; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; + moduleInstanceMock.defaultGas = 10; const transaction = { from: 0, - gas: 1, + gas: 0, gasPrice: 1, nonce: 1, chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; - - formatters.txInputFormatter.mockReturnValueOnce(transaction); + method.callback = jest.fn(); + method.parameters = [transaction]; - Utils.numberToHex.mockReturnValueOnce('0x0'); + const transactionhashCallback = jest.fn(); + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); - - const callback = jest.fn(); - method.callback = callback; + transactionhashCallback(); + }); const response = await method.execute(moduleInstanceMock, promiEvent); @@ -267,55 +268,49 @@ describe('SendTransactionMethodTest', () => { const mappedTransaction = { from: 0, - gas: 1, - gasPrice: 10, + gas: 10, + gasPrice: 1, nonce: 1, chainId: '0x0' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); - - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); - - expect(sendRawTransactionMethodMock.callback).toEqual(callback); + expect(transactionhashCallback).toHaveBeenCalled(); }); it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - providerMock.send.mockReturnValueOnce(Promise.resolve(10)); + transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { + promiEvent.resolve(true); + }); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; - moduleInstanceMock.transactionSigner = transactionSignerMock; - moduleInstanceMock.defaultGasPrice = false; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; + moduleInstanceMock.defaultGasPrice = 10; const transaction = { from: 0, gas: 1, - gasPrice: 1, + gasPrice: 0, nonce: 1, chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; - - formatters.txInputFormatter.mockReturnValueOnce(transaction); - - Utils.numberToHex.mockReturnValueOnce('0x0'); + method.callback = jest.fn(); + method.parameters = [transaction]; - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + const transactionhashCallback = jest.fn(); + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); - const callback = jest.fn(); - method.callback = callback; + transactionhashCallback(); + }); const response = await method.execute(moduleInstanceMock, promiEvent); @@ -329,51 +324,43 @@ describe('SendTransactionMethodTest', () => { chainId: '0x0' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); - - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); - expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); - - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); - - expect(sendRawTransactionMethodMock.callback).toEqual(callback); + expect(transactionhashCallback).toHaveBeenCalled(); }); it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - providerMock.send.mockReturnValueOnce(Promise.resolve(10)); + transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { + promiEvent.resolve(true); + }); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; - moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; moduleInstanceMock.defaultGasPrice = false; const transaction = { from: 0, gas: 1, - gasPrice: 1, + gasPrice: 0, nonce: 1, chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; - - formatters.txInputFormatter.mockReturnValueOnce(transaction); + method.callback = jest.fn(); + method.parameters = [transaction]; - Utils.numberToHex.mockReturnValueOnce('0x0'); + const transactionhashCallback = jest.fn(); + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); - - const callback = jest.fn(); - method.callback = callback; + transactionhashCallback(); + }); const response = await method.execute(moduleInstanceMock, promiEvent); @@ -387,18 +374,12 @@ describe('SendTransactionMethodTest', () => { chainId: '0x0' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); - - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); - expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); - - expect(sendRawTransactionMethodMock.callback).toEqual(callback); + expect(transactionhashCallback).toHaveBeenCalled(); }); }); From db234771ad221d86abf0b4f159016b1fcc23f2bd Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 25 Feb 2019 15:44:52 +0100 Subject: [PATCH 44/71] error case for local signing added and SendTransactionMethod updated --- .../transaction/SendTransactionMethod.js | 4 +- .../transaction/SendTransactionMethodTest.js | 110 +++++++++++++++++- 2 files changed, 111 insertions(+), 3 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index faa773e37bb..6c9469671f2 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -54,7 +54,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * * @method execute * - * @param {AbstractWeb3Module} moduleInstance + * @param {Eth} moduleInstance * @param {PromiEvent} promiEvent * * @callback callback callback(error, result) @@ -109,7 +109,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * * @param {String} privateKey * @param {PromiEvent} promiEvent - * @param {AbstractWeb3Module} moduleInstance + * @param {Eth} moduleInstance */ async sendRawTransaction(privateKey, promiEvent, moduleInstance) { if (this.parameters[0].chainId) { diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 0c76766f2d7..7a5565d0bc6 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -123,6 +123,47 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.callback).toEqual(callback); }); + it('calls execute with wallets defined and returns with a rejected promise', async () => { + transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + const error = new Error('ERROR'); + + formatters.txInputFormatter.mockReturnValueOnce(() => { + promiEvent.reject(error); + }); + + method.callback = jest.fn(); + + const errorCallback = jest.fn(); + promiEvent.on('error', (e) => { + expect(e).toEqual(error); + + errorCallback(); + }); + + await expect(method.execute(moduleInstanceMock, promiEvent)).rejects.toThrow('ERROR'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(method.callback).toHaveBeenCalledWith(error, null); + + expect(promiEvent.listenerCount('error')).toEqual(0); + }); + it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; @@ -185,6 +226,10 @@ describe('SendTransactionMethodTest', () => { providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + moduleInstanceMock.getChainId = jest.fn(() => { + return Promise.resolve(1); + }); + moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.accounts = {wallet: {}}; moduleInstanceMock.transactionSigner = customSigner; @@ -194,6 +239,67 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, + chainId: 0 + }; + + sendRawTransactionMethodMock.parameters = [transaction]; + + formatters.txInputFormatter.mockReturnValueOnce(transaction); + + Utils.numberToHex.mockReturnValueOnce('0x0'); + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + const callback = jest.fn(); + method.callback = callback; + + const response = await method.execute(moduleInstanceMock, promiEvent); + + expect(response).toEqual(true); + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: '0x0' + }; + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); + + expect(Utils.numberToHex).toHaveBeenCalledWith(1); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); + + expect(moduleInstanceMock.getChainId).toHaveBeenCalled(); + }); + + it('calls execute signs locally but doesnt have nonce defined and returns with a resolved promise', async () => { + const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; + + customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + + moduleInstanceMock.getTransactionCount = jest.fn(() => { + return Promise.resolve(1); + }); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.transactionSigner = customSigner; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 0, chainId: 1 }; @@ -231,9 +337,11 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); + + expect(moduleInstanceMock.getChainId).toHaveBeenCalled(); }); - it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async (done) => { + it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async () => { providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { From b8af36ac5eda1012bc9776fc36cfa08b1208c071 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 25 Feb 2019 18:06:05 +0100 Subject: [PATCH 45/71] SendTransactionMethod updated and SendTransactionMethodTest fixed --- .../transaction/SendTransactionMethod.js | 16 +- .../transaction/SendTransactionMethodTest.js | 267 +++++++++--------- 2 files changed, 151 insertions(+), 132 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 6c9469671f2..fd0a9c930c7 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -20,7 +20,6 @@ * @date 2018 */ -import {cloneDeep} from 'lodash/cloneDeep'; import AbstractSendMethod from '../../../lib/methods/AbstractSendMethod'; // TODO: Clean up this method and move the signing and observing logic to the eth module @@ -78,10 +77,17 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } + if ( + (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) || + this.hasCustomSigner(moduleInstance) + ) { + let privateKey; + if (moduleInstance.accounts.wallet[this.parameters[0].from]) { + privateKey = moduleInstance.accounts.wallet[this.parameters[0].from].privateKey; + } - if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance) || this.hasCustomSigner(moduleInstance)) { this.sendRawTransaction( - moduleInstance.accounts.wallet[this.parameters[0].from], + privateKey, promiEvent, moduleInstance ).catch((error) => { @@ -112,7 +118,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {Eth} moduleInstance */ async sendRawTransaction(privateKey, promiEvent, moduleInstance) { - if (this.parameters[0].chainId) { + if (!this.parameters[0].chainId) { this.parameters[0].chainId = await moduleInstance.getChainId(); } @@ -120,7 +126,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0].nonce = await moduleInstance.getTransactionCount(this.parameters[0].from); } - let transaction = this.formatters.txInputFormatter(cloneDeep(this.parameters[0])); + let transaction = this.formatters.txInputFormatter(this.parameters[0]); transaction.to = transaction.to || '0x'; transaction.data = transaction.data || '0x'; transaction.value = transaction.value || '0x'; diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 7a5565d0bc6..8da8d670aad 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -2,15 +2,17 @@ import {formatters} from 'web3-core-helpers'; import {PromiEvent} from 'web3-core-promievent'; import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; +import * as Utils from 'web3-utils'; import Accounts from '../../../__mocks__/Accounts'; import SendRawTransactionMethod from '../../../../src/methods/transaction/SendRawTransactionMethod'; import TransactionSigner from '../../../__mocks__/TransactionSigner'; import TransactionConfirmationWorkflow from '../../../../src/workflows/TransactionConfirmationWorkflow'; -import SendTransactionMethod from '../../../../src/methods/transaction/SendTransactionMethod'; import AbstractSendMethod from '../../../../lib/methods/AbstractSendMethod'; +import SendTransactionMethod from '../../../../src/methods/transaction/SendTransactionMethod'; // Mocks jest.mock('formatters'); +jest.mock('Utils'); jest.mock('WebsocketProvider'); jest.mock('AbstractWeb3Module'); jest.mock('../../../../src/workflows/TransactionConfirmationWorkflow'); @@ -40,6 +42,7 @@ describe('SendTransactionMethodTest', () => { accountsMock = new Accounts(); transactionSignerMock = new TransactionSigner(); + transactionSignerMock.sign = jest.fn(); promiEvent = new PromiEvent(); @@ -50,7 +53,7 @@ describe('SendTransactionMethodTest', () => { sendRawTransactionMethodMock = SendRawTransactionMethod.mock.instances[0]; method = new SendTransactionMethod( - {}, + Utils, formatters, transactionConfirmationWorkflowMock, sendRawTransactionMethodMock @@ -71,14 +74,18 @@ describe('SendTransactionMethodTest', () => { }); it('calls execute with wallets defined and returns with a resolved promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); + }); moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = transactionSignerMock; + sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { + promiEvent.resolve('0x0'); + }); + const transaction = { from: 0, gas: 1, @@ -87,7 +94,16 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: '0x0', + data: '0x', + to: '0x', + value: '0x' + }; formatters.txInputFormatter.mockReturnValueOnce(transaction); @@ -97,37 +113,27 @@ describe('SendTransactionMethodTest', () => { const callback = jest.fn(); method.callback = callback; + method.parameters = [transaction]; const response = await method.execute(moduleInstanceMock, promiEvent); expect(response).toEqual(true); - const mappedTransaction = { - from: 0, - gas: 1, - gasPrice: 1, - nonce: 1, - chainId: '0x0' - }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + expect(sendRawTransactionMethodMock.callback).toEqual(callback); + }); it('calls execute with wallets defined and returns with a rejected promise', async () => { - transactionSignerMock.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = transactionSignerMock; @@ -142,11 +148,12 @@ describe('SendTransactionMethodTest', () => { const error = new Error('ERROR'); - formatters.txInputFormatter.mockReturnValueOnce(() => { - promiEvent.reject(error); + formatters.txInputFormatter = jest.fn(() => { + throw error; }); method.callback = jest.fn(); + method.parameters = [transaction]; const errorCallback = jest.fn(); promiEvent.on('error', (e) => { @@ -160,16 +167,18 @@ describe('SendTransactionMethodTest', () => { expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); expect(method.callback).toHaveBeenCalledWith(error, null); - - expect(promiEvent.listenerCount('error')).toEqual(0); }); it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { - const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; + const customSigner = {constructor: {name: 'CustomSigner'}}; - customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); + customSigner.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); + }); - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + providerMock.send = jest.fn(() => { + return Promise.resolve('0x0'); + }); moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.accounts = {wallet: {}}; @@ -183,8 +192,6 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; - formatters.txInputFormatter.mockReturnValueOnce(transaction); Utils.numberToHex.mockReturnValueOnce('0x0'); @@ -193,6 +200,7 @@ describe('SendTransactionMethodTest', () => { const callback = jest.fn(); method.callback = callback; + method.parameters = [transaction]; const response = await method.execute(moduleInstanceMock, promiEvent); @@ -203,37 +211,43 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0' + chainId: '0x0', + data: '0x', + to: '0x', + value: '0x' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); + + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); }); it('calls execute signs locally but doesnt have chainId defined and returns with a resolved promise', async () => { - const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; - - customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + const customSigner = {constructor: {name: 'CustomSigner'}}; + customSigner.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); + }); moduleInstanceMock.getChainId = jest.fn(() => { return Promise.resolve(1); }); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = customSigner; + sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { + promiEvent.resolve('0x0'); + }); + const transaction = { from: 0, gas: 1, @@ -242,8 +256,6 @@ describe('SendTransactionMethodTest', () => { chainId: 0 }; - sendRawTransactionMethodMock.parameters = [transaction]; - formatters.txInputFormatter.mockReturnValueOnce(transaction); Utils.numberToHex.mockReturnValueOnce('0x0'); @@ -252,6 +264,7 @@ describe('SendTransactionMethodTest', () => { const callback = jest.fn(); method.callback = callback; + method.parameters = [transaction]; const response = await method.execute(moduleInstanceMock, promiEvent); @@ -262,30 +275,32 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0' + chainId: '0x0', + data: '0x', + to: '0x', + value: '0x' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + expect(moduleInstanceMock.getChainId).toHaveBeenCalled(); }); - it('calls execute signs locally but doesnt have nonce defined and returns with a resolved promise', async () => { - const customSigner = {constructor: {name: 'CustomSigner'}, sign: jest.fn()}; - - customSigner.sign.mockReturnValueOnce(Promise.resolve({rawTransaction: '0x0'})); - - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + it('calls execute signs locally but doesnt have an nonce defined and returns with a resolved promise', async () => { + const customSigner = {constructor: {name: 'CustomSigner'}}; + customSigner.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); + }); moduleInstanceMock.getTransactionCount = jest.fn(() => { return Promise.resolve(1); @@ -299,13 +314,19 @@ describe('SendTransactionMethodTest', () => { from: 0, gas: 1, gasPrice: 1, - nonce: 0, + nonce: undefined, chainId: 1 }; - sendRawTransactionMethodMock.parameters = [transaction]; + const transactionWithNonce = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - formatters.txInputFormatter.mockReturnValueOnce(transaction); + formatters.txInputFormatter.mockReturnValueOnce(transactionWithNonce); Utils.numberToHex.mockReturnValueOnce('0x0'); @@ -313,6 +334,7 @@ describe('SendTransactionMethodTest', () => { const callback = jest.fn(); method.callback = callback; + method.parameters = [transaction]; const response = await method.execute(moduleInstanceMock, promiEvent); @@ -323,31 +345,30 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0' + chainId: '0x0', + data: '0x', + to: '0x', + value: '0x' }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendRawTransaction', sendRawTransactionMethodMock.parameters); - expect(Utils.numberToHex).toHaveBeenCalledWith(1); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); - expect(moduleInstanceMock.getChainId).toHaveBeenCalled(); + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + + expect(moduleInstanceMock.getTransactionCount).toHaveBeenCalledWith(0); }); - it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', async () => { + it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', (done) => { providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { - promiEvent.resolve(true); - }); - moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; moduleInstanceMock.defaultGas = 10; @@ -360,44 +381,39 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; + const mappedTransaction = { + from: 0, + gas: 10, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + formatters.inputTransactionFormatter.mockReturnValueOnce(transaction); + method.callback = jest.fn(); method.parameters = [transaction]; - const transactionhashCallback = jest.fn(); promiEvent.on('transactionHash', (hash) => { expect(hash).toEqual('0x0'); - transactionhashCallback(); - }); - - const response = await method.execute(moduleInstanceMock, promiEvent); - - expect(response).toEqual(true); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); - const mappedTransaction = { - from: 0, - gas: 10, - gasPrice: 1, - nonce: 1, - chainId: '0x0' - }; + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); - expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + done(); + }); - expect(transactionhashCallback).toHaveBeenCalled(); + method.execute(moduleInstanceMock, promiEvent); }); - it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { + it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', (done) => { providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { - promiEvent.resolve(true); - }); - moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; moduleInstanceMock.defaultGasPrice = 10; @@ -410,44 +426,41 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: 1 + }; + + formatters.inputTransactionFormatter.mockReturnValueOnce(transaction); + method.callback = jest.fn(); method.parameters = [transaction]; - const transactionhashCallback = jest.fn(); promiEvent.on('transactionHash', (hash) => { expect(hash).toEqual('0x0'); - transactionhashCallback(); - }); + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); - const response = await method.execute(moduleInstanceMock, promiEvent); - - expect(response).toEqual(true); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - const mappedTransaction = { - from: 0, - gas: 1, - gasPrice: 10, - nonce: 1, - chainId: '0x0' - }; + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + done(); + }); - expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + method.execute(moduleInstanceMock, promiEvent); - expect(transactionhashCallback).toHaveBeenCalled(); }); - it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', async () => { + it('calls execute and the gasPrice will be defined with "eth_gasPrice" and returns with a resolved promise', (done) => { + providerMock.send.mockReturnValueOnce(Promise.resolve(10)); providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - transactionConfirmationWorkflowMock.execute = jest.fn((method, moduleInstance, promiEvent) => { - promiEvent.resolve(true); - }); - moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; moduleInstanceMock.defaultGasPrice = false; @@ -460,34 +473,34 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: 1 + }; + + formatters.inputTransactionFormatter.mockReturnValueOnce(transaction); + method.callback = jest.fn(); method.parameters = [transaction]; - const transactionhashCallback = jest.fn(); promiEvent.on('transactionHash', (hash) => { expect(hash).toEqual('0x0'); - transactionhashCallback(); - }); - - const response = await method.execute(moduleInstanceMock, promiEvent); - - expect(response).toEqual(true); + expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendTransaction', [transaction]); - const mappedTransaction = { - from: 0, - gas: 1, - gasPrice: 10, - nonce: 1, - chainId: '0x0' - }; + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); - expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [mappedTransaction]); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); - expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + done(); + }); - expect(transactionhashCallback).toHaveBeenCalled(); + method.execute(moduleInstanceMock, promiEvent); }); }); From 60f8d88d3b397c06560753e97cc88de508711e56 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Mon, 25 Feb 2019 18:11:52 +0100 Subject: [PATCH 46/71] TransactionSigner and MessageSigner in tests removed --- .../factories/AbstractMethodFactoryTest.js | 3 -- .../tests/lib/methods/AbstractMethodTest.js | 9 ---- .../tests/src/factories/ModuleFactoryTest.js | 10 ---- .../tests/src/methods/SignMethodTest.js | 8 +-- .../tests/src/signers/MessageSignerTest.js | 33 ------------ .../src/signers/TransactionSignerTest.js | 54 ------------------- 6 files changed, 1 insertion(+), 116 deletions(-) delete mode 100644 packages/web3-core-method/tests/src/signers/MessageSignerTest.js delete mode 100644 packages/web3-core-method/tests/src/signers/TransactionSignerTest.js diff --git a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js index 5c669522e59..35014f83d91 100644 --- a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js +++ b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js @@ -65,7 +65,6 @@ describe('AbstractMethodFactoryTest', () => { expect(abstractMethodFactory.createMethod('sendTransaction')).toBeInstanceOf(SendTransactionMethod); expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); @@ -78,7 +77,5 @@ describe('AbstractMethodFactoryTest', () => { expect(abstractMethodFactory.hasMethod('sign')).toEqual(true); expect(abstractMethodFactory.createMethod('sign')).toBeInstanceOf(SignMethod); - - expect(methodModuleFactoryMock.createMessageSigner).toHaveBeenCalled(); }); }); diff --git a/packages/web3-core-method/tests/lib/methods/AbstractMethodTest.js b/packages/web3-core-method/tests/lib/methods/AbstractMethodTest.js index 835dd24ea37..9f950382853 100644 --- a/packages/web3-core-method/tests/lib/methods/AbstractMethodTest.js +++ b/packages/web3-core-method/tests/lib/methods/AbstractMethodTest.js @@ -128,13 +128,4 @@ describe('AbstractMethodTest', () => { it('isHash returns false', () => { expect(abstractMethod.isHash(100)).toBeFalsy(); }); - - it('hasWallets returns true', () => { - abstractMethod.accounts = {wallet: [0]}; - expect(abstractMethod.hasWallets()).toBeTruthy(); - }); - - it('hasWallets returns false', () => { - expect(abstractMethod.hasWallets()).toBeFalsy(); - }); }); diff --git a/packages/web3-core-method/tests/src/factories/ModuleFactoryTest.js b/packages/web3-core-method/tests/src/factories/ModuleFactoryTest.js index 02c87a64f60..cedb4caed5c 100644 --- a/packages/web3-core-method/tests/src/factories/ModuleFactoryTest.js +++ b/packages/web3-core-method/tests/src/factories/ModuleFactoryTest.js @@ -1,6 +1,4 @@ import TransactionConfirmationWorkflow from '../../../src/workflows/TransactionConfirmationWorkflow'; -import TransactionSigner from '../../../src/signers/TransactionSigner'; -import MessageSigner from '../../../src/signers/MessageSigner'; import TransactionReceiptValidator from '../../../src/validators/TransactionReceiptValidator'; import NewHeadsWatcher from '../../../src/watchers/NewHeadsWatcher'; import SendRawTransactionMethod from '../../../src/methods/transaction/SendRawTransactionMethod'; @@ -22,14 +20,6 @@ describe('ModuleFactoryTest', () => { ); }); - it('calls createTransactionSigner and should return an instance of TransactionSigner', () => { - expect(moduleFactory.createTransactionSigner()).toBeInstanceOf(TransactionSigner); - }); - - it('calls createMessageSigner and should return an instance of MessageSigner', () => { - expect(moduleFactory.createMessageSigner()).toBeInstanceOf(MessageSigner); - }); - it('calls createTransactionReceiptValidator and should return an instance of TransactionReceiptValidator', () => { expect(moduleFactory.createTransactionReceiptValidator()).toBeInstanceOf(TransactionReceiptValidator); }); diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index f9d3f2bc589..0f3bbde2354 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -3,7 +3,6 @@ import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; import SignMethod from '../../../src/methods/SignMethod'; import Accounts from '../../__mocks__/Accounts'; -import MessageSigner from '../../../src/signers/MessageSigner'; import AbstractMethod from '../../../lib/methods/AbstractMethod'; // Mocks @@ -28,10 +27,7 @@ describe('SignMethodTest', () => { accountsMock = new Accounts(); - new MessageSigner(accountsMock); - messageSignerMock = MessageSigner.mock.instances[0]; - - method = new SignMethod({}, formatters, accountsMock, messageSignerMock); + method = new SignMethod({}, formatters, accountsMock); method.callback = jest.fn(); }); @@ -49,8 +45,6 @@ describe('SignMethodTest', () => { expect(method.formatters).toEqual(formatters); expect(method.accounts).toEqual(accountsMock); - - expect(method.messageSigner).toEqual(messageSignerMock); }); it('calls execute with wallets defined', async () => { diff --git a/packages/web3-core-method/tests/src/signers/MessageSignerTest.js b/packages/web3-core-method/tests/src/signers/MessageSignerTest.js deleted file mode 100644 index 7b357a08b93..00000000000 --- a/packages/web3-core-method/tests/src/signers/MessageSignerTest.js +++ /dev/null @@ -1,33 +0,0 @@ -import Accounts from '../../__mocks__/Accounts'; -import MessageSigner from '../../../src/signers/MessageSigner'; - -/** - * MessageSigner test - */ -describe('MessageSignerTest', () => { - let messageSigner, accountsMock; - - beforeEach(() => { - accountsMock = new Accounts(); - accountsMock.sign = jest.fn(); - - messageSigner = new MessageSigner(accountsMock); - }); - - it('calls sign and throws error', () => { - try { - messageSigner.sign('string', 0, accountsMock); - } catch (error) { - expect(error.message).toEqual('Wallet or privateKey in wallet is not set!'); - } - }); - - it('calls sign and returns signed message', () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; - accountsMock.sign.mockReturnValueOnce({signature: '0x00'}); - - expect(messageSigner.sign('string', 0, accountsMock)).toEqual('0x00'); - - expect(accountsMock.sign).toHaveBeenCalledWith('string', '0x0'); - }); -}); diff --git a/packages/web3-core-method/tests/src/signers/TransactionSignerTest.js b/packages/web3-core-method/tests/src/signers/TransactionSignerTest.js deleted file mode 100644 index 39431125f26..00000000000 --- a/packages/web3-core-method/tests/src/signers/TransactionSignerTest.js +++ /dev/null @@ -1,54 +0,0 @@ -import Accounts from '../../__mocks__/Accounts'; -import TransactionSigner from '../../../src/signers/TransactionSigner'; - -/** - * TransactionSigner test - */ -describe('TransactionSignerTest', () => { - let transactionSigner, accountsMock; - - beforeEach(() => { - accountsMock = new Accounts(); - accountsMock.signTransaction = jest.fn(); - - transactionSigner = new TransactionSigner(accountsMock); - }); - - it('calls sign and throws error', () => { - transactionSigner.sign({from: 0}, accountsMock).catch((error) => { - expect(error.message).toEqual('Wallet or privateKey in wallet is not set!'); - }); - }); - - it('calls sign and returns signed transaction', async () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; - const transaction = { - from: 0 - }; - - accountsMock.signTransaction.mockReturnValueOnce(Promise.resolve('0x0')); - - const returnValue = await transactionSigner.sign(transaction, accountsMock); - - expect(returnValue).toEqual('0x0'); - - expect(transaction.from).toEqual(undefined); - - expect(accountsMock.signTransaction).toHaveBeenCalledWith(transaction, '0x0'); - }); - - it('calls sign and signing with accounts throws an error', async () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; - const transaction = { - from: 0 - }; - - accountsMock.signTransaction.mockReturnValueOnce(Promise.reject(new Error())); - - try { - await transactionSigner.sign(transaction, accountsMock); - } catch (error) { - expect(error).toBeInstanceOf(Error); - } - }); -}); From 847497e2383cd741bfa95191a0d2a289d5180e34 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 10:49:58 +0100 Subject: [PATCH 47/71] SignMethod tested and updated --- .../src/methods/SignMethod.js | 25 ++++--- .../tests/src/methods/SignMethodTest.js | 69 +++++++++---------- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 825b67409df..c469f92fa8a 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -45,7 +45,7 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Promise} */ execute(moduleInstance) { - if (moduleInstance.accounts && moduleInstance.accounts.wallet.length > 0) { + if (moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[1]]) { this.beforeExecution(moduleInstance); return this.signOnClient(moduleInstance); @@ -63,13 +63,18 @@ export default class SignMethod extends AbstractCallMethod { * * @returns {Promise} */ - signOnClient(moduleInstance) { - let signedMessage; - + async signOnClient(moduleInstance) { try { - signedMessage = moduleInstance.accounts - .privateKeyToAccount(moduleInstance.accounts.wallet[this.parameters[1]]) - .sign(this.parameters[0]); + let signedMessage = moduleInstance.accounts.sign( + this.parameters[0], + moduleInstance.accounts.wallet[this.parameters[1]].privateKey + ); + + if (this.callback) { + this.callback(false, signedMessage); + } + + return signedMessage; } catch (error) { if (this.callback) { this.callback(error, null); @@ -77,12 +82,6 @@ export default class SignMethod extends AbstractCallMethod { throw error; } - - if (this.callback) { - this.callback(false, signedMessage); - } - - return Promise.resolve(signedMessage); } /** diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index 0f3bbde2354..06e8ec00b95 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -1,62 +1,55 @@ import {formatters} from 'web3-core-helpers'; import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; +import * as Utils from 'web3-utils'; import SignMethod from '../../../src/methods/SignMethod'; import Accounts from '../../__mocks__/Accounts'; import AbstractMethod from '../../../lib/methods/AbstractMethod'; // Mocks +jest.mock('Utils'); +jest.mock('formatters'); jest.mock('WebsocketProvider'); jest.mock('AbstractWeb3Module'); -jest.mock('formatters'); -jest.mock('../../../src/signers/MessageSigner'); /** * SignMethod test */ describe('SignMethodTest', () => { - let method, providerMock, moduleInstanceMock, messageSignerMock, accountsMock; + let method, providerMock, moduleInstanceMock, accountsMock; beforeEach(() => { new WebsocketProvider({}); providerMock = WebsocketProvider.mock.instances[0]; providerMock.send = jest.fn(); + accountsMock = new Accounts(); + accountsMock.sign = jest.fn(); + accountsMock.wallet = {'0x0': {privateKey: '0x0'}}; + new AbstractWeb3Module(providerMock, {}, {}, {}); moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; + moduleInstanceMock.accounts = accountsMock; - accountsMock = new Accounts(); - - method = new SignMethod({}, formatters, accountsMock); + method = new SignMethod(Utils, formatters); method.callback = jest.fn(); + method.parameters = ['nope', '0x0']; }); - it('contructor check', () => { + it('constructor check', () => { expect(method).toBeInstanceOf(AbstractMethod); - expect(SignMethod.Type).toEqual('CALL'); - expect(method.parametersAmount).toEqual(2); expect(method.rpcMethod).toEqual('eth_sign'); - - expect(method.utils).toEqual({}); - - expect(method.formatters).toEqual(formatters); - - expect(method.accounts).toEqual(accountsMock); }); it('calls execute with wallets defined', async () => { - method.parameters = ['nope', '0x00']; - - accountsMock.wallet[0] = {privateKey: '0x0'}; - formatters.inputSignFormatter.mockReturnValueOnce('string'); formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); - messageSignerMock.sign.mockReturnValueOnce('0x00'); + accountsMock.sign.mockReturnValueOnce('0x00'); const response = await method.execute(moduleInstanceMock); @@ -70,16 +63,18 @@ describe('SignMethodTest', () => { expect(formatters.inputSignFormatter).toHaveBeenCalledWith('nope'); - expect(formatters.inputAddressFormatter).toHaveBeenCalledWith('0x00'); + expect(formatters.inputAddressFormatter).toHaveBeenCalledWith('0x0'); + + expect(accountsMock.sign).toHaveBeenCalledWith('string', '0x0'); }); - it('calls execute with wallets defined but MessageSigner throws error', async () => { - method.parameters = ['nope', '0x00']; + it('calls execute with wallets defined but accounts.sign throws an error', async () => { + formatters.inputSignFormatter.mockReturnValueOnce('string'); - accountsMock.wallet[0] = {privateKey: '0x0'}; + formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); const error = new Error('SIGN ERROR'); - messageSignerMock.sign = jest.fn(() => { + accountsMock.sign = jest.fn(() => { throw error; }); @@ -89,18 +84,22 @@ describe('SignMethodTest', () => { expect(error2).toEqual(error); expect(method.callback).toHaveBeenCalledWith(error, null); + + expect(formatters.inputSignFormatter).toHaveBeenCalledWith('nope'); + + expect(formatters.inputAddressFormatter).toHaveBeenCalledWith('0x0'); + + expect(accountsMock.sign).toHaveBeenCalledWith('string', '0x0'); } }); - it('calls execute without wallets defined', async () => { - method.parameters = ['nope', '0x00']; - + it('calls execute and the account does not exist in the eth-accounts wallet', async () => { + moduleInstanceMock.accounts = false; + formatters.inputSignFormatter.mockReturnValueOnce('string'); formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); - messageSignerMock.sign.mockReturnValueOnce('0x00'); - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); moduleInstanceMock.currentProvider = providerMock; @@ -115,9 +114,11 @@ describe('SignMethodTest', () => { expect(method.parameters[1]).toEqual('0x0'); + expect(providerMock.send).toHaveBeenCalledWith('eth_sign', method.parameters); + expect(formatters.inputSignFormatter).toHaveBeenCalledWith('nope'); - expect(formatters.inputAddressFormatter).toHaveBeenCalledWith('0x00'); + expect(formatters.inputAddressFormatter).toHaveBeenCalledWith('0x0'); }); it('beforeExecution should call the inputSignFormatter and inputAddressFormatter', () => { @@ -127,7 +128,7 @@ describe('SignMethodTest', () => { formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); - method.beforeExecution({}); + method.beforeExecution(moduleInstanceMock); expect(method.parameters[0]).toEqual('string'); @@ -139,8 +140,6 @@ describe('SignMethodTest', () => { }); it('afterExecution should just return the response', () => { - const object = {}; - - expect(method.afterExecution(object)).toEqual(object); + expect(method.afterExecution({})).toEqual({}); }); }); From 9e74e0270b55a315fdcc307a578bb6e7d57c40b9 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 10:55:37 +0100 Subject: [PATCH 48/71] Dependency handling fixed in eth-accounts index.js file --- packages/web3-eth-accounts/src/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 880461e5eae..8e11ad3877c 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -22,7 +22,6 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import Wallet from './models/Wallet'; import {Accounts as AccountsModule} from './Accounts'; import {ProvidersModuleFactory} from 'web3-providers'; import {GetGasPriceMethod, GetChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; @@ -40,7 +39,6 @@ export const Accounts = (provider, options) => { return new AccountsModule( provider, new ProvidersModuleFactory(), - new Wallet(Utils), formatters, new GetChainIdMethod(Utils, formatters), new GetGasPriceMethod(Utils, formatters), From 8e34e801b9ad4b533cbb1e79f82dc8941360fc11 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 11:22:02 +0100 Subject: [PATCH 49/71] Readability of the TransactionSigner improved and eslint executed --- .../transaction/SendTransactionMethod.js | 6 +- .../tests/src/methods/SignMethodTest.js | 2 +- .../transaction/SendTransactionMethodTest.js | 27 +- packages/web3-eth-accounts/src/Accounts.js | 2 +- packages/web3-eth-accounts/src/index.js | 2 +- packages/web3-eth/package-lock.json | 333 +++++++++++++++++- packages/web3-eth/package.json | 1 + .../web3-eth/src/signers/TransactionSigner.js | 101 +++--- 8 files changed, 408 insertions(+), 66 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index fd0a9c930c7..82cdb6ad109 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -86,11 +86,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { privateKey = moduleInstance.accounts.wallet[this.parameters[0].from].privateKey; } - this.sendRawTransaction( - privateKey, - promiEvent, - moduleInstance - ).catch((error) => { + this.sendRawTransaction(privateKey, promiEvent, moduleInstance).catch((error) => { if (this.callback) { this.callback(error, null); } diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index 06e8ec00b95..b9f893fa0ed 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -95,7 +95,7 @@ describe('SignMethodTest', () => { it('calls execute and the account does not exist in the eth-accounts wallet', async () => { moduleInstanceMock.accounts = false; - + formatters.inputSignFormatter.mockReturnValueOnce('string'); formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 8da8d670aad..cbc4688d591 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -3,7 +3,6 @@ import {PromiEvent} from 'web3-core-promievent'; import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; import * as Utils from 'web3-utils'; -import Accounts from '../../../__mocks__/Accounts'; import SendRawTransactionMethod from '../../../../src/methods/transaction/SendRawTransactionMethod'; import TransactionSigner from '../../../__mocks__/TransactionSigner'; import TransactionConfirmationWorkflow from '../../../../src/workflows/TransactionConfirmationWorkflow'; @@ -28,7 +27,6 @@ describe('SendTransactionMethodTest', () => { promiEvent, transactionConfirmationWorkflowMock, transactionSignerMock, - accountsMock, sendRawTransactionMethodMock; beforeEach(() => { @@ -39,8 +37,6 @@ describe('SendTransactionMethodTest', () => { new AbstractWeb3Module(providerMock, {}, {}, {}); moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; - accountsMock = new Accounts(); - transactionSignerMock = new TransactionSigner(); transactionSignerMock.sign = jest.fn(); @@ -130,7 +126,6 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); expect(sendRawTransactionMethodMock.callback).toEqual(callback); - }); it('calls execute with wallets defined and returns with a rejected promise', async () => { @@ -399,7 +394,12 @@ describe('SendTransactionMethodTest', () => { expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( + method, + moduleInstanceMock, + '0x0', + promiEvent + ); expect(method.callback).toHaveBeenCalledWith(false, '0x0'); @@ -444,7 +444,12 @@ describe('SendTransactionMethodTest', () => { expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( + method, + moduleInstanceMock, + '0x0', + promiEvent + ); expect(method.callback).toHaveBeenCalledWith(false, '0x0'); @@ -454,7 +459,6 @@ describe('SendTransactionMethodTest', () => { }); method.execute(moduleInstanceMock, promiEvent); - }); it('calls execute and the gasPrice will be defined with "eth_gasPrice" and returns with a resolved promise', (done) => { @@ -492,7 +496,12 @@ describe('SendTransactionMethodTest', () => { expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendTransaction', [transaction]); - expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith(method, moduleInstanceMock, '0x0', promiEvent); + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( + method, + moduleInstanceMock, + '0x0', + promiEvent + ); expect(method.callback).toHaveBeenCalledWith(false, '0x0'); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 3d4473784cf..b137b5d67cf 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -92,7 +92,7 @@ export default class Accounts extends AbstractWeb3Module { case 'clear': return target.clear; default: - if(target.accounts[name]) { + if (target.accounts[name]) { return target.accounts[name]; } diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 8e11ad3877c..218288d0ce2 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -22,7 +22,7 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {Accounts as AccountsModule} from './Accounts'; +import AccountsModule from './Accounts'; import {ProvidersModuleFactory} from 'web3-providers'; import {GetGasPriceMethod, GetChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; diff --git a/packages/web3-eth/package-lock.json b/packages/web3-eth/package-lock.json index 71c145c4cc1..23402cc3c70 100644 --- a/packages/web3-eth/package-lock.json +++ b/packages/web3-eth/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/parsimmon": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@types/parsimmon/-/parsimmon-1.10.0.tgz", + "integrity": "sha512-bsTIJFVQv7jnvNiC42ld2pQW2KRI+pAG243L+iATvqzy3X6+NH1obz2itRKDZZ8VVhN3wjwYax/VBGCcXzgTqQ==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -57,6 +62,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -66,6 +76,16 @@ "concat-map": "0.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=" + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -122,26 +142,92 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "definitelytyped-header-parser": { + "version": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", + "from": "github:Microsoft/definitelytyped-header-parser#production", + "requires": { + "@types/parsimmon": "^1.3.0", + "parsimmon": "^1.2.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" }, + "dom-walk": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz", + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=" + }, "dtslint": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-0.4.2.tgz", "integrity": "sha512-ph4GXLw3HYzlQMJOFcpCqWHuL3MxJ/344OR7wn0wlQGchQGTIVNsSUl8iKEMatpy2geNMysgA9fQa6xVhHOkTQ==", "requires": { + "definitelytyped-header-parser": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", "fs-extra": "^6.0.1", "strip-json-comments": "^2.0.1", "tslint": "^5.12.0", "typescript": "^3.3.0-dev.20190126" - }, - "dependencies": { - "definitelytyped-header-parser": { - "version": "github:Microsoft/definitelytyped-header-parser#e0561530379dfa01324a89936b75d90b20df9bd2", - "from": "github:Microsoft/definitelytyped-header-parser#e0561530379dfa01324a89936b75d90b20df9bd2" - } + } + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, "escape-string-regexp": { @@ -159,6 +245,24 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -174,6 +278,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -187,11 +296,28 @@ "path-is-absolute": "^1.0.0" } }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "requires": { + "min-document": "^2.19.0", + "process": "~0.5.1" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==" }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -205,6 +331,30 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +369,37 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -241,6 +422,29 @@ "graceful-fs": "^4.1.6" } }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -249,6 +453,16 @@ "brace-expansion": "^1.1.7" } }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -257,6 +471,20 @@ "wrappy": "1" } }, + "parse-headers": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.2.tgz", + "integrity": "sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg==", + "requires": { + "for-each": "^0.3.3", + "string.prototype.trim": "^1.1.2" + } + }, + "parsimmon": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.12.0.tgz", + "integrity": "sha512-uC/BjuSfb4jfaWajKCp1mVncXXq+V1twbcYChbTxN3GM7fn+8XoHwUdvUz+PTaFtDSCRQxU8+Rnh+iMhAkVwdw==" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -267,6 +495,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", @@ -285,11 +528,41 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" + }, + "simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -308,6 +581,11 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -350,10 +628,53 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz", + "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==", + "requires": { + "global": "~4.3.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", + "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", + "requires": { + "xhr-request": "^1.0.1" + } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" } } } diff --git a/packages/web3-eth/package.json b/packages/web3-eth/package.json index 8c37d686ee9..be5d5d25096 100644 --- a/packages/web3-eth/package.json +++ b/packages/web3-eth/package.json @@ -16,6 +16,7 @@ }, "types": "types", "dependencies": { + "eth-lib": "0.2.8", "@babel/runtime": "^7.3.1", "web3-core": "1.0.0-beta.46", "web3-core-helpers": "1.0.0-beta.46", diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index a463e488906..78394ec55a9 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -26,53 +26,81 @@ export default class TransactionSigner { /** * Signs the transaction * - * @param {Transaction} transaction + * @param {Object} transaction * @param {String} privateKey * - * @returns {Promise} + * @returns {Promise<{messageHash, v, r, s, rawTransaction}>} */ async sign(transaction, privateKey) { - let result; + const rlpEncoded = this.createRlpEncodedTransaction(transaction); + const hash = Hash.keccak256(rlpEncoded); + const signature = this.createAccountSignature(hash, privateKey); + const rawTransaction = RLP.encode(this.mapRlpEncodedTransaction(rlpEncoded, signature)); + const values = RLP.decode(rawTransaction); + + return { + messageHash: hash, + v: this.trimLeadingZero(values[6]), + r: this.trimLeadingZero(values[7]), + s: this.trimLeadingZero(values[8]), + rawTransaction + }; + } - const rlpEncoded = RLP.encode([ + /** + * RLP encodes the transaction object + * + * @method createRlpEncodedTransaction + * + * @param {Object} transaction + * + * @returns {String} + */ + createRlpEncodedTransaction(transaction) { + return 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'), + Bytes.fromNat(transaction.chainId), '0x', '0x' ]); + } - const hash = Hash.keccak256(rlpEncoded); - - const signature = Account.makeSigner(Nat.toNumber(transaction.chainId || '0x1') * 2 + 35)( - Hash.keccak256(rlpEncoded), - privateKey - ); - - const rawTx = RLP.decode(rlpEncoded) - .slice(0, 6) - .concat(Account.decodeSignature(signature)); - - rawTx[6] = this.makeEven(this.trimLeadingZero(rawTx[6])); - rawTx[7] = this.makeEven(this.trimLeadingZero(rawTx[7])); - rawTx[8] = this.makeEven(this.trimLeadingZero(rawTx[8])); - - const rawTransaction = RLP.encode(rawTx); + /** + * Creates the signature of the current account + * + * @method createAccountSignature + * + * @param {String} hash + * @param {String} privateKey + * + * @returns {String} + */ + createAccountSignature(hash, privateKey) { + return Account.makeSigner( + Nat.toNumber(transaction.chainId) * 2 + 35 + )(hash, privateKey); + } - const values = RLP.decode(rawTransaction); - result = { - messageHash: hash, - v: this.trimLeadingZero(values[6]), - r: this.trimLeadingZero(values[7]), - s: this.trimLeadingZero(values[8]), - rawTransaction - }; + /** + * Combines the decoded transaction with the account decoded account signature and formats the r,v and s. + * + * @param {String} rlpEncoded + * @param {String} signature + * + * @returns {Array} + */ + mapRlpEncodedTransaction(rlpEncoded, signature) { + const rawTransaction = RLP.decode(rlpEncoded).slice(0, 6).concat(Account.decodeSignature(signature)); + rawTransaction[6] = this.makeEven(this.trimLeadingZero(rawTransaction[6])); + rawTransaction[7] = this.makeEven(this.trimLeadingZero(rawTransaction[7])); + rawTransaction[8] = this.makeEven(this.trimLeadingZero(rawTransaction[8])); - return result; + return rawTransaction; } /** @@ -108,17 +136,4 @@ export default class TransactionSigner { return hex; } - - /** - * Checks if the value is not undefined or null - * - * @method isNotUndefinedOrNull - * - * @param {any} value - * - * @returns {Boolean} - */ - isUndefinedOrNull(value) { - return typeof value === 'undefined' && value === null; - } } From 2565a34af1420a3cec1d8c64cd65c93d5d7530a0 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 12:05:58 +0100 Subject: [PATCH 50/71] transaction mapping moved to TransactionSigner and Accounts signTransaction fixed --- .../transaction/SendTransactionMethod.js | 6 ----- packages/web3-eth-accounts/src/Accounts.js | 2 +- packages/web3-eth/src/index.js | 14 +++++++++++- .../web3-eth/src/signers/TransactionSigner.js | 17 ++++++++++++++ .../src/signers/TransactionSignerTest.js | 22 +++++++++---------- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 82cdb6ad109..3d65ed8b815 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -122,12 +122,6 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0].nonce = await moduleInstance.getTransactionCount(this.parameters[0].from); } - let transaction = this.formatters.txInputFormatter(this.parameters[0]); - transaction.to = transaction.to || '0x'; - transaction.data = transaction.data || '0x'; - transaction.value = transaction.value || '0x'; - transaction.chainId = this.utils.numberToHex(transaction.chainId); - const response = await moduleInstance.transactionSigner.sign(transaction, privateKey); this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.callback = this.callback; diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index b137b5d67cf..f5780bcdd69 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -363,7 +363,7 @@ export default class Accounts extends AbstractWeb3Module { } try { - const signedTransaction = await account.signTransaction(tx); + const signedTransaction = await this.transactionSigner.sign(tx, account.privateKey); if (isFunction(callback)) { callback(false, signedTransaction); diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index f4c8d57068d..62c1c0f4e48 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -33,8 +33,18 @@ import {ProvidersModuleFactory} from 'web3-providers'; import {Network} from 'web3-net'; import * as Utils from 'web3-utils'; import EthModuleFactory from './factories/EthModuleFactory'; +import EthTransactionSigner from './signers/TransactionSigner'; -export TransactionSigner from './signers/TransactionSigner'; +/** + * Creates the TransactionSigner class + * + * @returns {TransactionSigner} + * + * @constructor + */ +export const TransactionSigner = () => { + return new EthTransactionSigner(Utils, formatters); +}; /** * Creates the Eth object @@ -45,6 +55,8 @@ export TransactionSigner from './signers/TransactionSigner'; * @param {Object} options * * @returns {Eth} + * + * @constructor */ export const Eth = (provider, options) => { const accounts = new Accounts(provider, options); diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 78394ec55a9..50310bcf714 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -23,6 +23,17 @@ import RLP from 'eth-lib/lib/rlp'; import Account from 'eth-lib/lib/account'; export default class TransactionSigner { + /** + * @param {Utils} utils // TODO: Remove utils dependency and use a Hex VO + * @param {Object} formatters // TODO: Remove formatters dependency and use a Transaction VO + * + * @constructor + */ + constructor(utils, formatters) { + this.utils = utils; + this.formatters = formatters; + } + /** * Signs the transaction * @@ -32,6 +43,12 @@ export default class TransactionSigner { * @returns {Promise<{messageHash, v, r, s, rawTransaction}>} */ async sign(transaction, privateKey) { + transaction = this.formatters.inputCallFormatter(transaction); + transaction.to = transaction.to || '0x'; + transaction.data = transaction.data || '0x'; + transaction.value = transaction.value || '0x'; + transaction.chainId = this.utils.numberToHex(transaction.chainId); + const rlpEncoded = this.createRlpEncodedTransaction(transaction); const hash = Hash.keccak256(rlpEncoded); const signature = this.createAccountSignature(hash, privateKey); diff --git a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js index e0bd3330469..8c6516e3a9a 100644 --- a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -1,22 +1,24 @@ -// Mocks -import Account from 'web3-eth-accounts/src/models/Account'; import {formatters} from 'web3-core-helpers'; +import TransactionSigner from '../../../src/signers/TransactionSigner'; -jest.mock(''); +// Mocks +jest.mock('formatters'); /** - * TransactionSignerTest test + * TransactionSigner test */ -describe('TransactionSignerTestTest', () => { - let TransactionSignerTest; +describe('TransactionSignerTest', () => { + let transactionSigner; beforeEach(() => { - TransactionSignerTest = new TransactionSignerTest(); + transactionSigner = new TransactionSigner(formatters); }); - it('constructor check', () => {}); + it('constructor check', () => { + expect(transactionSigner.formatters).toEqual(formatters); + }); - it('calls signTransaction and returns a resolved promise', async () => { + it('calls sign and returns the expected resolved promise', async () => { const callback = jest.fn(); const tx = { @@ -39,8 +41,6 @@ describe('TransactionSignerTestTest', () => { formatters.inputCallFormatter.mockReturnValueOnce(tx); - Utils.numberToHex.mockReturnValueOnce(1); - RLP.encode.mockReturnValue('encoded'); Bytes.fromNat.mockReturnValue(1); From 949b694376a7f17ce62aab12df635a0fd658f8cf Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 12:37:40 +0100 Subject: [PATCH 51/71] TransactionSigner and TransactionSignerTest updated --- .../transaction/SendTransactionMethod.js | 2 +- .../web3-eth/src/signers/TransactionSigner.js | 15 +- .../src/signers/TransactionSignerTest.js | 244 +----------------- 3 files changed, 23 insertions(+), 238 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 3d65ed8b815..44e6436e002 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -122,7 +122,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0].nonce = await moduleInstance.getTransactionCount(this.parameters[0].from); } - const response = await moduleInstance.transactionSigner.sign(transaction, privateKey); + const response = await moduleInstance.transactionSigner.sign(this.parameters[0], privateKey); this.sendRawTransactionMethod.parameters = [response.rawTransaction]; this.sendRawTransactionMethod.callback = this.callback; this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 50310bcf714..1a9ece22506 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -43,7 +43,7 @@ export default class TransactionSigner { * @returns {Promise<{messageHash, v, r, s, rawTransaction}>} */ async sign(transaction, privateKey) { - transaction = this.formatters.inputCallFormatter(transaction); + transaction = this.formatters.txInputFormatter(transaction); transaction.to = transaction.to || '0x'; transaction.data = transaction.data || '0x'; transaction.value = transaction.value || '0x'; @@ -51,7 +51,7 @@ export default class TransactionSigner { const rlpEncoded = this.createRlpEncodedTransaction(transaction); const hash = Hash.keccak256(rlpEncoded); - const signature = this.createAccountSignature(hash, privateKey); + const signature = this.createAccountSignature(hash, privateKey, transaction.chainId); const rawTransaction = RLP.encode(this.mapRlpEncodedTransaction(rlpEncoded, signature)); const values = RLP.decode(rawTransaction); @@ -94,13 +94,12 @@ export default class TransactionSigner { * * @param {String} hash * @param {String} privateKey + * @param {String} chainId * * @returns {String} */ - createAccountSignature(hash, privateKey) { - return Account.makeSigner( - Nat.toNumber(transaction.chainId) * 2 + 35 - )(hash, privateKey); + createAccountSignature(hash, privateKey, chainId) { + return Account.makeSigner(Nat.toNumber(chainId) * 2 + 35)(hash, privateKey); } /** @@ -112,7 +111,9 @@ export default class TransactionSigner { * @returns {Array} */ mapRlpEncodedTransaction(rlpEncoded, signature) { - const rawTransaction = RLP.decode(rlpEncoded).slice(0, 6).concat(Account.decodeSignature(signature)); + const rawTransaction = RLP.decode(rlpEncoded) + .slice(0, 6) + .concat(Account.decodeSignature(signature)); rawTransaction[6] = this.makeEven(this.trimLeadingZero(rawTransaction[6])); rawTransaction[7] = this.makeEven(this.trimLeadingZero(rawTransaction[7])); rawTransaction[8] = this.makeEven(this.trimLeadingZero(rawTransaction[8])); diff --git a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js index 8c6516e3a9a..0ce7b10be90 100644 --- a/packages/web3-eth/tests/src/signers/TransactionSignerTest.js +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -1,7 +1,14 @@ +import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; +import Nat from 'eth-lib/lib/nat'; +import Bytes from 'eth-lib/lib/bytes'; +import Hash from 'eth-lib/lib/hash'; +import RLP from 'eth-lib/lib/rlp'; +import Account from 'eth-lib/lib/account'; import TransactionSigner from '../../../src/signers/TransactionSigner'; // Mocks +jest.mock('Utils'); jest.mock('formatters'); /** @@ -11,16 +18,16 @@ describe('TransactionSignerTest', () => { let transactionSigner; beforeEach(() => { - transactionSigner = new TransactionSigner(formatters); + transactionSigner = new TransactionSigner(Utils, formatters); }); it('constructor check', () => { expect(transactionSigner.formatters).toEqual(formatters); + + expect(transactionSigner.utils).toEqual(Utils); }); it('calls sign and returns the expected resolved promise', async () => { - const callback = jest.fn(); - const tx = { gas: 1, nonce: 2, @@ -39,109 +46,7 @@ describe('TransactionSignerTest', () => { Nat.toNumber = jest.fn(); Bytes.fromNat = jest.fn(); - formatters.inputCallFormatter.mockReturnValueOnce(tx); - - RLP.encode.mockReturnValue('encoded'); - - Bytes.fromNat.mockReturnValue(1); - - Hash.keccak256.mockReturnValue('hash'); - - const signer = jest.fn(); - - Account.makeSigner.mockReturnValueOnce(signer); - - signer.mockReturnValueOnce('signature'); - - Nat.toNumber.mockReturnValueOnce(1); - - Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); - - RLP.decode - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); - - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(callback).toHaveBeenCalledWith(null, { - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); - - expect(Utils.numberToHex).toHaveBeenCalledWith(4); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(1, 2); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(2, 3); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(3, 1); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(4, 5); - - expect(Bytes.fromNat).toHaveBeenNthCalledWith(5, 1); - - expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); - - expect(RLP.encode).toHaveBeenNthCalledWith(2, [ - 'zero', - 'one', - 'two', - 'three', - 'four', - 'five', - 'seven', - 'eight', - 'nine' - ]); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); - - expect(Nat.toNumber).toHaveBeenCalledWith(1); - - expect(Account.makeSigner).toHaveBeenCalledWith(37); - - expect(signer).toHaveBeenCalledWith('hash', 'pk'); - - expect(RLP.decode).toHaveBeenCalledWith('encoded'); - - expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); - }); - - it('calls signTransaction without chainId, gasPrice, nonce and returns a resolved promise', async () => { - const callback = jest.fn(); - - const tx = { - gas: 1, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - RLP.encode = jest.fn(); - RLP.decode = jest.fn(); - Hash.keccak256 = jest.fn(); - Account.makeSigner = jest.fn(); - Account.decodeSignature = jest.fn(); - Nat.toNumber = jest.fn(); - Bytes.fromNat = jest.fn(); - accounts.getId = jest.fn(); - accounts.getGasPrice = jest.fn(); - accounts.getTransactionCount = jest.fn(); - - formatters.inputCallFormatter.mockReturnValueOnce(tx); + formatters.txInputFormatter.mockReturnValueOnce(tx); Utils.numberToHex.mockReturnValueOnce(1); @@ -165,27 +70,7 @@ describe('TransactionSignerTest', () => { .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); - accounts.getId.mockReturnValueOnce(Promise.resolve(4)); - - accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(3)); - - accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(2)); - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return {address: '0x0'}; - }); - - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); - - expect(callback).toHaveBeenCalledWith(null, { + await expect(transactionSigner.sign(tx, 'pk')).resolves.toEqual({ messageHash: 'hash', v: 'six', r: 'seven', @@ -193,7 +78,7 @@ describe('TransactionSignerTest', () => { rawTransaction: 'encoded' }); - expect(formatters.inputCallFormatter).toHaveBeenCalledWith(tx, accounts); + expect(formatters.txInputFormatter).toHaveBeenCalledWith(tx); expect(Utils.numberToHex).toHaveBeenCalledWith(4); @@ -221,9 +106,7 @@ describe('TransactionSignerTest', () => { 'nine' ]); - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); - - expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); + expect(Hash.keccak256).toHaveBeenCalledWith('encoded'); expect(Nat.toNumber).toHaveBeenCalledWith(1); @@ -234,104 +117,5 @@ describe('TransactionSignerTest', () => { expect(RLP.decode).toHaveBeenCalledWith('encoded'); expect(Account.decodeSignature).toHaveBeenCalledWith('signature'); - - expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); - - expect(accounts.getId).toHaveBeenCalled(); - - expect(accounts.getGasPrice).toHaveBeenCalled(); - }); - - it('calls singTransaction and returns a rejected promise because it could not fetch the missing properties', async () => { - accounts.getId = jest.fn(); - accounts.getGasPrice = jest.fn(); - accounts.getTransactionCount = jest.fn(); - - accounts.getId.mockReturnValueOnce(Promise.resolve(null)); - - accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(null)); - - accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(null)); - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return {address: '0x0'}; - }); - - await expect(accounts.signTransaction({}, 'pk', () => {})).rejects.toThrow( - `One of the values 'chainId', 'gasPrice', or 'nonce' couldn't be fetched: ${JSON.stringify([ - null, - null, - null - ])}` - ); - - expect(accounts.getTransactionCount).toHaveBeenCalledWith('0x0'); - - expect(accounts.getId).toHaveBeenCalled(); - - expect(accounts.getGasPrice).toHaveBeenCalled(); - }); - - it('calls singTransaction and returns a rejected promise because of invalid values in the TX', async () => { - const tx = { - gas: -1, - nonce: -2, - gasPrice: -3, - chainId: -4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow( - 'Gas, gasPrice, nonce or chainId is lower than 0' - ); - }); - - it('calls singTransaction and returns a rejected promise because the gas limit property is missing', async () => { - const tx = { - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow('gas is missing'); - }); - - it('calls singTransaction and returns a rejected promise because of the inputCallFormatter', async () => { - const tx = { - gas: 1, - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' - }; - - const callback = jest.fn(); - - formatters.inputCallFormatter = jest.fn(() => { - throw new Error('ERROR'); - }); - - await expect(accounts.signTransaction(tx, 'pk', callback)).rejects.toThrow('ERROR'); - - expect(callback).toHaveBeenCalledWith(new Error('ERROR')); - }); - - it('calls singTransaction and returns a rejected promise because of the missing TX parameter', async () => { - const callback = jest.fn(); - - await expect(accounts.signTransaction(undefined, 'pk', callback)).rejects.toThrow( - 'No transaction object given!' - ); - - expect(callback).toHaveBeenCalledWith(new Error('No transaction object given!')); }); }); From dc6818b8811e53366f811c4352d0a4e696fa10c9 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 12:46:50 +0100 Subject: [PATCH 52/71] factory pattern updated in eth module instead of updating the factory test --- .../src/factories/EthModuleFactory.js | 103 ------------------ packages/web3-eth/src/index.js | 20 +++- packages/web3-eth/tests/src/EthTest.js | 9 +- .../src/factories/EthModuleFactoryTest.js | 90 --------------- 4 files changed, 25 insertions(+), 197 deletions(-) delete mode 100644 packages/web3-eth/src/factories/EthModuleFactory.js delete mode 100644 packages/web3-eth/tests/src/factories/EthModuleFactoryTest.js diff --git a/packages/web3-eth/src/factories/EthModuleFactory.js b/packages/web3-eth/src/factories/EthModuleFactory.js deleted file mode 100644 index d7334cdad28..00000000000 --- a/packages/web3-eth/src/factories/EthModuleFactory.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file EthModuleFactory.js - * @author Samuel Furter - * @date 2018 - */ - -import MethodFactory from './MethodFactory'; -import Eth from '../Eth'; -import TransactionSigner from '../signers/TransactionSigner'; - -export default class EthModuleFactory { - /** - * @param {Utils} utils - * @param {Object} formatters - * - * @constructor - */ - constructor(utils, formatters) { - this.utils = utils; - this.formatters = formatters; - } - - /** - * Returns an object of type Eth - * - * @method createEthModule - * - * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @param {ProvidersModuleFactory} providersModuleFactory - * @param {MethodModuleFactory} methodModuleFactory - * @param {Network} net - * @param {Accounts} accounts - * @param {Personal} personal - * @param {Iban} iban - * @param {AbiCoder} abiCoder - * @param {Ens} ens - * @param {SubscriptionsFactory} subscriptionsFactory - * @param {ContractModuleFactory} contractModuleFactory - * @param {Object} options - * - * @returns {Eth} - */ - createEthModule( - provider, - providersModuleFactory, - methodModuleFactory, - net, - accounts, - personal, - iban, - abiCoder, - ens, - subscriptionsFactory, - contractModuleFactory, - options - ) { - return new Eth( - provider, - providersModuleFactory, - methodModuleFactory, - this.createMethodFactory(methodModuleFactory), - net, - accounts, - personal, - iban, - abiCoder, - ens, - this.utils, - this.formatters, - subscriptionsFactory, - contractModuleFactory, - new TransactionSigner(), - options - ); - } - - /** - * Returns an object of type MethodFactory - * - * @method createMethodFactory - * - * @returns {MethodFactory} - */ - createMethodFactory(methodModuleFactory) { - return new MethodFactory(methodModuleFactory, this.utils, this.formatters); - } -} diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 62c1c0f4e48..4c7f8fc5cc8 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -32,8 +32,9 @@ import {Iban} from 'web3-eth-iban'; import {ProvidersModuleFactory} from 'web3-providers'; import {Network} from 'web3-net'; import * as Utils from 'web3-utils'; -import EthModuleFactory from './factories/EthModuleFactory'; import EthTransactionSigner from './signers/TransactionSigner'; +import EthModule from 'Eth'; +import EthMethodFactory from './factories/MethodFactory'; /** * Creates the TransactionSigner class @@ -46,6 +47,17 @@ export const TransactionSigner = () => { return new EthTransactionSigner(Utils, formatters); }; +/** + * Creates the MethodFactory class of the eth module + * + * @returns {MethodFactory} + * + * @constructor + */ +export const MethodFactory = () => { + return new EthMethodFactory(new MethodModuleFactory(), Utils, formatters); +}; + /** * Creates the Eth object * @@ -63,18 +75,22 @@ export const Eth = (provider, options) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); - return new EthModuleFactory(Utils, formatters).createEthModule( + new EthModule( provider, new ProvidersModuleFactory(), methodModuleFactory, + new MethodFactory(), new Network(provider, options), accounts, new Personal(provider, accounts, options), Iban, abiCoder, new Ens(provider, accounts, options), + this.utils, + this.formatters, new SubscriptionsFactory(), new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), + new TransactionSigner(), options ); }; diff --git a/packages/web3-eth/tests/src/EthTest.js b/packages/web3-eth/tests/src/EthTest.js index 1c754025f04..45448c76135 100644 --- a/packages/web3-eth/tests/src/EthTest.js +++ b/packages/web3-eth/tests/src/EthTest.js @@ -43,6 +43,7 @@ import {Network} from 'web3-net'; import {AbstractContract, ContractModuleFactory} from 'web3-eth-contract'; import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; import MethodFactory from '../../src/factories/MethodFactory'; +import TransactionSigner from '../../src/signers/TransactionSigner'; import Eth from '../../src/Eth'; // Mocks @@ -64,7 +65,6 @@ jest.mock('Utils'); jest.mock('formatters'); jest.mock('AbstractContract'); jest.mock('ContractModuleFactory'); -jest.mock('../../src/factories/EthModuleFactory'); /** * Eth test @@ -83,7 +83,8 @@ describe('EthTest', () => { personalMock, abiCoderMock, ensMock, - subscriptionsFactoryMock; + subscriptionsFactoryMock, + transactionSignerMock; beforeEach(() => { new HttpProvider(); @@ -135,6 +136,9 @@ describe('EthTest', () => { new SubscriptionsFactory(); subscriptionsFactoryMock = SubscriptionsFactory.mock.instances[0]; + new TransactionSigner(); + transactionSignerMock = TransactionSigner.mock.instances[0]; + eth = new Eth( providerMock, providersModuleFactoryMock, @@ -150,6 +154,7 @@ describe('EthTest', () => { formatters, subscriptionsFactoryMock, contractModuleFactoryMock, + transactionSignerMock, {} ); }); diff --git a/packages/web3-eth/tests/src/factories/EthModuleFactoryTest.js b/packages/web3-eth/tests/src/factories/EthModuleFactoryTest.js deleted file mode 100644 index 0bb00f9ecd7..00000000000 --- a/packages/web3-eth/tests/src/factories/EthModuleFactoryTest.js +++ /dev/null @@ -1,90 +0,0 @@ -import * as Utils from 'web3-utils'; -import {formatters} from 'web3-core-helpers'; -import {MethodModuleFactory} from 'web3-core-method'; -import {PromiEvent} from 'web3-core-promievent'; -import {Accounts} from 'web3-eth-accounts'; -import {AbiCoder} from 'web3-eth-abi'; -import {ContractModuleFactory} from 'web3-eth-contract'; -import {HttpProvider, ProvidersModuleFactory} from 'web3-providers'; -import Eth from '../../../src/Eth'; -import EthModuleFactory from '../../../src/factories/EthModuleFactory'; - -// Mocks -jest.mock('HttpProvider'); -jest.mock('ProvidersModuleFactory'); -jest.mock('MethodModuleFactory'); -jest.mock('Accounts'); -jest.mock('ContractModuleFactory'); -jest.mock('AbiCoder'); -jest.mock('Utils'); -jest.mock('formatters'); -jest.mock('../../../src/Eth'); - -/** - * EthModuleFactory test - */ -describe('EthModuleFactoryTest', () => { - let ethModuleFactory, - providerMock, - providersModuleFactoryMock, - methodModuleFactoryMock, - accountsMock, - contractModuleFactoryMock, - abiCoderMock; - - beforeEach(() => { - new HttpProvider(); - providerMock = HttpProvider.mock.instances[0]; - - new ProvidersModuleFactory(); - providersModuleFactoryMock = ProvidersModuleFactory.mock.instances[0]; - - new MethodModuleFactory(); - methodModuleFactoryMock = MethodModuleFactory.mock.instances[0]; - - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - - new ContractModuleFactory(); - contractModuleFactoryMock = ContractModuleFactory.mock.instances[0]; - - new AbiCoder(); - abiCoderMock = AbiCoder.mock.instances[0]; - - ethModuleFactory = new EthModuleFactory( - providerMock, - providersModuleFactoryMock, - methodModuleFactoryMock, - accountsMock, - PromiEvent, - Utils, - formatters, - contractModuleFactoryMock, - abiCoderMock - ); - }); - - it('constructor check', () => { - expect(ethModuleFactory.provider).toEqual(providerMock); - - expect(ethModuleFactory.providersModuleFactory).toEqual(providersModuleFactoryMock); - - expect(ethModuleFactory.methodModuleFactory).toEqual(methodModuleFactoryMock); - - expect(ethModuleFactory.accounts).toEqual(accountsMock); - - expect(ethModuleFactory.PromiEvent).toEqual(PromiEvent); - - expect(ethModuleFactory.utils).toEqual(Utils); - - expect(ethModuleFactory.formatters).toEqual(formatters); - - expect(ethModuleFactory.contractModuleFactory).toEqual(contractModuleFactoryMock); - - expect(ethModuleFactory.abiCoder).toEqual(abiCoderMock); - }); - - it('calls createEthModule and returns a Contract object', () => { - expect(ethModuleFactory.createEthModule({}, '', {})).toBeInstanceOf(Eth); - }); -}); From de24e56d0226b91aabec8710f12dd4ad047d4016 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 12:52:21 +0100 Subject: [PATCH 53/71] EthTest updated --- packages/web3-eth/tests/src/EthTest.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/web3-eth/tests/src/EthTest.js b/packages/web3-eth/tests/src/EthTest.js index 45448c76135..2945525dfae 100644 --- a/packages/web3-eth/tests/src/EthTest.js +++ b/packages/web3-eth/tests/src/EthTest.js @@ -32,7 +32,9 @@ import { SendTransactionMethod, SignMethod, SignTransactionMethod, - SubmitWorkMethod + SubmitWorkMethod, + ChainIdMethod, + VersionMethod } from 'web3-core-method'; import {AbiCoder} from 'web3-eth-abi'; import {Accounts} from 'web3-eth-accounts'; @@ -65,6 +67,7 @@ jest.mock('Utils'); jest.mock('formatters'); jest.mock('AbstractContract'); jest.mock('ContractModuleFactory'); +jest.mock('../../src/signers/TransactionSigner'); /** * Eth test @@ -214,7 +217,9 @@ describe('EthTest', () => { submitWork: SubmitWorkMethod, getWork: GetWorkMethod, getPastLogs: GetPastLogsMethod, - requestAccounts: RequestAccountsMethod + requestAccounts: RequestAccountsMethod, + getChainId: ChainIdMethod, + getId: VersionMethod }); }); @@ -432,14 +437,11 @@ describe('EthTest', () => { networkMock.setProvider = jest.fn(); personalMock.setProvider = jest.fn(); - accountsMock.setProvider = jest.fn(); networkMock.setProvider.mockReturnValueOnce(true); personalMock.setProvider.mockReturnValueOnce(true); - accountsMock.setProvider.mockReturnValueOnce(true); - expect(eth.setProvider('provider', 'net')).toEqual(true); expect(eth.initiatedContracts[0].setProvider).toHaveBeenCalledWith('provider', 'net'); @@ -447,7 +449,5 @@ describe('EthTest', () => { expect(networkMock.setProvider).toHaveBeenCalledWith('provider', 'net'); expect(personalMock.setProvider).toHaveBeenCalledWith('provider', 'net'); - - expect(accountsMock.setProvider).toHaveBeenCalledWith('provider', 'net'); }); }); From f89f6ac6e578f7043a2d147f875d16e6e79d9d4b Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 14:46:10 +0100 Subject: [PATCH 54/71] core-method, core and eth-accounts module tests updated --- .../transaction/SendTransactionMethodTest.js | 77 +----- .../tests/src/AbstractWeb3ModuleTest.js | 10 - packages/web3-eth-accounts/src/Accounts.js | 33 +-- .../tests/src/AccountsTest.js | 241 ++++++++++++++++-- 4 files changed, 253 insertions(+), 108 deletions(-) diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index cbc4688d591..3d1a8b4d450 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -95,16 +95,9 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0', - data: '0x', - to: '0x', - value: '0x' + chainId: 1 }; - formatters.txInputFormatter.mockReturnValueOnce(transaction); - - Utils.numberToHex.mockReturnValueOnce('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); const callback = jest.fn(); @@ -117,10 +110,6 @@ describe('SendTransactionMethodTest', () => { expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(Utils.numberToHex).toHaveBeenCalledWith(1); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); @@ -129,24 +118,23 @@ describe('SendTransactionMethodTest', () => { }); it('calls execute with wallets defined and returns with a rejected promise', async () => { + const error = new Error('ERROR'); + moduleInstanceMock.currentProvider = providerMock; moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = transactionSignerMock; + moduleInstanceMock.getChainId = jest.fn(() => { + throw error; + }); const transaction = { from: 0, gas: 1, gasPrice: 1, nonce: 1, - chainId: 1 + chainId: 0 }; - const error = new Error('ERROR'); - - formatters.txInputFormatter = jest.fn(() => { - throw error; - }); - method.callback = jest.fn(); method.parameters = [transaction]; @@ -159,9 +147,7 @@ describe('SendTransactionMethodTest', () => { await expect(method.execute(moduleInstanceMock, promiEvent)).rejects.toThrow('ERROR'); - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(method.callback).toHaveBeenCalledWith(error, null); + expect(moduleInstanceMock.getChainId).toHaveBeenCalledWith(); }); it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { @@ -187,10 +173,6 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - formatters.txInputFormatter.mockReturnValueOnce(transaction); - - Utils.numberToHex.mockReturnValueOnce('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); const callback = jest.fn(); @@ -206,18 +188,11 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0', - data: '0x', - to: '0x', - value: '0x' + chainId: 1 }; expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(Utils.numberToHex).toHaveBeenCalledWith(1); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); @@ -251,10 +226,6 @@ describe('SendTransactionMethodTest', () => { chainId: 0 }; - formatters.txInputFormatter.mockReturnValueOnce(transaction); - - Utils.numberToHex.mockReturnValueOnce('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); const callback = jest.fn(); @@ -270,18 +241,11 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0', - data: '0x', - to: '0x', - value: '0x' + chainId: 1 }; expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(Utils.numberToHex).toHaveBeenCalledWith(1); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); @@ -313,18 +277,6 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - const transactionWithNonce = { - from: 0, - gas: 1, - gasPrice: 1, - nonce: 1, - chainId: 1 - }; - - formatters.txInputFormatter.mockReturnValueOnce(transactionWithNonce); - - Utils.numberToHex.mockReturnValueOnce('0x0'); - sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); const callback = jest.fn(); @@ -340,18 +292,11 @@ describe('SendTransactionMethodTest', () => { gas: 1, gasPrice: 1, nonce: 1, - chainId: '0x0', - data: '0x', - to: '0x', - value: '0x' + chainId: 1 }; expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); - expect(formatters.txInputFormatter).toHaveBeenCalledWith(transaction); - - expect(Utils.numberToHex).toHaveBeenCalledWith(1); - expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); expect(sendRawTransactionMethodMock.callback).toEqual(callback); diff --git a/packages/web3-core/tests/src/AbstractWeb3ModuleTest.js b/packages/web3-core/tests/src/AbstractWeb3ModuleTest.js index 9da975c8e56..f8435c528bd 100644 --- a/packages/web3-core/tests/src/AbstractWeb3ModuleTest.js +++ b/packages/web3-core/tests/src/AbstractWeb3ModuleTest.js @@ -84,16 +84,6 @@ describe('AbstractWeb3ModuleTest', () => { ); }); - it('constructor throws error on missing required parameters', () => { - expect(() => { - new AbstractWeb3Module(); - }).toThrow('Missing parameter: provider'); - - expect(() => { - new AbstractWeb3Module(''); - }).toThrow('Missing parameter: ProvidersModuleFactory'); - }); - it('constructor defines all properties', () => { expect(abstractWeb3Module.defaultAccount).toEqual('0x03C9A938fF7f54090d0d99e2c6f80380510Ea078'); diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index f5780bcdd69..d75222b3f49 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -28,7 +28,7 @@ import Hash from 'eth-lib/lib/hash'; import RLP from 'eth-lib/lib/rlp'; import Bytes from 'eth-lib/lib/bytes'; import {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove this dependency -import {isHexStrict, hexToBytes, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. +import {hexToBytes, isHexStrict, randomHex} from 'web3-utils'; // TODO: Use the VO's of a web3-types module. import {AbstractWeb3Module} from 'web3-core'; import Account from './models/Account'; @@ -159,16 +159,19 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Boolean} */ remove(addressOrIndex) { + let removed; + if (this.accounts[addressOrIndex]) { Object.keys(this.accounts).forEach((key) => { if (this.accounts[key].address === addressOrIndex || key === addressOrIndex) { delete this.accounts[key]; this.accountsIndex--; + removed = true; } }); - return true; + return !!removed; } return false; @@ -223,7 +226,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.fromV3Keystore(keystore, password, false, this); if (!account) { - throw new Error("Couldn't decrypt accounts. Password wrong?"); + throw new Error('Couldn\'t decrypt accounts. Password wrong?'); } this.add(account); @@ -346,23 +349,23 @@ export default class Accounts extends AbstractWeb3Module { * @returns {Promise} */ async signTransaction(tx, privateKey, callback) { - const account = Account.fromPrivateKey(privateKey, this); + try { + const account = Account.fromPrivateKey(privateKey, this); - if (!tx.chainId) { - tx.chainId = await this.chainIdMethod.execute(this); - } + if (!tx.chainId) { + tx.chainId = await this.chainIdMethod.execute(this); + } - if (!tx.getGasPrice) { - tx.getGasPrice = await this.getGasPriceMethod.execute(this); - } + if (!tx.gasPrice) { + tx.gasPrice = await this.getGasPriceMethod.execute(this); + } - if (!tx.nonce) { - this.getTransactionCountMethod.parameters = [account.address]; + if (!tx.nonce) { + this.getTransactionCountMethod.parameters = [account.address]; - tx.nonce = await this.getTransactionCountMethod.execute(this); - } + tx.nonce = await this.getTransactionCountMethod.execute(this); + } - try { const signedTransaction = await this.transactionSigner.sign(tx, account.privateKey); if (isFunction(callback)) { diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index 29bb391bb8e..0a3d5f60265 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,4 +1,4 @@ -import {isHexStrict, randomHex} from 'web3-utils'; +import {isHexStrict, randomHex, hexToBytes} from 'web3-utils'; import {formatters} from 'web3-core-helpers'; import {ChainIdMethod, GetGasPriceMethod, GetTransactionCountMethod} from 'web3-core-method'; import Hash from 'eth-lib/lib/hash'; @@ -44,6 +44,7 @@ describe('AccountsTest', () => { chainIdMethodMock, getGasPriceMethodMock, getTransactionCountMethodMock, + transactionSignerMock, options; beforeEach(() => { @@ -78,7 +79,9 @@ describe('AccountsTest', () => { new GetTransactionCountMethod(); getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; - options = {transactionSigner: new TransactionSigner()}; + transactionSignerMock = new TransactionSigner(); + + options = {transactionSigner: transactionSignerMock}; accounts = new Accounts( providerMock, @@ -124,36 +127,180 @@ describe('AccountsTest', () => { it('calls signTransaction and resolves with a promise', async () => { const callback = jest.fn(); - const signTransaction = jest.fn(); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); + + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); - signTransaction.mockReturnValueOnce(Promise.resolve('signed-transaction')); + const response = await accounts.signTransaction(transaction, 'pk', callback); - Account.fromPrivateKey.mockReturnValueOnce({signTransaction: signTransaction}); + expect(response).toEqual('signed-transaction'); - await expect(accounts.signTransaction({}, 'pk', callback)).resolves.toEqual('signed-transaction'); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(transaction, account.privateKey); + }); + + it('calls signTransaction without the chainId property and resolves with a promise', async () => { + const callback = jest.fn(); + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 0 + }; + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); + + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); + + chainIdMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); + }); + + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(signTransaction).toHaveBeenCalledWith({}); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); + + expect(chainIdMethodMock.execute).toHaveBeenCalledWith(accounts); }); - it('calls signTransaction and rejects with a promise', async () => { - const signTransaction = jest.fn(); - signTransaction.mockReturnValueOnce(Promise.reject(new Error('ERROR'))); + it('calls signTransaction without the gasPrice property and resolves with a promise', async () => { + const callback = jest.fn(); + + const transaction = { + from: 0, + gas: 1, + gasPrice: 0, + nonce: 1, + chainId: 1 + }; + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); + + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); + + getGasPriceMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); + }); + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); + + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); + + + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); + + expect(getGasPriceMethodMock.execute).toHaveBeenCalledWith(accounts); + }); + + it('calls signTransaction without the nonce property and resolves with a promise', async () => { const callback = jest.fn(); - Account.fromPrivateKey.mockReturnValueOnce({signTransaction: signTransaction}); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 0, + chainId: 1 + }; + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); + + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); + + getTransactionCountMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); + }); + + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); + + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); + + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); + + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); + + expect(getTransactionCountMethodMock.execute).toHaveBeenCalledWith(accounts); + }); + + it('calls signTransaction and rejects with a promise', async () => { + const callback = jest.fn(), + transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; + + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); + + transactionSignerMock.sign = jest.fn(() => { + return Promise.reject(new Error('ERROR')); + }); - await expect(accounts.signTransaction({}, 'pk', callback)).rejects.toEqual(new Error('ERROR')); + await expect(accounts.signTransaction(transaction, 'pk', callback)).rejects.toThrow('ERROR'); expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); expect(callback).toHaveBeenCalledWith(new Error('ERROR'), null); - expect(signTransaction).toHaveBeenCalledWith({}); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(transaction, 'pk'); }); it('calls recoverTransaction and returns the expected string', () => { @@ -188,9 +335,33 @@ describe('AccountsTest', () => { expect(RLP.decode).toHaveBeenCalledWith('rawTransaction'); }); - it('calls sign and returns the expected value', () => { + it('calls sign with strict hex string and returns the expected value', () => { const sign = jest.fn(); + isHexStrict.mockReturnValueOnce(true); + + hexToBytes.mockReturnValueOnce('data'); + + sign.mockReturnValueOnce(true); + + Account.fromPrivateKey.mockReturnValueOnce({sign: sign}); + + expect(accounts.sign('data', 'pk')).toEqual(true); + + expect(sign).toHaveBeenCalledWith('data'); + + expect(isHexStrict).toHaveBeenCalledWith('data'); + + expect(hexToBytes).toHaveBeenCalledWith('data'); + + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); + }); + + it('calls sign with non-strict hex string and returns the expected value', () => { + const sign = jest.fn(); + + isHexStrict.mockReturnValueOnce(false); + sign.mockReturnValueOnce(true); Account.fromPrivateKey.mockReturnValueOnce({sign: sign}); @@ -199,6 +370,8 @@ describe('AccountsTest', () => { expect(sign).toHaveBeenCalledWith('data'); + expect(isHexStrict).toHaveBeenCalledWith('data'); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); @@ -220,6 +393,28 @@ describe('AccountsTest', () => { expect(recover).toHaveBeenCalledWith('keccak', 'signature'); }); + it('calls recover with a strict hex string as message and returns the expected value', () => { + isHexStrict.mockReturnValueOnce(true); + + hexToBytes.mockReturnValueOnce('message'); + + Hash.keccak256s.mockReturnValueOnce('keccak'); + + recover.mockReturnValueOnce('recovered'); + + expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); + + expect(isHexStrict).toHaveBeenCalledWith('message'); + + expect(hexToBytes).toHaveBeenCalledWith('message'); + + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); + + expect(recover).toHaveBeenCalledWith('keccak', 'signature'); + }); + it('calls recover with a object as message and returns the expected value', () => { recover.mockReturnValueOnce('recovered'); @@ -305,6 +500,17 @@ describe('AccountsTest', () => { expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); }); + it('calls wallet.add with an already existing account and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; + accounts.accounts[accountMock.address] = accountMock; + + expect(accounts.wallet.add(accountMock)).toEqual(accountMock); + + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); + }); + it('calls wallet.add with a privateKey and returns the expected value', () => { new Account(); const accountMock = Account.mock.instances[0]; @@ -328,9 +534,10 @@ describe('AccountsTest', () => { const accountMock = Account.mock.instances[0]; accountMock.address = '0x0'; - accounts.accounts = {0: accountMock}; + accounts.accounts = {'0x0': accountMock}; + accounts.accountsIndex = 1; - expect(accounts.wallet.remove(0)).toEqual(true); + expect(accounts.wallet.remove('0x0')).toEqual(true); expect(accounts.accountsIndex).toEqual(0); }); @@ -398,7 +605,7 @@ describe('AccountsTest', () => { expect(() => { accounts.wallet.decrypt([true], 'pw'); - }).toThrow("Couldn't decrypt accounts. Password wrong?"); + }).toThrow('Couldn\'t decrypt accounts. Password wrong?'); expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); }); From 2c085d6e2d6986942023478f07b300ed37ddae3c Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 15:06:20 +0100 Subject: [PATCH 55/71] eth-contract tests updated --- .../web3-eth-contract/src/AbstractContract.js | 5 +++- .../src/factories/MethodFactory.js | 8 +------ packages/web3-eth-contract/src/index.js | 24 +++++++++++++++---- .../src/methods/ContractDeployMethod.js | 7 +----- .../src/methods/SendContractMethod.js | 7 +----- .../tests/__mocks__/TransactionSigner.js | 3 --- .../tests/src/AbstractContractTest.js | 2 +- .../tests/src/factories/MethodFactoryTest.js | 16 ++----------- .../src/methods/ContractDeployMethodTest.js | 19 +-------------- .../src/methods/SendContractMethodTest.js | 23 ------------------ 10 files changed, 30 insertions(+), 84 deletions(-) delete mode 100644 packages/web3-eth-contract/tests/__mocks__/TransactionSigner.js diff --git a/packages/web3-eth-contract/src/AbstractContract.js b/packages/web3-eth-contract/src/AbstractContract.js index 71c690a63a9..0650ef378c8 100644 --- a/packages/web3-eth-contract/src/AbstractContract.js +++ b/packages/web3-eth-contract/src/AbstractContract.js @@ -34,6 +34,7 @@ export default class AbstractContract extends AbstractWeb3Module { * @param {Object} formatters * @param {Array} abi * @param {String} address + * @param {Accounts} accounts * @param {Object} options * * @constructor @@ -47,8 +48,9 @@ export default class AbstractContract extends AbstractWeb3Module { abiCoder, utils, formatters, - abi = AbstractWeb3Module.throwIfMissing('abi'), + abi, address, + accounts, options = {} ) { super(provider, providersModuleFactory, methodModuleFactory, null, options); @@ -61,6 +63,7 @@ export default class AbstractContract extends AbstractWeb3Module { this.PromiEvent = PromiEvent; this.methodFactory = this.contractModuleFactory.createMethodFactory(); this.abiModel = this.abiMapper.map(abi); + this.accounts = accounts; this.options = options; if (address) { diff --git a/packages/web3-eth-contract/src/factories/MethodFactory.js b/packages/web3-eth-contract/src/factories/MethodFactory.js index 383882a440f..5d7cab6ef9c 100644 --- a/packages/web3-eth-contract/src/factories/MethodFactory.js +++ b/packages/web3-eth-contract/src/factories/MethodFactory.js @@ -29,7 +29,6 @@ import {EstimateGasMethod} from 'web3-core-method'; export default class MethodFactory { /** - * @param {Accounts} accounts * @param {Utils} utils * @param {Object} formatters * @param {ContractModuleFactory} contractModuleFactory @@ -38,8 +37,7 @@ export default class MethodFactory { * * @constructor */ - constructor(accounts, utils, formatters, contractModuleFactory, methodModuleFactory, abiCoder) { - this.accounts = accounts; + constructor(utils, formatters, contractModuleFactory, methodModuleFactory, abiCoder) { this.utils = utils; this.formatters = formatters; this.contractModuleFactory = contractModuleFactory; @@ -149,8 +147,6 @@ export default class MethodFactory { this.utils, this.formatters, this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.accounts, - this.methodModuleFactory.createTransactionSigner(), this.methodModuleFactory.createSendRawTransactionMethod(), this.contractModuleFactory.createAllEventsLogDecoder(), abiModel @@ -171,8 +167,6 @@ export default class MethodFactory { this.utils, this.formatters, this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.accounts, - this.methodModuleFactory.createTransactionSigner(), this.methodModuleFactory.createSendRawTransactionMethod(), contract ); diff --git a/packages/web3-eth-contract/src/index.js b/packages/web3-eth-contract/src/index.js index 09e20675fe4..0b15a72c4ed 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -27,11 +27,13 @@ import {AbiCoder} from 'web3-eth-abi'; import {MethodModuleFactory} from 'web3-core-method'; import {PromiEvent} from 'web3-core-promievent'; import ContractModuleFactory from './factories/ContractModuleFactory'; +import AbstractContract from './AbstractContract'; export AbstractContract from './AbstractContract'; export ContractModuleFactory from './factories/ContractModuleFactory'; /** + * TODO: Remove ContractModuleFactory and resolve dependencies here * Returns an object of type Contract * * @method Contract @@ -43,13 +45,25 @@ export ContractModuleFactory from './factories/ContractModuleFactory'; * @param {Object} options * * @returns {AbstractContract} + * + * @constructor */ export const Contract = (provider, accounts, abi, address, options) => { - return new ContractModuleFactory( - Utils, + const abiCoder = new AbiCoder(); + const methodModuleFactory = new MethodModuleFactory(); + + return new AbstractContract( + provider, + new ProvidersModuleFactory(), + new MethodModuleFactory(), + new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), + PromiEvent, + abiCoder, + utils, formatters, - new AbiCoder(), + abi, + address, accounts, - new MethodModuleFactory(accounts) - ).createContract(provider, new ProvidersModuleFactory(), PromiEvent, abi, address, options); + options + ); }; diff --git a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js index 0d1aff81915..827c5bf4512 100644 --- a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js +++ b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js @@ -27,8 +27,6 @@ export default class ContractDeployMethod extends SendTransactionMethod { * @param {Utils} utils * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {Accounts} accounts - * @param {TransactionSigner} transactionSigner * @param {AbstractContract} contract * @param {SendRawTransactionMethod} sendRawTransactionMethod * @@ -38,8 +36,6 @@ export default class ContractDeployMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod, contract ) { @@ -47,10 +43,9 @@ export default class ContractDeployMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod ); + this.contract = contract; } diff --git a/packages/web3-eth-contract/src/methods/SendContractMethod.js b/packages/web3-eth-contract/src/methods/SendContractMethod.js index acbdf88f665..787f86b3829 100644 --- a/packages/web3-eth-contract/src/methods/SendContractMethod.js +++ b/packages/web3-eth-contract/src/methods/SendContractMethod.js @@ -28,8 +28,6 @@ export default class SendContractMethod extends SendTransactionMethod { * @param {Utils} utils * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {Accounts} accounts - * @param {TransactionSigner} transactionSigner * @param {SendRawTransactionMethod} sendRawTransactionMethod * @param {AllEventsLogDecoder} allEventsLogDecoder * @param {AbiModel} abiModel @@ -40,8 +38,6 @@ export default class SendContractMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod, allEventsLogDecoder, abiModel @@ -50,10 +46,9 @@ export default class SendContractMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod ); + this.allEventsLogDecoder = allEventsLogDecoder; this.abiModel = abiModel; } diff --git a/packages/web3-eth-contract/tests/__mocks__/TransactionSigner.js b/packages/web3-eth-contract/tests/__mocks__/TransactionSigner.js deleted file mode 100644 index 2c0f4b84599..00000000000 --- a/packages/web3-eth-contract/tests/__mocks__/TransactionSigner.js +++ /dev/null @@ -1,3 +0,0 @@ -export default class TransactionSigner { - constructor() {} -} diff --git a/packages/web3-eth-contract/tests/src/AbstractContractTest.js b/packages/web3-eth-contract/tests/src/AbstractContractTest.js index 817e8b3422d..758658e7309 100644 --- a/packages/web3-eth-contract/tests/src/AbstractContractTest.js +++ b/packages/web3-eth-contract/tests/src/AbstractContractTest.js @@ -156,7 +156,7 @@ describe('AbstractContractTest', () => { expect(abstractContract.abiMapper).toEqual(abiMapperMock); - expect(abstractContract.options).toEqual(options); + expect(abstractContract.options).toEqual({address: '0x0'}); expect(abstractContract.PromiEvent).toEqual(PromiEvent); diff --git a/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js b/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js index 6fce6090804..9d915ba7626 100644 --- a/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js +++ b/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js @@ -1,5 +1,4 @@ import {MethodModuleFactory, EstimateGasMethod} from 'web3-core-method'; -import {Accounts} from 'web3-eth-accounts'; import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; import {AbiCoder} from 'web3-eth-abi'; @@ -30,15 +29,11 @@ jest.mock('../../../src/methods/AllPastEventLogsMethod'); * MethodFactory test */ describe('MethodFactoryTest', () => { - let methodFactory, accountsMock, contractModuleFactoryMock, methodModuleFactoryMock, abiCoderMock; + let methodFactory, contractModuleFactoryMock, methodModuleFactoryMock, abiCoderMock; beforeEach(() => { - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - - new MethodModuleFactory(accountsMock); + new MethodModuleFactory(); methodModuleFactoryMock = MethodModuleFactory.mock.instances[0]; - methodModuleFactoryMock.createTransactionSigner = jest.fn(); methodModuleFactoryMock.createTransactionConfirmationWorkflow = jest.fn(); methodModuleFactoryMock.createSendRawTransactionMethod = jest.fn(); @@ -49,7 +44,6 @@ describe('MethodFactoryTest', () => { abiCoderMock = AbiCoder.mock.instances[0]; methodFactory = new MethodFactory( - accountsMock, Utils, formatters, contractModuleFactoryMock, @@ -59,8 +53,6 @@ describe('MethodFactoryTest', () => { }); it('constructor check', () => { - expect(methodFactory.accounts).toEqual(accountsMock); - expect(methodFactory.utils).toEqual(Utils); expect(methodFactory.formatters).toEqual(formatters); @@ -115,8 +107,6 @@ describe('MethodFactoryTest', () => { expect(contractModuleFactoryMock.createAllEventsLogDecoder).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); @@ -125,8 +115,6 @@ describe('MethodFactoryTest', () => { it('calls createContractDeployMethod and returns ContractDeployMethod object', () => { expect(methodFactory.createContractDeployMethod({})).toBeInstanceOf(ContractDeployMethod); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); diff --git a/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js index 3797b77ffc0..f82e7bae6eb 100644 --- a/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js @@ -1,58 +1,41 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {Accounts} from 'web3-eth-accounts'; import {SendTransactionMethod} from 'web3-core-method'; import TransactionConfirmationWorkflow from '../../__mocks__/TransactionConfirmationWorkflow'; -import TransactionSigner from '../../__mocks__/TransactionSigner'; import AbstractContract from '../../../src/AbstractContract'; import ContractDeployMethod from '../../../src/methods/ContractDeployMethod'; // Mocks jest.mock('Utils'); jest.mock('formatters'); -jest.mock('Accounts'); jest.mock('../../../src/AbstractContract'); /** * ContractDeployMethod test */ describe('ContractDeployMethodTest', () => { - let contractDeployMethod, transactionConfirmationWorkflowMock, accountsMock, transactionSignerMock, contractMock; + let contractDeployMethod, transactionConfirmationWorkflowMock, contractMock; beforeEach(() => { - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - new AbstractContract(); contractMock = AbstractContract.mock.instances[0]; transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); - transactionSignerMock = new TransactionSigner(); contractDeployMethod = new ContractDeployMethod( Utils, formatters, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, {}, contractMock ); }); it('constructor check', () => { - expect(contractDeployMethod.utils).toEqual(Utils); - - expect(contractDeployMethod.formatters).toEqual(formatters); - expect(contractDeployMethod.transactionConfirmationWorkflow).toEqual(transactionConfirmationWorkflowMock); expect(contractDeployMethod.sendRawTransactionMethod).toEqual({}); - expect(contractDeployMethod.accounts).toEqual(accountsMock); - - expect(contractDeployMethod.transactionSigner).toEqual(transactionSignerMock); - expect(contractDeployMethod.contract).toEqual(contractMock); expect(contractDeployMethod).toBeInstanceOf(SendTransactionMethod); diff --git a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js index 2aa995baaad..1c7a28e0f90 100644 --- a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js @@ -1,9 +1,7 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {Accounts} from 'web3-eth-accounts'; import {SendTransactionMethod} from 'web3-core-method'; import TransactionConfirmationWorkflow from '../../__mocks__/TransactionConfirmationWorkflow'; -import TransactionSigner from '../../__mocks__/TransactionSigner'; import AllEventsLogDecoder from '../../../src/decoders/AllEventsLogDecoder'; import AbiModel from '../../../src/models/AbiModel'; import SendContractMethod from '../../../src/methods/SendContractMethod'; @@ -22,19 +20,12 @@ jest.mock('../../../src/models/AbiModel'); describe('SendContractMethodTest', () => { let sendContractMethod, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, allEventsLogDecoderMock, abiModelMock; beforeEach(() => { transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - - transactionSignerMock = new TransactionSigner(); - new AbiModel(); abiModelMock = AbiModel.mock.instances[0]; @@ -45,8 +36,6 @@ describe('SendContractMethodTest', () => { Utils, formatters, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, {}, allEventsLogDecoderMock, abiModelMock @@ -54,18 +43,6 @@ describe('SendContractMethodTest', () => { }); it('constructor check', () => { - expect(sendContractMethod.utils).toEqual(Utils); - - expect(sendContractMethod.formatters).toEqual(formatters); - - expect(sendContractMethod.transactionConfirmationWorkflow).toEqual(transactionConfirmationWorkflowMock); - - expect(sendContractMethod.sendRawTransactionMethod).toEqual({}); - - expect(sendContractMethod.accounts).toEqual(accountsMock); - - expect(sendContractMethod.transactionSigner).toEqual(transactionSignerMock); - expect(sendContractMethod.allEventsLogDecoder).toEqual(allEventsLogDecoderMock); expect(sendContractMethod.abiModel).toEqual(abiModelMock); From be3191d9fccfa5950e787a8ba28451b6d29da8ac Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 16:14:28 +0100 Subject: [PATCH 56/71] tests fixed and code style improved --- packages/web3-eth-accounts/src/Accounts.js | 2 +- .../tests/src/AccountsTest.js | 20 +++++++++---------- packages/web3-eth-contract/src/index.js | 2 +- .../src/methods/ContractDeployMethod.js | 15 ++------------ .../src/methods/SendContractMethod.js | 7 +------ .../src/methods/SendContractMethodTest.js | 5 +---- packages/web3-eth/src/index.js | 6 +++--- .../src/providers/HttpProvider.js | 2 +- 8 files changed, 20 insertions(+), 39 deletions(-) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index d75222b3f49..43e6b58038a 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -226,7 +226,7 @@ export default class Accounts extends AbstractWeb3Module { const account = Account.fromV3Keystore(keystore, password, false, this); if (!account) { - throw new Error('Couldn\'t decrypt accounts. Password wrong?'); + throw new Error("Couldn't decrypt accounts. Password wrong?"); } this.add(account); diff --git a/packages/web3-eth-accounts/tests/src/AccountsTest.js b/packages/web3-eth-accounts/tests/src/AccountsTest.js index 0a3d5f60265..6e75d03424d 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -228,7 +228,6 @@ describe('AccountsTest', () => { expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); @@ -278,14 +277,15 @@ describe('AccountsTest', () => { }); it('calls signTransaction and rejects with a promise', async () => { - const callback = jest.fn(), - transaction = { - from: 0, - gas: 1, - gasPrice: 1, - nonce: 1, - chainId: 1 - }; + const callback = jest.fn(); + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; const account = {privateKey: 'pk', address: '0x0'}; Account.fromPrivateKey.mockReturnValueOnce(account); @@ -605,7 +605,7 @@ describe('AccountsTest', () => { expect(() => { accounts.wallet.decrypt([true], 'pw'); - }).toThrow('Couldn\'t decrypt accounts. Password wrong?'); + }).toThrow("Couldn't decrypt accounts. Password wrong?"); expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); }); diff --git a/packages/web3-eth-contract/src/index.js b/packages/web3-eth-contract/src/index.js index 0b15a72c4ed..21920df6256 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -59,7 +59,7 @@ export const Contract = (provider, accounts, abi, address, options) => { new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), PromiEvent, abiCoder, - utils, + Utils, formatters, abi, address, diff --git a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js index 827c5bf4512..08f640fd3ee 100644 --- a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js +++ b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js @@ -32,19 +32,8 @@ export default class ContractDeployMethod extends SendTransactionMethod { * * @constructor */ - constructor( - utils, - formatters, - transactionConfirmationWorkflow, - sendRawTransactionMethod, - contract - ) { - super( - utils, - formatters, - transactionConfirmationWorkflow, - sendRawTransactionMethod - ); + constructor(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod, contract) { + super(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod); this.contract = contract; } diff --git a/packages/web3-eth-contract/src/methods/SendContractMethod.js b/packages/web3-eth-contract/src/methods/SendContractMethod.js index 787f86b3829..5f5e28e6fd6 100644 --- a/packages/web3-eth-contract/src/methods/SendContractMethod.js +++ b/packages/web3-eth-contract/src/methods/SendContractMethod.js @@ -42,12 +42,7 @@ export default class SendContractMethod extends SendTransactionMethod { allEventsLogDecoder, abiModel ) { - super( - utils, - formatters, - transactionConfirmationWorkflow, - sendRawTransactionMethod - ); + super(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod); this.allEventsLogDecoder = allEventsLogDecoder; this.abiModel = abiModel; diff --git a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js index 1c7a28e0f90..4b513c14363 100644 --- a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js @@ -18,10 +18,7 @@ jest.mock('../../../src/models/AbiModel'); * SendContractMethod test */ describe('SendContractMethodTest', () => { - let sendContractMethod, - transactionConfirmationWorkflowMock, - allEventsLogDecoderMock, - abiModelMock; + let sendContractMethod, transactionConfirmationWorkflowMock, allEventsLogDecoderMock, abiModelMock; beforeEach(() => { transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 4c7f8fc5cc8..198fc9b63da 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -33,7 +33,7 @@ import {ProvidersModuleFactory} from 'web3-providers'; import {Network} from 'web3-net'; import * as Utils from 'web3-utils'; import EthTransactionSigner from './signers/TransactionSigner'; -import EthModule from 'Eth'; +import EthModule from './Eth'; import EthMethodFactory from './factories/MethodFactory'; /** @@ -86,8 +86,8 @@ export const Eth = (provider, options) => { Iban, abiCoder, new Ens(provider, accounts, options), - this.utils, - this.formatters, + Utils, + formatters, new SubscriptionsFactory(), new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), new TransactionSigner(), diff --git a/packages/web3-providers/src/providers/HttpProvider.js b/packages/web3-providers/src/providers/HttpProvider.js index 77194695fbb..062ddb1b259 100644 --- a/packages/web3-providers/src/providers/HttpProvider.js +++ b/packages/web3-providers/src/providers/HttpProvider.js @@ -179,7 +179,7 @@ export default class HttpProvider { /** * Checks if the error `net::ERR_NAME_NOT_RESOLVED` or `net::ERR_CONNECTION_REFUSED` will appear. - * + * * @method isInvalidHttpEndpoint * * @param {Object} request From 3dc19873bd761aaa37bf33616efb9732100586c9 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 17:23:38 +0100 Subject: [PATCH 57/71] dependency handling of the transaction signer fixed --- packages/web3-eth-contract/src/AbstractContract.js | 6 +++--- .../tests/src/AbstractContractTest.js | 4 +++- packages/web3-eth-ens/src/Ens.js | 5 ++++- packages/web3-eth-ens/src/index.js | 5 ++--- packages/web3-eth/src/Eth.js | 10 ++++------ 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/web3-eth-contract/src/AbstractContract.js b/packages/web3-eth-contract/src/AbstractContract.js index 0650ef378c8..52cc98a4a7f 100644 --- a/packages/web3-eth-contract/src/AbstractContract.js +++ b/packages/web3-eth-contract/src/AbstractContract.js @@ -34,7 +34,7 @@ export default class AbstractContract extends AbstractWeb3Module { * @param {Object} formatters * @param {Array} abi * @param {String} address - * @param {Accounts} accounts + * @param {TransactionSigner} transactionSigner * @param {Object} options * * @constructor @@ -50,7 +50,7 @@ export default class AbstractContract extends AbstractWeb3Module { formatters, abi, address, - accounts, + transactionSigner, options = {} ) { super(provider, providersModuleFactory, methodModuleFactory, null, options); @@ -63,7 +63,7 @@ export default class AbstractContract extends AbstractWeb3Module { this.PromiEvent = PromiEvent; this.methodFactory = this.contractModuleFactory.createMethodFactory(); this.abiModel = this.abiMapper.map(abi); - this.accounts = accounts; + this.transactionSigner = options.transactionSigner; this.options = options; if (address) { diff --git a/packages/web3-eth-contract/tests/src/AbstractContractTest.js b/packages/web3-eth-contract/tests/src/AbstractContractTest.js index 758658e7309..1854976f4ca 100644 --- a/packages/web3-eth-contract/tests/src/AbstractContractTest.js +++ b/packages/web3-eth-contract/tests/src/AbstractContractTest.js @@ -88,7 +88,7 @@ describe('AbstractContractTest', () => { providerResolverMock = ProviderResolver.mock.instances[0]; abi = []; - options = {}; + options = {transactionSigner: {}}; providerDetectorMock.detect = jest.fn(() => { return null; @@ -166,6 +166,8 @@ describe('AbstractContractTest', () => { expect(abstractContract.address).toEqual('0x0'); + expect(abstractContract.transactionSigner).toEqual({}); + expect(abstractContract.methods).toEqual(methodsProxyMock); expect(abstractContract.events).toEqual(eventSubscriptionsProxyMock); diff --git a/packages/web3-eth-ens/src/Ens.js b/packages/web3-eth-ens/src/Ens.js index 96c5af34092..02e580cb875 100644 --- a/packages/web3-eth-ens/src/Ens.js +++ b/packages/web3-eth-ens/src/Ens.js @@ -36,6 +36,7 @@ export default class Ens extends AbstractWeb3Module { * @param {Object} formatters * @param {Object} registryOptions * @param {Network} net + * @param {TransactionSigner} transactionSigner * * @constructor */ @@ -50,7 +51,8 @@ export default class Ens extends AbstractWeb3Module { utils, formatters, registryOptions, - net + net, + transactionSigner ) { super(provider, providersModuleFactory, methodModuleFactory, null, options); @@ -61,6 +63,7 @@ export default class Ens extends AbstractWeb3Module { this.formatters = formatters; this.registryOptions = registryOptions; this.net = net; + this.transactionSigner = options.transactionSigner; this._registry = false; } diff --git a/packages/web3-eth-ens/src/index.js b/packages/web3-eth-ens/src/index.js index da6e0ae4d9d..d06b17fbbf5 100644 --- a/packages/web3-eth-ens/src/index.js +++ b/packages/web3-eth-ens/src/index.js @@ -33,12 +33,11 @@ import EnsModuleFactory from './factories/EnsModuleFactory'; * @method Ens * * @param {HttpProvider|WebsocketProvider|IpcProvider|EthereumProvider|String} provider - * @param {Accounts} accounts * @param {Object} options * * @returns {Ens} */ -export const Ens = (provider, accounts, options) => { +export const Ens = (provider, options) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); @@ -46,7 +45,7 @@ export const Ens = (provider, accounts, options) => { return new EnsModuleFactory().createENS( provider, new ProvidersModuleFactory(), - new MethodModuleFactory(accounts), + new MethodModuleFactory(), new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), PromiEvent, abiCoder, diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index 83f629ff9fb..c4ebc6c5d44 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -75,12 +75,7 @@ export default class Eth extends AbstractWeb3Module { this.subscriptionsFactory = subscriptionsFactory; this.contractModuleFactory = contractModuleFactory; this.initiatedContracts = []; - this._transactionSigner = transactionSigner; - - if (options.transactionSigner) { - this._transactionSigner = options.transactionSigner; - this.accounts.transactionSigner = options.transactionSigner; - } + this._transactionSigner = options.transactionSigner || transactionSigner; /** * This wrapper function is required for the "new web3.eth.Contract(...)" call. @@ -94,6 +89,8 @@ export default class Eth extends AbstractWeb3Module { * @constructor */ this.Contract = (abi, address, options) => { + options.transactionSigner = this.transactionSigner; + const contract = this.contractModuleFactory.createContract( this.currentProvider, this.providersModuleFactory, @@ -130,6 +127,7 @@ export default class Eth extends AbstractWeb3Module { set transactionSigner(transactionSigner) { this._transactionSigner = transactionSigner; this.accounts.transactionSigner = transactionSigner; + this.ens.transactionSigner = transactionSigner; } /** From cdc5e05e084802acfa2bb2a1400d6f258aa2f6e3 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 17:46:49 +0100 Subject: [PATCH 58/71] dependency handling checked and the eth module transactionSigner setter updated --- packages/web3-eth-contract/src/AbstractContract.js | 5 +++-- .../src/factories/ContractModuleFactory.js | 6 ++++-- packages/web3-eth-contract/src/index.js | 6 +++--- packages/web3-eth/src/Eth.js | 6 ++++++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/web3-eth-contract/src/AbstractContract.js b/packages/web3-eth-contract/src/AbstractContract.js index 52cc98a4a7f..3a5134c477d 100644 --- a/packages/web3-eth-contract/src/AbstractContract.js +++ b/packages/web3-eth-contract/src/AbstractContract.js @@ -30,11 +30,11 @@ export default class AbstractContract extends AbstractWeb3Module { * @param {ContractModuleFactory} contractModuleFactory * @param {PromiEvent} PromiEvent * @param {AbiCoder} abiCoder + * @param {Accounts} accounts * @param {Object} utils * @param {Object} formatters * @param {Array} abi * @param {String} address - * @param {TransactionSigner} transactionSigner * @param {Object} options * * @constructor @@ -45,12 +45,12 @@ export default class AbstractContract extends AbstractWeb3Module { methodModuleFactory, contractModuleFactory, PromiEvent, + accounts, abiCoder, utils, formatters, abi, address, - transactionSigner, options = {} ) { super(provider, providersModuleFactory, methodModuleFactory, null, options); @@ -61,6 +61,7 @@ export default class AbstractContract extends AbstractWeb3Module { this.abiMapper = this.contractModuleFactory.createAbiMapper(); this.options = options; this.PromiEvent = PromiEvent; + this.accounts = accounts; this.methodFactory = this.contractModuleFactory.createMethodFactory(); this.abiModel = this.abiMapper.map(abi); this.transactionSigner = options.transactionSigner; diff --git a/packages/web3-eth-contract/src/factories/ContractModuleFactory.js b/packages/web3-eth-contract/src/factories/ContractModuleFactory.js index 639c8db27a5..bc1989a8f5c 100644 --- a/packages/web3-eth-contract/src/factories/ContractModuleFactory.js +++ b/packages/web3-eth-contract/src/factories/ContractModuleFactory.js @@ -64,19 +64,21 @@ export default class ContractModuleFactory { * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider * @param {ProvidersModuleFactory} providersModuleFactory * @param {PromiEvent} PromiEvent - * @param {Object} abi + * @param {Accounts} accounts + * @param {Array} abi * @param {String} address * @param {Object} options * * @returns {AbstractContract} */ - createContract(provider, providersModuleFactory, PromiEvent, abi, address, options) { + createContract(provider, providersModuleFactory, PromiEvent, accounts, abi, address, options) { return new AbstractContract( provider, providersModuleFactory, this.methodModuleFactory, this, PromiEvent, + accounts, this.abiCoder, this.utils, this.formatters, diff --git a/packages/web3-eth-contract/src/index.js b/packages/web3-eth-contract/src/index.js index 21920df6256..df86bb052a6 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -39,8 +39,8 @@ export ContractModuleFactory from './factories/ContractModuleFactory'; * @method Contract * * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @param {Array} abi * @param {Accounts} accounts - * @param {Object} abi * @param {String} address * @param {Object} options * @@ -48,7 +48,7 @@ export ContractModuleFactory from './factories/ContractModuleFactory'; * * @constructor */ -export const Contract = (provider, accounts, abi, address, options) => { +export const Contract = (provider, abi, accounts, address, options) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); @@ -58,12 +58,12 @@ export const Contract = (provider, accounts, abi, address, options) => { new MethodModuleFactory(), new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), PromiEvent, + accounts, abiCoder, Utils, formatters, abi, address, - accounts, options ); }; diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index c4ebc6c5d44..ee9f2d99374 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -70,6 +70,7 @@ export default class Eth extends AbstractWeb3Module { this.Iban = Iban; this.abi = abiCoder; this.ens = ens; + this.utils = utils; this.formatters = formatters; this.subscriptionsFactory = subscriptionsFactory; @@ -95,6 +96,7 @@ export default class Eth extends AbstractWeb3Module { this.currentProvider, this.providersModuleFactory, PromiEvent, + this.accounts, abi, address, options @@ -128,6 +130,10 @@ export default class Eth extends AbstractWeb3Module { this._transactionSigner = transactionSigner; this.accounts.transactionSigner = transactionSigner; this.ens.transactionSigner = transactionSigner; + + this.initiatedContracts.forEach((contract) => { + contract.transactionSigner = transactionSigner; + }); } /** From a1aeeb797b724ef9b139e086b12dfb3f2450f407 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 18:10:43 +0100 Subject: [PATCH 59/71] tests updated --- .../tests/src/AbstractContractTest.js | 5 ++++- packages/web3-eth/tests/src/EthTest.js | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/tests/src/AbstractContractTest.js b/packages/web3-eth-contract/tests/src/AbstractContractTest.js index 1854976f4ca..14c6718831a 100644 --- a/packages/web3-eth-contract/tests/src/AbstractContractTest.js +++ b/packages/web3-eth-contract/tests/src/AbstractContractTest.js @@ -118,6 +118,7 @@ describe('AbstractContractTest', () => { methodModuleFactoryMock, contractModuleFactoryMock, PromiEvent, + {}, abiCoderMock, Utils, formatters, @@ -156,10 +157,12 @@ describe('AbstractContractTest', () => { expect(abstractContract.abiMapper).toEqual(abiMapperMock); - expect(abstractContract.options).toEqual({address: '0x0'}); + expect(abstractContract.options).toEqual({address: '0x0', transactionSigner: {}}); expect(abstractContract.PromiEvent).toEqual(PromiEvent); + expect(abstractContract.accounts).toEqual({}); + expect(abstractContract.methodFactory).toEqual(methodFactoryMock); expect(abstractContract.abiModel).toEqual(abiModelMock); diff --git a/packages/web3-eth/tests/src/EthTest.js b/packages/web3-eth/tests/src/EthTest.js index 2945525dfae..83fd9ab7894 100644 --- a/packages/web3-eth/tests/src/EthTest.js +++ b/packages/web3-eth/tests/src/EthTest.js @@ -421,9 +421,23 @@ describe('EthTest', () => { it('calls the Contract factory method from the constructor', () => { contractModuleFactoryMock.createContract.mockReturnValueOnce(new AbstractContract()); - expect(new eth.Contract()).toBeInstanceOf(AbstractContract); + expect(new eth.Contract([], '0x0', {})).toBeInstanceOf(AbstractContract); expect(eth.initiatedContracts).toHaveLength(1); + + const createContractCall = contractModuleFactoryMock.createContract.mock.calls[0]; + + expect(createContractCall[0]).toEqual(eth.currentProvider); + + expect(createContractCall[1]).toEqual(eth.providersModuleFactory); + + expect(createContractCall[3]).toEqual(eth.accounts); + + expect(createContractCall[4]).toEqual([]); + + expect(createContractCall[5]).toEqual('0x0'); + + expect(createContractCall[6]).toEqual({transactionSigner: transactionSignerMock}); }); it('calls setProvider and returns true', () => { From 8a4a0979375e1549367ca36d509768d3fdab5499 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 18:31:20 +0100 Subject: [PATCH 60/71] linter executed and errors fixed --- .../tests/src/methods/CallContractMethodTest.js | 11 +++++++---- packages/web3-eth-ens/src/Ens.js | 4 +--- packages/web3-eth-ens/src/index.js | 3 ++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/web3-eth-contract/tests/src/methods/CallContractMethodTest.js b/packages/web3-eth-contract/tests/src/methods/CallContractMethodTest.js index 11a163c2411..84f5a560f27 100644 --- a/packages/web3-eth-contract/tests/src/methods/CallContractMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/CallContractMethodTest.js @@ -43,14 +43,17 @@ describe('CallContractMethodTest', () => { it('calls afterExecution and returns the result array', () => { abiCoderMock.decodeParameters = jest.fn(); - + abiCoderMock.decodeParameters.mockReturnValueOnce(['0x0', '0x0']); - abiItemModelMock.getOutputs.mockReturnValueOnce([{name: "", type: 'bytes'}, {name: "", type: 'bytes'}]); + abiItemModelMock.getOutputs.mockReturnValueOnce([{name: '', type: 'bytes'}, {name: '', type: 'bytes'}]); expect(callContractMethod.afterExecution('0x0')).toEqual(['0x0', '0x0']); - expect(abiCoderMock.decodeParameters).toHaveBeenCalledWith([{name: "", type: 'bytes'}, {name: "", type: 'bytes'}], '0'); + expect(abiCoderMock.decodeParameters).toHaveBeenCalledWith( + [{name: '', type: 'bytes'}, {name: '', type: 'bytes'}], + '0' + ); }); it('calls afterExecution and returns the first array item as result', () => { @@ -58,7 +61,7 @@ describe('CallContractMethodTest', () => { abiCoderMock.decodeParameter.mockReturnValueOnce('0x0'); - abiItemModelMock.getOutputs.mockReturnValueOnce([{name: "result", type: 'bytes'}]); + abiItemModelMock.getOutputs.mockReturnValueOnce([{name: 'result', type: 'bytes'}]); expect(callContractMethod.afterExecution('0x0')).toEqual('0x0'); diff --git a/packages/web3-eth-ens/src/Ens.js b/packages/web3-eth-ens/src/Ens.js index 13f1d919b30..f035c04b271 100644 --- a/packages/web3-eth-ens/src/Ens.js +++ b/packages/web3-eth-ens/src/Ens.js @@ -36,7 +36,6 @@ export default class Ens extends AbstractWeb3Module { * @param {Object} formatters * @param {Object} registryOptions * @param {Network} net - * @param {TransactionSigner} transactionSigner * * @constructor */ @@ -52,8 +51,7 @@ export default class Ens extends AbstractWeb3Module { utils, formatters, registryOptions, - net, - transactionSigner + net ) { super(provider, providersModuleFactory, methodModuleFactory, null, options); diff --git a/packages/web3-eth-ens/src/index.js b/packages/web3-eth-ens/src/index.js index d06b17fbbf5..99c7a0b7996 100644 --- a/packages/web3-eth-ens/src/index.js +++ b/packages/web3-eth-ens/src/index.js @@ -34,10 +34,11 @@ import EnsModuleFactory from './factories/EnsModuleFactory'; * * @param {HttpProvider|WebsocketProvider|IpcProvider|EthereumProvider|String} provider * @param {Object} options + * @param {Accounts} accounts * * @returns {Ens} */ -export const Ens = (provider, options) => { +export const Ens = (provider, options, accounts) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); From 7e3c1f8c5ce51b6817ce10f1911acf80555abcdf Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Tue, 26 Feb 2019 21:25:33 +0100 Subject: [PATCH 61/71] contract handling tested and fixed --- packages/web3-core-helpers/package-lock.json | 116 ++++++++++++++ .../lib/factories/AbstractMethodFactory.js | 12 +- packages/web3-core-method/package-lock.json | 111 +++++++++++++ .../transaction/SendTransactionMethod.js | 18 ++- packages/web3-core/package-lock.json | 111 +++++++++++++ packages/web3-eth-accounts/package-lock.json | 111 +++++++++++++ packages/web3-eth-accounts/src/index.js | 4 +- packages/web3-eth-contract/package-lock.json | 116 ++++++++++++++ .../src/factories/ContractModuleFactory.js | 9 +- .../src/factories/MethodFactory.js | 10 +- .../src/methods/SendContractMethod.js | 13 +- packages/web3-eth-ens/package-lock.json | 116 ++++++++++++++ packages/web3-eth-personal/package-lock.json | 121 ++++++++++++++ packages/web3-eth/package-lock.json | 148 +++++++++++++++--- packages/web3-eth/src/Eth.js | 2 +- packages/web3-eth/src/index.js | 4 +- packages/web3-net/package-lock.json | 116 ++++++++++++++ packages/web3-providers/package.json | 48 ++---- packages/web3-shh/package-lock.json | 121 ++++++++++++++ packages/web3/package-lock.json | 116 ++++++++++++++ 20 files changed, 1346 insertions(+), 77 deletions(-) diff --git a/packages/web3-core-helpers/package-lock.json b/packages/web3-core-helpers/package-lock.json index c4803042f75..36b493a8d04 100644 --- a/packages/web3-core-helpers/package-lock.json +++ b/packages/web3-core-helpers/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -159,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -205,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -254,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -272,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -345,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -355,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js index 98e6a958a6e..21524a1b802 100644 --- a/packages/web3-core-method/lib/factories/AbstractMethodFactory.js +++ b/packages/web3-core-method/lib/factories/AbstractMethodFactory.js @@ -20,6 +20,10 @@ * @date 2018 */ +import SendRawTransactionMethod from '../../src/methods/transaction/SendRawTransactionMethod'; +import GetTransactionCountMethod from '../../src/methods/account/GetTransactionCountMethod'; +import ChainIdMethod from '../../src/methods/network/ChainIdMethod'; + export default class AbstractMethodFactory { /** * @param {MethodModuleFactory} methodModuleFactory @@ -92,11 +96,15 @@ export default class AbstractMethodFactory { return new method(this.utils, this.formatters); case 'SEND': if (method.name === 'SendTransactionMethod') { + const transactionConfirmationWorkflow = this.methodModuleFactory.createTransactionConfirmationWorkflow(); + return new method( this.utils, this.formatters, - this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.createSendRawTransactionMethod() + transactionConfirmationWorkflow, + new SendRawTransactionMethod(this.utils, this.formatters, transactionConfirmationWorkflow), + new ChainIdMethod(this.utils, this.formatters), + new GetTransactionCountMethod(this.utils, this.formatters) ); } diff --git a/packages/web3-core-method/package-lock.json b/packages/web3-core-method/package-lock.json index 208854fad59..36b493a8d04 100644 --- a/packages/web3-core-method/package-lock.json +++ b/packages/web3-core-method/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -210,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -224,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -259,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -277,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -350,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -360,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 44e6436e002..649e54b10f1 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -29,12 +29,23 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow * @param {SendRawTransactionMethod} sendRawTransactionMethod + * @param {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod * * @constructor */ - constructor(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod) { + constructor( + utils, + formatters, + transactionConfirmationWorkflow, + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod + ) { super('eth_sendTransaction', 1, utils, formatters, transactionConfirmationWorkflow); this.sendRawTransactionMethod = sendRawTransactionMethod; + this.chainIdMethod = chainIdMethod; + this.getTransactionCountMethod = getTransactionCountMethod; } /** @@ -115,11 +126,12 @@ export default class SendTransactionMethod extends AbstractSendMethod { */ async sendRawTransaction(privateKey, promiEvent, moduleInstance) { if (!this.parameters[0].chainId) { - this.parameters[0].chainId = await moduleInstance.getChainId(); + this.parameters[0].chainId = await this.chainIdMethod.execute(moduleInstance); } if (!this.parameters[0].nonce && this.parameters[0].nonce !== 0) { - this.parameters[0].nonce = await moduleInstance.getTransactionCount(this.parameters[0].from); + this.getTransactionCountMethod.parameters = [this.parameters[0].from]; + this.parameters[0].nonce = await this.getTransactionCountMethod.execute(moduleInstance); } const response = await moduleInstance.transactionSigner.sign(this.parameters[0], privateKey); diff --git a/packages/web3-core/package-lock.json b/packages/web3-core/package-lock.json index bf05c569e73..dc26172fbff 100644 --- a/packages/web3-core/package-lock.json +++ b/packages/web3-core/package-lock.json @@ -127,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -164,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -210,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -224,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -259,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -277,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -350,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -360,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth-accounts/package-lock.json b/packages/web3-eth-accounts/package-lock.json index 7cfc8a1c114..118b3123abc 100644 --- a/packages/web3-eth-accounts/package-lock.json +++ b/packages/web3-eth-accounts/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -218,6 +223,11 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", @@ -270,6 +280,14 @@ "randomfill": "^1.0.3" } }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -368,6 +386,11 @@ "xhr-request-promise": "^0.1.2" } }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -468,6 +491,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -492,6 +520,11 @@ "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -569,6 +602,11 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, "nan": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", @@ -579,6 +617,14 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -659,6 +705,11 @@ "strict-uri-encode": "^1.0.0" } }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -681,6 +732,11 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -827,6 +883,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -837,6 +901,15 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, "url-set-query": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", @@ -847,6 +920,31 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -885,10 +983,23 @@ "xhr-request": "^1.0.1" } }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth-accounts/src/index.js b/packages/web3-eth-accounts/src/index.js index 218288d0ce2..973e755584a 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -24,7 +24,7 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; import AccountsModule from './Accounts'; import {ProvidersModuleFactory} from 'web3-providers'; -import {GetGasPriceMethod, GetChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; +import {GetGasPriceMethod, ChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; /** * Returns the Accounts object @@ -40,7 +40,7 @@ export const Accounts = (provider, options) => { provider, new ProvidersModuleFactory(), formatters, - new GetChainIdMethod(Utils, formatters), + new ChainIdMethod(Utils, formatters), new GetGasPriceMethod(Utils, formatters), new GetTransactionCountMethod(Utils, formatters), options diff --git a/packages/web3-eth-contract/package-lock.json b/packages/web3-eth-contract/package-lock.json index c4803042f75..36b493a8d04 100644 --- a/packages/web3-eth-contract/package-lock.json +++ b/packages/web3-eth-contract/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -159,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -205,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -254,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -272,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -345,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -355,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth-contract/src/factories/ContractModuleFactory.js b/packages/web3-eth-contract/src/factories/ContractModuleFactory.js index bc1989a8f5c..000dad0344e 100644 --- a/packages/web3-eth-contract/src/factories/ContractModuleFactory.js +++ b/packages/web3-eth-contract/src/factories/ContractModuleFactory.js @@ -232,14 +232,7 @@ export default class ContractModuleFactory { * @returns {MethodFactory} */ createMethodFactory() { - return new MethodFactory( - this.accounts, - this.utils, - this.formatters, - this, - this.methodModuleFactory, - this.abiCoder - ); + return new MethodFactory(this.utils, this.formatters, this, this.methodModuleFactory, this.abiCoder); } /** diff --git a/packages/web3-eth-contract/src/factories/MethodFactory.js b/packages/web3-eth-contract/src/factories/MethodFactory.js index 5d7cab6ef9c..dca9b4835a9 100644 --- a/packages/web3-eth-contract/src/factories/MethodFactory.js +++ b/packages/web3-eth-contract/src/factories/MethodFactory.js @@ -25,7 +25,7 @@ import ContractDeployMethod from '../methods/ContractDeployMethod'; import PastEventLogsMethod from '../methods/PastEventLogsMethod'; import AllPastEventLogsMethod from '../methods/AllPastEventLogsMethod'; import SendContractMethod from '../methods/SendContractMethod'; -import {EstimateGasMethod} from 'web3-core-method'; +import {EstimateGasMethod, SendRawTransactionMethod, ChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; export default class MethodFactory { /** @@ -143,11 +143,15 @@ export default class MethodFactory { * @returns {SendContractMethod} */ createSendContractMethod(abiItem, abiModel) { + const transactionConfirmationWorkflow = this.methodModuleFactory.createTransactionConfirmationWorkflow(); + return new SendContractMethod( this.utils, this.formatters, - this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.createSendRawTransactionMethod(), + transactionConfirmationWorkflow, + new SendRawTransactionMethod(this.utils, this.formatters, transactionConfirmationWorkflow), + new ChainIdMethod(this.utils, this.formatters), + new GetTransactionCountMethod(this.utils, this.formatters), this.contractModuleFactory.createAllEventsLogDecoder(), abiModel ); diff --git a/packages/web3-eth-contract/src/methods/SendContractMethod.js b/packages/web3-eth-contract/src/methods/SendContractMethod.js index 5f5e28e6fd6..d938ae6fe5c 100644 --- a/packages/web3-eth-contract/src/methods/SendContractMethod.js +++ b/packages/web3-eth-contract/src/methods/SendContractMethod.js @@ -29,6 +29,8 @@ export default class SendContractMethod extends SendTransactionMethod { * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow * @param {SendRawTransactionMethod} sendRawTransactionMethod + * @param {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod * @param {AllEventsLogDecoder} allEventsLogDecoder * @param {AbiModel} abiModel * @@ -39,10 +41,19 @@ export default class SendContractMethod extends SendTransactionMethod { formatters, transactionConfirmationWorkflow, sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod, allEventsLogDecoder, abiModel ) { - super(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod); + super( + utils, + formatters, + transactionConfirmationWorkflow, + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod + ); this.allEventsLogDecoder = allEventsLogDecoder; this.abiModel = abiModel; diff --git a/packages/web3-eth-ens/package-lock.json b/packages/web3-eth-ens/package-lock.json index 3bb57ebf1f3..e8ad9d6aa4f 100644 --- a/packages/web3-eth-ens/package-lock.json +++ b/packages/web3-eth-ens/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -168,6 +186,11 @@ "js-sha3": "^0.5.7" } }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -214,6 +237,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "idna-uts46-hx": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", @@ -236,6 +264,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-sha3": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", @@ -276,6 +309,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -299,11 +350,21 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -372,6 +433,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -382,10 +451,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth-personal/package-lock.json b/packages/web3-eth-personal/package-lock.json index 71c145c4cc1..36b493a8d04 100644 --- a/packages/web3-eth-personal/package-lock.json +++ b/packages/web3-eth-personal/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -159,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -205,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -241,6 +274,11 @@ "graceful-fs": "^4.1.6" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -249,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -267,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -340,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -350,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth/package-lock.json b/packages/web3-eth/package-lock.json index 23402cc3c70..da34337f6f7 100644 --- a/packages/web3-eth/package-lock.json +++ b/packages/web3-eth/package-lock.json @@ -10,10 +10,10 @@ "regenerator-runtime": "^0.12.0" } }, - "@types/parsimmon": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@types/parsimmon/-/parsimmon-1.10.0.tgz", - "integrity": "sha512-bsTIJFVQv7jnvNiC42ld2pQW2KRI+pAG243L+iATvqzy3X6+NH1obz2itRKDZZ8VVhN3wjwYax/VBGCcXzgTqQ==" + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" }, "ansi-regex": { "version": "2.1.1", @@ -142,6 +142,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -163,14 +176,6 @@ "object-keys": "^1.0.12" } }, - "definitelytyped-header-parser": { - "version": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", - "from": "github:Microsoft/definitelytyped-header-parser#production", - "requires": { - "@types/parsimmon": "^1.3.0", - "parsimmon": "^1.2.0" - } - }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -186,11 +191,20 @@ "resolved": "https://registry.npmjs.org/dtslint/-/dtslint-0.4.2.tgz", "integrity": "sha512-ph4GXLw3HYzlQMJOFcpCqWHuL3MxJ/344OR7wn0wlQGchQGTIVNsSUl8iKEMatpy2geNMysgA9fQa6xVhHOkTQ==", "requires": { - "definitelytyped-header-parser": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", "fs-extra": "^6.0.1", "strip-json-comments": "^2.0.1", "tslint": "^5.12.0", "typescript": "^3.3.0-dev.20190126" + }, + "dependencies": { + "definitelytyped-header-parser": { + "version": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", + "from": "github:Microsoft/definitelytyped-header-parser#d957ad0bb2f4ecb60ac04f734e0b38fbc8e70b8a", + "requires": { + "@types/parsimmon": "^1.3.0", + "parsimmon": "^1.2.0" + } + } } }, "elliptic": { @@ -255,6 +269,11 @@ "xhr-request-promise": "^0.1.2" } }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -355,6 +374,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -400,6 +424,11 @@ "has-symbols": "^1.0.0" } }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -422,6 +451,11 @@ "graceful-fs": "^4.1.6" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -453,6 +487,16 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -463,6 +507,14 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==" }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -480,11 +532,6 @@ "string.prototype.trim": "^1.1.2" } }, - "parsimmon": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.12.0.tgz", - "integrity": "sha512-uC/BjuSfb4jfaWajKCp1mVncXXq+V1twbcYChbTxN3GM7fn+8XoHwUdvUz+PTaFtDSCRQxU8+Rnh+iMhAkVwdw==" - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -510,11 +557,21 @@ "strict-uri-encode": "^1.0.0" } }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -618,6 +675,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -628,11 +693,45 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, "url-set-query": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=" }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -671,10 +770,23 @@ "xhr-request": "^1.0.1" } }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-eth/src/Eth.js b/packages/web3-eth/src/Eth.js index ee9f2d99374..cb438a3e8b2 100644 --- a/packages/web3-eth/src/Eth.js +++ b/packages/web3-eth/src/Eth.js @@ -89,7 +89,7 @@ export default class Eth extends AbstractWeb3Module { * * @constructor */ - this.Contract = (abi, address, options) => { + this.Contract = (abi, address, options = {}) => { options.transactionSigner = this.transactionSigner; const contract = this.contractModuleFactory.createContract( diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 198fc9b63da..533f67b190b 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -33,7 +33,7 @@ import {ProvidersModuleFactory} from 'web3-providers'; import {Network} from 'web3-net'; import * as Utils from 'web3-utils'; import EthTransactionSigner from './signers/TransactionSigner'; -import EthModule from './Eth'; +import EthModule from './Eth.js'; import EthMethodFactory from './factories/MethodFactory'; /** @@ -75,7 +75,7 @@ export const Eth = (provider, options) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); - new EthModule( + return new EthModule( provider, new ProvidersModuleFactory(), methodModuleFactory, diff --git a/packages/web3-net/package-lock.json b/packages/web3-net/package-lock.json index c4803042f75..36b493a8d04 100644 --- a/packages/web3-net/package-lock.json +++ b/packages/web3-net/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -159,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -205,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -254,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -272,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -345,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -355,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3-providers/package.json b/packages/web3-providers/package.json index 248edb3fee7..cde7d5afea8 100644 --- a/packages/web3-providers/package.json +++ b/packages/web3-providers/package.json @@ -1,39 +1,13 @@ { - "name": "web3-providers", - "namespace": "ethereum", - "version": "1.0.0-beta.46", - "description": "Web3 module to handle requests to external providers.", - "repository": "https://github.com/ethereum/web3.js/tree/1.0/packages/web3-providers", - "license": "LGPL-3.0", - "main": "dist/web3-providers.cjs.js", - "module": "dist/web3-providers.esm.js", - "browser": "dist/web3-providers.umd.js", - "scripts": { - "build": "rollup -c", - "dev": "rollup -c -w", - "test": "jest", - "dtslint": "dtslint types --onlyTestTsNext" - }, - "types": "types", - "dependencies": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "oboe": "2.1.4", - "url-parse": "1.4.4", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "xhr2-cookies": "1.1.0" - }, - "devDependencies": { - "dtslint": "^0.4.2", - "web3-core": "1.0.0-beta.46", - "web3-core-helpers": "1.0.0-beta.46", - "web3-core-method": "1.0.0-beta.46", - "web3-utils": "1.0.0-beta.46" - }, - "files": [ - "dist", - "types/index.d.ts" - ] + "dependencies": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "dtslint": "^0.4.2", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "xhr2-cookies": "1.1.0" + } } diff --git a/packages/web3-shh/package-lock.json b/packages/web3-shh/package-lock.json index 71c145c4cc1..36b493a8d04 100644 --- a/packages/web3-shh/package-lock.json +++ b/packages/web3-shh/package-lock.json @@ -10,6 +10,11 @@ "regenerator-runtime": "^0.12.0" } }, + "@types/node": { + "version": "10.12.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.27.tgz", + "integrity": "sha512-e9wgeY6gaY21on3ve0xAjgBVjGDWq/xUteK0ujsE53bUoxycMkqfnkUgMt6ffZtykZ5X12Mg3T7Pw4TRCObDKg==" + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -122,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -159,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -205,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -219,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -241,6 +274,11 @@ "graceful-fs": "^4.1.6" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -249,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -267,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -340,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -350,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } diff --git a/packages/web3/package-lock.json b/packages/web3/package-lock.json index 88e6f3abcec..dc26172fbff 100644 --- a/packages/web3/package-lock.json +++ b/packages/web3/package-lock.json @@ -127,6 +127,19 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -164,6 +177,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "eventemitter3": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + }, "fs-extra": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", @@ -210,6 +228,11 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -224,6 +247,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -246,6 +274,11 @@ "graceful-fs": "^4.1.6" } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -254,6 +287,24 @@ "brace-expansion": "^1.1.7" } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==" + }, + "oboe": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.4.tgz", + "integrity": "sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY=", + "requires": { + "http-https": "^1.0.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -272,11 +323,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, + "querystringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==" + }, "regenerator-runtime": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -345,6 +406,14 @@ "tslib": "^1.8.1" } }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "3.3.0-dev.20190126", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.0-dev.20190126.tgz", @@ -355,10 +424,57 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "url-parse": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "web3-providers": { + "version": "1.0.0-beta.46", + "resolved": "https://registry.npmjs.org/web3-providers/-/web3-providers-1.0.0-beta.46.tgz", + "integrity": "sha512-5h4dFuASthr+EE8xBpAtQ5b5bngjv1ihIBcyEVQEP+bRtvU7qPKA8It2fQLtDl4iSADJDjhhQmvBPKbSlJ9jWg==", + "requires": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "xhr2-cookies": "1.1.0" + } + }, + "websocket": { + "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "requires": { + "debug": "^2.2.0", + "nan": "^2.3.3", + "typedarray-to-buffer": "^3.1.2", + "yaeti": "^0.0.6" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xhr2-cookies": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", + "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", + "requires": { + "cookiejar": "^2.1.1" + } + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } } } From 0325c483ea6586018b51e0be13b23abb3e58432e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 10:06:32 +0100 Subject: [PATCH 62/71] fixes for contract send methods in the browser --- .../transaction/SendTransactionMethod.js | 3 +- .../src/watchers/NewHeadsWatcher.js | 21 +------- .../src/factories/MethodFactory.js | 8 +++- .../src/methods/ContractDeployMethod.js | 23 +++++++-- .../src/proxies/MethodsProxy.js | 18 ++++--- packages/web3-providers/package.json | 48 ++++++++++++++----- .../src/resolvers/ProviderResolver.js | 9 ++-- packages/web3/src/Web3.js | 6 +-- 8 files changed, 86 insertions(+), 50 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 649e54b10f1..e0e245dc48c 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -88,6 +88,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } + if ( (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) || this.hasCustomSigner(moduleInstance) @@ -163,7 +164,7 @@ export default class SendTransactionMethod extends AbstractSendMethod { * @returns {Boolean} */ hasAccounts(moduleInstance) { - return moduleInstance.accounts && Object.keys(moduleInstance.accounts.wallet).length > 0; + return moduleInstance.accounts && moduleInstance.accounts.accountsIndex > 0; } /** diff --git a/packages/web3-core-method/src/watchers/NewHeadsWatcher.js b/packages/web3-core-method/src/watchers/NewHeadsWatcher.js index 5bfc640d978..ef2dbd5f378 100644 --- a/packages/web3-core-method/src/watchers/NewHeadsWatcher.js +++ b/packages/web3-core-method/src/watchers/NewHeadsWatcher.js @@ -20,7 +20,6 @@ * @date 2018 */ -import {WebsocketProvider, IpcProvider, EthereumProvider} from 'web3-providers'; import EventEmitter from 'eventemitter3'; export default class NewHeadsWatcher extends EventEmitter { @@ -47,10 +46,11 @@ export default class NewHeadsWatcher extends EventEmitter { * @returns {NewHeadsWatcher} */ watch(moduleInstance) { - if (this.isSocketConnection(moduleInstance.currentProvider)) { + if (moduleInstance.currentProvider.constructor.name !== 'HttpProvider') { this.confirmationSubscription = this.subscriptionsFactory .createNewHeadsSubscription(moduleInstance) .subscribe(() => { + console.log('newHEAD'); this.emit('newHead'); }); @@ -81,21 +81,4 @@ export default class NewHeadsWatcher extends EventEmitter { this.removeAllListeners('newHead'); } - - /** - * Checks if the given provider is a socket provider - * - * @method isSocketConnection - * - * @param {WebsocketProvider|EthereumProvider|IpcProvider} provider - * - * @returns {Boolean} - */ - isSocketConnection(provider) { - return ( - provider instanceof WebsocketProvider || - provider instanceof IpcProvider || - provider instanceof EthereumProvider - ); - } } diff --git a/packages/web3-eth-contract/src/factories/MethodFactory.js b/packages/web3-eth-contract/src/factories/MethodFactory.js index dca9b4835a9..7116acbe93e 100644 --- a/packages/web3-eth-contract/src/factories/MethodFactory.js +++ b/packages/web3-eth-contract/src/factories/MethodFactory.js @@ -167,11 +167,15 @@ export default class MethodFactory { * @returns {ContractDeployMethod} */ createContractDeployMethod(contract) { + const transactionConfirmationWorkflow = this.methodModuleFactory.createTransactionConfirmationWorkflow(); + return new ContractDeployMethod( this.utils, this.formatters, - this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.createSendRawTransactionMethod(), + transactionConfirmationWorkflow, + new SendRawTransactionMethod(this.utils, this.formatters, transactionConfirmationWorkflow), + new ChainIdMethod(this.utils, this.formatters), + new GetTransactionCountMethod(this.utils, this.formatters), contract ); } diff --git a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js index 08f640fd3ee..27504f8e1e8 100644 --- a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js +++ b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js @@ -27,13 +27,30 @@ export default class ContractDeployMethod extends SendTransactionMethod { * @param {Utils} utils * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {AbstractContract} contract * @param {SendRawTransactionMethod} sendRawTransactionMethod + * @param {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod + * @param {AbstractContract} contract * * @constructor */ - constructor(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod, contract) { - super(utils, formatters, transactionConfirmationWorkflow, sendRawTransactionMethod); + constructor( + utils, + formatters, + transactionConfirmationWorkflow, + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod, + contract + ) { + super( + utils, + formatters, + transactionConfirmationWorkflow, + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod + ); this.contract = contract; } diff --git a/packages/web3-eth-contract/src/proxies/MethodsProxy.js b/packages/web3-eth-contract/src/proxies/MethodsProxy.js index 4abdb97fbf9..fbe7ce05db2 100644 --- a/packages/web3-eth-contract/src/proxies/MethodsProxy.js +++ b/packages/web3-eth-contract/src/proxies/MethodsProxy.js @@ -82,15 +82,21 @@ export default class MethodsProxy { // have I to check here if it is a contract deployment. If this call is a contract deployment // then I have to set the right contract data and to map the arguments. // TODO: Change API or improve this - if (!isArray(abiItemModel) && abiItemModel.isOfType('constructor')) { - if (methodArguments[0]['data']) { - target.contract.options.data = methodArguments[0]['data']; - } + if (name === 'contractConstructor') { + if (methodArguments[0]) { + if (methodArguments[0]['data']) { + target.contract.options.data = methodArguments[0]['data']; + } - if (methodArguments[0]['arguments']) { - abiItemModel.contractMethodParameters = methodArguments[0]['arguments']; + if (methodArguments[0]['arguments']) { + abiItemModel.contractMethodParameters = methodArguments[0]['arguments']; + } + + return anonymousFunction; } + abiItemModel.contractMethodParameters = []; + return anonymousFunction; } diff --git a/packages/web3-providers/package.json b/packages/web3-providers/package.json index cde7d5afea8..248edb3fee7 100644 --- a/packages/web3-providers/package.json +++ b/packages/web3-providers/package.json @@ -1,13 +1,39 @@ { - "dependencies": { - "@babel/runtime": "^7.3.1", - "@types/node": "^10.12.18", - "dtslint": "^0.4.2", - "eventemitter3": "3.1.0", - "lodash": "^4.17.11", - "oboe": "2.1.4", - "url-parse": "1.4.4", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", - "xhr2-cookies": "1.1.0" - } + "name": "web3-providers", + "namespace": "ethereum", + "version": "1.0.0-beta.46", + "description": "Web3 module to handle requests to external providers.", + "repository": "https://github.com/ethereum/web3.js/tree/1.0/packages/web3-providers", + "license": "LGPL-3.0", + "main": "dist/web3-providers.cjs.js", + "module": "dist/web3-providers.esm.js", + "browser": "dist/web3-providers.umd.js", + "scripts": { + "build": "rollup -c", + "dev": "rollup -c -w", + "test": "jest", + "dtslint": "dtslint types --onlyTestTsNext" + }, + "types": "types", + "dependencies": { + "@babel/runtime": "^7.3.1", + "@types/node": "^10.12.18", + "eventemitter3": "3.1.0", + "lodash": "^4.17.11", + "oboe": "2.1.4", + "url-parse": "1.4.4", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "xhr2-cookies": "1.1.0" + }, + "devDependencies": { + "dtslint": "^0.4.2", + "web3-core": "1.0.0-beta.46", + "web3-core-helpers": "1.0.0-beta.46", + "web3-core-method": "1.0.0-beta.46", + "web3-utils": "1.0.0-beta.46" + }, + "files": [ + "dist", + "types/index.d.ts" + ] } diff --git a/packages/web3-providers/src/resolvers/ProviderResolver.js b/packages/web3-providers/src/resolvers/ProviderResolver.js index e3c59523543..ec04e14ba8f 100644 --- a/packages/web3-providers/src/resolvers/ProviderResolver.js +++ b/packages/web3-providers/src/resolvers/ProviderResolver.js @@ -23,11 +23,10 @@ import isFunction from 'lodash/isFunction'; import isObject from 'lodash/isObject'; -const global = - (function() { - return this || (typeof self === 'object' && self); - // eslint-disable-next-line no-new-func - })() || new Function('return this')(); +const global = (function() { + return this || (typeof self === 'object' && self); + // eslint-disable-next-line no-new-func +})() || new Function('return this')(); export default class ProviderResolver { /** diff --git a/packages/web3/src/Web3.js b/packages/web3/src/Web3.js index ba50fefe9ae..5769728a3cc 100644 --- a/packages/web3/src/Web3.js +++ b/packages/web3/src/Web3.js @@ -43,9 +43,9 @@ export default class Web3 extends AbstractWeb3Module { constructor(provider, net, options = {}) { super(provider, new ProvidersModuleFactory(), null, null, options); - this.eth = new Eth(provider, options); - this.shh = new Shh(provider, options); - this.bzz = new Bzz(provider); + this.eth = new Eth(this.currentProvider, options); + this.shh = new Shh(this.currentProvider, options); + this.bzz = new Bzz(this.currentProvider); this.utils = Utils; this.version = version; } From 39de6eca3c4933f772ff8216e44806f60bb551df Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 10:46:47 +0100 Subject: [PATCH 63/71] workflow logic for local or remote signing fixed in SendTransactionMethod --- .../transaction/SendTransactionMethod.js | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index e0e245dc48c..970ea92c91d 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -89,16 +89,28 @@ export default class SendTransactionMethod extends AbstractSendMethod { this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if ( - (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) || - this.hasCustomSigner(moduleInstance) - ) { - let privateKey; + if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { if (moduleInstance.accounts.wallet[this.parameters[0].from]) { - privateKey = moduleInstance.accounts.wallet[this.parameters[0].from].privateKey; + this.sendRawTransaction( + moduleInstance.accounts.wallet[this.parameters[0].from].privateKey, + promiEvent, + moduleInstance + ).catch((error) => { + if (this.callback) { + this.callback(error, null); + } + + promiEvent.reject(error); + promiEvent.emit('error', error); + promiEvent.removeAllListeners(); + }); + + return promiEvent; } + } - this.sendRawTransaction(privateKey, promiEvent, moduleInstance).catch((error) => { + if (this.hasCustomSigner(moduleInstance)) { + this.sendRawTransaction(null, promiEvent, moduleInstance).catch((error) => { if (this.callback) { this.callback(error, null); } From 34481300390063f16de82df3aea658136d4350b8 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 12:03:24 +0100 Subject: [PATCH 64/71] core-method module fixed --- .../factories/AbstractMethodFactoryTest.js | 1 - .../transaction/SendTransactionMethodTest.js | 56 +++++++++++++------ .../tests/src/watchers/NewHeadsWatcherTest.js | 1 + .../web3-eth-accounts/src/models/Account.js | 6 +- .../src/resolvers/ProviderResolver.js | 9 +-- 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js index 35014f83d91..95450763563 100644 --- a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js +++ b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js @@ -65,7 +65,6 @@ describe('AbstractMethodFactoryTest', () => { expect(abstractMethodFactory.createMethod('sendTransaction')).toBeInstanceOf(SendTransactionMethod); expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); it('calls createMethod and returns SignMethod', () => { diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index 3d1a8b4d450..f24f9b958b2 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -3,10 +3,12 @@ import {PromiEvent} from 'web3-core-promievent'; import {WebsocketProvider} from 'web3-providers'; import {AbstractWeb3Module} from 'web3-core'; import * as Utils from 'web3-utils'; -import SendRawTransactionMethod from '../../../../src/methods/transaction/SendRawTransactionMethod'; import TransactionSigner from '../../../__mocks__/TransactionSigner'; import TransactionConfirmationWorkflow from '../../../../src/workflows/TransactionConfirmationWorkflow'; import AbstractSendMethod from '../../../../lib/methods/AbstractSendMethod'; +import SendRawTransactionMethod from '../../../../src/methods/transaction/SendRawTransactionMethod'; +import ChainIdMethod from '../../../../src/methods/network/ChainIdMethod'; +import GetTransactionCountMethod from '../../../../src/methods/account/GetTransactionCountMethod'; import SendTransactionMethod from '../../../../src/methods/transaction/SendTransactionMethod'; // Mocks @@ -16,6 +18,8 @@ jest.mock('WebsocketProvider'); jest.mock('AbstractWeb3Module'); jest.mock('../../../../src/workflows/TransactionConfirmationWorkflow'); jest.mock('../../../../src/methods/transaction/SendRawTransactionMethod'); +jest.mock('../../../../src/methods/network/ChainIdMethod'); +jest.mock('../../../../src/methods/account/GetTransactionCountMethod'); /** * SendTransactionMethod test @@ -27,32 +31,43 @@ describe('SendTransactionMethodTest', () => { promiEvent, transactionConfirmationWorkflowMock, transactionSignerMock, - sendRawTransactionMethodMock; + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock; beforeEach(() => { + promiEvent = new PromiEvent(); + new WebsocketProvider({}); providerMock = WebsocketProvider.mock.instances[0]; providerMock.send = jest.fn(); new AbstractWeb3Module(providerMock, {}, {}, {}); moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; + moduleInstanceMock.currentProvider = providerMock; transactionSignerMock = new TransactionSigner(); transactionSignerMock.sign = jest.fn(); - promiEvent = new PromiEvent(); - new TransactionConfirmationWorkflow({}, {}, {}); transactionConfirmationWorkflowMock = TransactionConfirmationWorkflow.mock.instances[0]; new SendRawTransactionMethod(); sendRawTransactionMethodMock = SendRawTransactionMethod.mock.instances[0]; + new GetTransactionCountMethod(); + getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; + + new ChainIdMethod(); + chainIdMethodMock = ChainIdMethod.mock.instances[0]; + method = new SendTransactionMethod( Utils, formatters, transactionConfirmationWorkflowMock, - sendRawTransactionMethodMock + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock ); method.callback = jest.fn(); @@ -66,6 +81,10 @@ describe('SendTransactionMethodTest', () => { expect(method.sendRawTransactionMethod).toEqual(sendRawTransactionMethodMock); + expect(method.chainIdMethod).toEqual(chainIdMethodMock); + + expect(method.getTransactionCountMethod).toEqual(getTransactionCountMethodMock); + expect(method).toBeInstanceOf(AbstractSendMethod); }); @@ -74,8 +93,7 @@ describe('SendTransactionMethodTest', () => { return Promise.resolve({rawTransaction: '0x0'}); }); - moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = transactionSignerMock; sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { @@ -121,9 +139,9 @@ describe('SendTransactionMethodTest', () => { const error = new Error('ERROR'); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = transactionSignerMock; - moduleInstanceMock.getChainId = jest.fn(() => { + chainIdMethodMock.execute = jest.fn(() => { throw error; }); @@ -147,7 +165,7 @@ describe('SendTransactionMethodTest', () => { await expect(method.execute(moduleInstanceMock, promiEvent)).rejects.toThrow('ERROR'); - expect(moduleInstanceMock.getChainId).toHaveBeenCalledWith(); + expect(chainIdMethodMock.execute).toHaveBeenCalled(); }); it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { @@ -191,7 +209,7 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); @@ -206,12 +224,12 @@ describe('SendTransactionMethodTest', () => { return Promise.resolve({rawTransaction: '0x0'}); }); - moduleInstanceMock.getChainId = jest.fn(() => { + chainIdMethodMock.execute = jest.fn(() => { return Promise.resolve(1); }); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.accounts = {wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; moduleInstanceMock.transactionSigner = customSigner; sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { @@ -244,7 +262,7 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); @@ -252,7 +270,7 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); - expect(moduleInstanceMock.getChainId).toHaveBeenCalled(); + expect(chainIdMethodMock.execute).toHaveBeenCalled(); }); it('calls execute signs locally but doesnt have an nonce defined and returns with a resolved promise', async () => { @@ -261,7 +279,7 @@ describe('SendTransactionMethodTest', () => { return Promise.resolve({rawTransaction: '0x0'}); }); - moduleInstanceMock.getTransactionCount = jest.fn(() => { + getTransactionCountMethodMock.execute = jest.fn(() => { return Promise.resolve(1); }); @@ -295,7 +313,7 @@ describe('SendTransactionMethodTest', () => { chainId: 1 }; - expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, undefined); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); @@ -303,7 +321,9 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); - expect(moduleInstanceMock.getTransactionCount).toHaveBeenCalledWith(0); + expect(getTransactionCountMethodMock.parameters).toEqual([method.parameters[0].from]) + + expect(getTransactionCountMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock); }); it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', (done) => { diff --git a/packages/web3-core-method/tests/src/watchers/NewHeadsWatcherTest.js b/packages/web3-core-method/tests/src/watchers/NewHeadsWatcherTest.js index 2dfc251b114..da8c0ed2919 100644 --- a/packages/web3-core-method/tests/src/watchers/NewHeadsWatcherTest.js +++ b/packages/web3-core-method/tests/src/watchers/NewHeadsWatcherTest.js @@ -46,6 +46,7 @@ describe('NewHeadsWatcherTest', () => { new AbstractWeb3Module(providerMock, {}, {}, {}); moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; + moduleInstanceMock.currentProvider = providerMock; const newHeadsWatcherObject = newHeadsWatcher.watch(moduleInstanceMock); diff --git a/packages/web3-eth-accounts/src/models/Account.js b/packages/web3-eth-accounts/src/models/Account.js index 7b8c4fdd332..5750ba2c12e 100644 --- a/packages/web3-eth-accounts/src/models/Account.js +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -114,11 +114,11 @@ export default class Account { * @returns {Account} */ static from(entropy, accounts = {}) { - return new Account(create(entropy || randomHex(32)), accounts['transactionSigner']); + return new Account(create(entropy || randomHex(32)), accounts.transactionSigner); } /** - * This static method gived us the possibility to create a Account object from a private key. + * This static method gives us the possibility to create a Account object from a private key. * * @param {String} privateKey * @param {Accounts} accounts @@ -126,7 +126,7 @@ export default class Account { * @returns {Account} */ static fromPrivateKey(privateKey, accounts = {}) { - return new Account(fromPrivate(privateKey), accounts['transactionSigner']); + return new Account(fromPrivate(privateKey), accounts.transactionSigner); } /** diff --git a/packages/web3-providers/src/resolvers/ProviderResolver.js b/packages/web3-providers/src/resolvers/ProviderResolver.js index ec04e14ba8f..e3c59523543 100644 --- a/packages/web3-providers/src/resolvers/ProviderResolver.js +++ b/packages/web3-providers/src/resolvers/ProviderResolver.js @@ -23,10 +23,11 @@ import isFunction from 'lodash/isFunction'; import isObject from 'lodash/isObject'; -const global = (function() { - return this || (typeof self === 'object' && self); - // eslint-disable-next-line no-new-func -})() || new Function('return this')(); +const global = + (function() { + return this || (typeof self === 'object' && self); + // eslint-disable-next-line no-new-func + })() || new Function('return this')(); export default class ProviderResolver { /** From 06dea033e66ff7a7febf6fa8c4f791ac126926cb Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 12:25:55 +0100 Subject: [PATCH 65/71] eth-contract module tests fixed --- .../tests/src/proxy/MethodProxyTest.js | 8 ++-- packages/web3-eth-contract/jest.config.js | 3 ++ .../tests/src/factories/MethodFactoryTest.js | 5 --- .../src/methods/ContractDeployMethodTest.js | 40 +++++++++++++------ .../src/methods/SendContractMethodTest.js | 31 ++++++++++++-- .../tests/src/proxies/MethodsProxyTest.js | 6 +-- 6 files changed, 66 insertions(+), 27 deletions(-) diff --git a/packages/web3-core-method/tests/src/proxy/MethodProxyTest.js b/packages/web3-core-method/tests/src/proxy/MethodProxyTest.js index 2c15fdc5bc3..674aa6f0c6a 100644 --- a/packages/web3-core-method/tests/src/proxy/MethodProxyTest.js +++ b/packages/web3-core-method/tests/src/proxy/MethodProxyTest.js @@ -27,7 +27,7 @@ describe('MethodProxyTest', () => { methodMock = AbstractMethod.mock.instances[0]; }); - it('methodProxy return property from target', () => { + it('returns a property from the target object', () => { moduleInstanceMock.defaultGasPrice = 100; methodFactoryMock.hasMethod.mockReturnValueOnce(false); @@ -39,7 +39,7 @@ describe('MethodProxyTest', () => { expect(methodFactoryMock.hasMethod).toHaveBeenCalledWith('defaultGasPrice'); }); - it('methodProxy throws error because the property is defined on the target and as method', () => { + it('throws an error because the property is defined on the target and as method', () => { moduleInstanceMock.myMethod = 100; methodFactoryMock.hasMethod.mockReturnValueOnce(true); @@ -59,7 +59,7 @@ describe('MethodProxyTest', () => { } }); - it('the methodProxy executes the AbstractCallMethod myMethod and it returns the expected value', () => { + it('executes the AbstractCallMethod myMethod and it returns the expected value', () => { methodMock.parameters = []; methodMock.parametersAmount = 0; @@ -107,7 +107,7 @@ describe('MethodProxyTest', () => { expect(methodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, PromiEvent.mock.instances[0]); }); - it('methodProxy throws error because of invalid parameter length', () => { + it('throws an error because of an invalid parameter length', () => { methodMock.parameters = []; methodMock.parametersAmount = 2; diff --git a/packages/web3-eth-contract/jest.config.js b/packages/web3-eth-contract/jest.config.js index c1f273b635a..23c23d5b4fb 100644 --- a/packages/web3-eth-contract/jest.config.js +++ b/packages/web3-eth-contract/jest.config.js @@ -6,6 +6,9 @@ module.exports = jestConfig({ 'MethodModuleFactory': 'web3-core-method', 'EstimateGasMethod': 'web3-core-method', 'GetPastLogsMethod': 'web3-core-method', + 'SendRawTransactionMethod': 'web3-core-method', + 'ChainIdMethod': 'web3-core-method', + 'GetTransactionCountMethod': 'web3-core-method', 'Accounts': 'web3-eth-accounts', 'HttpProvider': 'web3-providers', 'ProvidersModuleFactory': 'web3-providers', diff --git a/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js b/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js index 9d915ba7626..e2e63da9faa 100644 --- a/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js +++ b/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js @@ -35,7 +35,6 @@ describe('MethodFactoryTest', () => { new MethodModuleFactory(); methodModuleFactoryMock = MethodModuleFactory.mock.instances[0]; methodModuleFactoryMock.createTransactionConfirmationWorkflow = jest.fn(); - methodModuleFactoryMock.createSendRawTransactionMethod = jest.fn(); new ContractModuleFactory({}, {}, {}, {}, {}); contractModuleFactoryMock = ContractModuleFactory.mock.instances[0]; @@ -108,16 +107,12 @@ describe('MethodFactoryTest', () => { expect(contractModuleFactoryMock.createAllEventsLogDecoder).toHaveBeenCalled(); expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - - expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); it('calls createContractDeployMethod and returns ContractDeployMethod object', () => { expect(methodFactory.createContractDeployMethod({})).toBeInstanceOf(ContractDeployMethod); expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - - expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); it('calls createEstimateGasMethod and returns EstimateGasMethod object', () => { diff --git a/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js index f82e7bae6eb..9c334483e8e 100644 --- a/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js @@ -1,6 +1,11 @@ import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {SendTransactionMethod} from 'web3-core-method'; +import { + ChainIdMethod, + GetTransactionCountMethod, + SendRawTransactionMethod, + SendTransactionMethod +} from 'web3-core-method'; import TransactionConfirmationWorkflow from '../../__mocks__/TransactionConfirmationWorkflow'; import AbstractContract from '../../../src/AbstractContract'; import ContractDeployMethod from '../../../src/methods/ContractDeployMethod'; @@ -8,49 +13,60 @@ import ContractDeployMethod from '../../../src/methods/ContractDeployMethod'; // Mocks jest.mock('Utils'); jest.mock('formatters'); +jest.mock('SendRawTransactionMethod'); +jest.mock('ChainIdMethod'); +jest.mock('GetTransactionCountMethod'); jest.mock('../../../src/AbstractContract'); /** * ContractDeployMethod test */ describe('ContractDeployMethodTest', () => { - let contractDeployMethod, transactionConfirmationWorkflowMock, contractMock; + let contractDeployMethod, + transactionConfirmationWorkflowMock, + contractMock, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock; beforeEach(() => { new AbstractContract(); contractMock = AbstractContract.mock.instances[0]; + new SendRawTransactionMethod(); + sendRawTransactionMethodMock = SendRawTransactionMethod.mock.instances[0]; + + new ChainIdMethod(); + chainIdMethodMock = ChainIdMethod.mock.instances[0]; + + new GetTransactionCountMethod(); + getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; + transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); contractDeployMethod = new ContractDeployMethod( Utils, formatters, transactionConfirmationWorkflowMock, - {}, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock, contractMock ); }); it('constructor check', () => { - expect(contractDeployMethod.transactionConfirmationWorkflow).toEqual(transactionConfirmationWorkflowMock); - - expect(contractDeployMethod.sendRawTransactionMethod).toEqual({}); - expect(contractDeployMethod.contract).toEqual(contractMock); expect(contractDeployMethod).toBeInstanceOf(SendTransactionMethod); }); it('calls beforeExecution and removes the to property from the options', () => { - contractDeployMethod.arguments = [{to: true}]; - - formatters.inputTransactionFormatter.mockReturnValueOnce({}); + contractDeployMethod.parameters = [{to: true}]; contractDeployMethod.beforeExecution(contractMock); expect(contractDeployMethod.parameters[0].to).toBeUndefined(); - - expect(formatters.inputTransactionFormatter).toHaveBeenCalled(); }); it('calls afterExecution and returns the cloned contract object', () => { diff --git a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js index 4b513c14363..dc3482cf45a 100644 --- a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js @@ -1,6 +1,11 @@ +import { + SendTransactionMethod, + SendRawTransactionMethod, + ChainIdMethod, + GetTransactionCountMethod +} from 'web3-core-method'; import * as Utils from 'web3-utils'; import {formatters} from 'web3-core-helpers'; -import {SendTransactionMethod} from 'web3-core-method'; import TransactionConfirmationWorkflow from '../../__mocks__/TransactionConfirmationWorkflow'; import AllEventsLogDecoder from '../../../src/decoders/AllEventsLogDecoder'; import AbiModel from '../../../src/models/AbiModel'; @@ -10,6 +15,9 @@ import SendContractMethod from '../../../src/methods/SendContractMethod'; jest.mock('Utils'); jest.mock('formatters'); jest.mock('Accounts'); +jest.mock('SendRawTransactionMethod'); +jest.mock('ChainIdMethod'); +jest.mock('GetTransactionCountMethod'); jest.mock('../../../src/decoders/AllEventsLogDecoder'); jest.mock('../../../src/models/AbiItemModel'); jest.mock('../../../src/models/AbiModel'); @@ -18,7 +26,13 @@ jest.mock('../../../src/models/AbiModel'); * SendContractMethod test */ describe('SendContractMethodTest', () => { - let sendContractMethod, transactionConfirmationWorkflowMock, allEventsLogDecoderMock, abiModelMock; + let sendContractMethod, + transactionConfirmationWorkflowMock, + allEventsLogDecoderMock, + abiModelMock, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock; beforeEach(() => { transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); @@ -29,11 +43,22 @@ describe('SendContractMethodTest', () => { new AllEventsLogDecoder(); allEventsLogDecoderMock = AllEventsLogDecoder.mock.instances[0]; + new SendRawTransactionMethod(); + sendRawTransactionMethodMock = SendRawTransactionMethod.mock.instances[0]; + + new ChainIdMethod(); + chainIdMethodMock = ChainIdMethod.mock.instances[0]; + + new GetTransactionCountMethod(); + getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; + sendContractMethod = new SendContractMethod( Utils, formatters, transactionConfirmationWorkflowMock, - {}, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock, allEventsLogDecoderMock, abiModelMock ); diff --git a/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js b/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js index 082db745279..e7ca73b1798 100644 --- a/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js +++ b/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js @@ -161,13 +161,13 @@ describe('MethodsProxyTest', () => { methodOptionsMapperMock.map.mockReturnValueOnce({options: true}); - await expect(methodsProxy.myMethod({arguments: [true], data: '0x0'}).send({options: false})).resolves.toEqual( + await expect(methodsProxy.contractConstructor({arguments: [true], data: '0x0'}).send({options: false})).resolves.toEqual( true ); - expect(abiModelMock.hasMethod).toHaveBeenCalledWith('myMethod'); + expect(abiModelMock.hasMethod).toHaveBeenCalledWith('contractConstructor'); - expect(abiModelMock.getMethod).toHaveBeenCalledWith('myMethod'); + expect(abiModelMock.getMethod).toHaveBeenCalledWith('contractConstructor'); expect(abiItemModelMock.isOfType).toHaveBeenCalledWith('constructor'); From 304517ca34f59705496a0519eed0bfff20aac509 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 12:53:04 +0100 Subject: [PATCH 66/71] SignMethod updated --- .../src/methods/SignMethod.js | 55 +++++++++++++++++-- .../tests/src/methods/SignMethodTest.js | 3 +- .../transaction/SendTransactionMethodTest.js | 2 +- .../tests/src/proxies/MethodsProxyTest.js | 6 +- 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index c469f92fa8a..42f71429df5 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -45,10 +45,14 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Promise} */ execute(moduleInstance) { - if (moduleInstance.accounts && moduleInstance.accounts.wallet[this.parameters[1]]) { - this.beforeExecution(moduleInstance); + if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { + if (moduleInstance.accounts.wallet[this.parameters[0].from]) { + return this.signLocally(moduleInstance); + } + } - return this.signOnClient(moduleInstance); + if (this.hasCustomSigner(moduleInstance)) { + return this.signLocally(moduleInstance); } return super.execute(moduleInstance); @@ -57,14 +61,16 @@ export default class SignMethod extends AbstractCallMethod { /** * Signs the message on the client. * - * @method signOnClient + * @method signLocally * * @param {AbstractWeb3Module} moduleInstance * * @returns {Promise} */ - async signOnClient(moduleInstance) { + async signLocally(moduleInstance) { try { + this.beforeExecution(moduleInstance); + let signedMessage = moduleInstance.accounts.sign( this.parameters[0], moduleInstance.accounts.wallet[this.parameters[1]].privateKey @@ -95,4 +101,43 @@ export default class SignMethod extends AbstractCallMethod { this.parameters[0] = this.formatters.inputSignFormatter(this.parameters[0]); this.parameters[1] = this.formatters.inputAddressFormatter(this.parameters[1]); } + + /** + * Checks if the current module has decrypted accounts + * + * @method isDefaultSigner + * + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ + isDefaultSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; + } + + /** + * Checks if the current module has decrypted accounts + * + * @method hasAccounts + * + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ + hasAccounts(moduleInstance) { + return moduleInstance.accounts && moduleInstance.accounts.accountsIndex > 0; + } + + /** + * Checks if a custom signer is given. + * + * @method hasCustomerSigner + * + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ + hasCustomSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner'; + } } diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index b9f893fa0ed..4fe91f2d254 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -26,6 +26,7 @@ describe('SignMethodTest', () => { accountsMock = new Accounts(); accountsMock.sign = jest.fn(); accountsMock.wallet = {'0x0': {privateKey: '0x0'}}; + accountsMock.accountsIndex = 1; new AbstractWeb3Module(providerMock, {}, {}, {}); moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; @@ -94,7 +95,7 @@ describe('SignMethodTest', () => { }); it('calls execute and the account does not exist in the eth-accounts wallet', async () => { - moduleInstanceMock.accounts = false; + accountsMock.wallet = {'nope': {privateKey: '0x0'}}; formatters.inputSignFormatter.mockReturnValueOnce('string'); diff --git a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js index f24f9b958b2..d013b1296c4 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -321,7 +321,7 @@ describe('SendTransactionMethodTest', () => { expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); - expect(getTransactionCountMethodMock.parameters).toEqual([method.parameters[0].from]) + expect(getTransactionCountMethodMock.parameters).toEqual([method.parameters[0].from]); expect(getTransactionCountMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock); }); diff --git a/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js b/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js index e7ca73b1798..892de30dba1 100644 --- a/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js +++ b/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js @@ -161,9 +161,9 @@ describe('MethodsProxyTest', () => { methodOptionsMapperMock.map.mockReturnValueOnce({options: true}); - await expect(methodsProxy.contractConstructor({arguments: [true], data: '0x0'}).send({options: false})).resolves.toEqual( - true - ); + await expect( + methodsProxy.contractConstructor({arguments: [true], data: '0x0'}).send({options: false}) + ).resolves.toEqual(true); expect(abiModelMock.hasMethod).toHaveBeenCalledWith('contractConstructor'); From faf074363ba56856fca0958e0858854230e16c4a Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 13:17:50 +0100 Subject: [PATCH 67/71] SignMethod updated --- .../src/methods/SignMethod.js | 46 ++++--------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 42f71429df5..d1cf7f61391 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -45,14 +45,8 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Promise} */ execute(moduleInstance) { - if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { - if (moduleInstance.accounts.wallet[this.parameters[0].from]) { + if (this.hasAccount(moduleInstance)) { return this.signLocally(moduleInstance); - } - } - - if (this.hasCustomSigner(moduleInstance)) { - return this.signLocally(moduleInstance); } return super.execute(moduleInstance); @@ -73,7 +67,7 @@ export default class SignMethod extends AbstractCallMethod { let signedMessage = moduleInstance.accounts.sign( this.parameters[0], - moduleInstance.accounts.wallet[this.parameters[1]].privateKey + moduleInstance.accounts.wallet[this.parameters[0].from] ); if (this.callback) { @@ -103,41 +97,17 @@ export default class SignMethod extends AbstractCallMethod { } /** - * Checks if the current module has decrypted accounts - * - * @method isDefaultSigner - * - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Boolean} - */ - isDefaultSigner(moduleInstance) { - return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; - } - - /** - * Checks if the current module has decrypted accounts - * - * @method hasAccounts - * - * @param {AbstractWeb3Module} moduleInstance - * - * @returns {Boolean} - */ - hasAccounts(moduleInstance) { - return moduleInstance.accounts && moduleInstance.accounts.accountsIndex > 0; - } - - /** - * Checks if a custom signer is given. + * Checks if the current account is unlocked * - * @method hasCustomerSigner + * @method hasAccount * * @param {AbstractWeb3Module} moduleInstance * * @returns {Boolean} */ - hasCustomSigner(moduleInstance) { - return moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner'; + hasAccount(moduleInstance) { + return moduleInstance.accounts && + moduleInstance.accounts.accountsIndex > 0 && + moduleInstance.accounts.wallet[this.parameters[1]]; } } From 2ed7046b1b041fdad7a39f866d7b5f83f42b5771 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 13:21:43 +0100 Subject: [PATCH 68/71] SignMethod and SignMethodTest fixed --- packages/web3-core-method/src/methods/SignMethod.js | 8 ++++---- .../web3-core-method/tests/src/methods/SignMethodTest.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index d1cf7f61391..030e4ec849f 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -46,7 +46,7 @@ export default class SignMethod extends AbstractCallMethod { */ execute(moduleInstance) { if (this.hasAccount(moduleInstance)) { - return this.signLocally(moduleInstance); + return this.signLocally(moduleInstance); } return super.execute(moduleInstance); @@ -67,7 +67,7 @@ export default class SignMethod extends AbstractCallMethod { let signedMessage = moduleInstance.accounts.sign( this.parameters[0], - moduleInstance.accounts.wallet[this.parameters[0].from] + moduleInstance.accounts.wallet[this.parameters[1]].address ); if (this.callback) { @@ -107,7 +107,7 @@ export default class SignMethod extends AbstractCallMethod { */ hasAccount(moduleInstance) { return moduleInstance.accounts && - moduleInstance.accounts.accountsIndex > 0 && - moduleInstance.accounts.wallet[this.parameters[1]]; + moduleInstance.accounts.accountsIndex > 0 && + moduleInstance.accounts.wallet[this.parameters[1]]; } } diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index 4fe91f2d254..9062917f562 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -25,7 +25,7 @@ describe('SignMethodTest', () => { accountsMock = new Accounts(); accountsMock.sign = jest.fn(); - accountsMock.wallet = {'0x0': {privateKey: '0x0'}}; + accountsMock.wallet = {'0x0': {privateKey: '0x0', address: '0x0'}}; accountsMock.accountsIndex = 1; new AbstractWeb3Module(providerMock, {}, {}, {}); From 13c68573c9c39bbc468d630b4db537d3e7ea1b73 Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 13:59:59 +0100 Subject: [PATCH 69/71] documentation updated --- docs/include_package-core.rst | 48 ++++++++++++++++++- .../src/methods/SignMethod.js | 6 ++- .../tests/src/methods/SignMethodTest.js | 2 +- .../web3-eth-contract/src/AbstractContract.js | 1 - .../web3-eth/src/signers/TransactionSigner.js | 8 ++++ 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/docs/include_package-core.rst b/docs/include_package-core.rst index aa92cb21269..ae0008471aa 100644 --- a/docs/include_package-core.rst +++ b/docs/include_package-core.rst @@ -1,4 +1,3 @@ - options ===================== @@ -23,6 +22,8 @@ Module Options :ref:`transactionPollingTimeout ` +:ref:`transactionPollingTimeout ` + ------- Example ------- @@ -38,7 +39,8 @@ Example defaultGasPrice: 0, transactionBlockTimeout: 50, transactionConfirmationBlocks: 24, - transactionPollingTimeout: 480 + transactionPollingTimeout: 480, + transactionSigner: new CustomTransactionSigner() } const web3 = new Web3('http://localhost:8545', options); @@ -207,6 +209,48 @@ Returns ------------------------------------------------------------------------------ + +.. _web3-module-transactionSigner: + +transactionSigner +================= + +.. code-block:: javascript + + web3.eth.transactionSigner + ... + + + +The ``transactionSigner`` property does provide us the possibility to customize the signing process +of the ``Eth`` module and the related sub-modules. + +The interface of a ``TransactionSigner``: + +.. code-block:: javascript + + interface TransactionSigner { + sign(txObject: Transaction): Promise + } + + interface SignedTransaction { + messageHash: string, + v: string, + r: string, + s: string, + rawTransaction: string + } + + + +------- +Returns +------- + +``TransactionSigner``: A JavaScript class of type TransactionSigner. + +------------------------------------------------------------------------------ + setProvider ===================== diff --git a/packages/web3-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 030e4ec849f..e995e34bd74 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -106,8 +106,10 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Boolean} */ hasAccount(moduleInstance) { - return moduleInstance.accounts && + return ( + moduleInstance.accounts && moduleInstance.accounts.accountsIndex > 0 && - moduleInstance.accounts.wallet[this.parameters[1]]; + moduleInstance.accounts.wallet[this.parameters[1]] + ); } } diff --git a/packages/web3-core-method/tests/src/methods/SignMethodTest.js b/packages/web3-core-method/tests/src/methods/SignMethodTest.js index 9062917f562..5ded4ff31c6 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -95,7 +95,7 @@ describe('SignMethodTest', () => { }); it('calls execute and the account does not exist in the eth-accounts wallet', async () => { - accountsMock.wallet = {'nope': {privateKey: '0x0'}}; + accountsMock.wallet = {nope: {privateKey: '0x0'}}; formatters.inputSignFormatter.mockReturnValueOnce('string'); diff --git a/packages/web3-eth-contract/src/AbstractContract.js b/packages/web3-eth-contract/src/AbstractContract.js index 3a5134c477d..d9fe0a06eb8 100644 --- a/packages/web3-eth-contract/src/AbstractContract.js +++ b/packages/web3-eth-contract/src/AbstractContract.js @@ -65,7 +65,6 @@ export default class AbstractContract extends AbstractWeb3Module { this.methodFactory = this.contractModuleFactory.createMethodFactory(); this.abiModel = this.abiMapper.map(abi); this.transactionSigner = options.transactionSigner; - this.options = options; if (address) { this.address = address; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index 1a9ece22506..da7a057cfb1 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -43,6 +43,14 @@ export default class TransactionSigner { * @returns {Promise<{messageHash, v, r, s, rawTransaction}>} */ async sign(transaction, privateKey) { + if (!privateKey) { + throw new Error('No privateKey given to the TransactionSigner.'); + } + + if (!privateKey.startsWith('0x')) { + privateKey = privateKey.substring(2); + } + transaction = this.formatters.txInputFormatter(transaction); transaction.to = transaction.to || '0x'; transaction.data = transaction.data || '0x'; From 5f4b9699fb8cadcf527437d88a8966d0cb72aacd Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 14:12:09 +0100 Subject: [PATCH 70/71] Accounts method hashMessage readded --- packages/web3-eth-accounts/src/Accounts.js | 33 +++++++++++++++------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/web3-eth-accounts/src/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index 43e6b58038a..73df0030a36 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -334,6 +334,28 @@ export default class Accounts extends AbstractWeb3Module { return Account.fromPrivateKey(privateKey, this); } + /** + * Hashes a given message + * + * @method hashMessage + * + * @param {String} data + * + * @returns {String} + */ + hashMessage(data) { + if (isHexStrict(data)) { + data = hexToBytes(data); + } + + const messageBuffer = Buffer.from(data); + const preamble = `\u0019Ethereum Signed Message:\n${data.length}`; + const preambleBuffer = Buffer.from(preamble); + const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); + + return Hash.keccak256s(ethMessage); + } + /** * TODO: Add deprecation message and extend the signTransaction method in the eth module * @@ -439,16 +461,7 @@ export default class Accounts extends AbstractWeb3Module { } if (!preFixed) { - if (isHexStrict(message)) { - message = hexToBytes(message); - } - - const messageBuffer = Buffer.from(message); - const preamble = `\u0019Ethereum Signed Message:\n${message.length}`; - const preambleBuffer = Buffer.from(preamble); - const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]); - - message = Hash.keccak256s(ethMessage); + message = this.hashMessage(message); } if (args.length >= 4) { From 13eb73d5a0a30ba1aba27b27a4487d32f1bd885e Mon Sep 17 00:00:00 2001 From: Samuel Furter Date: Wed, 27 Feb 2019 14:47:42 +0100 Subject: [PATCH 71/71] privatKey check in TransactionSigner fixed and link in documentation updated --- docs/include_package-core.rst | 2 +- packages/web3-eth/src/signers/TransactionSigner.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/include_package-core.rst b/docs/include_package-core.rst index ae0008471aa..68d329a5e17 100644 --- a/docs/include_package-core.rst +++ b/docs/include_package-core.rst @@ -22,7 +22,7 @@ Module Options :ref:`transactionPollingTimeout ` -:ref:`transactionPollingTimeout ` +:ref:`transactionSigner ` ------- Example diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js index da7a057cfb1..4409d2900a0 100644 --- a/packages/web3-eth/src/signers/TransactionSigner.js +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -47,7 +47,7 @@ export default class TransactionSigner { throw new Error('No privateKey given to the TransactionSigner.'); } - if (!privateKey.startsWith('0x')) { + if (privateKey.startsWith('0x')) { privateKey = privateKey.substring(2); }