diff --git a/docs/include_package-core.rst b/docs/include_package-core.rst index aa92cb21269..68d329a5e17 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:`transactionSigner ` + ------- 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/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 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 29a1804cabf..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 @@ -89,25 +93,18 @@ 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') { + const transactionConfirmationWorkflow = this.methodModuleFactory.createTransactionConfirmationWorkflow(); + return new method( this.utils, this.formatters, - this.methodModuleFactory.createTransactionConfirmationWorkflow(), - this.methodModuleFactory.accounts, - this.methodModuleFactory.createTransactionSigner(), - 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/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-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/factories/ModuleFactory.js b/packages/web3-core-method/src/factories/ModuleFactory.js index e51fefa17af..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,28 +55,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 - * - * @method createMessageSigner - * - * @returns {MessageSigner} - */ - createMessageSigner() { - return new MessageSigner(this.accounts); - } - /** * Returns the TransactionConfirmationWorkflow object * @@ -97,6 +71,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/index.js b/packages/web3-core-method/src/index.js index 184245e78a1..b50db0f8497 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'; @@ -49,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-core-method/src/methods/SignMethod.js b/packages/web3-core-method/src/methods/SignMethod.js index 46a5cb6b816..e995e34bd74 100644 --- a/packages/web3-core-method/src/methods/SignMethod.js +++ b/packages/web3-core-method/src/methods/SignMethod.js @@ -22,19 +22,16 @@ import AbstractCallMethod from '../../lib/methods/AbstractCallMethod'; +// TODO: Move local signing logic to the eth module 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,8 @@ export default class SignMethod extends AbstractCallMethod { * @returns {Promise} */ execute(moduleInstance) { - if (this.hasWallets()) { - this.beforeExecution(moduleInstance); - - return this.signOnClient(); + if (this.hasAccount(moduleInstance)) { + return this.signLocally(moduleInstance); } return super.execute(moduleInstance); @@ -60,15 +55,26 @@ export default class SignMethod extends AbstractCallMethod { /** * Signs the message on the client. * - * @method signOnClient + * @method signLocally + * + * @param {AbstractWeb3Module} moduleInstance * * @returns {Promise} */ - signOnClient() { - let signedMessage; - + async signLocally(moduleInstance) { try { - signedMessage = this.afterExecution(this.messageSigner.sign(this.parameters[0], this.parameters[1])); + this.beforeExecution(moduleInstance); + + let signedMessage = moduleInstance.accounts.sign( + this.parameters[0], + moduleInstance.accounts.wallet[this.parameters[1]].address + ); + + if (this.callback) { + this.callback(false, signedMessage); + } + + return signedMessage; } catch (error) { if (this.callback) { this.callback(error, null); @@ -76,12 +82,6 @@ export default class SignMethod extends AbstractCallMethod { throw error; } - - if (this.callback) { - this.callback(false, signedMessage); - } - - return Promise.resolve(signedMessage); } /** @@ -95,4 +95,21 @@ 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 account is unlocked + * + * @method hasAccount + * + * @param {AbstractWeb3Module} moduleInstance + * + * @returns {Boolean} + */ + hasAccount(moduleInstance) { + return ( + moduleInstance.accounts && + moduleInstance.accounts.accountsIndex > 0 && + moduleInstance.accounts.wallet[this.parameters[1]] + ); + } } diff --git a/packages/web3-eth-accounts/src/factories/MethodFactory.js b/packages/web3-core-method/src/methods/network/ChainIdMethod.js similarity index 61% rename from packages/web3-eth-accounts/src/factories/MethodFactory.js rename to packages/web3-core-method/src/methods/network/ChainIdMethod.js index 9696af2e8ab..d2a972defbe 100644 --- a/packages/web3-eth-accounts/src/factories/MethodFactory.js +++ b/packages/web3-core-method/src/methods/network/ChainIdMethod.js @@ -15,28 +15,34 @@ along with web3.js. If not, see . */ /** - * @file MethodFactory.js + * @file ListeningMethod.js * @author Samuel Furter * @date 2018 */ -import {AbstractMethodFactory, GetGasPriceMethod, GetTransactionCountMethod, VersionMethod} from 'web3-core-method'; +import AbstractCallMethod from '../../../lib/methods/AbstractCallMethod'; -export default class MethodFactory extends AbstractMethodFactory { +export default class ChainIdMethod extends AbstractCallMethod { /** - * @param {MethodModuleFactory} methodModuleFactory * @param {Utils} utils * @param {Object} formatters * * @constructor */ - constructor(methodModuleFactory, utils, formatters) { - super(methodModuleFactory, utils, formatters); + constructor(utils, formatters) { + super('eth_chainId', 0, utils, formatters); + } - this.methods = { - getGasPrice: GetGasPriceMethod, - getTransactionCount: GetTransactionCountMethod, - getId: VersionMethod - }; + /** + * 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/src/methods/transaction/SendTransactionMethod.js b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js index 455bfed04d3..970ea92c91d 100644 --- a/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js +++ b/packages/web3-core-method/src/methods/transaction/SendTransactionMethod.js @@ -20,18 +20,17 @@ * @date 2018 */ -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 * @param {Object} formatters * @param {TransactionConfirmationWorkflow} transactionConfirmationWorkflow - * @param {Accounts} accounts - * @param {TransactionSigner} transactionSigner * @param {SendRawTransactionMethod} sendRawTransactionMethod + * @param {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod * * @constructor */ @@ -39,14 +38,14 @@ export default class SendTransactionMethod extends AbstractSendMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, - sendRawTransactionMethod + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod ) { super('eth_sendTransaction', 1, utils, formatters, transactionConfirmationWorkflow); - this.accounts = accounts; - this.transactionSigner = transactionSigner; this.sendRawTransactionMethod = sendRawTransactionMethod; + this.chainIdMethod = chainIdMethod; + this.getTransactionCountMethod = getTransactionCountMethod; } /** @@ -65,40 +64,38 @@ export default class SendTransactionMethod extends AbstractSendMethod { * * @method execute * - * @param {AbstractWeb3Module} moduleInstance + * @param {Eth} moduleInstance * @param {PromiEvent} promiEvent * * @callback callback callback(error, result) * @returns {PromiEvent} */ execute(moduleInstance, promiEvent) { - if (!this.isGasLimitDefined()) { - if (this.hasDefaultGasLimit(moduleInstance)) { - this.parameters[0]['gas'] = moduleInstance.defaultGas; - } + if (!this.parameters[0].gas && moduleInstance.defaultGas) { + this.parameters[0]['gas'] = moduleInstance.defaultGas; } - if (!this.isGasPriceDefined() && this.hasDefaultGasPrice(moduleInstance)) { - this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; - } + if (!this.parameters[0].gasPrice) { + if (!moduleInstance.defaultGasPrice) { + moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { + this.parameters[0].gasPrice = gasPrice; - if (!this.isGasPriceDefined() && !this.hasDefaultGasPrice(moduleInstance)) { - moduleInstance.currentProvider.send('eth_gasPrice', []).then((gasPrice) => { - this.parameters[0]['gasPrice'] = gasPrice; - this.execute(moduleInstance, promiEvent); - }); + this.execute(moduleInstance, promiEvent); + }); - return promiEvent; + return promiEvent; + } + + this.parameters[0]['gasPrice'] = moduleInstance.defaultGasPrice; } - if (this.hasWallets()) { - this.transactionSigner - .sign(this.parameters[0]) - .then((response) => { - this.sendRawTransactionMethod.parameters = [response.rawTransaction]; - this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); - }) - .catch((error) => { + if (this.hasAccounts(moduleInstance) && this.isDefaultSigner(moduleInstance)) { + if (moduleInstance.accounts.wallet[this.parameters[0].from]) { + this.sendRawTransaction( + moduleInstance.accounts.wallet[this.parameters[0].from].privateKey, + promiEvent, + moduleInstance + ).catch((error) => { if (this.callback) { this.callback(error, null); } @@ -108,6 +105,21 @@ export default class SendTransactionMethod extends AbstractSendMethod { promiEvent.removeAllListeners(); }); + return promiEvent; + } + } + + if (this.hasCustomSigner(moduleInstance)) { + this.sendRawTransaction(null, promiEvent, moduleInstance).catch((error) => { + if (this.callback) { + this.callback(error, null); + } + + promiEvent.reject(error); + promiEvent.emit('error', error); + promiEvent.removeAllListeners(); + }); + return promiEvent; } @@ -117,50 +129,66 @@ export default class SendTransactionMethod extends AbstractSendMethod { } /** - * Checks if the given Web3Module has an default gasPrice defined + * Signs the transaction and executes the SendRawTransaction method. * - * @method hasDefaultGasPrice - * - * @param {AbstractWeb3Module} moduleInstance + * @method sendRawTransaction * - * @returns {Boolean} + * @param {String} privateKey + * @param {PromiEvent} promiEvent + * @param {Eth} moduleInstance */ - hasDefaultGasPrice(moduleInstance) { - return moduleInstance.defaultGasPrice !== null && typeof moduleInstance.defaultGasPrice !== 'undefined'; + async sendRawTransaction(privateKey, promiEvent, moduleInstance) { + if (!this.parameters[0].chainId) { + this.parameters[0].chainId = await this.chainIdMethod.execute(moduleInstance); + } + + if (!this.parameters[0].nonce && this.parameters[0].nonce !== 0) { + 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); + this.sendRawTransactionMethod.parameters = [response.rawTransaction]; + this.sendRawTransactionMethod.callback = this.callback; + this.sendRawTransactionMethod.execute(moduleInstance, promiEvent); } /** - * Checks if gasPrice is defined in the method options + * Checks if the current module has decrypted accounts * - * @method isGasPriceDefined + * @method isDefaultSigner + * + * @param {AbstractWeb3Module} moduleInstance * * @returns {Boolean} */ - isGasPriceDefined() { - return isObject(this.parameters[0]) && typeof this.parameters[0].gasPrice !== 'undefined'; + isDefaultSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name === 'TransactionSigner'; } /** - * Checks if the given Web3Module has an default gas limit defined + * Checks if the current module has decrypted accounts * - * @method hasDefaultGasLimit + * @method hasAccounts * * @param {AbstractWeb3Module} moduleInstance * * @returns {Boolean} */ - hasDefaultGasLimit(moduleInstance) { - return moduleInstance.defaultGas !== null && typeof moduleInstance.defaultGas !== 'undefined'; + hasAccounts(moduleInstance) { + return moduleInstance.accounts && moduleInstance.accounts.accountsIndex > 0; } /** - * Checks if a gas limit is defined + * Checks if a custom signer is given. + * + * @method hasCustomerSigner * - * @method isGasLimitDefined + * @param {AbstractWeb3Module} moduleInstance * * @returns {Boolean} */ - isGasLimitDefined() { - return isObject(this.parameters[0]) && typeof this.parameters[0].gas !== 'undefined'; + hasCustomSigner(moduleInstance) { + return moduleInstance.transactionSigner.constructor.name !== 'TransactionSigner'; } } 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 e934fcfc4d0..00000000000 --- a/packages/web3-core-method/src/signers/TransactionSigner.js +++ /dev/null @@ -1,58 +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) { - delete transaction.from; - 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-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-core-method/lib/signers/AbstractSigner.js b/packages/web3-core-method/tests/__mocks__/TransactionSigner.js similarity index 58% rename from packages/web3-core-method/lib/signers/AbstractSigner.js rename to packages/web3-core-method/tests/__mocks__/TransactionSigner.js index 3ff678cec1a..c88cae6f7f8 100644 --- a/packages/web3-core-method/lib/signers/AbstractSigner.js +++ b/packages/web3-core-method/tests/__mocks__/TransactionSigner.js @@ -1,48 +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 AbstractSigner.js + * @file TransactionSigner.js * @author Samuel Furter - * @date 2018 + * @date 2019 */ -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; - } +export default class TransactionSigner { + sign() {} } diff --git a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js index 5c669522e59..95450763563 100644 --- a/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js +++ b/packages/web3-core-method/tests/lib/factories/AbstractMethodFactoryTest.js @@ -65,8 +65,6 @@ describe('AbstractMethodFactoryTest', () => { expect(abstractMethodFactory.createMethod('sendTransaction')).toBeInstanceOf(SendTransactionMethod); expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); it('calls createMethod and returns SignMethod', () => { @@ -78,7 +76,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..5ded4ff31c6 100644 --- a/packages/web3-core-method/tests/src/methods/SignMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/SignMethodTest.js @@ -1,68 +1,56 @@ 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 MessageSigner from '../../../src/signers/MessageSigner'; 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(); - new AbstractWeb3Module(providerMock, {}, {}, {}); - moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; - accountsMock = new Accounts(); + accountsMock.sign = jest.fn(); + accountsMock.wallet = {'0x0': {privateKey: '0x0', address: '0x0'}}; + accountsMock.accountsIndex = 1; - new MessageSigner(accountsMock); - messageSignerMock = MessageSigner.mock.instances[0]; + new AbstractWeb3Module(providerMock, {}, {}, {}); + moduleInstanceMock = AbstractWeb3Module.mock.instances[0]; + moduleInstanceMock.accounts = accountsMock; - method = new SignMethod({}, formatters, accountsMock, messageSignerMock); + 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); - - expect(method.messageSigner).toEqual(messageSignerMock); }); 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); @@ -76,16 +64,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; }); @@ -95,18 +85,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 () => { + accountsMock.wallet = {nope: {privateKey: '0x0'}}; formatters.inputSignFormatter.mockReturnValueOnce('string'); formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); - messageSignerMock.sign.mockReturnValueOnce('0x00'); - providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); moduleInstanceMock.currentProvider = providerMock; @@ -121,9 +115,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', () => { @@ -133,7 +129,7 @@ describe('SignMethodTest', () => { formatters.inputAddressFormatter.mockReturnValueOnce('0x0'); - method.beforeExecution({}); + method.beforeExecution(moduleInstanceMock); expect(method.parameters[0]).toEqual('string'); @@ -145,8 +141,6 @@ describe('SignMethodTest', () => { }); it('afterExecution should just return the response', () => { - const object = {}; - - expect(method.afterExecution(object)).toEqual(object); + expect(method.afterExecution({})).toEqual({}); }); }); 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..cd51ef802b6 --- /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'); + +/** + * ChainIdMethod test + */ +describe('ChainIdMethodTest', () => { + 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'); + }); +}); 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..d013b1296c4 100644 --- a/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js +++ b/packages/web3-core-method/tests/src/methods/transaction/SendTransactionMethodTest.js @@ -2,19 +2,24 @@ import {formatters} from 'web3-core-helpers'; import {PromiEvent} from 'web3-core-promievent'; 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 * as Utils from 'web3-utils'; +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 jest.mock('formatters'); +jest.mock('Utils'); jest.mock('WebsocketProvider'); jest.mock('AbstractWeb3Module'); jest.mock('../../../../src/workflows/TransactionConfirmationWorkflow'); -jest.mock('../../../../src/signers/TransactionSigner'); jest.mock('../../../../src/methods/transaction/SendRawTransactionMethod'); +jest.mock('../../../../src/methods/network/ChainIdMethod'); +jest.mock('../../../../src/methods/account/GetTransactionCountMethod'); /** * SendTransactionMethod test @@ -26,23 +31,23 @@ describe('SendTransactionMethodTest', () => { promiEvent, transactionConfirmationWorkflowMock, transactionSignerMock, - accountsMock, - 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; - accountsMock = new Accounts(); - - new TransactionSigner(accountsMock); - transactionSignerMock = TransactionSigner.mock.instances[0]; - - promiEvent = new PromiEvent(); + transactionSignerMock = new TransactionSigner(); + transactionSignerMock.sign = jest.fn(); new TransactionConfirmationWorkflow({}, {}, {}); transactionConfirmationWorkflowMock = TransactionConfirmationWorkflow.mock.instances[0]; @@ -50,13 +55,19 @@ describe('SendTransactionMethodTest', () => { 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, - accountsMock, - transactionSignerMock, - sendRawTransactionMethodMock + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock ); method.callback = jest.fn(); @@ -64,52 +75,104 @@ 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.transactionConfirmationWorkflow).toEqual(transactionConfirmationWorkflowMock); + expect(method.chainIdMethod).toEqual(chainIdMethodMock); - expect(method.transactionSigner).toEqual(transactionSignerMock); - }); + expect(method.getTransactionCountMethod).toEqual(getTransactionCountMethodMock); - it('calls execute with wallets defined', async () => { - accountsMock.wallet[0] = {privateKey: '0x0'}; + expect(method).toBeInstanceOf(AbstractSendMethod); + }); + it('calls execute with wallets defined and returns with a resolved promise', async () => { transactionSignerMock.sign = jest.fn(() => { - return Promise.resolve('0x0'); + return Promise.resolve({rawTransaction: '0x0'}); }); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + + sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { + promiEvent.resolve('0x0'); }); - moduleInstanceMock.currentProvider = providerMock; + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, givenPromiEvent) => { - expect(moduleInstance).toEqual(moduleInstanceMock); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - expect(givenPromiEvent).toEqual(promiEvent); + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); - givenPromiEvent.resolve(true); - }); + const callback = jest.fn(); + method.callback = callback; + method.parameters = [transaction]; const response = await method.execute(moduleInstanceMock, promiEvent); expect(response).toEqual(true); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: '0x0'}); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, '0x0'); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + + 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 wallets defined and returns with a rejected promise', async () => { + const error = new Error('ERROR'); - transactionSignerMock.sign = jest.fn(() => { - return Promise.resolve('0x0'); + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = transactionSignerMock; + chainIdMethodMock.execute = jest.fn(() => { + throw error; + }); + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 0 + }; + + method.callback = jest.fn(); + method.parameters = [transaction]; + + const errorCallback = jest.fn(); + promiEvent.on('error', (e) => { + expect(e).toEqual(error); + + errorCallback(); + }); + + await expect(method.execute(moduleInstanceMock, promiEvent)).rejects.toThrow('ERROR'); + + expect(chainIdMethodMock.execute).toHaveBeenCalled(); + }); + + it('calls execute with a custom transaction signer defined and returns with a resolved promise', async () => { + const customSigner = {constructor: {name: 'CustomSigner'}}; + + customSigner.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); }); providerMock.send = jest.fn(() => { @@ -117,74 +180,234 @@ describe('SendTransactionMethodTest', () => { }); moduleInstanceMock.currentProvider = providerMock; - moduleInstanceMock.defaultGas = 100; - moduleInstanceMock.defaultGasPrice = 100; + moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.transactionSigner = customSigner; - 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.execute.mockReturnValueOnce(promiEvent.resolve(true)); - givenPromiEvent.resolve(true); - }); + const callback = jest.fn(); + method.callback = callback; + method.parameters = [transaction]; 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: 1, + nonce: 1, + chainId: 1 + }; - expect(method.parameters[0].gasPrice).toEqual(100); + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: 100, gas: 100}); - }); + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); - it('calls execute and TransactionSigner throws error', async (done) => { - accountsMock.wallet[0] = {privateKey: '0x0'}; + expect(sendRawTransactionMethodMock.callback).toEqual(callback); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); + 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'}}; + customSigner.sign = jest.fn(() => { + return Promise.resolve({rawTransaction: '0x0'}); }); - const error = new Error('SIGN ERROR'); - transactionSignerMock.sign = jest.fn(() => { - return new Promise((resolve, reject) => { - reject(error); - }); + chainIdMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); }); moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {accountsIndex: 1, wallet: {0: {address: '0x0', privateKey: '0x0'}}}; + moduleInstanceMock.transactionSigner = customSigner; - promiEvent.on('error', (e) => { - expect(e).toEqual(error); + sendRawTransactionMethodMock.execute = jest.fn((moduleInstance, promiEvent) => { + promiEvent.resolve('0x0'); + }); - expect(providerMock.send).toHaveBeenCalledWith('eth_gasPrice', []); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 0 + }; - expect(transactionSignerMock.sign).toHaveBeenCalledWith({gasPrice: '0x0'}); + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); - done(); + 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: 1 + }; + + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); + + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + + expect(chainIdMethodMock.execute).toHaveBeenCalled(); + }); + + 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'}); }); - try { - await method.execute(moduleInstanceMock, promiEvent); - } catch (error2) { - expect(error2).toEqual(error); + getTransactionCountMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); + }); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.accounts = {wallet: {}}; + moduleInstanceMock.transactionSigner = customSigner; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: undefined, + chainId: 1 + }; + + sendRawTransactionMethodMock.execute.mockReturnValueOnce(promiEvent.resolve(true)); + + 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: 1 + }; + + expect(customSigner.sign).toHaveBeenCalledWith(mappedTransaction, null); + + expect(sendRawTransactionMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock, promiEvent); + + expect(sendRawTransactionMethodMock.callback).toEqual(callback); + + expect(sendRawTransactionMethodMock.parameters).toEqual(['0x0']); + + expect(getTransactionCountMethodMock.parameters).toEqual([method.parameters[0].from]); - expect(method.callback).toHaveBeenCalledWith(error, null); - } + expect(getTransactionCountMethodMock.execute).toHaveBeenCalledWith(moduleInstanceMock); }); - it('calls execute without wallets defined', async (done) => { - method.parameters = [{gasPrice: false}]; + it('calls execute with no gas defined and uses the defaultGas and returns with a resolved promise', (done) => { + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); - providerMock.send = jest.fn(() => { - return Promise.resolve('0x0'); + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; + moduleInstanceMock.defaultGas = 10; + + const transaction = { + from: 0, + gas: 0, + gasPrice: 1, + nonce: 1, + 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]; + + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); + + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( + method, + moduleInstanceMock, + '0x0', + promiEvent + ); + + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); + + done(); }); + method.execute(moduleInstanceMock, promiEvent); + }); + + it('calls execute with no gasPrice defined and uses the defaultGasPrice and returns with a resolved promise', (done) => { + providerMock.send.mockReturnValueOnce(Promise.resolve('0x0')); + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; + moduleInstanceMock.defaultGasPrice = 10; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 0, + nonce: 1, + 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]; - promiEvent.on('transactionHash', (response) => { - expect(response).toEqual('0x0'); + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); + + expect(providerMock.send).toHaveBeenCalledWith('eth_sendTransaction', [transaction]); expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( method, @@ -193,15 +416,65 @@ describe('SendTransactionMethodTest', () => { promiEvent ); - expect(providerMock.send).toHaveBeenCalledWith(method.rpcMethod, method.parameters); + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); done(); }); - const response = await method.execute(moduleInstanceMock, promiEvent); + method.execute(moduleInstanceMock, promiEvent); + }); + + 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')); + + moduleInstanceMock.currentProvider = providerMock; + moduleInstanceMock.transactionSigner = {constructor: {name: 'TransactionSigner'}}; + moduleInstanceMock.defaultGasPrice = false; + + const transaction = { + from: 0, + gas: 1, + gasPrice: 0, + nonce: 1, + chainId: 1 + }; + + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 10, + nonce: 1, + chainId: 1 + }; + + formatters.inputTransactionFormatter.mockReturnValueOnce(transaction); - expect(response).toEqual('0x0'); + method.callback = jest.fn(); + method.parameters = [transaction]; + + promiEvent.on('transactionHash', (hash) => { + expect(hash).toEqual('0x0'); + + expect(providerMock.send).toHaveBeenNthCalledWith(1, 'eth_gasPrice', []); + expect(providerMock.send).toHaveBeenNthCalledWith(2, 'eth_sendTransaction', [transaction]); + + expect(transactionConfirmationWorkflowMock.execute).toHaveBeenCalledWith( + method, + moduleInstanceMock, + '0x0', + promiEvent + ); + + expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + + expect(formatters.inputTransactionFormatter).toHaveBeenCalledWith(mappedTransaction, moduleInstanceMock); + + done(); + }); - expect(method.callback).toHaveBeenCalledWith(false, '0x0'); + method.execute(moduleInstanceMock, promiEvent); }); }); 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-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); - } - }); -}); 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-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-core/src/AbstractWeb3Module.js b/packages/web3-core/src/AbstractWeb3Module.js index c2d15caa421..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 = AbstractWeb3Module.throwIfMissing('provider'), - providersModuleFactory = AbstractWeb3Module.throwIfMissing('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(); @@ -320,13 +314,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}`); - } } 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/jest.config.js b/packages/web3-eth-accounts/jest.config.js index 2d3e15221af..2a398143d0d 100644 --- a/packages/web3-eth-accounts/jest.config.js +++ b/packages/web3-eth-accounts/jest.config.js @@ -1,12 +1,17 @@ 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' + 'hexToBytes': 'web3-utils', + 'isHexStrict': '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', + 'EthAccount': 'eth-lib/lib/account', + 'scryptsy': 'scrypt.js' }); 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/Accounts.js b/packages/web3-eth-accounts/src/Accounts.js index dc8dd904f2a..73df0030a36 100644 --- a/packages/web3-eth-accounts/src/Accounts.js +++ b/packages/web3-eth-accounts/src/Accounts.js @@ -16,528 +16,90 @@ */ /** * @file Accounts.js - * @author Fabian Vogelsteller + * @author Samuel Furter , Fabian Vogelsteller * @date 2017 */ -import isUndefined from 'lodash/isUndefined'; -import isNull from 'lodash/isNull'; +import isFunction from 'lodash/isFunction'; 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 {encodeSignature, recover} from 'eth-lib/lib/account'; // TODO: Remove this dependency +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'; -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; -}; - +// 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 {MethodModuleFactory} methodModuleFactory - * @param {MethodFactory} methodFactory - * @param {Utils} utils * @param {Object} formatters - * @param {Object} options + * @param {ChainIdMethod} chainIdMethod + * @param {GetGasPriceMethod} getGasPriceMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod + * @param options * * @constructor */ - constructor(provider, providersModuleFactory, methodModuleFactory, methodFactory, utils, formatters, options) { - super(provider, providersModuleFactory, methodModuleFactory, methodFactory, options); - - this.utils = utils; + constructor( + provider, + providersModuleFactory, + formatters, + chainIdMethod, + getGasPriceMethod, + getTransactionCountMethod, + options + ) { + super(provider, providersModuleFactory, null, null, options); + this.transactionSigner = options.transactionSigner; 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; - } - - /** - * Creates an account with a given entropy - * - * @method create - * - * @param {String} entropy - * - * @returns {Object} - */ - create(entropy) { - return this._addAccountFunctions(Account.create(entropy || this.utils.randomHex(32))); - } - - /** - * Creates an Account object from a privateKey - * - * @method privateKeyToAccount - * - * @param {String} privateKey - * - * @returns {Object} - */ - privateKeyToAccount(privateKey) { - return this._addAccountFunctions(Account.fromPrivate(privateKey)); - } - - /** - * 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, 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); - } - - 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; - } - - // Resolve immediately if nonce, chainId and price are provided - if (tx.nonce !== undefined && tx.chainId !== undefined && tx.gasPrice !== undefined) { - return Promise.resolve(signed(tx)); - } + this.chainIdMethod = chainIdMethod; + this.getGasPriceMethod = getGasPriceMethod; + this.getTransactionCountMethod = getTransactionCountMethod; + this.defaultKeyName = 'web3js_wallet'; + this.accounts = {}; + this.accountsIndex = 0; + this.wallet = this.createWalletProxy(); - // 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 new Proxy(this, { + get: (target, name) => { + return target[name]; } - - return signed(extend(tx, {chainId: args[0], gasPrice: args[1], nonce: args[2]})); }); } /** - * Recovers transaction - * - * @method recoverTransaction - * - * @param {String} rawTx - * - * @returns {String} - */ - recoverTransaction(rawTx) { - const values = RLP.decode(rawTx); - const signature = Account.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); - } - - /** - * 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 - * - * @method sign - * - * @param {String} data - * @param {String} privateKey - * - * @returns {Object} - */ - sign(data, privateKey) { - const hash = this.hashMessage(data); - const signature = Account.sign(hash, privateKey); - const vrs = Account.decodeSignature(signature); - - return { - message: data, - messageHash: hash, - v: vrs[0], - r: vrs[1], - s: vrs[2], - signature - }; - } - - /** - * Recovers - * - * @method recover - * - * @param {String|Object} message - * @param {String} signature - * @param {Boolean} preFixed - * - * @returns {*} - */ - recover(message, signature, preFixed) { - const args = [].slice.apply(arguments); - - if (isObject(message)) { - return this.recover(message.messageHash, Account.encodeSignature([message.v, message.r, message.s]), true); - } - - if (!preFixed) { - message = this.hashMessage(message); - } - - if (args.length >= 4) { - 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 Account.recover(message, signature); - } - - /** - * Decrypts account - * - * Note: Taken from https://github.com/ethereumjs/ethereumjs-wallet - * - * @method decrypt - * - * @param {Object|String} v3Keystore - * @param {String} password - * @param {Boolean} nonStrict - * - * @returns {Object} - */ - 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 = cryp.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 = cryp.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); - } - - /** - * Encrypts the account + * This is for compatibility reasons and will be removed later when it got added to the eth-module * - * @method encrypt + * @method createWalletProxy * - * @param {String} privateKey - * @param {String} password - * @param {Object} options - * - * @returns {Object} + * @returns {Accounts} */ - encrypt(privateKey, password, options) { - const account = this.privateKeyToAccount(privateKey); - - options = options || {}; - const salt = options.salt || cryp.randomBytes(32); - const iv = options.iv || cryp.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 = cryp.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 = cryp.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 || cryp.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') + createWalletProxy() { + return new Proxy(this, { + get: (target, name) => { + switch (name) { + case 'create': + return target.addGeneratedAccountsToWallet; + case 'encrypt': + return target.encryptWallet; + case 'decrypt': + return target.decryptWallet; + case 'clear': + return target.clear; + default: + if (target.accounts[name]) { + return target.accounts[name]; + } + + return target[name]; + } } - }; - } -} - -// 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; + }); } /** @@ -550,10 +112,13 @@ class Wallet { * * @returns {Wallet} */ - create(numberOfAccounts, entropy) { + addGeneratedAccountsToWallet(numberOfAccounts, entropy) { + const account = Account.from(entropy || randomHex(32), this); + for (let i = 0; i < numberOfAccounts; ++i) { - this.add(this._accounts.create(entropy).privateKey); + this.add(account); } + return this; } @@ -562,28 +127,26 @@ class Wallet { * * @method add * - * @param {Object} account + * @param {Account|String} account - A Account object or privateKey * - * @returns {Object} + * @returns {Account} */ add(account) { if (isString(account)) { - account = this._accounts.privateKeyToAccount(account); + account = Account.fromPrivateKey(account, this); } - 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; + if (!this[account.address]) { + this.accounts[this.accountsIndex] = account; + this.accounts[account.address] = account; + this.accounts[account.address.toLowerCase()] = account; - this.length++; + this.accountsIndex++; return account; - } else { - return this[account.address]; } + + return this.accounts[account.address]; } /** @@ -593,28 +156,25 @@ class Wallet { * * @param {String|Number} addressOrIndex * - * @returns {boolean} + * @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; + 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 !!removed; } + + return false; } /** @@ -625,12 +185,8 @@ class Wallet { * @returns {Wallet} */ clear() { - const _this = this; - const indexes = this._currentIndexes(); - - indexes.forEach((index) => { - _this.remove(index); - }); + this.accounts = {}; + this.accountsIndex = 0; return this; } @@ -645,15 +201,14 @@ class Wallet { * * @returns {any[]} */ - encrypt(password, options) { - const _this = this; - const indexes = this._currentIndexes(); + encryptWallet(password, options) { + let encryptedAccounts = []; - const accounts = indexes.map((index) => { - return _this[index].encrypt(password, options); + Object.keys(this.accounts).forEach((key) => { + return encryptedAccounts.push(this.accounts[key].encrypt(password, options)); }); - return accounts; + return encryptedAccounts; } /** @@ -666,17 +221,15 @@ class Wallet { * * @returns {Wallet} */ - decrypt(encryptedWallet, password) { - const _this = this; - + decryptWallet(encryptedWallet, password) { encryptedWallet.forEach((keystore) => { - const account = _this._accounts.decrypt(keystore, password); + const account = Account.fromV3Keystore(keystore, password, false, this); - if (account) { - _this.add(account); - } else { + if (!account) { throw new Error("Couldn't decrypt accounts. Password wrong?"); } + + this.add(account); }); return this; @@ -693,8 +246,12 @@ class Wallet { * @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))); + 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 @@ -703,10 +260,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; @@ -723,14 +280,16 @@ class Wallet { * @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) { - try { - keystore = JSON.parse(keystore); - } catch (error) {} + 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 @@ -746,22 +305,204 @@ class Wallet { } } - return this.decrypt(keystore || [], password); + return this.decryptWallet(keystore || [], password); } -} -try { - if (typeof localStorage === 'undefined') { - delete Wallet.prototype.save; - delete Wallet.prototype.load; + /** + * Creates an account with a given entropy + * + * @method create + * + * @param {String} entropy + * + * @returns {Account} + */ + create(entropy) { + return Account.from(entropy, this); + } + + /** + * Creates an Account object from a privateKey + * + * @method privateKeyToAccount + * + * @param {String} privateKey + * + * @returns {Account} + */ + privateKeyToAccount(privateKey) { + 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 + * + * 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} + */ + async signTransaction(tx, privateKey, callback) { + try { + const account = Account.fromPrivateKey(privateKey, this); + + if (!tx.chainId) { + tx.chainId = await this.chainIdMethod.execute(this); + } + + if (!tx.gasPrice) { + tx.gasPrice = await this.getGasPriceMethod.execute(this); + } + + if (!tx.nonce) { + this.getTransactionCountMethod.parameters = [account.address]; + + tx.nonce = await this.getTransactionCountMethod.execute(this); + } + + const signedTransaction = await this.transactionSigner.sign(tx, account.privateKey); + + if (isFunction(callback)) { + callback(false, signedTransaction); + } + + return signedTransaction; + } catch (error) { + if (isFunction(callback)) { + callback(error, null); + } + + throw error; + } + } + + /** + * Recovers transaction + * + * @method recoverTransaction + * + * @param {String} rawTx + * + * @returns {String} + */ + recoverTransaction(rawTx) { + const values = RLP.decode(rawTx); + 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 recover(Hash.keccak256(signingDataHex), signature); + } + + /** + * Signs a string with the given privateKey + * + * @method sign + * + * @param {String} data + * @param {String} privateKey + * + * @returns {Object} + */ + sign(data, privateKey) { + if (isHexStrict(data)) { + data = hexToBytes(data); + } + + return Account.fromPrivateKey(privateKey, this).sign(data); + } + + /** + * Recovers the Ethereum address which was used to sign the given data. + * + * @method recover + * + * @param {String|Object} message + * @param {String} signature + * @param {Boolean} preFixed + * + * @returns {String} + */ + recover(message, signature, preFixed) { + const args = [].slice.apply(arguments); + + if (isObject(message)) { + return this.recover(message.messageHash, encodeSignature([message.v, message.r, message.s]), true); + } + + if (!preFixed) { + message = this.hashMessage(message); + } + + if (args.length >= 4) { + preFixed = args.slice(-1)[0]; + preFixed = isBoolean(preFixed) ? preFixed : false; + + return this.recover(message, encodeSignature(args.slice(1, 4)), preFixed); // v, r, s + } + + return recover(message, signature); + } + + /** + * 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} + */ + decrypt(v3Keystore, password, nonStrict) { + return Account.fromV3Keystore(v3Keystore, password, nonStrict, this); } -} 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); + + /** + * Encrypts the account + * + * @method encrypt + * + * @param {String} privateKey + * @param {String} password + * @param {Object} options + * + * @returns {Object} + */ + encrypt(privateKey, password, options) { + return Account.fromPrivateKey(privateKey, this).toV3Keystore(password, options); } } 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 c251ec5c410..00000000000 --- a/packages/web3-eth-accounts/src/factories/AccountsModuleFactory.js +++ /dev/null @@ -1,72 +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 MethodFactory from './MethodFactory'; -import Accounts from '../Accounts'; - -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 - * - * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider - * @param {ProvidersModuleFactory} providersModuleFactory - * @param {MethodModuleFactory} methodModuleFactory - * @param {Object} options - * - * @returns {Accounts} - */ - createAccounts(provider, providersModuleFactory, methodModuleFactory, options) { - return new Accounts( - provider, - providersModuleFactory, - methodModuleFactory, - this.createMethodFactory(methodModuleFactory), - this.utils, - this.formatters, - options - ); - } - - /** - * 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..973e755584a 100644 --- a/packages/web3-eth-accounts/src/index.js +++ b/packages/web3-eth-accounts/src/index.js @@ -20,27 +20,29 @@ * @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 AccountsModuleFactory from './factories/AccountsModuleFactory'; +import AccountsModule from './Accounts'; +import {ProvidersModuleFactory} from 'web3-providers'; +import {GetGasPriceMethod, ChainIdMethod, GetTransactionCountMethod} from 'web3-core-method'; /** * Returns the Accounts object * - * @method Accounts - * - * @params {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider * @params {Object} options * * @returns {Accounts} + * @constructor */ export const Accounts = (provider, options) => { - return new AccountsModuleFactory(Utils, formatters).createAccounts( + return new AccountsModule( provider, new ProvidersModuleFactory(), - new MethodModuleFactory(), + formatters, + new ChainIdMethod(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 new file mode 100644 index 00000000000..5750ba2c12e --- /dev/null +++ b/packages/web3-eth-accounts/src/models/Account.js @@ -0,0 +1,272 @@ +/* + 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 , Fabian Vogelsteller + * @date 2019 + */ + +import scryptsy from 'scrypt.js'; +import isString from 'lodash/isString'; +import isObject from 'lodash/isObject'; +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, 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 { + /** + * @param {Object} options TODO: Pass a Address VO in the options + * @param {Accounts} accounts + * + * @constructor + */ + constructor(options, accounts = null) { + this.address = options.address; + this.privateKey = options.privateKey; + this.accounts = accounts; + + return new Proxy(this, { + get: (target, name) => { + return target[name]; + } + }); + } + + /** + * 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 {Function} callback + * + * @callback callback callback(error, result) + * @returns {Promise} + */ + signTransaction(tx, 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) { + 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]); + const hash = Hash.keccak256s(ethMessage); + const signature = sign(hash, this.privateKey); + const vrs = decodeSignature(signature); + + return { + message: data, + messageHash: hash, + v: vrs[0], + r: vrs[1], + s: vrs[2], + signature + }; + } + + /** + * 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 Account.fromPrivateKey(this.privateKey, this.accounts.transactionSinger).toV3Keystore(password, options); + } + + /** + * This static methods gives us the possibility to create a new account. + * + * @param {String} entropy + * @param {Accounts} accounts + * + * @returns {Account} + */ + static from(entropy, accounts = {}) { + return new Account(create(entropy || randomHex(32)), accounts.transactionSigner); + } + + /** + * This static method gives us the possibility to create a Account object from a private key. + * + * @param {String} privateKey + * @param {Accounts} accounts + * + * @returns {Account} + */ + static fromPrivateKey(privateKey, accounts = {}) { + return new Account(fromPrivate(privateKey), accounts.transactionSigner); + } + + /** + * 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); + 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 = 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') + } + }; + } + + /** + * TODO: Clean up this method + * + * Returns an Account object by the given V3Keystore object. + * + * Note: Taken from https://github.com/ethereumjs/ethereumjs-wallet + * + * @method fromV3Keystore + * + * @param {Object|String} v3Keystore + * @param {String} password + * @param {Boolean} nonStrict + * @param {Accounts} accounts + * + * @returns {Account} + */ + static fromV3Keystore(v3Keystore, password, nonStrict = false, accounts = {}) { + 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 = 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, accounts); + } +} 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..6e75d03424d 100644 --- a/packages/web3-eth-accounts/tests/src/AccountsTest.js +++ b/packages/web3-eth-accounts/tests/src/AccountsTest.js @@ -1,45 +1,51 @@ -import * as Utils from 'web3-utils'; +import {isHexStrict, randomHex, hexToBytes} 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 {ChainIdMethod, GetGasPriceMethod, GetTransactionCountMethod} 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 {encodeSignature, recover} from 'eth-lib/lib/account'; +import {HttpProvider, ProviderDetector, ProviderResolver, ProvidersModuleFactory} from 'web3-providers'; +import TransactionSigner from '../__mocks__/TransactionSigner'; import Accounts from '../../src/Accounts'; +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'); +jest.mock('ProviderResolver'); jest.mock('ProvidersModuleFactory'); -jest.mock('MethodModuleFactory'); -jest.mock('eth-lib/lib/account'); +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'); 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/Account'); /** * Accounts test */ describe('AccountsTest', () => { let accounts, - methodFactory, - methodModuleFactoryMock, providerMock, providersModuleFactoryMock, providerDetectorMock, - providerResolverMock; + providerResolverMock, + chainIdMethodMock, + getGasPriceMethodMock, + getTransactionCountMethodMock, + transactionSignerMock, + options; beforeEach(() => { new HttpProvider(); @@ -64,647 +70,355 @@ describe('AccountsTest', () => { providersModuleFactoryMock.createProviderResolver.mockReturnValueOnce(providerResolverMock); - new MethodModuleFactory(); - methodModuleFactoryMock = MethodModuleFactory.mock.instances[0]; - methodModuleFactoryMock.createMethodProxy = jest.fn(); + new ChainIdMethod(); + chainIdMethodMock = ChainIdMethod.mock.instances[0]; + + new GetGasPriceMethod(); + getGasPriceMethodMock = GetGasPriceMethod.mock.instances[0]; + + new GetTransactionCountMethod(); + getTransactionCountMethodMock = GetTransactionCountMethod.mock.instances[0]; - methodFactory = new MethodFactory(methodModuleFactoryMock, Utils, formatters); + transactionSignerMock = new TransactionSigner(); + + options = {transactionSigner: transactionSignerMock}; accounts = new Accounts( providerMock, providersModuleFactoryMock, - methodModuleFactoryMock, - methodFactory, - Utils, formatters, - {} + chainIdMethodMock, + getGasPriceMethodMock, + getTransactionCountMethodMock, + options ); }); it('constructor check', () => { - expect(accounts.utils).toEqual(Utils); - expect(accounts.formatters).toEqual(formatters); - expect(accounts.wallet.defaultKeyName).toEqual('web3js_wallet'); + expect(accounts.chainIdMethod).toEqual(chainIdMethodMock); - expect(accounts).toBeInstanceOf(AbstractWeb3Module); - }); - - it('JSON-RPC methods check', () => { - expect(accounts.methodFactory.methods).toEqual({ - getGasPrice: GetGasPriceMethod, - getTransactionCount: GetTransactionCountMethod, - getId: VersionMethod - }); - }); + expect(accounts.getGasPriceMethod).toEqual(getGasPriceMethodMock); - it('calls addAccountFunctions and returns the expected object', () => { - const object = {}; + expect(accounts.getTransactionCountMethod).toEqual(getTransactionCountMethodMock); - expect(accounts._addAccountFunctions(object)).toBeInstanceOf(Object); + expect(accounts.transactionSigner).toEqual(options.transactionSigner); - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); + expect(accounts).toBeInstanceOf(AbstractWeb3Module); }); it('calls create with the entropy parameter and returns the expected object', () => { - const object = {}; + Account.from.mockReturnValueOnce(true); - Account.create = jest.fn((entropy) => { - expect(entropy).toEqual('entropy'); + expect(accounts.create('entropy')).toEqual(true); - 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; - }); - - expect(accounts.create()).toBeInstanceOf(Object); - - 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', accounts); }); it('calls privateKeyToAccount with the privateKey parameter and returns the expected object', () => { - const object = {}; + Account.fromPrivateKey.mockReturnValueOnce(true); - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); - - return object; - }); + expect(accounts.privateKeyToAccount('pk')).toEqual(true); - expect(accounts.privateKeyToAccount('pk')).toBeInstanceOf(Object); - - expect(object.signTransaction).toBeInstanceOf(Function); - - expect(object.sign).toBeInstanceOf(Function); - - expect(object.encrypt).toBeInstanceOf(Function); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); - it('calls signTransaction and returns a resolved promise', async () => { + it('calls signTransaction and resolves with a promise', async () => { const callback = jest.fn(); - const tx = { + const transaction = { + from: 0, gas: 1, - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' + gasPrice: 1, + nonce: 1, + chainId: 1 }; - 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(); + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); - formatters.inputCallFormatter.mockReturnValueOnce(tx); - - Utils.numberToHex.mockReturnValueOnce(1); + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); - RLP.encode.mockReturnValue('encoded'); + const response = await accounts.signTransaction(transaction, 'pk', callback); - Bytes.fromNat.mockReturnValue(1); + expect(response).toEqual('signed-transaction'); - Hash.keccak256.mockReturnValue('hash'); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - const signer = jest.fn(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - Account.makeSigner.mockReturnValueOnce(signer); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(transaction, account.privateKey); + }); - signer.mockReturnValueOnce('signature'); + it('calls signTransaction without the chainId property and resolves with a promise', async () => { + const callback = jest.fn(); - Nat.toNumber.mockReturnValueOnce(1); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 0 + }; - Account.decodeSignature.mockReturnValueOnce(['seven', 'eight', 'nine']); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - RLP.decode - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six']) - .mockReturnValueOnce(['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight']); + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); }); - expect(callback).toHaveBeenCalledWith(null, { - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' + chainIdMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); }); - 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']); + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); - expect(RLP.encode).toHaveBeenNthCalledWith(2, [ - 'zero', - 'one', - 'two', - 'three', - 'four', - 'five', - 'seven', - 'eight', - 'nine' - ]); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - expect(Hash.keccak256).toHaveBeenNthCalledWith(2, 'encoded'); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); - 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(chainIdMethodMock.execute).toHaveBeenCalledWith(accounts); }); - it('calls signTransaction without chainId, gasPrice, nonce and returns a resolved promise', async () => { + it('calls signTransaction without the gasPrice property and resolves with a promise', async () => { const callback = jest.fn(); - const tx = { + const transaction = { + from: 0, gas: 1, - value: 5, - to: 'LOWERCASE', - data: 'data' + gasPrice: 0, + nonce: 1, + chainId: 1 }; - 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'); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - return {address: '0x0'}; + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); }); - await expect(accounts.signTransaction(tx, 'pk', callback)).resolves.toEqual({ - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' - }); + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); - expect(callback).toHaveBeenCalledWith(null, { - messageHash: 'hash', - v: 'six', - r: 'seven', - s: 'eight', - rawTransaction: 'encoded' + getGasPriceMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); }); - 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); + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); - expect(RLP.encode).toHaveBeenNthCalledWith(1, [1, 1, 1, 'lowercase', 1, 'data', 1, '0x', '0x']); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(RLP.encode).toHaveBeenNthCalledWith(2, [ - 'zero', - 'one', - 'two', - 'three', - 'four', - 'five', - 'seven', - 'eight', - 'nine' - ]); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - expect(Hash.keccak256).toHaveBeenNthCalledWith(1, 'encoded'); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); - 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(getGasPriceMethodMock.execute).toHaveBeenCalledWith(accounts); }); - 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(); + it('calls signTransaction without the nonce property and resolves with a promise', async () => { + const callback = jest.fn(); - accounts.getId.mockReturnValueOnce(Promise.resolve(null)); + const transaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 0, + chainId: 1 + }; - accounts.getGasPrice.mockReturnValueOnce(Promise.resolve(null)); + const mappedTransaction = { + from: 0, + gas: 1, + gasPrice: 1, + nonce: 1, + chainId: 1 + }; - accounts.getTransactionCount.mockReturnValueOnce(Promise.resolve(null)); + transactionSignerMock.sign = jest.fn(() => { + return Promise.resolve('signed-transaction'); + }); - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); - return {address: '0x0'}; + getTransactionCountMethodMock.execute = jest.fn(() => { + return Promise.resolve(1); }); - 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'); + await expect(accounts.signTransaction(transaction, 'pk', callback)).resolves.toEqual('signed-transaction'); - expect(accounts.getId).toHaveBeenCalled(); + expect(callback).toHaveBeenCalledWith(false, 'signed-transaction'); - expect(accounts.getGasPrice).toHaveBeenCalled(); - }); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - 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' - }; + expect(transactionSignerMock.sign).toHaveBeenCalledWith(mappedTransaction, account.privateKey); - await expect(accounts.signTransaction(tx, 'pk', () => {})).rejects.toThrow( - 'Gas, gasPrice, nonce or chainId is lower than 0' - ); + expect(getTransactionCountMethodMock.execute).toHaveBeenCalledWith(accounts); }); - 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 signTransaction and rejects with a promise', async () => { + const callback = jest.fn(); - it('calls singTransaction and returns a rejected promise because of the inputCallFormatter', async () => { - const tx = { + const transaction = { + from: 0, gas: 1, - nonce: 2, - gasPrice: 3, - chainId: 4, - value: 5, - to: 'LOWERCASE', - data: 'data' + gasPrice: 1, + nonce: 1, + chainId: 1 }; - const callback = jest.fn(); + const account = {privateKey: 'pk', address: '0x0'}; + Account.fromPrivateKey.mockReturnValueOnce(account); - formatters.inputCallFormatter = jest.fn(() => { - throw new Error('ERROR'); + transactionSignerMock.sign = jest.fn(() => { + return Promise.reject(new Error('ERROR')); }); - await expect(accounts.signTransaction(tx, 'pk', callback)).rejects.toThrow('ERROR'); + await expect(accounts.signTransaction(transaction, 'pk', callback)).rejects.toThrow('ERROR'); - expect(callback).toHaveBeenCalledWith(new Error('ERROR')); - }); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - it('calls singTransaction and returns a rejected promise because of the missing TX parameter', async () => { - const callback = jest.fn(); + expect(callback).toHaveBeenCalledWith(new Error('ERROR'), null); - await expect(accounts.signTransaction(undefined, 'pk', callback)).rejects.toThrow( - 'No transaction object given!' - ); - - expect(callback).toHaveBeenCalledWith(new Error('No transaction object given!')); + expect(transactionSignerMock.sign).toHaveBeenCalledWith(transaction, 'pk'); }); it('calls recoverTransaction and returns the expected string', () => { - RLP.decode = jest.fn((rawTransaction) => { - expect(rawTransaction).toEqual('rawTransaction'); - - return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - }); - - Account.encodeSignature = jest.fn((values) => { - expect(values).toEqual([6, 7, 8]); - - return 'signature'; - }); - - Bytes.toNumber = jest.fn((value) => { - expect(value).toEqual(6); - - return 40; - }); + RLP.decode.mockReturnValueOnce([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - Bytes.fromNumber = jest.fn((recovery) => { - expect(recovery).toEqual(2); + encodeSignature.mockReturnValueOnce('signature'); - return 1; - }); - - RLP.encode = jest.fn((signingData) => { - expect(signingData).toEqual([0, 1, 2, 3, 4, 5, 1, '0x', '0x']); + Bytes.toNumber.mockReturnValueOnce(40); - return 'encoded'; - }); + Bytes.fromNumber.mockReturnValueOnce(1); - Hash.keccak256 = jest.fn((signingDataHex) => { - expect(signingDataHex).toEqual('encoded'); - - return 'hash'; - }); + RLP.encode.mockReturnValueOnce('encoded'); - Account.recover = jest.fn((hash, signature) => { - expect(hash).toEqual('hash'); + Hash.keccak256.mockReturnValueOnce('hash'); - expect(signature).toEqual('signature'); - - return 'recovered'; - }); + recover.mockReturnValueOnce('recovered'); expect(accounts.recoverTransaction('rawTransaction')).toEqual('recovered'); - expect(Account.recover).toHaveBeenCalled(); + expect(recover).toHaveBeenCalledWith('hash', 'signature'); - expect(Hash.keccak256).toHaveBeenCalled(); + expect(Hash.keccak256).toHaveBeenCalledWith('encoded'); - expect(RLP.encode).toHaveBeenCalled(); + expect(RLP.encode).toHaveBeenCalledWith([0, 1, 2, 3, 4, 5, 1, '0x', '0x']); - expect(Bytes.fromNumber).toHaveBeenCalled(); + expect(Bytes.fromNumber).toHaveBeenCalledWith(2); - expect(Bytes.toNumber).toHaveBeenCalled(); + expect(Bytes.toNumber).toHaveBeenCalledWith(6); - expect(Account.encodeSignature).toHaveBeenCalled(); + expect(encodeSignature).toHaveBeenCalledWith([6, 7, 8]); - expect(RLP.decode).toHaveBeenCalled(); + 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; - }); + it('calls sign with strict hex string and returns the expected value', () => { + const sign = jest.fn(); - Utils.hexToBytes = jest.fn((data) => { - expect(data).toEqual('data'); + isHexStrict.mockReturnValueOnce(true); - return 'message'; - }); + hexToBytes.mockReturnValueOnce('data'); - 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]); + sign.mockReturnValueOnce(true); - expect(ethMessage).toEqual(message); + Account.fromPrivateKey.mockReturnValueOnce({sign: sign}); - return 'keccak'; - }); + expect(accounts.sign('data', 'pk')).toEqual(true); - expect(accounts.hashMessage('data')).toEqual('keccak'); + expect(sign).toHaveBeenCalledWith('data'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(isHexStrict).toHaveBeenCalledWith('data'); - expect(Utils.hexToBytes).toHaveBeenCalled(); + expect(hexToBytes).toHaveBeenCalledWith('data'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); - it('calls hashMessage with non-strict hex and returns the expected string', () => { - Utils.isHexStrict = jest.fn((data) => { - expect(data).toEqual('message'); + it('calls sign with non-strict hex string and returns the expected value', () => { + const sign = jest.fn(); - return false; - }); + isHexStrict.mockReturnValueOnce(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]); + sign.mockReturnValueOnce(true); - expect(ethMessage).toEqual(message); + Account.fromPrivateKey.mockReturnValueOnce({sign: sign}); - return 'keccak'; - }); + expect(accounts.sign('data', 'pk')).toEqual(true); - expect(accounts.hashMessage('message')).toEqual('keccak'); + expect(sign).toHaveBeenCalledWith('data'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(isHexStrict).toHaveBeenCalledWith('data'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); }); - 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); - - return 'keccak'; - }); - - Account.sign = jest.fn((hash, privateKey) => { - expect(hash).toEqual('keccak'); - - expect(privateKey).toEqual('pk'); + it('calls recover with a string as message and returns the expected value', () => { + isHexStrict.mockReturnValueOnce(false); - return 'signed'; - }); + Hash.keccak256s.mockReturnValueOnce('keccak'); - Account.decodeSignature = jest.fn((signature) => { - expect(signature).toEqual('signed'); + recover.mockReturnValueOnce('recovered'); - return ['v', 'r', 's']; - }); + expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); - expect(accounts.sign('message', 'pk')).toEqual({ - message: 'message', - messageHash: 'keccak', - v: 'v', - r: 'r', - s: 's', - signature: 'signed' - }); + expect(isHexStrict).toHaveBeenCalledWith('message'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(recover).toHaveBeenCalledWith('keccak', 'signature'); }); - 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); + it('calls recover with a strict hex string as message and returns the expected value', () => { + isHexStrict.mockReturnValueOnce(true); - return 'keccak'; - }); - - Account.recover = jest.fn((message, signature) => { - expect(message).toEqual('keccak'); + hexToBytes.mockReturnValueOnce('message'); - expect(signature).toEqual('signature'); + Hash.keccak256s.mockReturnValueOnce('keccak'); - return 'recovered'; - }); + recover.mockReturnValueOnce('recovered'); expect(accounts.recover('message', 'signature', false)).toEqual('recovered'); - expect(Utils.isHexStrict).toHaveBeenCalled(); + expect(isHexStrict).toHaveBeenCalledWith('message'); - expect(Hash.keccak256s).toHaveBeenCalled(); + expect(hexToBytes).toHaveBeenCalledWith('message'); + + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); - expect(Account.recover).toHaveBeenCalled(); + expect(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'); + recover.mockReturnValueOnce('recovered'); - expect(signature).toEqual('signature'); - - return 'recovered'; - }); - - Account.encodeSignature = jest.fn((vrs) => { - expect(vrs).toEqual(['v', 'r', 's']); - - return 'signature'; - }); + encodeSignature.mockReturnValueOnce('signature'); expect( accounts.recover( @@ -719,500 +433,180 @@ describe('AccountsTest', () => { ) ).toEqual('recovered'); - expect(Account.recover).toHaveBeenCalled(); + expect(recover).toHaveBeenCalledWith('message', 'signature'); + + expect(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'); - - expect(signature).toEqual('signature'); - - return 'recovered'; - }); + recover.mockReturnValueOnce('recovered'); - Account.encodeSignature = jest.fn((vrs) => { - expect(vrs).toEqual(['v', 'r', 's']); - - return 'signature'; - }); + 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() - }; - - decipher.update.mockReturnValueOnce(Buffer.from('0')); - - decipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { - expect(cipher).toEqual('cipher'); + expect(recover).toHaveBeenCalledWith('message', 'signature'); - 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(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')}`); + it('calls decrypt and returns the expected value', () => { + Account.fromV3Keystore.mockReturnValueOnce(true); - return object; - }); - - Utils.sha3.mockReturnValueOnce('0xmac'); - - const decipher = { - update: jest.fn(), - final: jest.fn() - }; - - decipher.update.mockReturnValueOnce(Buffer.from('0')); + expect(accounts.decrypt('v3Keystore', 'password', false)).toEqual(true); - decipher.final.mockReturnValueOnce(Buffer.from('0')); - - crypto.createDecipheriv = jest.fn((cipher, derivedKey, buffer) => { - expect(cipher).toEqual('cipher'); - - expect(derivedKey).toEqual(Buffer.from('0000000000000000')); + expect(Account.fromV3Keystore).toHaveBeenCalledWith('v3Keystore', 'password', false, accounts); + }); - expect(buffer).toEqual(Buffer.from(['0x0'], 'hex')); + it('calls encrypt and returns the expected value', () => { + const toV3Keystore = jest.fn(); - return decipher; - }); + toV3Keystore.mockReturnValueOnce(true); - crypto.pbkdf2Sync = jest.fn((password, salt, c, dklen, sha256) => { - expect(password).toEqual(Buffer.from(password)); + Account.fromPrivateKey.mockReturnValueOnce({toV3Keystore: toV3Keystore}); - expect(salt).toEqual(Buffer.from('salt', 'hex')); + expect(accounts.encrypt('pk', 'password', {})).toEqual(true); - expect(c).toEqual(1); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('pk', accounts); - expect(dklen).toEqual('dklen'); + expect(toV3Keystore).toHaveBeenCalledWith('password', {}); + }); - expect(sha256).toEqual('sha256'); + it('calls wallet.create and returns the expected value', () => { + randomHex.mockReturnValueOnce('asdf'); - return Buffer.from('00000000000000000000000000000000'); - }); + Account.from.mockReturnValueOnce({address: '0x0', privateKey: '0x0'}); - expect(accounts.decrypt(json, 'password', false)).toEqual(object); + expect(accounts.wallet.create(1)).toEqual(accounts); - expect(crypto.pbkdf2Sync).toHaveBeenCalled(); + expect(randomHex).toHaveBeenCalledWith(32); - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) - ); + expect(Account.from).toHaveBeenCalledWith('asdf', accounts); - expect(crypto.createDecipheriv).toHaveBeenCalled(); + expect(accounts.accountsIndex).toEqual(1); + }); - expect(decipher.update).toHaveBeenCalledWith(Buffer.from(json.crypto.ciphertext, 'hex')); + 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(decipher.final).toHaveBeenCalled(); + expect(accounts.wallet.add(accountMock)).toEqual(accountMock); - expect(object.signTransaction).toBeInstanceOf(Function); + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); - expect(object.sign).toBeInstanceOf(Function); + expect(accounts.accounts[0]).toEqual(accountMock); - expect(object.encrypt).toBeInstanceOf(Function); + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); }); - it('calls decrypt and throws an error because of the missing password paramerter', () => { - expect(() => { - accounts.decrypt(''); - }).toThrow('No password given.'); - }); + 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; - 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'); - }); + expect(accounts.wallet.add(accountMock)).toEqual(accountMock); - 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(accounts.accounts[accountMock.address]).toEqual(accountMock); }); - 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); + it('calls wallet.add with a privateKey and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; - expect(dklen).toEqual('dklen'); + Account.fromPrivateKey.mockReturnValueOnce(accountMock); - expect(sha256).toEqual('sha256'); + expect(accounts.wallet.add('0x0')).toEqual(accountMock); - return Buffer.from('00000000000000000000000000000000'); - }); + expect(Account.fromPrivateKey).toHaveBeenCalledWith('0x0', accounts); - expect(() => { - accounts.decrypt(json, 'password', false); - }).toThrow('Key derivation failed - possibly wrong password'); + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); - expect(crypto.pbkdf2Sync).toHaveBeenCalled(); + expect(accounts.accounts[0]).toEqual(accountMock); - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) - ); + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); }); - 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')); + it('calls wallet.remove and returns true', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; - expect(cipher.final).toHaveBeenCalled(); + accounts.accounts = {'0x0': accountMock}; + accounts.accountsIndex = 1; - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([ - Buffer.from('0000000000000000').slice(16, 32), - Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') - ]) - ); + expect(accounts.wallet.remove('0x0')).toEqual(true); - expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); + expect(accounts.accountsIndex).toEqual(0); }); - 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); + it('calls wallet.remove and returns false', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + delete accountMock.address; - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + accounts.accounts = {}; - expect(crypto.randomBytes).toHaveBeenNthCalledWith(3, 16); + expect(accounts.wallet.remove(0)).toEqual(false); - 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(accounts.accountsIndex).toEqual(0); + }); - expect(cipher.update).toHaveBeenCalledWith(Buffer.from(account.privateKey.replace('0x', ''), 'hex')); + it('calls wallet.clear and returns the expect value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; - expect(cipher.final).toHaveBeenCalled(); + accounts.accounts = {0: accountMock}; - expect(Utils.sha3).toHaveBeenCalledWith( - Buffer.concat([ - Buffer.from('0000000000000000').slice(16, 32), - Buffer.from(Buffer.concat([Buffer.from('0'), Buffer.from('0')]), 'hex') - ]) - ); + expect(accounts.wallet.clear()).toEqual(accounts); - expect(uuid.v4).toHaveBeenCalledWith({random: Buffer.from('random')}); + expect(accounts.accountsIndex).toEqual(0); }); - it('calls encrypt with a unsupported sheme', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; - - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); + it('calls wallet.encrypt and returns the expect value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; - return account; - }); + accountMock.encrypt.mockReturnValueOnce(true); - crypto.randomBytes.mockReturnValue(Buffer.from('random')); + accounts.accounts = {0: accountMock}; - expect(() => { - accounts.encrypt('pk', 'password', {kdf: 'nope'}); - }).toThrow('Unsupported kdf'); + expect(accounts.wallet.encrypt('pw', {})).toEqual([true]); - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + expect(accountMock.encrypt).toHaveBeenCalledWith('pw', {}); - expect(crypto.randomBytes).toHaveBeenNthCalledWith(2, 16); + expect(accounts.accountsIndex).toEqual(0); }); - it('calls encrypt with a unsupported cipher', () => { - const account = { - privateKey: '0xxx', - address: '0xA' - }; + it('calls wallet.decrypt and returns the expected value', () => { + new Account(); + const accountMock = Account.mock.instances[0]; + accountMock.address = '0x0'; - const options = {kdf: 'pbkdf2'}; + Account.fromV3Keystore.mockReturnValueOnce(accountMock); - Account.fromPrivate = jest.fn((pk) => { - expect(pk).toEqual('pk'); + expect(accounts.wallet.decrypt([true], 'pw')).toEqual(accounts); - return account; - }); + expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); - crypto.randomBytes.mockReturnValue(Buffer.from('random')); + expect(accounts.accounts[accountMock.address]).toEqual(accountMock); - crypto.createCipheriv.mockReturnValue(false); + expect(accounts.accounts[0]).toEqual(accountMock); - crypto.pbkdf2Sync = jest.fn(() => { - return Buffer.from('0000000000000000'); - }); + expect(accounts.accounts[accountMock.address.toLowerCase()]).toEqual(accountMock); + }); - Utils.sha3.mockReturnValueOnce('0xmac'); + it('calls wallet.decrypt and throws an error', () => { + Account.fromV3Keystore.mockReturnValueOnce(false); expect(() => { - accounts.encrypt('pk', 'password', options); - }).toThrow('Unsupported cipher'); - - expect(crypto.randomBytes).toHaveBeenNthCalledWith(1, 32); + accounts.wallet.decrypt([true], 'pw'); + }).toThrow("Couldn't decrypt accounts. Password wrong?"); - 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') - ); + expect(Account.fromV3Keystore).toHaveBeenCalledWith(true, 'pw', false, accounts); }); }); 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 new file mode 100644 index 00000000000..d822436a0d7 --- /dev/null +++ b/packages/web3-eth-accounts/tests/src/models/AccountTest.js @@ -0,0 +1,565 @@ +import scryptsy from 'scrypt.js'; +import crypto from 'crypto'; +import uuid from 'uuid'; +import Hash from 'eth-lib/lib/hash'; +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'; +import Account from '../../../src/models/Account'; + +// Mocks +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('AccountTest', () => { + let account, accountsMock, transactionSignerMock; + + beforeEach(() => { + transactionSignerMock = new TransactionSigner(); + + new Accounts(); + accountsMock = Accounts.mock.instances[0]; + accountsMock.transactionSigner = transactionSignerMock; + + account = new Account({address: 'address', privateKey: 'pk'}, accountsMock); + }); + + it('constructor check', () => { + expect(account.address).toEqual('address'); + + expect(account.privateKey).toEqual('pk'); + + expect(account.accounts).toEqual(accountsMock); + }); + + it('calls signTransaction and returns the expected value', () => { + const callback = jest.fn(); + + accountsMock.signTransaction.mockReturnValueOnce(true); + + expect(account.signTransaction({}, callback)).toEqual(true); + + 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'); + + sign.mockReturnValueOnce('signed'); + + decodeSignature.mockReturnValueOnce(['v', 'r', 's']); + + expect(account.sign('message')).toEqual({ + message: 'message', + messageHash: 'keccak', + v: 'v', + r: 'r', + s: 's', + signature: 'signed' + }); + + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); + + expect(sign).toHaveBeenCalledWith('keccak', 'pk'); + + expect(decodeSignature).toHaveBeenCalledWith('signed'); + + expect(isHexStrict).toHaveBeenCalledWith('message'); + }); + + it('calls sign with strict hex and returns the expected string', () => { + isHexStrict.mockReturnValue(true); + + hexToBytes.mockReturnValue('message'); + + Hash.keccak256s.mockReturnValueOnce('keccak'); + + sign.mockReturnValueOnce('signed'); + + decodeSignature.mockReturnValueOnce(['v', 'r', 's']); + + expect(account.sign('message')).toEqual({ + message: 'message', + messageHash: 'keccak', + v: 'v', + r: 'r', + s: 's', + signature: 'signed' + }); + + expect(Hash.keccak256s).toHaveBeenCalledWith( + Buffer.concat([Buffer.from(`\u0019Ethereum Signed Message:\n${'message'.length}`), Buffer.from('message')]) + ); + + expect(sign).toHaveBeenCalledWith('keccak', 'pk'); + + expect(decodeSignature).toHaveBeenCalledWith('signed'); + + expect(hexToBytes).toHaveBeenCalledWith('message'); + + expect(isHexStrict).toHaveBeenCalledWith('message'); + }); + + it('calls the factory method fromV3Keystore and returns the expected Account class', () => { + 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' + } + } + }; + + fromPrivate.mockReturnValueOnce({ + address: '0x0', + privateKey: '0x0' + }); + + scryptsy.mockReturnValueOnce(Buffer.from('00000000000000000000000000000000')); + + 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(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'), + Buffer.from('salt', 'hex'), + 'n', + 'r', + 'p', + 'dklen' + ); + + expect(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(); + }); + + it('calls the factory method fromV3Keystore 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' + } + } + }; + + fromPrivate.mockReturnValueOnce({ + address: '0x0', + privateKey: '0x0' + }); + + 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(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(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(); + }); + + it('calls decrypt and throws an error because of the missing password paramerter', () => { + expect(() => { + Account.fromV3Keystore(''); + }).toThrow('No password given.'); + }); + + it('calls decrypt and throws an error because of a wrong keystore version', () => { + expect(() => { + 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(() => { + 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(() => { + Account.fromV3Keystore({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' + } + } + }; + + 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(() => { + Account.fromV3Keystore(json, 'password', false); + }).toThrow('Key derivation failed - possibly wrong password'); + + expect(crypto.pbkdf2Sync).toHaveBeenCalled(); + + expect(sha3).toHaveBeenCalledWith( + Buffer.concat([Buffer.from('0000000000000000'), Buffer.from(json.crypto.ciphertext, 'hex')]) + ); + }); + + it('calls toV3Keystore and returns the expected object', () => { + const options = {}; + + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' + }); + + 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')); + + sha3.mockReturnValueOnce('0xmac'); + + uuid.v4.mockReturnValueOnce(0); + + expect(Account.fromPrivateKey('pk').toV3Keystore('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(fromPrivate).toHaveBeenCalledWith('pk'); + + 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(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 toV3Keystore with the pbkdf2 sheme and returns the expected object', () => { + const options = {kdf: 'pbkdf2'}; + + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' + }); + + 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'); + }); + + sha3.mockReturnValueOnce('0xmac'); + + uuid.v4.mockReturnValueOnce(0); + + expect(Account.fromPrivateKey('pk').toV3Keystore('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(fromPrivate).toHaveBeenCalledWith('pk'); + + 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(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', () => { + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + expect(() => { + 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 options = {kdf: 'pbkdf2'}; + + fromPrivate.mockReturnValueOnce({ + privateKey: '0xxx', + address: '0xA' + }); + + crypto.randomBytes.mockReturnValue(Buffer.from('random')); + + crypto.createCipheriv.mockReturnValue(false); + + crypto.pbkdf2Sync = jest.fn(() => { + return Buffer.from('0000000000000000'); + }); + + sha3.mockReturnValueOnce('0xmac'); + + expect(() => { + 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); + + 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-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/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/AbstractContract.js b/packages/web3-eth-contract/src/AbstractContract.js index 71c690a63a9..d9fe0a06eb8 100644 --- a/packages/web3-eth-contract/src/AbstractContract.js +++ b/packages/web3-eth-contract/src/AbstractContract.js @@ -30,6 +30,7 @@ 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 @@ -44,10 +45,11 @@ export default class AbstractContract extends AbstractWeb3Module { methodModuleFactory, contractModuleFactory, PromiEvent, + accounts, abiCoder, utils, formatters, - abi = AbstractWeb3Module.throwIfMissing('abi'), + abi, address, options = {} ) { @@ -59,9 +61,10 @@ 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.options = options; + this.transactionSigner = options.transactionSigner; if (address) { this.address = address; diff --git a/packages/web3-eth-contract/src/factories/ContractModuleFactory.js b/packages/web3-eth-contract/src/factories/ContractModuleFactory.js index 639c8db27a5..000dad0344e 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, @@ -230,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 383882a440f..7116acbe93e 100644 --- a/packages/web3-eth-contract/src/factories/MethodFactory.js +++ b/packages/web3-eth-contract/src/factories/MethodFactory.js @@ -25,11 +25,10 @@ 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 { /** - * @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; @@ -145,13 +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.accounts, - this.methodModuleFactory.createTransactionSigner(), - 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 ); @@ -167,13 +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.accounts, - this.methodModuleFactory.createTransactionSigner(), - 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/index.js b/packages/web3-eth-contract/src/index.js index 09e20675fe4..df86bb052a6 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -27,29 +27,43 @@ 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 * * @param {EthereumProvider|HttpProvider|WebsocketProvider|IpcProvider|String} provider + * @param {Array} abi * @param {Accounts} accounts - * @param {Object} abi * @param {String} address * @param {Object} options * * @returns {AbstractContract} + * + * @constructor */ -export const Contract = (provider, accounts, abi, address, options) => { - return new ContractModuleFactory( +export const Contract = (provider, abi, accounts, address, options) => { + const abiCoder = new AbiCoder(); + const methodModuleFactory = new MethodModuleFactory(); + + return new AbstractContract( + provider, + new ProvidersModuleFactory(), + new MethodModuleFactory(), + new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), + PromiEvent, + accounts, + abiCoder, Utils, formatters, - new AbiCoder(), - accounts, - new MethodModuleFactory(accounts) - ).createContract(provider, new ProvidersModuleFactory(), PromiEvent, abi, address, options); + abi, + address, + options + ); }; diff --git a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js index 0d1aff81915..27504f8e1e8 100644 --- a/packages/web3-eth-contract/src/methods/ContractDeployMethod.js +++ b/packages/web3-eth-contract/src/methods/ContractDeployMethod.js @@ -27,10 +27,10 @@ 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 + * @param {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod + * @param {AbstractContract} contract * * @constructor */ @@ -38,19 +38,20 @@ export default class ContractDeployMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod, contract ) { super( utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, - sendRawTransactionMethod + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod ); + 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..d938ae6fe5c 100644 --- a/packages/web3-eth-contract/src/methods/SendContractMethod.js +++ b/packages/web3-eth-contract/src/methods/SendContractMethod.js @@ -28,9 +28,9 @@ 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 {ChainIdMethod} chainIdMethod + * @param {GetTransactionCountMethod} getTransactionCountMethod * @param {AllEventsLogDecoder} allEventsLogDecoder * @param {AbiModel} abiModel * @@ -40,9 +40,9 @@ export default class SendContractMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod, allEventsLogDecoder, abiModel ) { @@ -50,10 +50,11 @@ export default class SendContractMethod extends SendTransactionMethod { utils, formatters, transactionConfirmationWorkflow, - accounts, - transactionSigner, - sendRawTransactionMethod + sendRawTransactionMethod, + chainIdMethod, + getTransactionCountMethod ); + this.allEventsLogDecoder = allEventsLogDecoder; this.abiModel = abiModel; } 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-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..14c6718831a 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; @@ -118,6 +118,7 @@ describe('AbstractContractTest', () => { methodModuleFactoryMock, contractModuleFactoryMock, PromiEvent, + {}, abiCoderMock, Utils, formatters, @@ -156,16 +157,20 @@ describe('AbstractContractTest', () => { expect(abstractContract.abiMapper).toEqual(abiMapperMock); - expect(abstractContract.options).toEqual(options); + 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); 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-contract/tests/src/factories/MethodFactoryTest.js b/packages/web3-eth-contract/tests/src/factories/MethodFactoryTest.js index 6fce6090804..e2e63da9faa 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,17 +29,12 @@ 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(); new ContractModuleFactory({}, {}, {}, {}, {}); contractModuleFactoryMock = ContractModuleFactory.mock.instances[0]; @@ -49,7 +43,6 @@ describe('MethodFactoryTest', () => { abiCoderMock = AbiCoder.mock.instances[0]; methodFactory = new MethodFactory( - accountsMock, Utils, formatters, contractModuleFactoryMock, @@ -59,8 +52,6 @@ describe('MethodFactoryTest', () => { }); it('constructor check', () => { - expect(methodFactory.accounts).toEqual(accountsMock); - expect(methodFactory.utils).toEqual(Utils); expect(methodFactory.formatters).toEqual(formatters); @@ -115,21 +106,13 @@ describe('MethodFactoryTest', () => { expect(contractModuleFactoryMock.createAllEventsLogDecoder).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); - expect(methodModuleFactoryMock.createTransactionConfirmationWorkflow).toHaveBeenCalled(); - - expect(methodModuleFactoryMock.createSendRawTransactionMethod).toHaveBeenCalled(); }); it('calls createContractDeployMethod and returns ContractDeployMethod object', () => { expect(methodFactory.createContractDeployMethod({})).toBeInstanceOf(ContractDeployMethod); - expect(methodModuleFactoryMock.createTransactionSigner).toHaveBeenCalled(); - 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/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-contract/tests/src/methods/ContractDeployMethodTest.js b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js index 3797b77ffc0..9c334483e8e 100644 --- a/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/ContractDeployMethodTest.js @@ -1,73 +1,72 @@ 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 { + ChainIdMethod, + GetTransactionCountMethod, + SendRawTransactionMethod, + 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('SendRawTransactionMethod'); +jest.mock('ChainIdMethod'); +jest.mock('GetTransactionCountMethod'); jest.mock('../../../src/AbstractContract'); /** * ContractDeployMethod test */ describe('ContractDeployMethodTest', () => { - let contractDeployMethod, transactionConfirmationWorkflowMock, accountsMock, transactionSignerMock, contractMock; + let contractDeployMethod, + transactionConfirmationWorkflowMock, + contractMock, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock; beforeEach(() => { - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - 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(); - transactionSignerMock = new TransactionSigner(); contractDeployMethod = new ContractDeployMethod( Utils, formatters, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, - {}, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock, 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); }); 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 2aa995baaad..dc3482cf45a 100644 --- a/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js +++ b/packages/web3-eth-contract/tests/src/methods/SendContractMethodTest.js @@ -1,9 +1,12 @@ +import { + SendTransactionMethod, + SendRawTransactionMethod, + ChainIdMethod, + GetTransactionCountMethod +} from 'web3-core-method'; 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'; @@ -12,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'); @@ -22,50 +28,43 @@ jest.mock('../../../src/models/AbiModel'); describe('SendContractMethodTest', () => { let sendContractMethod, transactionConfirmationWorkflowMock, - accountsMock, - transactionSignerMock, allEventsLogDecoderMock, - abiModelMock; + abiModelMock, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock; beforeEach(() => { transactionConfirmationWorkflowMock = new TransactionConfirmationWorkflow(); - new Accounts(); - accountsMock = Accounts.mock.instances[0]; - - transactionSignerMock = new TransactionSigner(); - new AbiModel(); abiModelMock = AbiModel.mock.instances[0]; 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, - accountsMock, - transactionSignerMock, - {}, + sendRawTransactionMethodMock, + chainIdMethodMock, + getTransactionCountMethodMock, allEventsLogDecoderMock, abiModelMock ); }); 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); diff --git a/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js b/packages/web3-eth-contract/tests/src/proxies/MethodsProxyTest.js index 082db745279..892de30dba1 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( - true - ); + 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'); 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-ens/src/Ens.js b/packages/web3-eth-ens/src/Ens.js index 64413724753..f035c04b271 100644 --- a/packages/web3-eth-ens/src/Ens.js +++ b/packages/web3-eth-ens/src/Ens.js @@ -63,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..99c7a0b7996 100644 --- a/packages/web3-eth-ens/src/index.js +++ b/packages/web3-eth-ens/src/index.js @@ -33,12 +33,12 @@ import EnsModuleFactory from './factories/EnsModuleFactory'; * @method Ens * * @param {HttpProvider|WebsocketProvider|IpcProvider|EthereumProvider|String} provider - * @param {Accounts} accounts * @param {Object} options + * @param {Accounts} accounts * * @returns {Ens} */ -export const Ens = (provider, accounts, options) => { +export const Ens = (provider, options, accounts) => { const abiCoder = new AbiCoder(); const methodModuleFactory = new MethodModuleFactory(); @@ -46,7 +46,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-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 71c145c4cc1..da34337f6f7 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/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", @@ -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,11 +142,50 @@ "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", + "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" + } + }, "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", @@ -139,11 +198,52 @@ }, "dependencies": { "definitelytyped-header-parser": { - "version": "github:Microsoft/definitelytyped-header-parser#e0561530379dfa01324a89936b75d90b20df9bd2", - "from": "github:Microsoft/definitelytyped-header-parser#e0561530379dfa01324a89936b75d90b20df9bd2" + "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": { + "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": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -159,6 +259,29 @@ "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" + } + }, + "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", + "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 +297,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 +315,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 +350,35 @@ "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" + } + }, + "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 +393,42 @@ "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" + } + }, + "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 +451,34 @@ "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", + "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 +487,34 @@ "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", + "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==" + }, + "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", @@ -257,6 +523,15 @@ "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" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -267,11 +542,36 @@ "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" + } + }, + "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", @@ -285,11 +585,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 +638,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", @@ -340,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", @@ -350,10 +693,100 @@ "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", "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" + } + }, + "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/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/Eth.js b/packages/web3-eth/src/Eth.js index 79c9fe6f9b9..cb438a3e8b2 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 @@ -58,6 +59,7 @@ export default class Eth extends AbstractWeb3Module { formatters, subscriptionsFactory, contractModuleFactory, + transactionSigner, options ) { super(provider, providersModuleFactory, methodModuleFactory, methodFactory, options); @@ -68,11 +70,13 @@ export default class Eth extends AbstractWeb3Module { this.Iban = Iban; this.abi = abiCoder; this.ens = ens; + this.utils = utils; this.formatters = formatters; 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. @@ -85,11 +89,14 @@ 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( this.currentProvider, this.providersModuleFactory, PromiEvent, + this.accounts, abi, address, options @@ -101,6 +108,34 @@ 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} transactionSigner + */ + set transactionSigner(transactionSigner) { + this._transactionSigner = transactionSigner; + this.accounts.transactionSigner = transactionSigner; + this.ens.transactionSigner = transactionSigner; + + this.initiatedContracts.forEach((contract) => { + contract.transactionSigner = transactionSigner; + }); + } + /** * Clears all subscriptions and listeners * @@ -365,7 +400,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 deleted file mode 100644 index 0d1ca2ed65e..00000000000 --- a/packages/web3-eth/src/factories/EthModuleFactory.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 . -*/ -/** - * @file EthModuleFactory.js - * @author Samuel Furter - * @date 2018 - */ - -import MethodFactory from './MethodFactory'; -import Eth from '../Eth'; - -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; - } - - /** - * Returns an object of type Eth - * - * @method createEthModule - * - * @param {Network} net - * @param {Personal} personal - * @param {Iban} iban - * @param {Ens} ens - * @param {SubscriptionsFactory} subscriptionsFactory - * @param {Object} options - * - * @returns {Eth} - */ - createEthModule(net, personal, iban, ens, subscriptionsFactory, options) { - return new Eth( - this.provider, - this.providersModuleFactory, - this.methodModuleFactory, - this.createMethodFactory(), - net, - this.accounts, - personal, - iban, - this.abiCoder, - ens, - this.utils, - this.formatters, - subscriptionsFactory, - this.contractModuleFactory, - options - ); - } - - /** - * Returns an object of type MethodFactory - * - * @method createMethodFactory - * - * @returns {MethodFactory} - */ - createMethodFactory() { - return new MethodFactory(this.methodModuleFactory, this.utils, this.formatters); - } -} diff --git a/packages/web3-eth/src/factories/MethodFactory.js b/packages/web3-eth/src/factories/MethodFactory.js index 1d8180590d0..7021652f126 100644 --- a/packages/web3-eth/src/factories/MethodFactory.js +++ b/packages/web3-eth/src/factories/MethodFactory.js @@ -51,7 +51,9 @@ import { SubmitWorkMethod, GetWorkMethod, GetPastLogsMethod, - RequestAccountsMethod + RequestAccountsMethod, + VersionMethod, + ChainIdMethod } from 'web3-core-method'; export default class MethodFactory extends AbstractMethodFactory { @@ -95,7 +97,9 @@ export default class MethodFactory extends AbstractMethodFactory { submitWork: SubmitWorkMethod, getWork: GetWorkMethod, getPastLogs: GetPastLogsMethod, - requestAccounts: RequestAccountsMethod + requestAccounts: RequestAccountsMethod, + getId: VersionMethod, + getChainId: ChainIdMethod }; } } diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 9874ad9d981..533f67b190b 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -22,7 +22,6 @@ import {MethodModuleFactory} 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'; @@ -33,7 +32,31 @@ 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.js'; +import EthMethodFactory from './factories/MethodFactory'; + +/** + * Creates the TransactionSigner class + * + * @returns {TransactionSigner} + * + * @constructor + */ +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 @@ -44,30 +67,30 @@ import EthModuleFactory from './factories/EthModuleFactory'; * @param {Object} options * * @returns {Eth} + * + * @constructor */ export const Eth = (provider, options) => { const accounts = new Accounts(provider, options); - const abiCoder = new AbiCoder(); + const methodModuleFactory = new MethodModuleFactory(); - const methodModuleFactory = new MethodModuleFactory(accounts); - - return new EthModuleFactory( + return new EthModule( provider, new ProvidersModuleFactory(), methodModuleFactory, - accounts, - PromiEvent, - Utils, - formatters, - new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), - abiCoder - ).createEthModule( + new MethodFactory(), new Network(provider, options), + accounts, new Personal(provider, accounts, options), Iban, - new Ens(provider, accounts), + abiCoder, + new Ens(provider, accounts, options), + Utils, + formatters, new SubscriptionsFactory(), + new ContractModuleFactory(Utils, formatters, abiCoder, accounts, methodModuleFactory), + new TransactionSigner(), options ); }; diff --git a/packages/web3-eth/src/signers/TransactionSigner.js b/packages/web3-eth/src/signers/TransactionSigner.js new file mode 100644 index 00000000000..4409d2900a0 --- /dev/null +++ b/packages/web3-eth/src/signers/TransactionSigner.js @@ -0,0 +1,165 @@ +/* + 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 , 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'; + +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 + * + * @param {Object} transaction + * @param {String} privateKey + * + * @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'; + 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, transaction.chainId); + 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 + }; + } + + /** + * 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), + '0x', + '0x' + ]); + } + + /** + * Creates the signature of the current account + * + * @method createAccountSignature + * + * @param {String} hash + * @param {String} privateKey + * @param {String} chainId + * + * @returns {String} + */ + createAccountSignature(hash, privateKey, chainId) { + return Account.makeSigner(Nat.toNumber(chainId) * 2 + 35)(hash, privateKey); + } + + /** + * 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 rawTransaction; + } + + /** + * 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; + } +} diff --git a/packages/web3-eth/tests/src/EthTest.js b/packages/web3-eth/tests/src/EthTest.js index 1c754025f04..83fd9ab7894 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'; @@ -43,6 +45,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 +67,7 @@ jest.mock('Utils'); jest.mock('formatters'); jest.mock('AbstractContract'); jest.mock('ContractModuleFactory'); -jest.mock('../../src/factories/EthModuleFactory'); +jest.mock('../../src/signers/TransactionSigner'); /** * Eth test @@ -83,7 +86,8 @@ describe('EthTest', () => { personalMock, abiCoderMock, ensMock, - subscriptionsFactoryMock; + subscriptionsFactoryMock, + transactionSignerMock; beforeEach(() => { new HttpProvider(); @@ -135,6 +139,9 @@ describe('EthTest', () => { new SubscriptionsFactory(); subscriptionsFactoryMock = SubscriptionsFactory.mock.instances[0]; + new TransactionSigner(); + transactionSignerMock = TransactionSigner.mock.instances[0]; + eth = new Eth( providerMock, providersModuleFactoryMock, @@ -150,6 +157,7 @@ describe('EthTest', () => { formatters, subscriptionsFactoryMock, contractModuleFactoryMock, + transactionSignerMock, {} ); }); @@ -209,7 +217,9 @@ describe('EthTest', () => { submitWork: SubmitWorkMethod, getWork: GetWorkMethod, getPastLogs: GetPastLogsMethod, - requestAccounts: RequestAccountsMethod + requestAccounts: RequestAccountsMethod, + getChainId: ChainIdMethod, + getId: VersionMethod }); }); @@ -411,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', () => { @@ -427,14 +451,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'); @@ -442,7 +463,5 @@ describe('EthTest', () => { expect(networkMock.setProvider).toHaveBeenCalledWith('provider', 'net'); expect(personalMock.setProvider).toHaveBeenCalledWith('provider', 'net'); - - expect(accountsMock.setProvider).toHaveBeenCalledWith('provider', 'net'); }); }); 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); - }); -}); 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..0ce7b10be90 --- /dev/null +++ b/packages/web3-eth/tests/src/signers/TransactionSignerTest.js @@ -0,0 +1,121 @@ +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'); + +/** + * TransactionSigner test + */ +describe('TransactionSignerTest', () => { + let transactionSigner; + + beforeEach(() => { + 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 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.txInputFormatter.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(transactionSigner.sign(tx, 'pk')).resolves.toEqual({ + messageHash: 'hash', + v: 'six', + r: 'seven', + s: 'eight', + rawTransaction: 'encoded' + }); + + expect(formatters.txInputFormatter).toHaveBeenCalledWith(tx); + + 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).toHaveBeenCalledWith('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'); + }); +}); 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-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=" } } } 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; }