From e09e54bebb55735de777811fde37dbece6dad0f5 Mon Sep 17 00:00:00 2001 From: Jenny Pollack Date: Mon, 25 Mar 2019 23:27:36 -1000 Subject: [PATCH 01/87] remove user actions controller --- app/scripts/controllers/user-actions.js | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 app/scripts/controllers/user-actions.js diff --git a/app/scripts/controllers/user-actions.js b/app/scripts/controllers/user-actions.js deleted file mode 100644 index f777054b8..000000000 --- a/app/scripts/controllers/user-actions.js +++ /dev/null @@ -1,17 +0,0 @@ -const MessageManager = require('./lib/message-manager') -const PersonalMessageManager = require('./lib/personal-message-manager') -const TypedMessageManager = require('./lib/typed-message-manager') - -class UserActionController { - - constructor (opts = {}) { - - this.messageManager = new MessageManager() - this.personalMessageManager = new PersonalMessageManager() - this.typedMessageManager = new TypedMessageManager() - - } - -} - -module.exports = UserActionController From 0762aaa5daab1fb47dfb3cb20b834383793ffb93 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 27 Mar 2019 22:50:33 -0230 Subject: [PATCH 02/87] Remove broken image walkthrough from metamaskbot comment --- development/metamaskbot-build-announce.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index 07adbcb5d..b254c8a90 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -27,20 +27,8 @@ async function start () { const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip` const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip` const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip` - const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` - const commentBody = ` -
- - Builds ready [${SHORT_SHA1}]: - chrome, - firefox, - edge, - opera - - -
- ` + const commentBody = `Builds ready [${SHORT_SHA1}]: chrome, firefox, edge, opera` const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` From 89693a23151d4ff37295f14b04d7c64297d842c5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 4 Apr 2019 22:11:28 +0800 Subject: [PATCH 03/87] metamask-controller - use improved provider-as-middleware utility --- app/scripts/lib/createProviderMiddleware.js | 16 ---------------- app/scripts/metamask-controller.js | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 app/scripts/lib/createProviderMiddleware.js diff --git a/app/scripts/lib/createProviderMiddleware.js b/app/scripts/lib/createProviderMiddleware.js deleted file mode 100644 index 8a939ba4e..000000000 --- a/app/scripts/lib/createProviderMiddleware.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = createProviderMiddleware - -/** - * Forwards an HTTP request to the current Web3 provider - * - * @param {{ provider: Object }} config Configuration containing current Web3 provider - */ -function createProviderMiddleware ({ provider }) { - return (req, res, next, end) => { - provider.sendAsync(req, (err, _res) => { - if (err) return end(err) - res.result = _res.result - end() - }) - } -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 4108ed4c0..d2a55acaa 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -18,7 +18,7 @@ const createFilterMiddleware = require('eth-json-rpc-filters') const createSubscriptionManager = require('eth-json-rpc-filters/subscriptionManager') const createOriginMiddleware = require('./lib/createOriginMiddleware') const createLoggerMiddleware = require('./lib/createLoggerMiddleware') -const createProviderMiddleware = require('./lib/createProviderMiddleware') +const providerAsMiddleware = require('eth-json-rpc-middleware/providerAsMiddleware') const {setupMultiplex} = require('./lib/stream-utils.js') const KeyringController = require('eth-keyring-controller') const NetworkController = require('./controllers/network') @@ -1373,7 +1373,7 @@ module.exports = class MetamaskController extends EventEmitter { // watch asset engine.push(this.preferencesController.requestWatchAsset.bind(this.preferencesController)) // forward to metamask primary provider - engine.push(createProviderMiddleware({ provider })) + engine.push(providerAsMiddleware(provider)) // setup connection const providerStream = createEngineStream({ engine }) From 55cb4bf907e930f04ed692fe3e59dc25cec64823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20Mi=C3=B1o?= Date: Thu, 4 Apr 2019 15:49:10 -0300 Subject: [PATCH 04/87] pin eth-contract-metadata to last commit hash (#6396) --- package-lock.json | 565 +++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 208 insertions(+), 359 deletions(-) diff --git a/package-lock.json b/package-lock.json index dad45f6ca..11eab5718 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9759,8 +9759,8 @@ } }, "eth-contract-metadata": { - "version": "github:MetaMask/eth-contract-metadata#4d855fea9a5c899059134e03986be9d98e844270", - "from": "github:MetaMask/eth-contract-metadata#master" + "version": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe", + "from": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe" }, "eth-ens-namehash": { "version": "2.0.8", @@ -9796,7 +9796,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" }, "dependencies": { @@ -9804,8 +9804,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } } } @@ -9814,8 +9814,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-util": { @@ -9886,16 +9886,16 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } } } @@ -9904,8 +9904,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-util": { @@ -10065,7 +10065,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" }, "dependencies": { @@ -10074,8 +10074,8 @@ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } } } @@ -10084,8 +10084,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-util": { @@ -10192,8 +10192,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-util": { @@ -10241,7 +10241,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", "ethereumjs-util": "^5.1.1" } }, @@ -10502,8 +10502,8 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-util": { @@ -10693,7 +10693,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", "ethereumjs-util": "^5.1.1" } }, @@ -10809,7 +10809,7 @@ "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", "requires": { - "async-eventemitter": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "eth-query": "^2.1.0", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.1.3", @@ -10842,6 +10842,39 @@ } } }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", @@ -10939,18 +10972,8 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", "ethereumjs-util": "^5.1.1" - }, - "dependencies": { - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", - "from": "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", - "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - } - } } }, "ethereumjs-util": { @@ -13087,7 +13110,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", "ethereumjs-util": "^5.1.1" } }, @@ -13239,7 +13262,7 @@ "integrity": "sha512-VU6/DSUX93d1fCzBz7WP/SGCQizO1rKZi4Px9j/3yRyfssHyFcZamMw2/sj4E8TlfMXONvZLoforR8B4bRoyTQ==", "dev": true, "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2-cookies": "^1.1.0", @@ -13331,7 +13354,6 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, - "optional": true, "requires": { "mime-types": "~2.1.18", "negotiator": "0.6.1" @@ -13372,15 +13394,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true, - "optional": true + "dev": true }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true, - "optional": true + "dev": true }, "asn1": { "version": "0.2.4", @@ -13396,7 +13416,6 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, - "optional": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -13524,7 +13543,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -13693,13 +13712,13 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", "dev": true }, @@ -14119,7 +14138,7 @@ }, "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "dev": true, "requires": { @@ -14162,8 +14181,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true, - "optional": true + "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -14207,10 +14225,9 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -14244,7 +14261,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "dev": true, - "optional": true, "requires": { "bytes": "3.0.0", "content-type": "~1.0.4", @@ -14263,7 +14279,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -14288,7 +14303,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -14327,10 +14342,9 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, - "optional": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -14399,7 +14413,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -14410,7 +14423,6 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, - "optional": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -14420,8 +14432,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true, - "optional": true + "dev": true }, "buffer-crc32": { "version": "0.2.13", @@ -14434,8 +14445,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true, - "optional": true + "dev": true }, "buffer-from": { "version": "1.1.1", @@ -14447,8 +14457,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=", - "dev": true, - "optional": true + "dev": true }, "buffer-xor": { "version": "1.0.3", @@ -14460,8 +14469,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, - "optional": true + "dev": true }, "bytewise": { "version": "1.1.0", @@ -14523,7 +14531,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14607,10 +14615,9 @@ }, "commander": { "version": "2.8.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, - "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -14637,15 +14644,13 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true, - "optional": true + "dev": true }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "optional": true + "dev": true }, "convert-source-map": { "version": "1.6.0", @@ -14660,22 +14665,19 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true, - "optional": true + "dev": true }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true, - "optional": true + "dev": true }, "cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true, - "optional": true + "dev": true }, "core-js": { "version": "2.6.5", @@ -14694,7 +14696,6 @@ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, - "optional": true, "requires": { "object-assign": "^4", "vary": "^1" @@ -14713,7 +14714,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -14726,7 +14727,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -14796,8 +14797,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "optional": true + "dev": true }, "decompress": { "version": "4.2.0", @@ -14818,7 +14818,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "optional": true @@ -14830,7 +14830,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, - "optional": true, "requires": { "mimic-response": "^1.0.0" } @@ -14840,7 +14839,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, - "optional": true, "requires": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -14897,14 +14895,14 @@ "dependencies": { "file-type": { "version": "3.9.0", - "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", "dev": true, "optional": true }, "get-stream": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, "optional": true, @@ -14915,7 +14913,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "optional": true @@ -14981,8 +14979,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "optional": true + "dev": true }, "des.js": { "version": "1.0.0", @@ -14999,8 +14996,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true, - "optional": true + "dev": true }, "detect-indent": { "version": "4.0.0", @@ -15013,7 +15009,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "optional": true, @@ -15044,8 +15040,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true + "dev": true }, "ecc-jsbn": { "version": "0.1.2", @@ -15061,8 +15056,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true, - "optional": true + "dev": true }, "electron-to-chromium": { "version": "1.3.113", @@ -15089,8 +15083,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "optional": true + "dev": true }, "encoding": { "version": "0.1.12", @@ -15189,8 +15182,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true, - "optional": true + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -15208,8 +15200,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true, - "optional": true + "dev": true }, "eth-block-tracker": { "version": "3.0.1", @@ -15228,7 +15219,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -15249,7 +15240,7 @@ }, "eth-json-rpc-middleware": { "version": "1.6.0", - "resolved": "http://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", "dev": true, "requires": { @@ -15276,7 +15267,7 @@ }, "ethereumjs-block": { "version": "1.7.1", - "resolved": "http://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", "dev": true, "requires": { @@ -15294,7 +15285,6 @@ "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", "integrity": "sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA==", "dev": true, - "optional": true, "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", @@ -15378,7 +15368,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" } }, @@ -15389,34 +15379,17 @@ "dev": true }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } } }, "ethereumjs-block": { "version": "1.7.1", - "resolved": "http://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", "dev": true, "requires": { @@ -15448,7 +15421,7 @@ }, "fs-extra": { "version": "0.30.0", - "resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "dev": true, "requires": { @@ -15461,7 +15434,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -15486,7 +15459,7 @@ }, "web3-provider-engine": { "version": "13.8.0", - "resolved": "http://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", + "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", "dev": true, "requires": { @@ -15531,7 +15504,7 @@ "dependencies": { "ethereumjs-util": { "version": "4.5.0", - "resolved": "http://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", "dev": true, "requires": { @@ -15762,7 +15735,6 @@ "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "number-to-bn": "1.7.0" @@ -15772,8 +15744,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -15791,8 +15762,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.1.1.tgz", "integrity": "sha1-R3hr2qCHyvext15zq8XH1UAVjNA=", - "dev": true, - "optional": true + "dev": true }, "events": { "version": "3.0.0", @@ -15815,7 +15785,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "dev": true, - "optional": true, "requires": { "accepts": "~1.3.5", "array-flatten": "1.1.1", @@ -15854,7 +15823,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -15863,8 +15831,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -15936,8 +15903,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true }, "file-uri-to-path": { "version": "1.0.0", @@ -15947,10 +15913,9 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "dev": true, - "optional": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -15966,7 +15931,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -15975,8 +15939,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -16020,29 +15983,25 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true, - "optional": true + "dev": true }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true, - "optional": true + "dev": true }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true + "dev": true }, "fs-extra": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0" @@ -16551,7 +16510,6 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -16579,10 +16537,9 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true + "dev": true }, "getpass": { "version": "0.1.7", @@ -16628,7 +16585,6 @@ "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", "dev": true, - "optional": true, "requires": { "decompress-response": "^3.2.0", "duplexer3": "^0.1.4", @@ -16656,8 +16612,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true, - "optional": true + "dev": true }, "har-schema": { "version": "2.0.0", @@ -16697,8 +16652,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true, - "optional": true + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -16711,7 +16665,6 @@ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, - "optional": true, "requires": { "has-symbol-support-x": "^1.4.1" } @@ -16783,10 +16736,9 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, - "optional": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -16798,8 +16750,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=", - "dev": true, - "optional": true + "dev": true }, "http-signature": { "version": "1.2.0", @@ -16825,8 +16776,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", - "dev": true, - "optional": true + "dev": true }, "immediate": { "version": "3.2.3", @@ -16869,8 +16819,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", - "dev": true, - "optional": true + "dev": true }, "is-arrayish": { "version": "0.2.1", @@ -16937,15 +16886,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true, - "optional": true + "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true + "dev": true }, "is-regex": { "version": "1.0.4", @@ -16960,8 +16907,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", @@ -17007,7 +16953,6 @@ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, - "optional": true, "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -17033,7 +16978,7 @@ }, "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, @@ -17095,13 +17040,13 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -17183,7 +17128,7 @@ }, "level-iterator-stream": { "version": "1.3.1", - "resolved": "http://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", "dev": true, "requires": { @@ -17204,7 +17149,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -17274,7 +17219,7 @@ "dependencies": { "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -17341,7 +17286,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -17354,7 +17299,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -17391,8 +17336,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "3.2.0", @@ -17441,10 +17385,9 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, - "optional": true + "dev": true }, "memdown": { "version": "1.4.1", @@ -17481,12 +17424,11 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true, - "optional": true + "dev": true }, "merkle-patricia-tree": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz", "integrity": "sha512-Qp9Mpb3xazznXzzGQBqHbqCpT2AR9joUOHYYPiQjYCarrdCPCnLWXo4BFv77y4xN26KR224xoU1n/qYY7RYYgw==", "dev": true, "requires": { @@ -17502,7 +17444,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, @@ -17542,8 +17484,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true, - "optional": true + "dev": true }, "miller-rabin": { "version": "4.0.1", @@ -17560,8 +17501,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "optional": true + "dev": true }, "mime-db": { "version": "1.38.0", @@ -17582,8 +17522,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "optional": true + "dev": true }, "min-document": { "version": "2.19.0", @@ -17617,13 +17556,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -17674,26 +17613,24 @@ }, "nan": { "version": "2.10.0", - "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=", - "dev": true, - "optional": true + "dev": true }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true, - "optional": true + "dev": true }, "node-fetch": { "version": "2.1.2", - "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", "dev": true }, @@ -17720,7 +17657,6 @@ "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "strip-hex-prefix": "1.0.0" @@ -17730,8 +17666,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -17764,7 +17699,6 @@ "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.3.tgz", "integrity": "sha1-K0hl29Rr6BIlcT9Om/5Lz09oCk8=", "dev": true, - "optional": true, "requires": { "http-https": "^1.0.0" } @@ -17774,7 +17708,6 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, - "optional": true, "requires": { "ee-first": "1.1.1" } @@ -17790,13 +17723,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -17805,7 +17738,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -17813,22 +17746,19 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", - "dev": true, - "optional": true + "dev": true }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-timeout": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -17838,7 +17768,6 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "dev": true, - "optional": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -17871,8 +17800,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "dev": true, - "optional": true + "dev": true }, "path-exists": { "version": "2.1.0", @@ -17885,7 +17813,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -17899,8 +17827,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true, - "optional": true + "dev": true }, "path-type": { "version": "1.1.0", @@ -17915,7 +17842,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -17972,8 +17899,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true, - "optional": true + "dev": true }, "private": { "version": "0.1.8", @@ -18008,7 +17934,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "dev": true, - "optional": true, "requires": { "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" @@ -18119,10 +18044,9 @@ }, "query-string": { "version": "5.1.1", - "resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dev": true, - "optional": true, "requires": { "decode-uri-component": "^0.2.0", "object-assign": "^4.1.0", @@ -18153,22 +18077,19 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/randomhex/-/randomhex-0.1.5.tgz", "integrity": "sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU=", - "dev": true, - "optional": true + "dev": true }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true, - "optional": true + "dev": true }, "raw-body": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", "dev": true, - "optional": true, "requires": { "bytes": "3.0.0", "http-errors": "1.6.3", @@ -18199,7 +18120,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -18265,7 +18186,7 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, @@ -18486,7 +18407,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "dev": true, - "optional": true, "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -18508,7 +18428,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -18517,8 +18436,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -18527,7 +18445,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, - "optional": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -18540,7 +18457,6 @@ "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", "dev": true, - "optional": true, "requires": { "body-parser": "^1.16.0", "cors": "^2.8.1", @@ -18572,12 +18488,11 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "optional": true + "dev": true }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -18598,15 +18513,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", - "dev": true, - "optional": true + "dev": true }, "simple-get": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "dev": true, - "optional": true, "requires": { "decompress-response": "^3.3.0", "once": "^1.3.1", @@ -18688,8 +18601,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "optional": true + "dev": true }, "stream-to-pull-stream": { "version": "1.7.2", @@ -18713,8 +18625,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true, - "optional": true + "dev": true }, "string-width": { "version": "1.0.2", @@ -18746,7 +18657,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -18832,7 +18743,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -18840,7 +18751,7 @@ }, "tar": { "version": "2.2.1", - "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "dev": true, "optional": true, @@ -18855,7 +18766,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -18882,7 +18792,7 @@ "dependencies": { "bluebird": { "version": "2.11.0", - "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", "dev": true, "optional": true @@ -18894,7 +18804,6 @@ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", "dev": true, - "optional": true, "requires": { "any-promise": "^1.0.0" } @@ -18904,14 +18813,13 @@ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", "dev": true, - "optional": true, "requires": { "thenify": ">= 3.1.0 < 4" } }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -18929,8 +18837,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true + "dev": true }, "tmp": { "version": "0.0.33", @@ -18945,8 +18852,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "1.0.3", @@ -19004,7 +18910,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, - "optional": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.18" @@ -19050,8 +18955,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true, - "optional": true + "dev": true }, "unbzip2-stream": { "version": "1.3.3", @@ -19068,8 +18972,7 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true, - "optional": true + "dev": true }, "unorm": { "version": "1.5.0", @@ -19081,8 +18984,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true, - "optional": true + "dev": true }, "uri-js": { "version": "4.2.2", @@ -19098,7 +19000,6 @@ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, - "optional": true, "requires": { "prepend-http": "^1.0.1" } @@ -19107,15 +19008,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=", - "dev": true, - "optional": true + "dev": true }, "url-to-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true + "dev": true }, "utf8": { "version": "3.0.0", @@ -19134,8 +19033,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "optional": true + "dev": true }, "uuid": { "version": "3.3.2", @@ -19157,8 +19055,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "optional": true + "dev": true }, "verror": { "version": "1.10.0", @@ -19204,7 +19101,6 @@ "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.35.tgz", "integrity": "sha512-ayGavbgVk4KL9Y88Uv411fBJ0SVgVfKhKEBweKYzmP0zOqneMzWt6YsyD1n6kRvjAbqA0AfUPEOKyMNjcx2tjw==", "dev": true, - "optional": true, "requires": { "web3-core-helpers": "1.0.0-beta.35", "web3-core-method": "1.0.0-beta.35", @@ -19217,7 +19113,6 @@ "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz", "integrity": "sha512-APOu3sEsamyqWt//8o4yq9KF25/uqGm+pQShson/sC4gKzmfJB07fLo2ond0X30E8fIqAPeVCotPXQxGciGUmA==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-eth-iban": "1.0.0-beta.35", @@ -19229,7 +19124,6 @@ "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz", "integrity": "sha512-jidImCide8q0GpfsO4L73qoHrbkeWgwU3uOH5DKtJtv0ccmG086knNMRgryb/o9ZgetDWLmDEsJnHjBSoIwcbA==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", @@ -19243,7 +19137,6 @@ "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz", "integrity": "sha512-GvqXqKq07OmHuVi5uNRg6k79a1/CI0ViCC+EtNv4CORHtDRmYEt5Bvdv6z6FJEiaaQkD0lKbFwNhLxutx7HItw==", "dev": true, - "optional": true, "requires": { "any-promise": "1.3.0", "eventemitter3": "1.1.1" @@ -19254,7 +19147,6 @@ "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz", "integrity": "sha512-S+zW2h17ZZQU9oe3yaCJE0E7aJS4C3Kf4kGPDv+nXjW0gKhQQhgVhw1Doq/aYQGqNSWJp7f1VHkz5gQWwg6RRg==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", @@ -19268,7 +19160,6 @@ "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz", "integrity": "sha512-gXzLrWvcGkGiWq1y33Z4Y80XI8XMrwowiQJkrPSjQ81K5PBKquOGwcMffLaKcwdmEy/NpsOXDeFo3eLE1Ghvvw==", "dev": true, - "optional": true, "requires": { "eventemitter3": "1.1.1", "underscore": "1.8.3", @@ -19301,7 +19192,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz", "integrity": "sha512-KUDC+EtFFYG8z01ZleKrASdjj327/rtWHzEt6RWsEj7bBa0bGp9nEh+nqdZx/Sdgz1O8tnfFzJlrRcXpfr1vGg==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "underscore": "1.8.3", @@ -19313,8 +19203,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19362,7 +19251,7 @@ }, "uuid": { "version": "2.0.1", - "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", "dev": true, "optional": true @@ -19391,7 +19280,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz", "integrity": "sha512-H5wkcNcAIc+h/WoDIKv7ZYmrM2Xqu3O7jBQl1IWo73EDVQji+AoB2i3J8tuwI1yZRInRwrfpI3Zuwuf54hXHmQ==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "web3-utils": "1.0.0-beta.35" @@ -19401,8 +19289,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19411,7 +19298,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz", "integrity": "sha512-AcM9nnlxu7ZRRxPvkrFB9eLxMM4A2cPfj2aCg21Wb2EpMnhR+b/O1cT33k7ApRowoMpM+T9M8vx2oPNwXfaCOQ==", "dev": true, - "optional": true, "requires": { "web3-core": "1.0.0-beta.35", "web3-core-helpers": "1.0.0-beta.35", @@ -19425,7 +19311,6 @@ "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.35.tgz", "integrity": "sha512-bbwaQ/KohGjIJ6HAKbZ6KrklCAaG6/B7hIbAbVLSFLxF+Yz9lmAgQYaDInpidpC/NLb3WOmcbRF+P77J4qMVIA==", "dev": true, - "optional": true, "requires": { "web3-core": "1.0.0-beta.35", "web3-core-method": "1.0.0-beta.35", @@ -19466,7 +19351,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" } }, @@ -19477,29 +19362,12 @@ "dev": true }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", - "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", - "dev": true, - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "0.1.6", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } } }, "ethereumjs-block": { @@ -19531,7 +19399,6 @@ "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz", "integrity": "sha512-DcIMFq52Fb08UpWyZ3ZlES6NsNqJnco4hBS/Ej6eOcASfuUayPI+GLkYVZsnF3cBYqlH+DOKuArcKSuIxK7jIA==", "dev": true, - "optional": true, "requires": { "web3-core-helpers": "1.0.0-beta.35", "xhr2-cookies": "1.1.0" @@ -19542,7 +19409,6 @@ "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz", "integrity": "sha512-iB0FG0HcpUnayfa8pn4guqEQ4Y1nrroi/jffdtQgFkrNt0sD3fMSwwC0AbmECqj3tDLl0e1slBR0RENll+ZF0g==", "dev": true, - "optional": true, "requires": { "oboe": "2.1.3", "underscore": "1.8.3", @@ -19554,11 +19420,10 @@ "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz", "integrity": "sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { "debug": { @@ -19566,7 +19431,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -19575,7 +19439,6 @@ "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", "dev": true, - "optional": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -19603,7 +19466,6 @@ "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.35.tgz", "integrity": "sha512-Dq6f0SOKj3BDFRgOPnE6ALbzBDCKVIW8mKWVf7tGVhTDHf+wQaWwQSC3aArFSqdExB75BPBPyDpuMTNszhljpA==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "eth-lib": "0.1.27", @@ -19618,15 +19480,13 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true }, "utf8": { "version": "2.1.1", - "resolved": "http://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19655,7 +19515,7 @@ }, "whatwg-fetch": { "version": "2.0.4", - "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==", "dev": true }, @@ -19673,7 +19533,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -19692,7 +19552,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, - "optional": true, "requires": { "async-limiter": "~1.0.0", "safe-buffer": "~5.1.0", @@ -19716,7 +19575,6 @@ "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", "dev": true, - "optional": true, "requires": { "buffer-to-arraybuffer": "^0.0.5", "object-assign": "^4.1.1", @@ -19732,7 +19590,6 @@ "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", "dev": true, - "optional": true, "requires": { "xhr-request": "^1.0.1" } @@ -19742,7 +19599,6 @@ "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", "dev": true, - "optional": true, "requires": { "cookiejar": "^2.1.1" } @@ -19767,7 +19623,7 @@ }, "yargs": { "version": "4.8.1", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", "dev": true, "requires": { @@ -19789,7 +19645,7 @@ }, "yargs-parser": { "version": "2.4.1", - "resolved": "http://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", "dev": true, "requires": { @@ -27531,8 +27387,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "tar": { "version": "4.4.6", @@ -27552,8 +27407,7 @@ "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "optional": true + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -27800,7 +27654,6 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -28179,8 +28032,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true, - "optional": true + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -28276,7 +28128,6 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -28319,8 +28170,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "4.1.3", @@ -28550,8 +28400,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "optional": true + "dev": true }, "require-directory": { "version": "2.1.1", @@ -38922,7 +38771,7 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.3.tgz", "integrity": "sha1-yqRDc9yIFayHZ73ba6cwc5ZMqos=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -38993,12 +38842,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { diff --git a/package.json b/package.json index 993ca0caa..884c77387 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "ensnare": "^1.0.0", "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^4.1.0", - "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", + "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe", "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^1.2.2", "eth-json-rpc-filters": "^3.0.1", From 12cca730000085a3441c2629fedc0cfbec85a1a9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 5 Apr 2019 02:49:37 +0800 Subject: [PATCH 05/87] doc - publishing - typo fix (#6399) --- docs/publishing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/publishing.md b/docs/publishing.md index 132c28d9b..1668afe1e 100644 --- a/docs/publishing.md +++ b/docs/publishing.md @@ -15,7 +15,7 @@ We try to ensure certain criteria are met before deploying: Version can be automatically incremented [using our bump script](./bumping-version.md). -npm run version:bump $BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`. +npm run version:bump `$BUMP_TYPE` where `$BUMP_TYPE` is one of `major`, `minor`, or `patch`. ## Preparing for Sensitive Changes From 4963ed65c0ee6f827fa6302079d4d8e0a4fdb0aa Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Fri, 5 Apr 2019 00:46:25 -0230 Subject: [PATCH 06/87] Track seed phrase validation errors with MetaMetrics --- .../import-with-seed-phrase.component.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js index 433dad6e2..96ff11eaf 100644 --- a/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js +++ b/ui/app/pages/first-time-flow/create-password/import-with-seed-phrase/import-with-seed-phrase.component.js @@ -36,6 +36,20 @@ export default class ImportWithSeedPhrase extends PureComponent { .join(' ') } + componentWillMount () { + window.onbeforeunload = () => this.context.metricsEvent({ + eventOpts: { + category: 'Onboarding', + action: 'Import Seed Phrase', + name: 'Close window on import screen', + }, + customVariables: { + errorLabel: 'Seed Phrase Error', + errorMessage: this.state.seedPhraseError, + }, + }) + } + handleSeedPhraseChange (seedPhrase) { let seedPhraseError = '' @@ -172,6 +186,10 @@ export default class ImportWithSeedPhrase extends PureComponent { action: 'Import Seed Phrase', name: 'Go Back from Onboarding Import', }, + customVariables: { + errorLabel: 'Seed Phrase Error', + errorMessage: seedPhraseError, + }, }) this.props.history.push(INITIALIZE_SELECT_ACTION_ROUTE) }} From 5454266d7c5f49c3cce59a673674371bb5ccfb7f Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Fri, 5 Apr 2019 01:32:47 -0230 Subject: [PATCH 07/87] Metrics tracking gas changed - slow, average, fast, custom - on edit screen.- --- .../app/send/send-footer/send-footer.component.js | 5 +++++ .../app/send/send-footer/send-footer.container.js | 12 ++++++++++++ .../send-footer/tests/send-footer-container.test.js | 5 +++++ ui/app/helpers/utils/metametrics.util.js | 2 ++ 4 files changed, 24 insertions(+) diff --git a/ui/app/components/app/send/send-footer/send-footer.component.js b/ui/app/components/app/send/send-footer/send-footer.component.js index cc891a9b3..7d894391f 100644 --- a/ui/app/components/app/send/send-footer/send-footer.component.js +++ b/ui/app/components/app/send/send-footer/send-footer.component.js @@ -27,6 +27,7 @@ export default class SendFooter extends Component { unapprovedTxs: PropTypes.object, update: PropTypes.func, sendErrors: PropTypes.object, + gasChangedLabel: PropTypes.string, } static contextTypes = { @@ -57,6 +58,7 @@ export default class SendFooter extends Component { update, toAccounts, history, + gasChangedLabel, } = this.props const { metricsEvent } = this.context @@ -91,6 +93,9 @@ export default class SendFooter extends Component { action: 'Edit Screen', name: 'Complete', }, + customVariables: { + gasChanged: gasChangedLabel, + }, }) history.push(CONFIRM_TRANSACTION_ROUTE) }) diff --git a/ui/app/components/app/send/send-footer/send-footer.container.js b/ui/app/components/app/send/send-footer/send-footer.container.js index ea3fd7ee4..4757f6bec 100644 --- a/ui/app/components/app/send/send-footer/send-footer.container.js +++ b/ui/app/components/app/send/send-footer/send-footer.container.js @@ -31,10 +31,21 @@ import { constructTxParams, constructUpdatedTx, } from './send-footer.utils' +import { + getRenderableEstimateDataForSmallButtonsFromGWEI, + getDefaultActiveButtonIndex, +} from '../../../../selectors/custom-gas' export default connect(mapStateToProps, mapDispatchToProps)(SendFooter) function mapStateToProps (state) { + const gasButtonInfo = getRenderableEstimateDataForSmallButtonsFromGWEI(state) + const gasPrice = getGasPrice(state) + const activeButtonIndex = getDefaultActiveButtonIndex(gasButtonInfo, gasPrice) + const gasChangedLabel = activeButtonIndex >= 0 + ? gasButtonInfo[activeButtonIndex].labelKey + : 'custom' + return { amount: getSendAmount(state), data: getSendHexData(state), @@ -50,6 +61,7 @@ function mapStateToProps (state) { tokenBalance: getTokenBalance(state), unapprovedTxs: getUnapprovedTxs(state), sendErrors: getSendErrors(state), + gasChangedLabel, } } diff --git a/ui/app/components/app/send/send-footer/tests/send-footer-container.test.js b/ui/app/components/app/send/send-footer/tests/send-footer-container.test.js index 878b0aa19..64c6451f2 100644 --- a/ui/app/components/app/send/send-footer/tests/send-footer-container.test.js +++ b/ui/app/components/app/send/send-footer/tests/send-footer-container.test.js @@ -46,6 +46,10 @@ proxyquire('../send-footer.container.js', { }, './send-footer.selectors': { isSendFormInError: (s) => `mockInError:${s}` }, './send-footer.utils': utilsStubs, + '../../../../selectors/custom-gas': { + getRenderableEstimateDataForSmallButtonsFromGWEI: (s) => ([{ labelKey: `mockLabel:${s}` }]), + getDefaultActiveButtonIndex: () => 0, + }, }) describe('send-footer container', () => { @@ -68,6 +72,7 @@ describe('send-footer container', () => { tokenBalance: 'mockTokenBalance:mockState', unapprovedTxs: 'mockUnapprovedTxs:mockState', sendErrors: 'mockSendErrors:mockState', + gasChangedLabel: 'mockLabel:mockState', }) }) diff --git a/ui/app/helpers/utils/metametrics.util.js b/ui/app/helpers/utils/metametrics.util.js index 01984bd5e..5ae3e8937 100644 --- a/ui/app/helpers/utils/metametrics.util.js +++ b/ui/app/helpers/utils/metametrics.util.js @@ -23,6 +23,7 @@ const METAMETRICS_CUSTOM_ERROR_FIELD = 'errorField' const METAMETRICS_CUSTOM_ERROR_MESSAGE = 'errorMessage' const METAMETRICS_CUSTOM_RPC_NETWORK_ID = 'networkId' const METAMETRICS_CUSTOM_RPC_CHAIN_ID = 'chainId' +const METAMETRICS_CUSTOM_GAS_CHANGED = 'gasChanged' const METAMETRICS_CUSTOM_NETWORK = 'network' const METAMETRICS_CUSTOM_ENVIRONMENT_TYPE = 'environmentType' @@ -43,6 +44,7 @@ const customVariableNameIdMap = { [METAMETRICS_CUSTOM_RPC_CHAIN_ID]: 2, [METAMETRICS_CUSTOM_ERROR_FIELD]: 1, [METAMETRICS_CUSTOM_ERROR_MESSAGE]: 2, + [METAMETRICS_CUSTOM_GAS_CHANGED]: 1, } const customDimensionsNameIdMap = { From 5d948360c06c250dcf7261c8624f792a8c21fbae Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Mon, 8 Apr 2019 10:52:26 -0230 Subject: [PATCH 08/87] Distinguish between token and eth selected in home screen send button metrics event. --- .../transaction-view-balance.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js b/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js index 8559e2233..fa63b6fd3 100644 --- a/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js +++ b/ui/app/components/app/transaction-view-balance/transaction-view-balance.component.js @@ -112,7 +112,7 @@ export default class TransactionViewBalance extends PureComponent { eventOpts: { category: 'Navigation', action: 'Home', - name: 'Clicked Send', + name: selectedToken ? 'Clicked Send: Token' : 'Clicked Send: Eth', }, }) history.push(SEND_ROUTE) From c80b295ccccc5d57a5dfe0ca8cc2d663609b7a26 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Mon, 8 Apr 2019 11:32:51 -0230 Subject: [PATCH 09/87] Only pass english function names to functionType metric --- .../confirm-deploy-contract.component.js | 2 +- .../confirm-send-ether.component.js | 2 +- .../confirm-transaction-base.component.js | 22 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js b/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js index 9bc0daab9..c90ccc917 100644 --- a/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js +++ b/ui/app/pages/confirm-deploy-contract/confirm-deploy-contract.component.js @@ -56,7 +56,7 @@ export default class ConfirmDeployContract extends Component { render () { return ( ) diff --git a/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js b/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js index 8daad675e..68280f624 100644 --- a/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js +++ b/ui/app/pages/confirm-send-ether/confirm-send-ether.component.js @@ -30,7 +30,7 @@ export default class ConfirmSendEther extends Component { return ( this.handleEdit(confirmTransactionData)} /> diff --git a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js index 9e749322f..5cafe91c9 100644 --- a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -64,7 +64,7 @@ export default class ConfirmTransactionBase extends Component { updateGasAndCalculate: PropTypes.func, customGas: PropTypes.object, // Component props - action: PropTypes.string, + actionKey: PropTypes.string, contentComponent: PropTypes.node, dataComponent: PropTypes.node, detailsComponent: PropTypes.node, @@ -159,7 +159,7 @@ export default class ConfirmTransactionBase extends Component { } handleEditGas () { - const { onEditGas, showCustomizeGasModal, action, txData: { origin }, methodData = {} } = this.props + const { onEditGas, showCustomizeGasModal, actionKey, txData: { origin }, methodData = {} } = this.props this.context.metricsEvent({ eventOpts: { @@ -169,7 +169,7 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), + functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -292,7 +292,7 @@ export default class ConfirmTransactionBase extends Component { } handleEdit () { - const { txData, tokenData, tokenProps, onEdit, action, txData: { origin }, methodData = {} } = this.props + const { txData, tokenData, tokenProps, onEdit, actionKey, txData: { origin }, methodData = {} } = this.props this.context.metricsEvent({ eventOpts: { @@ -302,7 +302,7 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), + functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -331,7 +331,7 @@ export default class ConfirmTransactionBase extends Component { handleCancel () { const { metricsEvent } = this.context - const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction, action, txData: { origin }, methodData = {} } = this.props + const { onCancel, txData, cancelTransaction, history, clearConfirmTransaction, actionKey, txData: { origin }, methodData = {} } = this.props if (onCancel) { metricsEvent({ @@ -342,7 +342,7 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), + functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -358,7 +358,7 @@ export default class ConfirmTransactionBase extends Component { handleSubmit () { const { metricsEvent } = this.context - const { txData: { origin }, sendTransaction, clearConfirmTransaction, txData, history, onSubmit, action, metaMetricsSendCount = 0, setMetaMetricsSendCount, methodData = {} } = this.props + const { txData: { origin }, sendTransaction, clearConfirmTransaction, txData, history, onSubmit, actionKey, metaMetricsSendCount = 0, setMetaMetricsSendCount, methodData = {} } = this.props const { submitting } = this.state if (submitting) { @@ -377,7 +377,7 @@ export default class ConfirmTransactionBase extends Component { }, customVariables: { recipientKnown: null, - functionType: action || getMethodName(methodData.name) || this.context.t('contractInteraction'), + functionType: actionKey || getMethodName(methodData.name) || 'contractInteraction', origin, }, }) @@ -517,7 +517,7 @@ export default class ConfirmTransactionBase extends Component { valid: propsValid = true, errorMessage, errorKey: propsErrorKey, - action, + actionKey, title, subtitle, hideSubtitle, @@ -543,7 +543,7 @@ export default class ConfirmTransactionBase extends Component { toName={toName} toAddress={toAddress} showEdit={onEdit && !isTxReprice} - action={action || getMethodName(name) || this.context.t('contractInteraction')} + action={this.context.t(actionKey) || getMethodName(name) || this.context.t('contractInteraction')} title={title} titleComponent={this.renderTitleComponent()} subtitle={subtitle} From 79804ec79bda1cffa530743ddb8d299c257092a2 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 8 Apr 2019 15:52:23 -0230 Subject: [PATCH 10/87] Version 6.3.2 (#6418) --- CHANGELOG.md | 6 ++++++ app/manifest.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98ed6ac69..69ca119ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Develop Branch +## 6.3.2 Mon Apr 8 2019 + +- [#6389](https://github.com/MetaMask/metamask-extension/pull/6389): Fix display of gas chart on ethereum networks +- [#6395](https://github.com/MetaMask/metamask-extension/pull/6395): Fixes for signing methods for ledger and trezor devices +- [#6397](https://github.com/MetaMask/metamask-extension/pull/6397): Fix Wyre link + ## 6.3.1 Fri Mar 26 2019 - [#6353](https://github.com/MetaMask/metamask-extension/pull/6353): Open restore vault in full screen when clicked from popup diff --git a/app/manifest.json b/app/manifest.json index 941842636..5e464dc2f 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "6.3.1", + "version": "6.3.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 7b13e9ae2e1756aca4c2a9ffb7d23026353c1d27 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 8 Apr 2019 15:43:34 -0400 Subject: [PATCH 11/87] Update porting_to_new_environment.md This MetamaskInpageProvider file was moved out into its own repo, this updates the link to point to that repo. --- docs/porting_to_new_environment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md index d901f2b78..f7a2ac8b7 100644 --- a/docs/porting_to_new_environment.md +++ b/docs/porting_to_new_environment.md @@ -10,7 +10,7 @@ The `metamask-background` describes the file at `app/scripts/background.js`, whi When a new site is visited, the WebExtension creates a new `ContentScript` in that page's context, which can be seen at `app/scripts/contentscript.js`. This script represents a per-page setup process, which creates the per-page `web3` api, connects it to the background script via the Port API (wrapped in a [stream abstraction](https://github.com/substack/stream-handbook)), and injected into the DOM before anything loads. -The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API over a series of streams between contexts. Once you understand how we create the [InpageProvider](../app/scripts/lib/inpage-provider.js) in the [inpage.js script](../app/scripts/inpage.js), you will be able to understand how the [port-stream](../app/scripts/lib/port-stream.js) is just a thin wrapper around the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage), and a similar stream API can be wrapped around any communication channel to communicate with the `MetaMaskController` via its `setupUntrustedCommunication(stream, domain)` method. +The most confusing part about porting MetaMask to a new platform is the way we provide the Web3 API over a series of streams between contexts. Once you understand how we create the [MetamaskInpageProvider](https://github.com/MetaMask/metamask-inpage-provider/blob/master/index.js) in the [inpage.js script](../app/scripts/inpage.js), you will be able to understand how the [port-stream](../app/scripts/lib/port-stream.js) is just a thin wrapper around the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage), and a similar stream API can be wrapped around any communication channel to communicate with the `MetaMaskController` via its `setupUntrustedCommunication(stream, domain)` method. ### The MetaMask Controller @@ -89,7 +89,7 @@ MetaMask has two kinds of [duplex stream APIs](https://github.com/substack/strea If you are making a MetaMask-powered browser for a new platform, one of the trickiest tasks will be injecting the Web3 API into websites that are visited. On WebExtensions, we actually have to pipe data through a total of three JS contexts just to let sites talk to our background process (site -> contentscript -> background). -To see how we do that, you can refer to the [inpage script](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/inpage.js) that we inject into every website. There you can see it creates a multiplex stream to the background, and uses it to initialize what we call the [inpage-provider](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/lib/inpage-provider.js), which you can see stubs a few methods out, but mostly just passes calls to `sendAsync` through the stream it's passed! That's really all the magic that's needed to create a web3-like API in a remote context, once you have a stream to MetaMask available. +To see how we do that, you can refer to the [inpage script](https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/inpage.js) that we inject into every website. There you can see it creates a multiplex stream to the background, and uses it to initialize what we call the [MetamaskInpageProvider](https://github.com/MetaMask/metamask-inpage-provider/blob/master/index.js), which you can see stubs a few methods out, but mostly just passes calls to `sendAsync` through the stream it's passed! That's really all the magic that's needed to create a web3-like API in a remote context, once you have a stream to MetaMask available. In `inpage.js` you can see we create a `PortStream`, that's just a class we use to wrap WebExtension ports as streams, so we can reuse our favorite stream abstraction over the more irregular API surface of the WebExtension. In a new platform, you will probably need to construct this stream differently. The key is that you need to construct a stream that talks from the site context to the background. Once you have that set up, it works like magic! From 24761326de652e14533c8f51498a25e875ab429b Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 9 Apr 2019 14:14:04 -0230 Subject: [PATCH 12/87] Don't inject web3 on sharefile.com --- app/scripts/contentscript.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 68b6117e5..2325cecdd 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -275,6 +275,7 @@ function blacklistedDomainCheck () { 'harbourair.com', 'ani.gamer.com.tw', 'blueskybooking.com', + 'sharefile.com', ] const currentUrl = window.location.href let currentRegex From d7a2ea9a2b28678bf46dfb606187f4bbb7d22453 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Wed, 10 Apr 2019 16:34:13 -0500 Subject: [PATCH 13/87] Add Localhost 8545 for network dropdown names --- app/_locales/en/messages.json | 3 +++ ui/app/components/app/dropdowns/network-dropdown.js | 2 ++ .../loading-network-screen.component.js | 2 ++ ui/app/components/app/network.js | 2 +- ui/app/pages/routes/index.js | 4 ++++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 154925d1a..f9d23f69e 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -308,6 +308,9 @@ "connectingToRinkeby": { "message": "Connecting to Rinkeby Test Network" }, + "connectingToLocalhost": { + "message": "Connecting to Localhost 8545" + }, "connectingToUnknown": { "message": "Connecting to Unknown Network" }, diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index 3d9037a06..7e645725c 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -285,6 +285,8 @@ NetworkDropdown.prototype.getNetworkName = function () { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') + } else if (providerName === 'localhost') { + name = this.context.t('localhost') } else { name = provider.nickname || this.context.t('unknownNetwork') } diff --git a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js index 348a997c8..b79051d0b 100644 --- a/ui/app/components/app/loading-network-screen/loading-network-screen.component.js +++ b/ui/app/components/app/loading-network-screen/loading-network-screen.component.js @@ -45,6 +45,8 @@ export default class LoadingNetworkScreen extends PureComponent { name = this.context.t('connectingToKovan') } else if (providerName === 'rinkeby') { name = this.context.t('connectingToRinkeby') + } else if (providerName === 'localhost') { + name = this.context.t('connectingToLocalhost') } else { name = this.context.t('connectingTo', [providerId]) } diff --git a/ui/app/components/app/network.js b/ui/app/components/app/network.js index e18404f42..54065dd73 100644 --- a/ui/app/components/app/network.js +++ b/ui/app/components/app/network.js @@ -139,7 +139,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', providerNick || context.t('privateNetwork')), + h('.network-name', providerName === 'localhost' ? context.t('localhost') : providerNick || context.t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index e06d88c90..37ff2df61 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -267,6 +267,8 @@ class Routes extends Component { name = this.context.t('connectingToKovan') } else if (providerName === 'rinkeby') { name = this.context.t('connectingToRinkeby') + } else if (providerName === 'localhost') { + name = this.context.t('connectingToLocalhost') } else { name = this.context.t('connectingTo', [providerId]) } @@ -288,6 +290,8 @@ class Routes extends Component { name = this.context.t('kovan') } else if (providerName === 'rinkeby') { name = this.context.t('rinkeby') + } else if (providerName === 'localhost') { + name = this.context.t('localhost') } else { name = this.context.t('unknownNetwork') } From a973a7420abed55998b88c339d1c6a1c53bd63e2 Mon Sep 17 00:00:00 2001 From: Paul Bouchon Date: Wed, 10 Apr 2019 18:37:15 -0400 Subject: [PATCH 14/87] feature: switch token pricing to CoinGecko API (#6424) --- app/scripts/controllers/token-rates.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js index 867d36433..4e396bb59 100644 --- a/app/scripts/controllers/token-rates.js +++ b/app/scripts/controllers/token-rates.js @@ -28,16 +28,16 @@ class TokenRatesController { async updateExchangeRates () { if (!this.isActive) { return } const contractExchangeRates = {} - const nativeCurrency = this.currency ? this.currency.getState().nativeCurrency.toUpperCase() : 'ETH' - const pairs = this._tokens.map(token => `pairs[]=${token.address}/${nativeCurrency}`) - const query = pairs.join('&') + const nativeCurrency = this.currency ? this.currency.getState().nativeCurrency.toLowerCase() : 'eth' + const pairs = this._tokens.map(token => token.address).join(',') + const query = `contract_addresses=${pairs}&vs_currencies=${nativeCurrency}` if (this._tokens.length > 0) { try { - const response = await fetch(`https://exchanges.balanc3.net/pie?${query}&autoConversion=false`) - const { prices = [] } = await response.json() - prices.forEach(({ pair, price }) => { - const address = pair.split('/')[0] - contractExchangeRates[normalizeAddress(address)] = typeof price === 'number' ? price : 0 + const response = await fetch(`https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`) + const prices = await response.json() + this._tokens.forEach(token => { + const price = prices[token.address.toLowerCase()] + contractExchangeRates[normalizeAddress(token.address)] = price ? price[nativeCurrency] : 0 }) } catch (error) { log.warn(`MetaMask - TokenRatesController exchange rate fetch failed.`, error) From 7ceb1c63ccceeb631c148b9244987dba54f77b12 Mon Sep 17 00:00:00 2001 From: Etienne Dusseault Date: Thu, 11 Apr 2019 09:26:47 +0800 Subject: [PATCH 15/87] Added Chrome limited site access solution doc (#6422) --- docs/limited_site_access.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/limited_site_access.md diff --git a/docs/limited_site_access.md b/docs/limited_site_access.md new file mode 100644 index 000000000..f703d5c7e --- /dev/null +++ b/docs/limited_site_access.md @@ -0,0 +1,5 @@ +# Google Chrome/Brave Limited Site Access for Extensions + +Problem: MetaMask doesn't work with limited site access enabled under Chrome's extensions. + +Solution: In addition to the site you wish to whitelist, you must add 'api.infura.io' as another domain, so the MetaMask extension is authorized to make RPC calls to Infura. From 2786932576a92f8e75ee798d91c8222741c774c9 Mon Sep 17 00:00:00 2001 From: Sneh Koul <35871990+Sneh1999@users.noreply.github.com> Date: Thu, 11 Apr 2019 10:50:03 -0700 Subject: [PATCH 16/87] repeated getSelectedAddress() func send.selectors.js removed (#6056) --- ui/app/components/app/send/send.container.js | 5 ++++- ui/app/components/app/send/send.selectors.js | 8 +------- ui/app/components/app/send/tests/send-container.test.js | 5 ++++- ui/app/components/app/send/tests/send-selectors.test.js | 9 --------- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/ui/app/components/app/send/send.container.js b/ui/app/components/app/send/send.container.js index e65463b93..303639c76 100644 --- a/ui/app/components/app/send/send.container.js +++ b/ui/app/components/app/send/send.container.js @@ -2,6 +2,10 @@ import { connect } from 'react-redux' import SendEther from './send.component' import { withRouter } from 'react-router-dom' import { compose } from 'recompose' +const { + getSelectedAddress, +} = require('../../../selectors/selectors') + import { getAmountConversionRate, getBlockGasLimit, @@ -12,7 +16,6 @@ import { getGasTotal, getPrimaryCurrency, getRecentBlocks, - getSelectedAddress, getSelectedToken, getSelectedTokenContract, getSelectedTokenToFiatRate, diff --git a/ui/app/components/app/send/send.selectors.js b/ui/app/components/app/send/send.selectors.js index 2ec677ad1..89f047d50 100644 --- a/ui/app/components/app/send/send.selectors.js +++ b/ui/app/components/app/send/send.selectors.js @@ -5,6 +5,7 @@ const { } = require('../../../helpers/utils/conversion-util') const { getMetaMaskAccounts, + getSelectedAddress, } = require('../../../selectors/selectors') const { estimateGasPriceFromRecentBlocks, @@ -33,7 +34,6 @@ const selectors = { getPrimaryCurrency, getRecentBlocks, getSelectedAccount, - getSelectedAddress, getSelectedIdentity, getSelectedToken, getSelectedTokenContract, @@ -149,12 +149,6 @@ function getSelectedAccount (state) { return accounts[selectedAddress] } -function getSelectedAddress (state) { - const selectedAddress = state.metamask.selectedAddress || Object.keys(getMetaMaskAccounts(state))[0] - - return selectedAddress -} - function getSelectedIdentity (state) { const selectedAddress = getSelectedAddress(state) const identities = state.metamask.identities diff --git a/ui/app/components/app/send/tests/send-container.test.js b/ui/app/components/app/send/tests/send-container.test.js index 9538b67b3..9d7365ac9 100644 --- a/ui/app/components/app/send/tests/send-container.test.js +++ b/ui/app/components/app/send/tests/send-container.test.js @@ -35,7 +35,6 @@ proxyquire('../send.container.js', { getGasTotal: (s) => `mockGasTotal:${s}`, getPrimaryCurrency: (s) => `mockPrimaryCurrency:${s}`, getRecentBlocks: (s) => `mockRecentBlocks:${s}`, - getSelectedAddress: (s) => `mockSelectedAddress:${s}`, getSelectedToken: (s) => `mockSelectedToken:${s}`, getSelectedTokenContract: (s) => `mockTokenContract:${s}`, getSelectedTokenToFiatRate: (s) => `mockTokenToFiatRate:${s}`, @@ -47,11 +46,15 @@ proxyquire('../send.container.js', { getTokenBalance: (s) => `mockTokenBalance:${s}`, getQrCodeData: (s) => `mockQrCodeData:${s}`, }, + '../../../selectors/selectors': { + getSelectedAddress: (s) => `mockSelectedAddress:${s}`, + }, '../../../store/actions': actionSpies, '../../../ducks/send/send.duck': duckActionSpies, './send.utils.js': { calcGasTotal: (gasLimit, gasPrice) => gasLimit + gasPrice, }, + }) describe('send container', () => { diff --git a/ui/app/components/app/send/tests/send-selectors.test.js b/ui/app/components/app/send/tests/send-selectors.test.js index cdc86fe59..ccc126795 100644 --- a/ui/app/components/app/send/tests/send-selectors.test.js +++ b/ui/app/components/app/send/tests/send-selectors.test.js @@ -20,7 +20,6 @@ const { getPrimaryCurrency, getRecentBlocks, getSelectedAccount, - getSelectedAddress, getSelectedIdentity, getSelectedToken, getSelectedTokenContract, @@ -274,14 +273,6 @@ describe('send selectors', () => { }) }) - describe('getSelectedAddress()', () => { - it('should', () => { - assert.equal( - getSelectedAddress(mockState), - '0xd85a4b6a394794842887b8284293d69163007bbb' - ) - }) - }) describe('getSelectedIdentity()', () => { it('should return the identity object of the currently selected address', () => { From c4a3d4ea82ef5488c8c91db77beca85679447722 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Thu, 11 Apr 2019 21:33:33 -0230 Subject: [PATCH 17/87] Remove unneeded array cloning in getSendToAccounts selector The use of `Object.entries` here to map the accounts into a new array effectively produces a shallow clone of the array without guaranteeing the order of the original array (as object iteration order is implementation-specific and variable). From MDN [1]: > The **`Object.entries()`** method returns an array of a given object's own enumerable > string-keyed property `[key, value]` pairs, in the same order as that provided by a > `for...in` loop And also: > The ordering of the properties is the same as that given by looping over the > property values of the object manually. Both of which suggest that the iteration order is the same as `for...in`, which is to say that it's not specified. [2] [3] This changeset removes the cloning, keeping the shallow clone created the line before which preserves the order of the items in the array. [1]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries [2]:https://stackoverflow.com/a/5525820/1267663 [3]:https://stackoverflow.com/a/30919039/1267663 --- ui/app/components/app/send/send.selectors.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ui/app/components/app/send/send.selectors.js b/ui/app/components/app/send/send.selectors.js index 89f047d50..6056dea21 100644 --- a/ui/app/components/app/send/send.selectors.js +++ b/ui/app/components/app/send/send.selectors.js @@ -240,9 +240,7 @@ function getSendTo (state) { function getSendToAccounts (state) { const fromAccounts = accountsWithSendEtherInfoSelector(state) const addressBookAccounts = getAddressBook(state) - const allAccounts = [...fromAccounts, ...addressBookAccounts] - // TODO: figure out exactly what the below returns and put a descriptive variable name on it - return Object.entries(allAccounts).map(([key, account]) => account) + return [...fromAccounts, ...addressBookAccounts] } function getSendWarnings (state) { From 7c38ad9356bdf87d4a1aed15ec31c8968ed49cb8 Mon Sep 17 00:00:00 2001 From: Esteban Mino Date: Fri, 12 Apr 2019 12:26:39 -0400 Subject: [PATCH 18/87] bump contract metadata --- package-lock.json | 97 +++++++++++++++++++++++++++++++++++++++++------ package.json | 2 +- 2 files changed, 86 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 11eab5718..88f1832ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9759,8 +9759,8 @@ } }, "eth-contract-metadata": { - "version": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe", - "from": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe" + "version": "github:MetaMask/eth-contract-metadata#41a14e8004bdd37eaba5af5f2bb1fc4f4ff7063f", + "from": "github:MetaMask/eth-contract-metadata#41a14e8004bdd37eaba5af5f2bb1fc4f4ff7063f" }, "eth-ens-namehash": { "version": "2.0.8", @@ -9806,6 +9806,31 @@ "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } @@ -9814,8 +9839,7 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -9896,6 +9920,31 @@ "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } @@ -9904,8 +9953,7 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -10076,6 +10124,33 @@ "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } @@ -10084,14 +10159,14 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -10192,8 +10267,7 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -10502,8 +10576,7 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { diff --git a/package.json b/package.json index 884c77387..2c81507ce 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "ensnare": "^1.0.0", "eth-bin-to-ops": "^1.0.1", "eth-block-tracker": "^4.1.0", - "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#92e7d1442c7585bfd24e50a0fda78df11dedadfe", + "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#41a14e8004bdd37eaba5af5f2bb1fc4f4ff7063f", "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^1.2.2", "eth-json-rpc-filters": "^3.0.1", From 33836c04638bd0ef023ed913e4c8ec976ad3caae Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Tue, 16 Apr 2019 11:15:53 -0600 Subject: [PATCH 19/87] Set rpcTarget, nickname, and ticker when selecting one of the default networks --- app/scripts/controllers/network/network.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 47432c1e2..ab1198dd3 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -140,10 +140,10 @@ module.exports = class NetworkController extends EventEmitter { this.providerConfig = providerConfig } - async setProviderType (type) { + async setProviderType (type, rpcTarget = '', ticker = 'ETH', nickname = '') { assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`) assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`) - const providerConfig = { type } + const providerConfig = { type, rpcTarget, ticker, nickname } this.providerConfig = providerConfig } From fb22fb12cafec238a2143df6e94218c890e4ba4e Mon Sep 17 00:00:00 2001 From: Sneh Koul <35871990+Sneh1999@users.noreply.github.com> Date: Tue, 16 Apr 2019 10:59:11 -0700 Subject: [PATCH 20/87] Adds e2e test for most web3 methods that dapps use (#6160) * schema added * ui for the dapp added and schema.js changed according to the comments in PR * added tests for all web3 methods * Update run-all.sh * Update web3.spec.js to work with new onboarding flow * changes made according to the comments * Create stand alone script for web3 e2e tests. * Lint fixes for web3 e2e tests. --- package.json | 2 + test/e2e/beta/run-web3.sh | 9 + test/e2e/beta/web3.spec.js | 365 +++++++++++++++++++++++++++++++++++++ test/web3/index.html | 105 +++++++++++ test/web3/schema.js | 209 +++++++++++++++++++++ test/web3/web3.js | 34 ++++ 6 files changed, 724 insertions(+) create mode 100755 test/e2e/beta/run-web3.sh create mode 100644 test/e2e/beta/web3.spec.js create mode 100644 test/web3/index.html create mode 100644 test/web3/schema.js create mode 100644 test/web3/web3.js diff --git a/package.json b/package.json index 2c81507ce..c0355d12c 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "test:integration:build": "gulp build:scss", "test:e2e:drizzle:beta": "SELENIUM_BROWSER=chrome test/e2e/beta/run-drizzle.sh", "test:e2e:chrome": "SELENIUM_BROWSER=chrome test/e2e/beta/run-all.sh", + "test:web3:chrome": "SELENIUM_BROWSER=chrome test/e2e/beta/run-web3.sh", + "test:web3:firefox": "SELENIUM_BROWSER=firefox test/e2e/beta/run-web3.sh", "test:e2e:firefox": "SELENIUM_BROWSER=firefox test/e2e/beta/run-all.sh", "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'", "test:screens:run": "node test/screens/new-ui.js", diff --git a/test/e2e/beta/run-web3.sh b/test/e2e/beta/run-web3.sh new file mode 100755 index 000000000..9f77060de --- /dev/null +++ b/test/e2e/beta/run-web3.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e +set -u +set -o pipefail + +export PATH="$PATH:./node_modules/.bin" + +shell-parallel -s 'static-server test/web3 --port 8080' -x 'sleep 5 && mocha test/e2e/beta/web3.spec' \ No newline at end of file diff --git a/test/e2e/beta/web3.spec.js b/test/e2e/beta/web3.spec.js new file mode 100644 index 000000000..b3962c821 --- /dev/null +++ b/test/e2e/beta/web3.spec.js @@ -0,0 +1,365 @@ +const path = require('path') +const assert = require('assert') +const webdriver = require('selenium-webdriver') +const { By } = webdriver +const { + delay, + buildChromeWebDriver, + buildFirefoxWebdriver, + installWebExt, + getExtensionIdChrome, + getExtensionIdFirefox, +} = require('../func') +const { + checkBrowserForConsoleErrors, + closeAllWindowHandlesExcept, + findElement, + findElements, + openNewPage, + switchToWindowWithTitle, + verboseReportOnFailure, + waitUntilXWindowHandles, +} = require('./helpers') +const fetchMockResponses = require('./fetch-mocks.js') + + +describe('Using MetaMask with an existing account', function () { + let extensionId + let driver + + const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' + const regularDelayMs = 1000 + const largeDelayMs = regularDelayMs * 2 + + const button = async (x) => { + const buttoncheck = x + await buttoncheck.click() + await delay(largeDelayMs) + const [results] = await findElements(driver, By.css('#results')) + const resulttext = await results.getText() + var parsedData = JSON.parse(resulttext) + + return (parsedData) + + } + + this.timeout(0) + this.bail(true) + + before(async function () { + let extensionUrl + switch (process.env.SELENIUM_BROWSER) { + case 'chrome': { + const extensionPath = path.resolve('dist/chrome') + driver = buildChromeWebDriver(extensionPath) + extensionId = await getExtensionIdChrome(driver) + await delay(regularDelayMs) + extensionUrl = `chrome-extension://${extensionId}/home.html` + break + } + case 'firefox': { + const extensionPath = path.resolve('dist/firefox') + driver = buildFirefoxWebdriver() + await installWebExt(driver, extensionPath) + await delay(regularDelayMs) + extensionId = await getExtensionIdFirefox(driver) + extensionUrl = `moz-extension://${extensionId}/home.html` + break + } + } + // Depending on the state of the application built into the above directory (extPath) and the value of + // METAMASK_DEBUG we will see different post-install behaviour and possibly some extra windows. Here we + // are closing any extraneous windows to reset us to a single window before continuing. + const [tab1] = await driver.getAllWindowHandles() + await closeAllWindowHandlesExcept(driver, [tab1]) + await driver.switchTo().window(tab1) + await driver.get(extensionUrl) + }) + + beforeEach(async function () { + await driver.executeScript( + 'window.origFetch = window.fetch.bind(window);' + + 'window.fetch = ' + + '(...args) => { ' + + 'if (args[0] === "https://ethgasstation.info/json/ethgasAPI.json") { return ' + + 'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.ethGasBasic + '\')) }); } else if ' + + '(args[0] === "https://ethgasstation.info/json/predictTable.json") { return ' + + 'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.ethGasPredictTable + '\')) }); } else if ' + + '(args[0].match(/chromeextensionmm/)) { return ' + + 'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.metametrics + '\')) }); } else if ' + + '(args[0] === "https://dev.blockscale.net/api/gasexpress.json") { return ' + + 'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.gasExpress + '\')) }); } ' + + 'return window.origFetch(...args); };' + + 'function cancelInfuraRequest(requestDetails) {' + + 'console.log("Canceling: " + requestDetails.url);' + + 'return {' + + 'cancel: true' + + '};' + + ' }' + + 'window.chrome && window.chrome.webRequest && window.chrome.webRequest.onBeforeRequest.addListener(' + + 'cancelInfuraRequest,' + + '{urls: ["https://*.infura.io/*"]},' + + '["blocking"]' + + ');' + ) + }) + + afterEach(async function () { + if (process.env.SELENIUM_BROWSER === 'chrome') { + const errors = await checkBrowserForConsoleErrors(driver) + if (errors.length) { + const errorReports = errors.map(err => err.message) + const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` + console.error(new Error(errorMessage)) + } + } + if (this.currentTest.state === 'failed') { + await verboseReportOnFailure(driver, this.currentTest) + } + }) + + after(async function () { + await driver.quit() + }) + + describe('First time flow starting from an existing seed phrase', () => { + it('clicks the continue button on the welcome screen', async () => { + await findElement(driver, By.css('.welcome-page__header')) + const welcomeScreenBtn = await findElement(driver, By.css('.first-time-flow__button')) + welcomeScreenBtn.click() + await delay(largeDelayMs) + }) + + it('clicks the "Import Wallet" option', async () => { + const customRpcButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Import Wallet')]`)) + customRpcButton.click() + await delay(largeDelayMs) + }) + + it('clicks the "No thanks" option on the metametrics opt-in screen', async () => { + const optOutButton = await findElement(driver, By.css('.btn-default')) + optOutButton.click() + await delay(largeDelayMs) + }) + + it('imports a seed phrase', async () => { + const [seedTextArea] = await findElements(driver, By.css('textarea.first-time-flow__textarea')) + await seedTextArea.sendKeys(testSeedPhrase) + await delay(regularDelayMs) + + const [password] = await findElements(driver, By.id('password')) + await password.sendKeys('correct horse battery staple') + const [confirmPassword] = await findElements(driver, By.id('confirm-password')) + confirmPassword.sendKeys('correct horse battery staple') + + const tosCheckBox = await findElement(driver, By.css('.first-time-flow__checkbox')) + await tosCheckBox.click() + + const [importButton] = await findElements(driver, By.xpath(`//button[contains(text(), 'Import')]`)) + await importButton.click() + await delay(regularDelayMs) + }) + + it('clicks through the success screen', async () => { + await findElement(driver, By.xpath(`//div[contains(text(), 'Congratulations')]`)) + const doneButton = await findElement(driver, By.css('button.first-time-flow__button')) + await doneButton.click() + await delay(regularDelayMs) + }) + }) + + + describe('opens dapp', () => { + + it('switches to mainnet', async () => { + const networkDropdown = await findElement(driver, By.css('.network-name')) + await networkDropdown.click() + await delay(regularDelayMs) + + const [mainnet] = await findElements(driver, By.xpath(`//span[contains(text(), 'Main Ethereum Network')]`)) + await mainnet.click() + await delay(largeDelayMs * 2) + }) + + it('', async () => { + await openNewPage(driver, 'http://127.0.0.1:8080/') + await delay(regularDelayMs) + + await waitUntilXWindowHandles(driver, 3) + const windowHandles = await driver.getAllWindowHandles() + + const extension = windowHandles[0] + const popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles) + const dapp = windowHandles.find(handle => handle !== extension && handle !== popup) + + await delay(regularDelayMs) + const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`)) + await approveButton.click() + + await driver.switchTo().window(dapp) + await delay(regularDelayMs) + + + }) + }) + + describe('testing web3 methods', async () => { + + + it('testing hexa methods', async () => { + + + var List = await driver.findElements(By.className('hexaNumberMethods')) + + for (let i = 0; i < List.length; i++) { + try { + + var parsedData = await button(List[i]) + console.log(parsedData) + var result = parseInt(parsedData.result, 16) + + assert.equal((typeof result === 'number'), true) + await delay(regularDelayMs) + } catch (err) { + console.log(err) + assert(false) + + } + } + }) + + it('testing booleanMethods', async () => { + + var List = await driver.findElements(By.className('booleanMethods')) + + for (let i = 0; i < List.length; i++) { + try { + + var parsedData = await button(List[i]) + console.log(parsedData) + var result = parsedData.result + + assert.equal(result, false) + await delay(regularDelayMs) + } catch (err) { + console.log(err) + assert(false) + + + } + } + + }) + + it('testing transactionMethods', async () => { + + var List = await driver.findElements(By.className('transactionMethods')) + + for (let i = 0; i < List.length; i++) { + try { + + var parsedData = await button(List[i]) + + console.log(parsedData.result.blockHash) + + var result = [] + result.push(parseInt(parsedData.result.blockHash, 16)) + result.push(parseInt(parsedData.result.blockNumber, 16)) + result.push(parseInt(parsedData.result.gas, 16)) + result.push(parseInt(parsedData.result.gasPrice, 16)) + result.push(parseInt(parsedData.result.hash, 16)) + result.push(parseInt(parsedData.result.input, 16)) + result.push(parseInt(parsedData.result.nonce, 16)) + result.push(parseInt(parsedData.result.r, 16)) + result.push(parseInt(parsedData.result.s, 16)) + result.push(parseInt(parsedData.result.v, 16)) + result.push(parseInt(parsedData.result.to, 16)) + result.push(parseInt(parsedData.result.value, 16)) + + + result.forEach((value) => { + assert.equal((typeof value === 'number'), true) + }) + + + } catch (err) { + + console.log(err) + assert(false) + + + } + } + + }) + + it('testing blockMethods', async () => { + + var List = await driver.findElements(By.className('blockMethods')) + + for (let i = 0; i < List.length; i++) { + try { + + var parsedData = await button(List[i]) + console.log(JSON.stringify(parsedData) + i) + + console.log(parsedData.result.parentHash) + + var result = parseInt(parsedData.result.parentHash, 16) + + assert.equal((typeof result === 'number'), true) + await delay(regularDelayMs) + } catch (err) { + + console.log(err) + assert(false) + + + } + } + }) + + it('testing methods', async () => { + + var List = await driver.findElements(By.className('methods')) + var parsedData + var result + + for (let i = 0; i < List.length; i++) { + try { + + if (i === 2) { + + parsedData = await button(List[i]) + console.log(parsedData.result.blockHash) + + result = parseInt(parsedData.result.blockHash, 16) + + assert.equal((typeof result === 'number' || (result === 0)), true) + await delay(regularDelayMs) + } else { + parsedData = await button(List[i]) + console.log(parsedData.result) + + result = parseInt(parsedData.result, 16) + + assert.equal((typeof result === 'number' || (result === 0)), true) + await delay(regularDelayMs) + } + + + } catch (err) { + + console.log(err) + assert(false) + + + } + } + }) + + + }) + + + }) diff --git a/test/web3/index.html b/test/web3/index.html new file mode 100644 index 000000000..cbc43290c --- /dev/null +++ b/test/web3/index.html @@ -0,0 +1,105 @@ + + + Web3 Test Dapp + + +
+
hexaNumberMethods
+
+ + + + + + + +
+
+ + + +
+
+ + + + + + +
+
+
+
booleanMethods
+
+ + + +
+
+
+
transactionMethods
+
+ + + + + +
+
+ +
+
blockMethods
+ +
+ + + + +
+
+ + + +
+
+ +
+
Methods
+
+ + + + +
+
+
+
+
+ + + + + + + + + + diff --git a/test/web3/schema.js b/test/web3/schema.js new file mode 100644 index 000000000..61977f140 --- /dev/null +++ b/test/web3/schema.js @@ -0,0 +1,209 @@ +/* eslint no-unused-vars: 0 */ + +var params = { + // diffrent params used in the methods + param: [], + blockHashParams: '0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35', + filterParams: ['0xfe704947a3cd3ca12541458a4321c869'], + transactionHashParams: [ + '0xbb3a336e3f823ec18197f1e13ee875700f08f03e2cab75f0d0b118dabb44cba0', + ], + blockHashAndIndexParams: [ + '0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35', + '0x0', + ], + uncleByBlockNumberAndIndexParams: ['0x29c', '0x0'], + blockParameterParams: '0x5bad55', + data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', + addressParams: '0xc94770007dda54cF92009BFF0dE90c06F603a09f', + getStorageAtParams: [ + '0x295a70b2de5e3953354a6a8344e616ed314d7251', + '0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9', + '0x65a8db', + ], + getCodeParams: ['0x06012c8cf97bead5deae237070f9587f8e7a266d', '0x65a8db'], + estimateTransaction: { + from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155', + to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567', + gas: '0x76c0', + gasPrice: '0x9184e72a000', + value: '0x9184e72a', + data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', + }, + filterGetLogs: [{'blockHash': '0x7c5a35e9cb3e8ae0e221ab470abae9d446c3a5626ce6689fc777dcffcab52c70', 'topics': ['0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80']}], + block: { + __required: [], + number: 'Q', + hash: 'D32', + parentHash: 'D32', + nonce: 'D', + sha3Uncles: 'D', + logsBloom: 'D', + transactionsRoot: 'D', + stateRoot: 'D', + receiptsRoot: 'D', + miner: 'D', + difficulty: 'Q', + totalDifficulty: 'Q', + extraData: 'D', + size: 'Q', + gasLimit: 'Q', + gasUsed: 'Q', + timestamp: 'Q', + transactions: ['DATA|Transaction'], + uncles: ['D'], + }, + transaction: { + __required: [], + hash: 'D32', + nonce: 'Q', + blockHash: 'D32', + blockNumber: 'Q', + transactionIndex: 'Q', + from: 'D20', + to: 'D20', + value: 'Q', + gasPrice: 'Q', + gas: 'Q', + input: 'D', + }, + receipt: { + __required: [], + transactionHash: 'D32', + transactionIndex: 'Q', + blockHash: 'D32', + blockNumber: 'Q', + cumulativeGasUsed: 'Q', + gasUsed: 'Q', + contractAddress: 'D20', + logs: ['FilterChange'], + }, + + filterChange: { + __required: [], + removed: 'B', + logIndex: 'Q', + transactionIndex: 'Q', + transactionHash: 'D32', + blockHash: 'D32', + blockNumber: 'Q', + address: 'D20', + data: 'Array|DATA', + topics: ['D'], + }, +} + +var methods = { + hexaNumberMethods: { + // these are the methods which have output in the form of hexa decimal numbers + eth_blockNumber: ['eth_blockNumber', params.param, 'Q'], + eth_gasPrice: ['eth_gasPrice', params.param, 'Q'], + eth_newBlockFilter: ['eth_newBlockFilter', params.param, 'Q'], + eth_newPendingTransactionFilter: [ + 'eth_newPendingTransactionFilter', + params.param, + 'Q', + ], + eth_getUncleCountByBlockHash: [ + 'eth_getUncleCountByBlockHash', + [params.blockHashParams], + 'Q', + 1, + ], + eth_getBlockTransactionCountByHash: [ + 'eth_getBlockTransactionCountByHash', + [params.blockHashParams], + 'Q', + 1, + ], + eth_getTransactionCount: [ + 'eth_getTransactionCount', + [params.addressParams, params.blockParameterParams], + 'Q', + 1, + 2, + ], + eth_getBalance: ['eth_getBalance', [params.addressParams, 'latest'], 'Q', 1, 2], + eth_estimateGas: ['eth_estimateGas', [params.estimateTransaction], 'Q', 1], + eth_getUncleCountByBlockNumber: [ + 'eth_getUncleCountByBlockNumber', + [params.blockParameterParams], + 'Q', + 1, + ], + eth_getBlockTransactionCountByNumber: [ + 'eth_getBlockTransactionCountByNumber', + ['latest'], + 'Q', + 1, + ], + eth_protocolVersion: ['eth_protocolVersion', params.param, 'S'], + eth_getCode: ['eth_getCode', params.getCodeParams, 'D', 1, 2], + }, + booleanMethods: { + // these are the methods which have output in the form of boolean + eth_uninstallFilter: ['eth_uninstallFilter', params.filterParams, 'B', 1], + eth_mining: ['eth_mining', params.param, 'B'], + eth_syncing: ['eth_syncing', params.param, 'B|EthSyncing'], + }, + transactionMethods: { + // these are the methods which have output in the form of transaction object + eth_getTransactionByHash: [ + 'eth_getTransactionByHash', + params.transactionHashParams, + params.transaction, + 1, + ], + eth_getTransactionByBlockHashAndIndex: [ + 'eth_getTransactionByBlockHashAndIndex', + params.blockHashAndIndexParams, + params.transaction, + 2, + ], + eth_getTransactionByBlockNumberAndIndex: [ + 'eth_getTransactionByBlockNumberAndIndex', + [params.blockParameterParams, '0x0'], + params.transaction, + 2, + ], + + }, + blockMethods: { + // these are the methods which have output in the form of a block + + eth_getUncleByBlockNumberAndIndex: [ + 'eth_getUncleByBlockNumberAndIndex', + params.uncleByBlockNumberAndIndexParams, + params.block, + 2, + ], + eth_getBlockByHash: [ + 'eth_getBlockByHash', + [params.params, false], + params.block, + 2, + ], + eth_getBlockByNumber: [ + 'eth_getBlockByNumber', + [params.blockParameterParams, false], + params.block, + 2, + ], + }, + + methods: { + // these are the methods which have output in the form of bytes data + + eth_call: ['eth_call', [params.estimateTransaction, 'latest'], 'D', 1, 2], + eth_getStorageAt: ['eth_getStorageAt', params.getStorageAtParams, 'D', 2, 2], + eth_getTransactionReceipt: [ + 'eth_getTransactionReceipt', + params.transactionHashParams, + params.receipt, + 1, + ], + + }, + +} + diff --git a/test/web3/web3.js b/test/web3/web3.js new file mode 100644 index 000000000..5c2de078d --- /dev/null +++ b/test/web3/web3.js @@ -0,0 +1,34 @@ +/* eslint no-undef: 0 */ + +var json = methods + +web3.currentProvider.enable().then(() => { + + Object.keys(json).forEach(methodGroupKey => { + + console.log(methodGroupKey) + const methodGroup = json[methodGroupKey] + console.log(methodGroup) + Object.keys(methodGroup).forEach(methodKey => { + + const methodButton = document.getElementById(methodKey) + methodButton.addEventListener('click', function (event) { + + window.ethereum.sendAsync({ + method: methodKey, + params: methodGroup[methodKey][1], + }, function (err, result) { + if (err) { + console.log(err) + console.log(methodKey) + } else { + document.getElementById('results').innerHTML = JSON.stringify(result) + } + }) + }) + + }) + + }) + }) + From 92c03bdff2281b5901151ad0840b83e40dad73bc Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Tue, 16 Apr 2019 12:35:22 -0700 Subject: [PATCH 21/87] Update buttons & colors to match design system (#6446) * Refactoring button styles * renaming buttons * Add Link and Button styles * Update new btn styles and storybook * Fix tests * Change font weight; Update storybook * Fix linter --- test/integration/lib/confirm-sig-requests.js | 6 +- test/integration/lib/send-new-ui.js | 6 +- .../app/add-token-button/index.scss | 5 +- ui/app/components/app/coinbase-form.js | 69 ----- .../app/customize-gas-modal/index.js | 2 +- .../components/app/modal/modal.component.js | 2 +- .../app/modal/tests/modal.component.test.js | 4 +- .../app/modals/account-details-modal.js | 4 +- .../customize-gas/customize-gas.component.js | 2 +- .../app/modals/deposit-ether-modal.js | 2 +- .../app/modals/edit-account-name-modal.js | 2 +- .../app/modals/export-private-key-modal.js | 4 +- .../modals/hide-token-confirmation-modal.js | 4 +- .../app/modals/notification-modal.js | 4 +- ui/app/components/app/shapeshift-form.js | 2 +- ui/app/components/app/signature-request.js | 2 +- .../transaction-view-balance.component.js | 4 +- ui/app/components/app/wallet-view.js | 2 +- .../components/ui/button/button.component.js | 4 + ui/app/components/ui/button/button.stories.js | 47 ++-- ui/app/components/ui/button/buttons.scss | 244 ++++++++++++++++++ .../components/ui/page-container/index.scss | 8 - .../page-container-footer.component.js | 2 +- ui/app/css/itcss/components/buttons.scss | 230 ----------------- ui/app/css/itcss/components/index.scss | 2 +- ui/app/css/itcss/components/modal.scss | 2 + ui/app/css/itcss/generic/index.scss | 1 + ui/app/css/itcss/settings/typography.scss | 37 +++ ui/app/css/itcss/settings/variables.scss | 18 +- .../token-list-placeholder/index.scss | 3 +- .../confirm-add-suggested-token.component.js | 2 +- .../confirm-add-token.component.js | 2 +- .../connect-hardware/account-list.js | 2 +- .../connect-hardware/connect-screen.js | 2 +- .../create-account/import-account/json.js | 2 +- .../import-account/private-key.js | 2 +- ui/app/pages/create-account/new-account.js | 2 +- .../import-with-seed-phrase.component.js | 2 +- .../new-account/new-account.component.js | 2 +- .../unique-image/unique-image.component.js | 2 +- .../end-of-flow/end-of-flow.component.js | 2 +- .../confirm-seed-phrase.component.js | 2 +- .../reveal-seed-phrase.component.js | 2 +- .../select-action/select-action.component.js | 2 +- .../welcome/welcome.component.js | 2 +- ui/app/pages/keychains/reveal-seed.js | 2 +- ui/app/pages/mobile-sync/index.js | 2 +- .../advanced-tab/advanced-tab.component.js | 6 +- ui/app/pages/settings/info-tab/index.scss | 2 +- .../security-tab/security-tab.component.js | 6 +- ui/app/pages/settings/settings-tab/index.scss | 20 +- 51 files changed, 391 insertions(+), 401 deletions(-) delete mode 100644 ui/app/components/app/coinbase-form.js create mode 100644 ui/app/components/ui/button/buttons.scss delete mode 100644 ui/app/css/itcss/components/buttons.scss diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js index e4540c4f2..c3b0dfcff 100644 --- a/test/integration/lib/confirm-sig-requests.js +++ b/test/integration/lib/confirm-sig-requests.js @@ -44,7 +44,7 @@ async function runConfirmSigRequestsTest (assert, done) { let confirmSigRowValue = await queryAsync($, '.request-signature__row-value') assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0') - let confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') + let confirmSigSignButton = await queryAsync($, 'button.btn-secondary.btn--large') confirmSigSignButton[0].click() await timeout(1000) confirmSigHeadline = await queryAsync($, '.request-signature__headline') @@ -53,7 +53,7 @@ async function runConfirmSigRequestsTest (assert, done) { confirmSigRowValue = await queryAsync($, '.request-signature__row-value') assert.ok(confirmSigRowValue[0].textContent.match(/^#\sTerms\sof\sUse/)) - confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') + confirmSigSignButton = await queryAsync($, 'button.btn-secondary.btn--large') confirmSigSignButton[0].click() await timeout(1000) confirmSigHeadline = await queryAsync($, '.request-signature__headline') @@ -63,7 +63,7 @@ async function runConfirmSigRequestsTest (assert, done) { assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!') assert.equal(confirmSigRowValue[1].textContent, '1337') - confirmSigSignButton = await queryAsync($, 'button.btn-primary.btn--large') + confirmSigSignButton = await queryAsync($, 'button.btn-secondary.btn--large') confirmSigSignButton[0].click() await timeout(2000) diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index d7003f4cc..ce470fc02 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -43,7 +43,7 @@ async function runSendFlowTest (assert, done) { selectState.val('send new ui') reactTriggerChange(selectState[0]) - const sendScreenButton = await queryAsync($, 'button.btn-primary.transaction-view-balance__button') + const sendScreenButton = await queryAsync($, 'button.btn-secondary.transaction-view-balance__button') assert.ok(sendScreenButton[1], 'send screen button present') sendScreenButton[1].click() @@ -88,7 +88,7 @@ async function runSendFlowTest (assert, done) { errorMessage = $('.send-v2__error') assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected') - const sendButton = await queryAsync($, 'button.btn-primary.btn--large.page-container__footer-button') + const sendButton = await queryAsync($, 'button.btn-secondary.btn--large.page-container__footer-button') assert.equal(sendButton[0].textContent, 'Next', 'next button rendered') sendButton[0].click() await timeout() @@ -122,7 +122,7 @@ async function runSendFlowTest (assert, done) { sendAmountFieldInputInEdit.val('1.0') reactTriggerChange(sendAmountFieldInputInEdit[0]) - const sendButtonInEdit = await queryAsync($, '.btn-primary.btn--large.page-container__footer-button') + const sendButtonInEdit = await queryAsync($, '.btn-secondary.btn--large.page-container__footer-button') assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered') selectState.val('send new ui') diff --git a/ui/app/components/app/add-token-button/index.scss b/ui/app/components/app/add-token-button/index.scss index 39f404716..c4350a2d3 100644 --- a/ui/app/components/app/add-token-button/index.scss +++ b/ui/app/components/app/add-token-button/index.scss @@ -17,10 +17,7 @@ } &__button { - font-size: 0.75rem; + @extend %small-link; margin: 1rem; - text-transform: uppercase; - color: $curious-blue; - cursor: pointer; } } diff --git a/ui/app/components/app/coinbase-form.js b/ui/app/components/app/coinbase-form.js deleted file mode 100644 index 24d287604..000000000 --- a/ui/app/components/app/coinbase-form.js +++ /dev/null @@ -1,69 +0,0 @@ -const Component = require('react').Component -const PropTypes = require('prop-types') -const h = require('react-hyperscript') -const inherits = require('util').inherits -const connect = require('react-redux').connect -const actions = require('../../store/actions') - -CoinbaseForm.contextTypes = { - t: PropTypes.func, -} - -module.exports = connect(mapStateToProps)(CoinbaseForm) - - -function mapStateToProps (state) { - return { - warning: state.appState.warning, - } -} - -inherits(CoinbaseForm, Component) - -function CoinbaseForm () { - Component.call(this) -} - -CoinbaseForm.prototype.render = function () { - var props = this.props - - return h('.flex-column', { - style: { - marginTop: '35px', - padding: '25px', - width: '100%', - }, - }, [ - h('.flex-row', { - style: { - justifyContent: 'space-around', - margin: '33px', - marginTop: '0px', - }, - }, [ - h('button.btn-green', { - onClick: this.toCoinbase.bind(this), - }, this.context.t('continueToCoinbase')), - - h('button.btn-red', { - onClick: () => props.dispatch(actions.goHome()), - }, this.context.t('cancel')), - ]), - ]) -} - -CoinbaseForm.prototype.toCoinbase = function () { - const props = this.props - const address = props.buyView.buyAddress - props.dispatch(actions.buyEth({ network: '1', address, amount: 0 })) -} - -CoinbaseForm.prototype.renderLoading = function () { - return h('img', { - style: { - width: '27px', - marginRight: '-27px', - }, - src: 'images/loading.svg', - }) -} diff --git a/ui/app/components/app/customize-gas-modal/index.js b/ui/app/components/app/customize-gas-modal/index.js index dca77bb00..4434b8c25 100644 --- a/ui/app/components/app/customize-gas-modal/index.js +++ b/ui/app/components/app/customize-gas-modal/index.js @@ -382,7 +382,7 @@ CustomizeGasModal.prototype.render = function () { onClick: this.props.hideModal, }, [this.context.t('cancel')]), h(Button, { - type: 'primary', + type: 'secondary', className: 'send-v2__customize-gas__save', onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), disabled: error, diff --git a/ui/app/components/app/modal/modal.component.js b/ui/app/components/app/modal/modal.component.js index 49e131b3c..44b180ac8 100644 --- a/ui/app/components/app/modal/modal.component.js +++ b/ui/app/components/app/modal/modal.component.js @@ -20,7 +20,7 @@ export default class Modal extends PureComponent { } static defaultProps = { - submitType: 'primary', + submitType: 'secondary', cancelType: 'default', } diff --git a/ui/app/components/app/modal/tests/modal.component.test.js b/ui/app/components/app/modal/tests/modal.component.test.js index a13d7c06a..5922177a6 100644 --- a/ui/app/components/app/modal/tests/modal.component.test.js +++ b/ui/app/components/app/modal/tests/modal.component.test.js @@ -12,7 +12,7 @@ describe('Modal Component', () => { assert.equal(wrapper.find('.modal-container').length, 1) const buttons = wrapper.find(Button) assert.equal(buttons.length, 1) - assert.equal(buttons.at(0).props().type, 'primary') + assert.equal(buttons.at(0).props().type, 'secondary') }) it('should render a modal with a cancel and a submit button', () => { @@ -38,7 +38,7 @@ describe('Modal Component', () => { cancelButton.simulate('click') assert.equal(handleCancel.callCount, 1) - assert.equal(submitButton.props().type, 'primary') + assert.equal(submitButton.props().type, 'secondary') assert.equal(submitButton.props().children, 'Submit') assert.equal(handleSubmit.callCount, 0) submitButton.simulate('click') diff --git a/ui/app/components/app/modals/account-details-modal.js b/ui/app/components/app/modals/account-details-modal.js index 94ed04df9..1b1ca6b8e 100644 --- a/ui/app/components/app/modals/account-details-modal.js +++ b/ui/app/components/app/modals/account-details-modal.js @@ -84,7 +84,7 @@ AccountDetailsModal.prototype.render = function () { h('div.account-modal-divider'), h(Button, { - type: 'primary', + type: 'secondary', className: 'account-modal__button', onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), }, this.context.t('etherscanView')), @@ -92,7 +92,7 @@ AccountDetailsModal.prototype.render = function () { // Holding on redesign for Export Private Key functionality exportPrivateKeyFeatureEnabled ? h(Button, { - type: 'primary', + type: 'secondary', className: 'account-modal__button', onClick: () => showExportPrivateKeyModal(), }, this.context.t('exportPrivateKey')) : null, diff --git a/ui/app/components/app/modals/customize-gas/customize-gas.component.js b/ui/app/components/app/modals/customize-gas/customize-gas.component.js index 5db5c79e7..178f45729 100644 --- a/ui/app/components/app/modals/customize-gas/customize-gas.component.js +++ b/ui/app/components/app/modals/customize-gas/customize-gas.component.js @@ -128,7 +128,7 @@ export default class CustomizeGas extends Component { { t('cancel') } ) - .add('secondary', () => + .add('Button - Secondary', () => ) - .add('default', () => ( + .add('Button - Default', () => - )) - .add('large primary', () => ( + ) + .add('Button - Warning', () => - )) - .add('large secondary', () => ( + ) + .add('Button - Danger', () => - )) - .add('large default', () => ( + ) + .add('Button - Danger Primary', () => - )) + ) + .add('Button - Link', () => + + ) diff --git a/ui/app/components/ui/button/buttons.scss b/ui/app/components/ui/button/buttons.scss new file mode 100644 index 000000000..0fc87415b --- /dev/null +++ b/ui/app/components/ui/button/buttons.scss @@ -0,0 +1,244 @@ +/* + Buttons + */ + +$hover-secondary: #B0D7F2; +$hover-default: #B3B3B3; +$hover-confirm: #0372C3; +$hover-red: #FEB6BF; +$hover-red-primary: #C72837; +$hover-orange: #FFD3B5; + +%button { + @include h6; + + font-weight: 500; + font-family: Roboto, Arial; + line-height: 1.25rem; + padding: .75rem 1rem; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; + border-radius: 6px; + width: 100%; + outline: none; + transition: border-color .3s ease, background-color .3s ease; + + &--disabled, + &[disabled] { + cursor: auto; + opacity: .5; + pointer-events: none; + } +} + +%link { + @include h4; + + color: $Blue-500; + line-height: 1.25rem; + cursor: pointer; + background-color: transparent; + + &:hover { + color: $Blue-400; + } + + &:active { + color: $Blue-600; + } + + &--disabled, + &[disabled] { + cursor: auto; + opacity: 1; + pointer-events: none; + color: $hover-secondary; + } +} + +%small-link { + @extend %link; + @include h6; +} + +.button { + @extend %button; +} + +.btn-secondary { + color: $Blue-500; + border: 2px solid $hover-secondary; + + &:hover { + border-color: $Blue-500; + } + + &:active { + background: $Blue-000; + border-color: $Blue-500; + } + + &--disabled, + &[disabled] { + opacity: 1; + color: $hover-secondary; + } +} + +.btn-warning { + color: $Orange-500; + border: 2px solid $hover-orange; + + &:hover { + border-color: $Orange-500; + } + + &:active { + background: $Orange-000; + border-color: $Orange-500; + } + + &--disabled, + &[disabled] { + opacity: 1; + color: $hover-orange; + } +} + +.btn-danger { + color: $Red-500; + border: 2px solid $hover-red; + + &:hover { + border-color: $Red-500; + } + + &:active { + background: $Red-000; + border-color: $Red-500; + } + + &--disabled, + &[disabled] { + opacity: 1; + color: $hover-red; + } +} + +.btn-danger-primary { + color: $white; + border: 2px solid $Red-500; + background-color: $Red-500; + + &:hover { + border-color: $hover-red-primary; + background-color: $hover-red-primary; + } + + &:active { + background: $Red-600; + border-color: $Red-600; + } + + &--disabled, + &[disabled] { + opacity: 1; + border-color: $hover-red; + background-color: $hover-red; + } +} + +.btn-default { + color: $Grey-500; + border: 2px solid $hover-default; + + &:hover { + border-color: $Grey-500; + } + + &:active { + background: #FBFBFC; + border-color: $Grey-500; + } + + &--disabled, + &[disabled] { + opacity: 1; + color: $hover-default; + } +} + +.btn-primary { + color: $white; + border: 2px solid $Blue-500; + background-color: $Blue-500; + + &:hover { + border-color: $hover-confirm; + background-color: $hover-confirm; + } + + &:active { + background: $Blue-600; + border-color: $Blue-600; + } + + &--disabled, + &[disabled] { + border-color: $hover-secondary; + background-color: $hover-secondary; + } +} + +.btn-link { + @extend %link; +} + +.btn--large { + min-height: 54px; +} + +/** + All Buttons styles are deviations from design guide + */ + +.btn-raised { + color: $curious-blue; + background-color: $white; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08); + padding: 6px; + height: initial; + min-height: initial; + width: initial; + min-width: initial; +} + +.btn--first-time { + height: 54px; + width: 198px; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .14); + color: $white; + font-size: 1.25rem; + font-weight: 500; + transition: 200ms ease-in-out; + background-color: rgba(247, 134, 28, .9); + border-radius: 0; +} + +button[disabled], +input[type="submit"][disabled] { + cursor: not-allowed; + opacity: .5; +} + +button.primary { + padding: 8px 12px; + background: #f7861c; + box-shadow: 0 3px 6px rgba(247, 134, 28, .36); + color: $white; + font-size: 1.1em; + font-family: Roboto; + text-transform: uppercase; +} diff --git a/ui/app/components/ui/page-container/index.scss b/ui/app/components/ui/page-container/index.scss index b71a3cb9d..003c5a0e2 100644 --- a/ui/app/components/ui/page-container/index.scss +++ b/ui/app/components/ui/page-container/index.scss @@ -55,11 +55,6 @@ border-top: 1px solid $geyser; flex: 0 0 auto; - .btn-default, - .btn-confirm { - font-size: 1rem; - } - header { display: flex; flex-flow: row; @@ -86,9 +81,6 @@ } &__footer-button { - height: 55px; - font-size: 1rem; - text-transform: uppercase; margin-right: 16px; &:last-of-type { diff --git a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js index 85b16cefe..4ef203521 100644 --- a/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js +++ b/ui/app/components/ui/page-container/page-container-footer/page-container-footer.component.js @@ -45,7 +45,7 @@ export default class PageContainerFooter extends Component { } + + + + ) + } + renderContent () { const { warning } = this.props @@ -368,6 +412,7 @@ export default class AdvancedTab extends PureComponent { { this.renderAdvancedGasInputInline() } { this.renderHexDataOptIn() } { this.renderShowConversionInTestnets() } + { this.renderAutoLogoutTimeLimit() } ) } diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js index 69d7e07e6..bcac55f5e 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js @@ -8,10 +8,11 @@ import { setFeatureFlag, showModal, setShowFiatConversionOnTestnetsPreference, + setAutoLogoutTimeLimit, } from '../../../store/actions' import {preferencesSelector} from '../../../selectors/selectors' -const mapStateToProps = state => { +export const mapStateToProps = state => { const { appState: { warning }, metamask } = state const { featureFlags: { @@ -19,17 +20,18 @@ const mapStateToProps = state => { advancedInlineGas, } = {}, } = metamask - const { showFiatInTestnets } = preferencesSelector(state) + const { showFiatInTestnets, autoLogoutTimeLimit } = preferencesSelector(state) return { warning, sendHexData, advancedInlineGas, showFiatInTestnets, + autoLogoutTimeLimit, } } -const mapDispatchToProps = dispatch => { +export const mapDispatchToProps = dispatch => { return { setHexDataFeatureFlag: shouldShow => dispatch(setFeatureFlag('sendHexData', shouldShow)), setRpcTarget: (newRpc, chainId, ticker, nickname) => dispatch(updateAndSetCustomRpc(newRpc, chainId, ticker, nickname)), @@ -39,6 +41,9 @@ const mapDispatchToProps = dispatch => { setShowFiatConversionOnTestnetsPreference: value => { return dispatch(setShowFiatConversionOnTestnetsPreference(value)) }, + setAutoLogoutTimeLimit: value => { + return dispatch(setAutoLogoutTimeLimit(value)) + }, } } diff --git a/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js new file mode 100644 index 000000000..f81329533 --- /dev/null +++ b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-component.test.js @@ -0,0 +1,44 @@ +import React from 'react' +import assert from 'assert' +import sinon from 'sinon' +import { shallow } from 'enzyme' +import AdvancedTab from '../advanced-tab.component' +import TextField from '../../../../components/ui/text-field' + +describe('AdvancedTab Component', () => { + it('should render correctly', () => { + const root = shallow( + , + { + context: { + t: s => `_${s}`, + }, + } + ) + + assert.equal(root.find('.settings-page__content-row').length, 8) + }) + + it('should update autoLogoutTimeLimit', () => { + const setAutoLogoutTimeLimitSpy = sinon.spy() + const root = shallow( + , + { + context: { + t: s => `_${s}`, + }, + } + ) + + const autoTimeout = root.find('.settings-page__content-row').last() + const textField = autoTimeout.find(TextField) + + textField.props().onChange({ target: { value: 1440 } }) + assert.equal(root.state().autoLogoutTimeLimit, 1440) + + autoTimeout.find('button').simulate('click') + assert.equal(setAutoLogoutTimeLimitSpy.args[0][0], 1440) + }) +}) diff --git a/ui/app/pages/settings/advanced-tab/tests/advanced-tab-container.test.js b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-container.test.js new file mode 100644 index 000000000..62122073d --- /dev/null +++ b/ui/app/pages/settings/advanced-tab/tests/advanced-tab-container.test.js @@ -0,0 +1,46 @@ +import assert from 'assert' +import { mapStateToProps, mapDispatchToProps } from '../advanced-tab.container' + +const defaultState = { + appState: { + warning: null, + }, + metamask: { + featureFlags: { + sendHexData: false, + advancedInlineGas: false, + }, + preferences: { + autoLogoutTimeLimit: 0, + showFiatInTestnets: false, + useNativeCurrencyAsPrimaryCurrency: true, + }, + }, +} + +describe('AdvancedTab Container', () => { + it('should map state to props correctly', () => { + const props = mapStateToProps(defaultState) + const expected = { + warning: null, + sendHexData: false, + advancedInlineGas: false, + showFiatInTestnets: false, + autoLogoutTimeLimit: 0, + } + + assert.deepEqual(props, expected) + }) + + it('should map dispatch to props correctly', () => { + const props = mapDispatchToProps(() => 'mockDispatch') + + assert.ok(typeof props.setHexDataFeatureFlag === 'function') + assert.ok(typeof props.setRpcTarget === 'function') + assert.ok(typeof props.displayWarning === 'function') + assert.ok(typeof props.showResetAccountConfirmationModal === 'function') + assert.ok(typeof props.setAdvancedInlineGasFeatureFlag === 'function') + assert.ok(typeof props.setShowFiatConversionOnTestnetsPreference === 'function') + assert.ok(typeof props.setAutoLogoutTimeLimit === 'function') + }) +}) diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index e7b855119..f2a9ed08f 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -316,6 +316,7 @@ var actions = { UPDATE_PREFERENCES: 'UPDATE_PREFERENCES', setUseNativeCurrencyAsPrimaryCurrencyPreference, setShowFiatConversionOnTestnetsPreference, + setAutoLogoutTimeLimit, // Migration of users to new UI setCompletedUiMigration, @@ -2439,6 +2440,10 @@ function setShowFiatConversionOnTestnetsPreference (value) { return setPreference('showFiatInTestnets', value) } +function setAutoLogoutTimeLimit (value) { + return setPreference('autoLogoutTimeLimit', value) +} + function setCompletedOnboarding () { return async dispatch => { dispatch(actions.showLoadingIndication()) From ef8a07c2ce2b1c5fc4ef18f48592b2e7da178c44 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 8 May 2019 16:48:33 -0230 Subject: [PATCH 60/87] Adds a transactionCategory to txMeta for use in UI (#6567) * Adds a transactionCategory to txMeta for use in UI * Update transaction controller and tx-gas-util documentation on new code param in multiple functions. --- app/scripts/controllers/transactions/index.js | 55 ++++++++++++++++++- .../controllers/transactions/tx-gas-utils.js | 11 ++-- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 2ce736beb..dc6a043e4 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -3,6 +3,17 @@ const ObservableStore = require('obs-store') const ethUtil = require('ethereumjs-util') const Transaction = require('ethereumjs-tx') const EthQuery = require('ethjs-query') +const abi = require('human-standard-token-abi') +const abiDecoder = require('abi-decoder') +abiDecoder.addABI(abi) +const { + TOKEN_METHOD_APPROVE, + TOKEN_METHOD_TRANSFER, + TOKEN_METHOD_TRANSFER_FROM, + SEND_ETHER_ACTION_KEY, + DEPLOY_CONTRACT_ACTION_KEY, + CONTRACT_INTERACTION_KEY, +} = require('../../../../ui/app/helpers/constants/transactions.js') const TransactionStateManager = require('./tx-state-manager') const TxGasUtil = require('./tx-gas-utils') const PendingTransactionTracker = require('./pending-tx-tracker') @@ -180,9 +191,11 @@ class TransactionController extends EventEmitter { } txUtils.validateTxParams(normalizedTxParams) // construct txMeta + const { transactionCategory, code } = await this._determineTransactionCategory(txParams) let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams, type: TRANSACTION_TYPE_STANDARD, + transactionCategory, }) this.addTx(txMeta) this.emit('newUnapprovedTx', txMeta) @@ -191,7 +204,7 @@ class TransactionController extends EventEmitter { // check whether recipient account is blacklisted recipientBlacklistChecker.checkAccount(txMeta.metamaskNetworkId, normalizedTxParams.to) // add default tx params - txMeta = await this.addTxGasDefaults(txMeta) + txMeta = await this.addTxGasDefaults(txMeta, code) } catch (error) { log.warn(error) txMeta.loadingDefaults = false @@ -211,7 +224,7 @@ class TransactionController extends EventEmitter { @param txMeta {Object} - the txMeta object @returns {Promise} resolves with txMeta */ - async addTxGasDefaults (txMeta) { + async addTxGasDefaults (txMeta, code) { const txParams = txMeta.txParams // ensure value txParams.value = txParams.value ? ethUtil.addHexPrefix(txParams.value) : '0x0' @@ -222,7 +235,7 @@ class TransactionController extends EventEmitter { } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) // set gasLimit - return await this.txGasUtil.analyzeGasUsage(txMeta) + return await this.txGasUtil.analyzeGasUsage(txMeta, code) } /** @@ -555,6 +568,42 @@ class TransactionController extends EventEmitter { }) } + /** + Returns a "type" for a transaction out of the following list: simpleSend, tokenTransfer, tokenApprove, + contractDeployment, contractMethodCall + */ + async _determineTransactionCategory (txParams) { + const { data, to } = txParams + const { name } = data && abiDecoder.decodeMethod(data) || {} + const tokenMethodName = [ + TOKEN_METHOD_APPROVE, + TOKEN_METHOD_TRANSFER, + TOKEN_METHOD_TRANSFER_FROM, + ].find(tokenMethodName => tokenMethodName === name && name.toLowerCase()) + + let result + let code + if (!txParams.data) { + result = SEND_ETHER_ACTION_KEY + } else if (tokenMethodName) { + result = tokenMethodName + } else if (!to) { + result = DEPLOY_CONTRACT_ACTION_KEY + } else { + try { + code = await this.query.getCode(to) + } catch (e) { + log.warn(e) + } + // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0' + const codeIsEmpty = !code || code === '0x' || code === '0x0' + + result = codeIsEmpty ? SEND_ETHER_ACTION_KEY : CONTRACT_INTERACTION_KEY + } + + return { transactionCategory: result, code } + } + /** Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions in the list have the same nonce diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 765551167..2dc461f48 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -4,6 +4,7 @@ const { BnMultiplyByFraction, bnToHex, } = require('../../lib/util') +const log = require('loglevel') const { addHexPrefix } = require('ethereumjs-util') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. @@ -24,14 +25,16 @@ class TxGasUtil { /** @param txMeta {Object} - the txMeta object + @param code {string} - the code at the txs address, as returned by this.query.getCode(to) @returns {object} the txMeta object with the gas written to the txParams */ - async analyzeGasUsage (txMeta) { + async analyzeGasUsage (txMeta, code) { const block = await this.query.getBlockByNumber('latest', false) let estimatedGasHex try { - estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit) + estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit, code) } catch (err) { + log.warn(err) txMeta.simulationFails = { reason: err.message, errorKey: err.errorKey, @@ -52,9 +55,10 @@ class TxGasUtil { Estimates the tx's gas usage @param txMeta {Object} - the txMeta object @param blockGasLimitHex {string} - hex string of the block's gas limit + @param code {string} - the code at the txs address, as returned by this.query.getCode(to) @returns {string} the estimated gas limit as a hex string */ - async estimateTxGas (txMeta, blockGasLimitHex) { + async estimateTxGas (txMeta, blockGasLimitHex, code) { const txParams = txMeta.txParams // check if gasLimit is already specified @@ -70,7 +74,6 @@ class TxGasUtil { // see if we can set the gas based on the recipient if (hasRecipient) { - const code = await this.query.getCode(recipient) // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0' const codeIsEmpty = !code || code === '0x' || code === '0x0' From 094e4cf555c698bfef50ca6679cd1e98f4ea9aa1 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Wed, 8 May 2019 17:21:33 -0230 Subject: [PATCH 61/87] Check for unused function arguments (#6583) * eslint: Check for unused function arguments * eslint: Ignore unused '_' in argument list Also allow any number of '_' e.g., '__' or '___' which is to be used sparingly * Remove and rename unused arguments --- .eslintrc | 2 +- app/scripts/controllers/balance.js | 2 +- app/scripts/controllers/preferences.js | 6 +-- app/scripts/controllers/shapeshift.js | 2 +- .../transactions/tx-state-manager.js | 4 +- app/scripts/lib/message-manager.js | 2 +- app/scripts/lib/personal-message-manager.js | 2 +- app/scripts/metamask-controller.js | 9 ++-- app/scripts/migrations/024.js | 2 +- app/scripts/migrations/025.js | 2 +- development/backGroundConnectionModifiers.js | 6 +-- gentests.js | 6 +-- gulpfile.js | 2 +- test/e2e/beta/contract-test/contract.js | 12 ++--- test/integration/lib/confirm-sig-requests.js | 2 +- test/integration/lib/currency-localization.js | 2 +- test/integration/lib/send-new-ui.js | 2 +- test/integration/lib/tx-list-items.js | 2 +- test/lib/mock-encryptor.js | 6 +-- test/lib/util.js | 2 +- test/unit/actions/tx_test.js | 4 +- .../controllers/currency-controller-test.js | 2 +- .../controllers/metamask-controller-test.js | 20 +++---- .../transactions/pending-tx-test.js | 12 ++--- .../transactions/tx-gas-util-test.js | 2 +- .../tx-state-history-helper-test.js | 2 +- .../transactions/tx-state-manager-test.js | 2 +- test/unit/app/edge-encryptor-test.js | 2 +- test/unit/migrations/migrator-test.js | 2 +- test/unit/ui/app/actions.spec.js | 52 +++++++++---------- test/web3/web3.js | 2 +- ui/app/components/app/account-panel.js | 17 ++---- ui/app/components/app/bn-as-decimal-input.js | 2 +- ui/app/components/app/ens-input.js | 2 +- .../advanced-gas-inputs.component.js | 2 +- .../advanced-gas-inputs.container.js | 4 +- .../advanced-tab-content.component.js | 3 +- .../gas-modal-page-container.component.js | 2 - .../gas-price-button-group.component.js | 2 +- .../gas-price-chart/gas-price-chart.utils.js | 6 +-- .../tests/gas-price-chart.component.test.js | 2 +- .../app/modals/deposit-ether-modal.js | 2 +- .../app/modals/export-private-key-modal.js | 4 +- .../metametrics-opt-in-modal.container.js | 2 +- .../modals/qr-scanner/qr-scanner.component.js | 2 +- .../reject-transactions.container.js | 2 +- ui/app/components/app/token-cell.js | 2 +- ...erenced-currency-display.container.test.js | 2 +- ...-preferenced-currency-display.container.js | 2 +- ui/app/components/ui/alert/index.js | 4 +- .../tests/currency-display.container.test.js | 2 +- .../tests/currency-input.container.test.js | 2 +- .../tests/token-input.container.test.js | 2 +- .../ui/unit-input/unit-input.component.js | 2 +- .../confirm-transaction.duck.test.js | 2 +- ui/app/ducks/gas/gas-duck.test.js | 4 +- .../metametrics/metametrics.provider.js | 2 +- .../tests/with-modal-props.test.js | 2 +- ui/app/helpers/utils/conversion-util.js | 2 +- ui/app/helpers/utils/metametrics.util.js | 2 +- ui/app/helpers/utils/util.js | 9 ++-- .../connect-hardware/account-list.js | 4 -- .../connect-hardware/connect-screen.js | 4 +- .../create-account/connect-hardware/index.js | 4 +- .../create-account/import-account/seed.js | 2 +- .../metametrics-opt-in.component.js | 2 +- .../confirm-seed-phrase.component.js | 6 +-- .../draggable-seed.component.js | 2 +- ui/app/pages/routes/index.js | 2 +- .../tests/account-list-item-container.test.js | 2 +- .../send-row-error-message-container.test.js | 2 +- ...send-row-warning-message-container.test.js | 2 +- .../send-to-row/send-to-row.utils.js | 2 +- .../pages/send/tests/send-container.test.js | 2 +- ui/app/pages/send/tests/send-utils.test.js | 4 +- .../send/to-autocomplete/to-autocomplete.js | 2 +- ui/app/store/actions.js | 45 ++++++++-------- ui/example.js | 2 +- ui/lib/test-timeout.js | 2 +- 79 files changed, 172 insertions(+), 191 deletions(-) diff --git a/.eslintrc b/.eslintrc index ecf59c68c..53033b753 100644 --- a/.eslintrc +++ b/.eslintrc @@ -133,7 +133,7 @@ "no-unneeded-ternary": [2, { "defaultAssignment": false }], "no-unreachable": 2, "no-unsafe-finally": 2, - "no-unused-vars": [2, { "vars": "all", "args": "none" }], + "no-unused-vars": [2, { "vars": "all", "args": "all", "argsIgnorePattern": "[_]+" }], "no-useless-call": 2, "no-useless-computed-key": 2, "no-useless-constructor": 2, diff --git a/app/scripts/controllers/balance.js b/app/scripts/controllers/balance.js index 465751e61..b227d5d0a 100644 --- a/app/scripts/controllers/balance.js +++ b/app/scripts/controllers/balance.js @@ -68,7 +68,7 @@ class BalanceController { _registerUpdates () { const update = this.updateBalance.bind(this) - this.txController.on('tx:status-update', (txId, status) => { + this.txController.on('tx:status-update', (_, status) => { switch (status) { case 'submitted': case 'confirmed': diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 9fe8bee4b..bbb13bd8e 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -339,7 +339,7 @@ class PreferencesController { } removeSuggestedTokens () { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { this.store.updateState({ suggestedTokens: {} }) resolve({}) }) @@ -396,7 +396,7 @@ class PreferencesController { const newEntry = { address, symbol, decimals } const tokens = this.store.getState().tokens const assetImages = this.getAssetImages() - const previousEntry = tokens.find((token, index) => { + const previousEntry = tokens.find((token) => { return token.address === address }) const previousIndex = tokens.indexOf(previousEntry) @@ -461,7 +461,7 @@ class PreferencesController { * */ setCurrentAccountTab (currentAccountTab) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { this.store.updateState({ currentAccountTab }) resolve() }) diff --git a/app/scripts/controllers/shapeshift.js b/app/scripts/controllers/shapeshift.js index b2a1462c2..9b0287007 100644 --- a/app/scripts/controllers/shapeshift.js +++ b/app/scripts/controllers/shapeshift.js @@ -136,7 +136,7 @@ class ShapeshiftController { * @param {ShapeShiftTx} tx The tx to remove * */ - removeShapeShiftTx (tx) { + removeShapeShiftTx () { const { shapeShiftTxList } = this.store.getState() const index = shapeShiftTxList.indexOf(index) if (index !== -1) { diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 420191d9c..1a2cb5dee 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -126,10 +126,10 @@ class TransactionStateManager extends EventEmitter { @returns {object} the txMeta */ addTx (txMeta) { - this.once(`${txMeta.id}:signed`, function (txId) { + this.once(`${txMeta.id}:signed`, function () { this.removeAllListeners(`${txMeta.id}:rejected`) }) - this.once(`${txMeta.id}:rejected`, function (txId) { + this.once(`${txMeta.id}:rejected`, function () { this.removeAllListeners(`${txMeta.id}:signed`) }) // initialize history diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index e86629590..ac41de523 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -34,7 +34,7 @@ module.exports = class MessageManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this MessageManager * */ - constructor (opts) { + constructor () { super() this.memStore = new ObservableStore({ unapprovedMsgs: {}, diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index fdb94f5ec..7c13e521a 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -36,7 +36,7 @@ module.exports = class PersonalMessageManager extends EventEmitter { * @property {array} messages Holds all messages that have been created by this PersonalMessageManager * */ - constructor (opts) { + constructor () { super() this.memStore = new ObservableStore({ unapprovedPersonalMsgs: {}, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 7d666ae88..b190dd452 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1222,9 +1222,8 @@ module.exports = class MetamaskController extends EventEmitter { * with higher gas. * * @param {string} txId - The ID of the transaction to speed up. - * @param {Function} cb - The callback function called with a full state update. */ - async retryTransaction (txId, gasPrice, cb) { + async retryTransaction (txId, gasPrice) { await this.txController.retryTransaction(txId, gasPrice) const state = await this.getState() return state @@ -1237,7 +1236,7 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string=} customGasPrice - the hex value to use for the cancel transaction * @returns {object} MetaMask state */ - async createCancelTransaction (originalTxId, customGasPrice, cb) { + async createCancelTransaction (originalTxId, customGasPrice) { try { await this.txController.createCancelTransaction(originalTxId, customGasPrice) const state = await this.getState() @@ -1247,7 +1246,7 @@ module.exports = class MetamaskController extends EventEmitter { } } - async createSpeedUpTransaction (originalTxId, customGasPrice, cb) { + async createSpeedUpTransaction (originalTxId, customGasPrice) { await this.txController.createSpeedUpTransaction(originalTxId, customGasPrice) const state = await this.getState() return state @@ -1463,7 +1462,7 @@ module.exports = class MetamaskController extends EventEmitter { * * @param {*} outStream - The stream to provide the api over. */ - setupPublicApi (outStream, originDomain) { + setupPublicApi (outStream) { const dnode = Dnode() // connect dnode api to remote connection pump( diff --git a/app/scripts/migrations/024.js b/app/scripts/migrations/024.js index d0b276a79..6239bab13 100644 --- a/app/scripts/migrations/024.js +++ b/app/scripts/migrations/024.js @@ -27,7 +27,7 @@ function transformState (state) { const newState = state if (!newState.TransactionController) return newState const transactions = newState.TransactionController.transactions - newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { + newState.TransactionController.transactions = transactions.map((txMeta, _) => { if ( txMeta.status === 'unapproved' && txMeta.txParams && diff --git a/app/scripts/migrations/025.js b/app/scripts/migrations/025.js index fc3b20a44..fd4faa782 100644 --- a/app/scripts/migrations/025.js +++ b/app/scripts/migrations/025.js @@ -43,7 +43,7 @@ function normalizeTxParams (txParams) { // functions that handle normalizing of that key in txParams const whiteList = { from: from => ethUtil.addHexPrefix(from).toLowerCase(), - to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(), + to: () => ethUtil.addHexPrefix(txParams.to).toLowerCase(), nonce: nonce => ethUtil.addHexPrefix(nonce), value: value => ethUtil.addHexPrefix(value), data: data => ethUtil.addHexPrefix(data), diff --git a/development/backGroundConnectionModifiers.js b/development/backGroundConnectionModifiers.js index aee68854b..cf1a723d0 100644 --- a/development/backGroundConnectionModifiers.js +++ b/development/backGroundConnectionModifiers.js @@ -1,20 +1,20 @@ module.exports = { 'confirm sig requests': { - signMessage: (msgData, cb) => { + signMessage: (_, cb) => { const stateUpdate = { unapprovedMsgs: {}, unapprovedMsgCount: 0, } return cb(null, stateUpdate) }, - signPersonalMessage: (msgData, cb) => { + signPersonalMessage: (_, cb) => { const stateUpdate = { unapprovedPersonalMsgs: {}, unapprovedPersonalMsgCount: 0, } return cb(null, stateUpdate) }, - signTypedMessage: (msgData, cb) => { + signTypedMessage: (_, cb) => { const stateUpdate = { unapprovedTypedMessages: {}, unapprovedTypedMessagesCount: 0, diff --git a/gentests.js b/gentests.js index 9c591e98c..a84c2079d 100644 --- a/gentests.js +++ b/gentests.js @@ -48,11 +48,11 @@ async function start (fileRegEx, testGenerator) { } */ -async function startContainer (fileRegEx, testGenerator) { +async function startContainer (fileRegEx) { const fileNames = await getAllFileNames('./ui/app') const sFiles = fileNames.filter(name => name.match(fileRegEx)) - async.each(sFiles, async (sFile, cb) => { + async.each(sFiles, async (sFile) => { console.log(`sFile`, sFile) const [, sRootPath, sPath] = sFile.match(/^(.+\/)([^/]+)$/) @@ -91,7 +91,7 @@ async function startContainer (fileRegEx, testGenerator) { const proxyquireObject = ('{\n ' + result .match(/import\s{[\s\S]+?}\sfrom\s.+/g) .map(s => s.replace(/\n/g, '')) - .map((s, i) => { + .map((s) => { const proxyKeys = s.match(/{.+}/)[0].match(/\w+/g) return '\'' + s.match(/'(.+)'/)[1] + '\': { ' + (proxyKeys.length > 1 ? '\n ' + proxyKeys.join(': () => {},\n ') + ': () => {},\n ' diff --git a/gulpfile.js b/gulpfile.js index caddb620a..35c6331e8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -315,7 +315,7 @@ createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:test-extension:j createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:extension:js' }) createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:test:extension:js', testing: 'true' }) -function createTasksForBuildJsUIDeps ({ dependenciesToBundle, filename }) { +function createTasksForBuildJsUIDeps ({ filename }) { const destinations = browserPlatforms.map(platform => `./dist/${platform}`) diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js index 65fb9377f..e247e26ea 100644 --- a/test/e2e/beta/contract-test/contract.js +++ b/test/e2e/beta/contract-test/contract.js @@ -38,7 +38,7 @@ web3.currentProvider.enable().then(() => { const transferTokens = document.getElementById('transferTokens') const approveTokens = document.getElementById('approveTokens') - deployButton.addEventListener('click', async function (event) { + deployButton.addEventListener('click', async function () { document.getElementById('contractStatus').innerHTML = 'Deploying' var piggybank = await piggybankContract.new( @@ -55,7 +55,7 @@ web3.currentProvider.enable().then(() => { document.getElementById('contractStatus').innerHTML = 'Deployed' - depositButton.addEventListener('click', function (event) { + depositButton.addEventListener('click', function () { document.getElementById('contractStatus').innerHTML = 'Deposit initiated' contract.deposit({ from: web3.eth.accounts[0], value: '0x3782dace9d900000' }, function (result) { console.log(result) @@ -63,7 +63,7 @@ web3.currentProvider.enable().then(() => { }) }) - withdrawButton.addEventListener('click', function (event) { + withdrawButton.addEventListener('click', function () { contract.withdraw('0xde0b6b3a7640000', { from: web3.eth.accounts[0] }, function (result) { console.log(result) document.getElementById('contractStatus').innerHTML = 'Withdrawn' @@ -75,7 +75,7 @@ web3.currentProvider.enable().then(() => { console.log(piggybank) }) - sendButton.addEventListener('click', function (event) { + sendButton.addEventListener('click', function () { web3.eth.sendTransaction({ from: web3.eth.accounts[0], to: '0x2f318C334780961FB129D2a6c30D0763d9a5C970', @@ -88,7 +88,7 @@ web3.currentProvider.enable().then(() => { }) - createToken.addEventListener('click', async function (event) { + createToken.addEventListener('click', async function () { var _initialAmount = 100 var _tokenName = 'TST' var _decimalUnits = 0 @@ -124,7 +124,7 @@ web3.currentProvider.enable().then(() => { }) }) - approveTokens.addEventListener('click', function (event) { + approveTokens.addEventListener('click', function () { contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { from: web3.eth.accounts[0], to: contract.address, diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js index 4c2b56c21..699527609 100644 --- a/test/integration/lib/confirm-sig-requests.js +++ b/test/integration/lib/confirm-sig-requests.js @@ -17,7 +17,7 @@ QUnit.test('successful confirmation of sig requests', (assert) => { global.ethQuery = global.ethQuery || {} -async function runConfirmSigRequestsTest (assert, done) { +async function runConfirmSigRequestsTest (assert) { const selectState = await queryAsync($, 'select') selectState.val('confirm sig requests') reactTriggerChange(selectState[0]) diff --git a/test/integration/lib/currency-localization.js b/test/integration/lib/currency-localization.js index 36837e059..24c3a1a2d 100644 --- a/test/integration/lib/currency-localization.js +++ b/test/integration/lib/currency-localization.js @@ -16,7 +16,7 @@ QUnit.test('renders localized currency', (assert) => { }) }) -async function runCurrencyLocalizationTest (assert, done) { +async function runCurrencyLocalizationTest (assert) { console.log('*** start runCurrencyLocalizationTest') const selectState = await queryAsync($, 'select') selectState.val('currency localization') diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index 85487a59f..78014feef 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -22,7 +22,7 @@ global.ethQuery = { global.ethereumProvider = {} -async function runSendFlowTest (assert, done) { +async function runSendFlowTest (assert) { const tempFetch = global.fetch const realFetch = window.fetch.bind(window) diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js index 91645c5c5..e4478614e 100644 --- a/test/integration/lib/tx-list-items.js +++ b/test/integration/lib/tx-list-items.js @@ -20,7 +20,7 @@ global.ethQuery.getTransactionCount = (_, cb) => { cb(null, '0x4') } -async function runTxListItemsTest (assert, done) { +async function runTxListItemsTest (assert) { console.log('*** start runTxListItemsTest') const selectState = await queryAsync($, 'select') selectState.val('tx list items') diff --git a/test/lib/mock-encryptor.js b/test/lib/mock-encryptor.js index 852c536c2..23ab2404f 100644 --- a/test/lib/mock-encryptor.js +++ b/test/lib/mock-encryptor.js @@ -4,12 +4,12 @@ let cacheVal module.exports = { - encrypt (password, dataObj) { + encrypt (_, dataObj) { cacheVal = dataObj return Promise.resolve(mockHex) }, - decrypt (password, text) { + decrypt () { return Promise.resolve(cacheVal || {}) }, @@ -21,7 +21,7 @@ module.exports = { return this.decrypt(key, text) }, - keyFromPassword (password) { + keyFromPassword () { return Promise.resolve(mockKey) }, diff --git a/test/lib/util.js b/test/lib/util.js index 858565bb9..4c5d789d1 100644 --- a/test/lib/util.js +++ b/test/lib/util.js @@ -6,7 +6,7 @@ module.exports = { } function timeout (time) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(resolve, time || 1500) }) } diff --git a/test/unit/actions/tx_test.js b/test/unit/actions/tx_test.js index 8c64d844f..f2f8f1d1c 100644 --- a/test/unit/actions/tx_test.js +++ b/test/unit/actions/tx_test.js @@ -33,8 +33,8 @@ describe('tx confirmation screen', function () { describe('cancelTx', function () { before(function (done) { actions._setBackgroundConnection({ - approveTransaction (txId, cb) { cb('An error!') }, - cancelTransaction (txId, cb) { cb() }, + approveTransaction (_, cb) { cb('An error!') }, + cancelTransaction (_, cb) { cb() }, clearSeedWordCache (cb) { cb() }, getState (cb) { cb() }, }) diff --git a/test/unit/app/controllers/currency-controller-test.js b/test/unit/app/controllers/currency-controller-test.js index 7c4644d9f..8b6fbb719 100644 --- a/test/unit/app/controllers/currency-controller-test.js +++ b/test/unit/app/controllers/currency-controller-test.js @@ -59,7 +59,7 @@ describe('currency-controller', function () { var promise = new Promise( - function (resolve, reject) { + function (resolve) { currencyController.setCurrentCurrency('jpy') currencyController.updateConversionRate().then(function () { resolve() diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 1ed6a95fb..0a1a85d5e 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -49,7 +49,7 @@ describe('MetaMaskController', function () { showUnapprovedTx: noop, showUnconfirmedMessage: noop, encryptor: { - encrypt: function (password, object) { + encrypt: function (_, object) { this.object = object return Promise.resolve('mock-encrypted') }, @@ -144,7 +144,7 @@ describe('MetaMaskController', function () { sandbox.stub(metamaskController, 'getBalance') metamaskController.getBalance.callsFake(() => { return Promise.resolve('0x0') }) - await metamaskController.createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)).catch((e) => null) + await metamaskController.createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)).catch(() => null) await metamaskController.createNewVaultAndRestore(password, TEST_SEED) assert(metamaskController.keyringController.createNewVaultAndRestore.calledTwice) @@ -207,7 +207,7 @@ describe('MetaMaskController', function () { const accounts = {} const balance = '0x14ced5122ce0a000' const ethQuery = new EthQuery() - sinon.stub(ethQuery, 'getBalance').callsFake((account, callback) => { + sinon.stub(ethQuery, 'getBalance').callsFake((_, callback) => { callback(undefined, balance) }) @@ -295,7 +295,7 @@ describe('MetaMaskController', function () { it('should add the Trezor Hardware keyring', async function () { sinon.spy(metamaskController.keyringController, 'addNewKeyring') - await metamaskController.connectHardware('trezor', 0).catch((e) => null) + await metamaskController.connectHardware('trezor', 0).catch(() => null) const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Trezor Hardware' ) @@ -305,7 +305,7 @@ describe('MetaMaskController', function () { it('should add the Ledger Hardware keyring', async function () { sinon.spy(metamaskController.keyringController, 'addNewKeyring') - await metamaskController.connectHardware('ledger', 0).catch((e) => null) + await metamaskController.connectHardware('ledger', 0).catch(() => null) const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Ledger Hardware' ) @@ -325,7 +325,7 @@ describe('MetaMaskController', function () { }) it('should be locked by default', async function () { - await metamaskController.connectHardware('trezor', 0).catch((e) => null) + await metamaskController.connectHardware('trezor', 0).catch(() => null) const status = await metamaskController.checkHardwareStatus('trezor') assert.equal(status, false) }) @@ -341,7 +341,7 @@ describe('MetaMaskController', function () { }) it('should wipe all the keyring info', async function () { - await metamaskController.connectHardware('trezor', 0).catch((e) => null) + await metamaskController.connectHardware('trezor', 0).catch(() => null) await metamaskController.forgetDevice('trezor') const keyrings = await metamaskController.keyringController.getKeyringsByType( 'Trezor Hardware' @@ -376,7 +376,7 @@ describe('MetaMaskController', function () { sinon.spy(metamaskController.preferencesController, 'setAddresses') sinon.spy(metamaskController.preferencesController, 'setSelectedAddress') sinon.spy(metamaskController.preferencesController, 'setAccountLabel') - await metamaskController.connectHardware('trezor', 0, `m/44/0'/0'`).catch((e) => null) + await metamaskController.connectHardware('trezor', 0, `m/44/0'/0'`).catch(() => null) await metamaskController.unlockHardwareWalletAccount(accountToUnlock, 'trezor', `m/44/0'/0'`) }) @@ -757,7 +757,7 @@ describe('MetaMaskController', function () { const { promise, resolve } = deferredPromise() - streamTest = createThoughStream((chunk, enc, cb) => { + streamTest = createThoughStream((chunk, _, cb) => { if (chunk.name !== 'phishing') return cb() assert.equal(chunk.data.hostname, phishingUrl) resolve() @@ -777,7 +777,7 @@ describe('MetaMaskController', function () { }) it('sets up controller dnode api for trusted communication', function (done) { - streamTest = createThoughStream((chunk, enc, cb) => { + streamTest = createThoughStream((chunk, _, cb) => { assert.equal(chunk.name, 'controller') cb() done() diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index 2988bf61f..1c5f59f5a 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -100,7 +100,7 @@ describe('PendingTransactionTracker', function () { describe('#_checkPendingTx', function () { it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { - pendingTxTracker.once('tx:failed', (txId, err) => { + pendingTxTracker.once('tx:failed', (txId) => { assert(txId, txMetaNoHash.id, 'should pass txId') done() }) @@ -128,7 +128,7 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.getPendingTransactions = () => txList pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) } Promise.all(txList.map((tx) => tx.processed)) - .then((txCompletedList) => done()) + .then(() => done()) .catch(done) pendingTxTracker.updatePendingTxs() @@ -152,7 +152,7 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.getPendingTransactions = () => txList pendingTxTracker._resubmitTx = async (tx) => { tx.resolve(tx) } Promise.all(txList.map((tx) => tx.processed)) - .then((txCompletedList) => done()) + .then(() => done()) .catch(done) pendingTxTracker.resubmitPendingTxs(blockNumberStub) }) @@ -178,7 +178,7 @@ describe('PendingTransactionTracker', function () { throw new Error(knownErrors.pop()) } Promise.all(txList.map((tx) => tx.processed)) - .then((txCompletedList) => done()) + .then(() => done()) .catch(done) pendingTxTracker.resubmitPendingTxs(blockNumberStub) @@ -194,9 +194,9 @@ describe('PendingTransactionTracker', function () { }) pendingTxTracker.getPendingTransactions = () => txList - pendingTxTracker._resubmitTx = async (tx) => { throw new TypeError('im some real error') } + pendingTxTracker._resubmitTx = async () => { throw new TypeError('im some real error') } Promise.all(txList.map((tx) => tx.processed)) - .then((txCompletedList) => done()) + .then(() => done()) .catch(done) pendingTxTracker.resubmitPendingTxs(blockNumberStub) diff --git a/test/unit/app/controllers/transactions/tx-gas-util-test.js b/test/unit/app/controllers/transactions/tx-gas-util-test.js index 31defd6ed..f92d95507 100644 --- a/test/unit/app/controllers/transactions/tx-gas-util-test.js +++ b/test/unit/app/controllers/transactions/tx-gas-util-test.js @@ -11,7 +11,7 @@ describe('txUtils', function () { before(function () { txUtils = new TxUtils(new Proxy({}, { - get: (obj, name) => { + get: () => { return () => {} }, })) diff --git a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js index fba0e7fda..328c2ac6f 100644 --- a/test/unit/app/controllers/transactions/tx-state-history-helper-test.js +++ b/test/unit/app/controllers/transactions/tx-state-history-helper-test.js @@ -29,7 +29,7 @@ describe('Transaction state history helper', function () { describe('#migrateFromSnapshotsToDiffs', function () { it('migrates history to diffs and can recover original values', function () { - testVault.data.TransactionController.transactions.forEach((tx, index) => { + testVault.data.TransactionController.transactions.forEach((tx) => { const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history) newHistory.forEach((newEntry, index) => { if (index === 0) { diff --git a/test/unit/app/controllers/transactions/tx-state-manager-test.js b/test/unit/app/controllers/transactions/tx-state-manager-test.js index 88bdaa60e..4ccade2aa 100644 --- a/test/unit/app/controllers/transactions/tx-state-manager-test.js +++ b/test/unit/app/controllers/transactions/tx-state-manager-test.js @@ -55,7 +55,7 @@ describe('TransactionStateManager', function () { it('should emit a rejected event to signal the exciton of callback', (done) => { const tx = { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} } txStateManager.addTx(tx) - const noop = function (err, txId) { + const noop = function (err) { if (err) { console.log('Error: ', err) } diff --git a/test/unit/app/edge-encryptor-test.js b/test/unit/app/edge-encryptor-test.js index 1a6255b36..52817cd09 100644 --- a/test/unit/app/edge-encryptor-test.js +++ b/test/unit/app/edge-encryptor-test.js @@ -83,7 +83,7 @@ describe('EdgeEncryptor', function () { edgeEncryptor.encrypt(password, data) .then(function (encryptedData) { edgeEncryptor.decrypt('wrong password', encryptedData) - .then(function (decryptedData) { + .then(function () { assert.fail('could decrypt with wrong password') done() }) diff --git a/test/unit/migrations/migrator-test.js b/test/unit/migrations/migrator-test.js index a9374dff1..693c5830d 100644 --- a/test/unit/migrations/migrator-test.js +++ b/test/unit/migrations/migrator-test.js @@ -61,7 +61,7 @@ describe('Migrator', () => { const migrator = new Migrator({ migrations: [{ version: 1, migrate: async () => { throw new Error('test') } } ] }) migrator.on('error', () => done()) migrator.migrateData({ meta: {version: 0} }) - .then((migratedData) => { + .then(() => { }).catch(done) }) diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js index edbcb4a8b..34dd6a39b 100644 --- a/test/unit/ui/app/actions.spec.js +++ b/test/unit/ui/app/actions.spec.js @@ -44,7 +44,7 @@ describe('Actions', () => { showUnapprovedTx: noop, showUnconfirmedMessage: noop, encryptor: { - encrypt: function (password, object) { + encrypt: function (_, object) { this.object = object return Promise.resolve('mock-encrypted') }, @@ -103,7 +103,7 @@ describe('Actions', () => { submitPasswordSpy = sinon.stub(background, 'submitPassword') - submitPasswordSpy.callsFake((password, callback) => { + submitPasswordSpy.callsFake((_, callback) => { callback(new Error('error in submitPassword')) }) @@ -235,7 +235,7 @@ describe('Actions', () => { createNewVaultAndRestoreSpy = sinon.stub(background, 'createNewVaultAndRestore') - createNewVaultAndRestoreSpy.callsFake((password, seed, callback) => { + createNewVaultAndRestoreSpy.callsFake((_, __, callback) => { callback(new Error('error')) }) @@ -279,7 +279,7 @@ describe('Actions', () => { ] createNewVaultAndKeychainSpy = sinon.stub(background, 'createNewVaultAndKeychain') - createNewVaultAndKeychainSpy.callsFake((password, callback) => { + createNewVaultAndKeychainSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -342,7 +342,7 @@ describe('Actions', () => { ] submitPasswordSpy = sinon.stub(background, 'submitPassword') - submitPasswordSpy.callsFake((password, callback) => { + submitPasswordSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -414,7 +414,7 @@ describe('Actions', () => { it('displays warning error message when submitPassword in background errors', () => { submitPasswordSpy = sinon.stub(background, 'submitPassword') - submitPasswordSpy.callsFake((password, callback) => { + submitPasswordSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -483,7 +483,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] removeAccountSpy = sinon.stub(background, 'removeAccount') - removeAccountSpy.callsFake((address, callback) => { + removeAccountSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -522,7 +522,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] - addNewKeyringSpy.callsFake((type, opts, callback) => { + addNewKeyringSpy.callsFake((_, __, callback) => { callback(new Error('error')) }) @@ -611,7 +611,7 @@ describe('Actions', () => { ] importAccountWithStrategySpy = sinon.stub(background, 'importAccountWithStrategy') - importAccountWithStrategySpy.callsFake((strategy, args, callback) => { + importAccountWithStrategySpy.callsFake((_, __, callback) => { callback(new Error('error')) }) @@ -668,7 +668,7 @@ describe('Actions', () => { { type: 'HIDE_LOADING_INDICATION' }, { type: 'DISPLAY_WARNING', value: 'error' }, ] - setCurrentCurrencySpy.callsFake((currencyCode, callback) => { + setCurrentCurrencySpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -720,7 +720,7 @@ describe('Actions', () => { ] signMessageSpy = sinon.stub(background, 'signMessage') - signMessageSpy.callsFake((msgData, callback) => { + signMessageSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -775,7 +775,7 @@ describe('Actions', () => { ] signPersonalMessageSpy = sinon.stub(background, 'signPersonalMessage') - signPersonalMessageSpy.callsFake((msgData, callback) => { + signPersonalMessageSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -812,7 +812,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, { type: 'SHOW_CONF_TX_PAGE', transForward: true, id: undefined }, ] - sendTransactionSpy.callsFake((txData, callback) => { + sendTransactionSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -906,7 +906,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] - setSelectedAddressSpy.callsFake((address, callback) => { + setSelectedAddressSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -941,7 +941,7 @@ describe('Actions', () => { { type: 'HIDE_LOADING_INDICATION' }, { type: 'DISPLAY_WARNING', value: 'error' }, ] - setSelectedAddressSpy.callsFake((address, callback) => { + setSelectedAddressSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -980,7 +980,7 @@ describe('Actions', () => { { type: 'UPDATE_TOKENS', newTokens: undefined }, ] - addTokenSpy.callsFake((address, symbol, decimals, image, callback) => { + addTokenSpy.callsFake((_, __, ___, ____, callback) => { callback(new Error('error')) }) @@ -1020,7 +1020,7 @@ describe('Actions', () => { { type: 'UPDATE_TOKENS', newTokens: undefined }, ] - removeTokenSpy.callsFake((address, callback) => { + removeTokenSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1054,7 +1054,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, ] - setProviderTypeSpy.callsFake((type, callback) => { + setProviderTypeSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1087,7 +1087,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'Had a problem changing networks!' }, ] - setRpcTargetSpy.callsFake((newRpc, chainId, ticker, nickname, callback) => { + setRpcTargetSpy.callsFake((_, __, ___, ____, callback) => { callback(new Error('error')) }) @@ -1134,7 +1134,7 @@ describe('Actions', () => { exportAccountSpy = sinon.spy(background, 'exportAccount') return store.dispatch(actions.exportAccount(password, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc')) - .then((result) => { + .then(() => { assert(submitPasswordSpy.calledOnce) assert(exportAccountSpy.calledOnce) assert.deepEqual(store.getActions(), expectedActions) @@ -1150,7 +1150,7 @@ describe('Actions', () => { ] submitPasswordSpy = sinon.stub(background, 'submitPassword') - submitPasswordSpy.callsFake((password, callback) => { + submitPasswordSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1169,7 +1169,7 @@ describe('Actions', () => { ] exportAccountSpy = sinon.stub(background, 'exportAccount') - exportAccountSpy.callsFake((address, callback) => { + exportAccountSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1246,7 +1246,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] - setFeatureFlagSpy.callsFake((feature, activated, callback) => { + setFeatureFlagSpy.callsFake((_, __, callback) => { callback(new Error('error')) }) @@ -1300,7 +1300,7 @@ describe('Actions', () => { ] getTransactionCountSpy = sinon.stub(global.ethQuery, 'getTransactionCount') - getTransactionCountSpy.callsFake((address, callback) => { + getTransactionCountSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1338,7 +1338,7 @@ describe('Actions', () => { { type: 'SET_USE_BLOCKIE', value: undefined }, ] - setUseBlockieSpy.callsFake((val, callback) => { + setUseBlockieSpy.callsFake((_, callback) => { callback(new Error('error')) }) @@ -1385,7 +1385,7 @@ describe('Actions', () => { { type: 'DISPLAY_WARNING', value: 'error' }, ] setCurrentLocaleSpy = sinon.stub(background, 'setCurrentLocale') - setCurrentLocaleSpy.callsFake((key, callback) => { + setCurrentLocaleSpy.callsFake((_, callback) => { callback(new Error('error')) }) diff --git a/test/web3/web3.js b/test/web3/web3.js index 5c2de078d..0f7a4c3cd 100644 --- a/test/web3/web3.js +++ b/test/web3/web3.js @@ -12,7 +12,7 @@ web3.currentProvider.enable().then(() => { Object.keys(methodGroup).forEach(methodKey => { const methodButton = document.getElementById(methodKey) - methodButton.addEventListener('click', function (event) { + methodButton.addEventListener('click', function () { window.ethereum.sendAsync({ method: methodKey, diff --git a/ui/app/components/app/account-panel.js b/ui/app/components/app/account-panel.js index 79882f34a..e61cb8ad6 100644 --- a/ui/app/components/app/account-panel.js +++ b/ui/app/components/app/account-panel.js @@ -69,18 +69,9 @@ AccountPanel.prototype.render = function () { ) } -function balanceOrFaucetingIndication (account, isFauceting) { - // Temporarily deactivating isFauceting indication - // because it shows fauceting for empty restored accounts. - if (/* isFauceting*/ false) { - return { - key: 'Account is auto-funding.', - value: 'Please wait.', - } - } else { - return { - key: 'BALANCE', - value: formatBalance(account.balance), - } +function balanceOrFaucetingIndication (account) { + return { + key: 'BALANCE', + value: formatBalance(account.balance), } } diff --git a/ui/app/components/app/bn-as-decimal-input.js b/ui/app/components/app/bn-as-decimal-input.js index 9a033f893..834bab0a4 100644 --- a/ui/app/components/app/bn-as-decimal-input.js +++ b/ui/app/components/app/bn-as-decimal-input.js @@ -116,7 +116,7 @@ BnAsDecimalInput.prototype.render = function () { ) } -BnAsDecimalInput.prototype.setValid = function (message) { +BnAsDecimalInput.prototype.setValid = function () { this.setState({ invalid: null }) } diff --git a/ui/app/components/app/ens-input.js b/ui/app/components/app/ens-input.js index 424c5061e..5eea0dd90 100644 --- a/ui/app/components/app/ens-input.js +++ b/ui/app/components/app/ens-input.js @@ -144,7 +144,7 @@ EnsInput.prototype.ensIcon = function (recipient) { }, this.ensIconContents(recipient)) } -EnsInput.prototype.ensIconContents = function (recipient) { +EnsInput.prototype.ensIconContents = function () { const { loadingEns, ensFailure, ensResolution, toError } = this.state || { ensResolution: ZERO_ADDRESS } if (toError) return diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js index 95894140c..d6c259033 100644 --- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js +++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.component.js @@ -58,7 +58,7 @@ export default class AdvancedTabContent extends Component { } } - gasInput ({ labelKey, value, onChange, insufficientBalance, showGWEI, customPriceIsSafe, isSpeedUp }) { + gasInput ({ labelKey, value, onChange, insufficientBalance, customPriceIsSafe, isSpeedUp }) { const { isInError, errorText, diff --git a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js index 90fef1a1b..73bc13481 100644 --- a/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js +++ b/ui/app/components/app/gas-customization/advanced-gas-inputs/advanced-gas-inputs.container.js @@ -17,8 +17,8 @@ function convertGasLimitForInputs (gasLimitInHexWEI) { const mapDispatchToProps = dispatch => { return { - showGasPriceInfoModal: modalName => dispatch(showModal({ name: 'GAS_PRICE_INFO_MODAL' })), - showGasLimitInfoModal: modalName => dispatch(showModal({ name: 'GAS_LIMIT_INFO_MODAL' })), + showGasPriceInfoModal: () => dispatch(showModal({ name: 'GAS_PRICE_INFO_MODAL' })), + showGasLimitInfoModal: () => dispatch(showModal({ name: 'GAS_LIMIT_INFO_MODAL' })), } } diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js index ad8628621..eab3434df 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/advanced-tab-content/advanced-tab-content.component.js @@ -67,7 +67,7 @@ export default class AdvancedTabContent extends Component { } } - gasInput ({ labelKey, value, onChange, insufficientBalance, showGWEI, customPriceIsSafe, isSpeedUp }) { + gasInput ({ labelKey, value, onChange, insufficientBalance, customPriceIsSafe, isSpeedUp }) { const { isInError, errorText, @@ -148,7 +148,6 @@ export default class AdvancedTabContent extends Component { customGasPrice, updateCustomGasPrice, customGasLimit, - updateCustomGasLimit, insufficientBalance, customPriceIsSafe, isSpeedUp, diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js index 8aaccafd5..e18c1067e 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.component.js @@ -122,8 +122,6 @@ export default class GasModalPageContainer extends Component { } renderTabs ({ - originalTotalFiat, - originalTotalEth, newTotalFiat, newTotalEth, sendAmount, diff --git a/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js b/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js index 0456f5262..14952a49a 100644 --- a/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js +++ b/ui/app/components/app/gas-customization/gas-price-button-group/gas-price-button-group.component.js @@ -49,7 +49,7 @@ export default class GasPriceButtonGroup extends Component { priceInHexWei, ...renderableGasInfo }, { - buttonDataLoading, + buttonDataLoading: _, handleGasPriceSelection, ...buttonContentPropsAndFlags }, index) { diff --git a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js index f19dafcc1..55512ce09 100644 --- a/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js +++ b/ui/app/components/app/gas-customization/gas-price-chart/gas-price-chart.utils.js @@ -68,7 +68,7 @@ export function handleChartUpdate ({ chart, gasPrices, newPrice, cssId }) { export function getAdjacentGasPrices ({ gasPrices, priceToPosition }) { const closestLowerValueIndex = gasPrices.findIndex((e, i, a) => e <= priceToPosition && a[i + 1] >= priceToPosition) - const closestHigherValueIndex = gasPrices.findIndex((e, i, a) => e > priceToPosition) + const closestHigherValueIndex = gasPrices.findIndex((e) => e > priceToPosition) return { closestLowerValueIndex, closestHigherValueIndex, @@ -133,7 +133,7 @@ export function setTickPosition (axis, n, newPosition, secondNewPosition) { d3.select('#chart') .select(`.c3-axis-${axis}`) .selectAll('.tick') - .filter((d, i) => i === n) + .filter((_, i) => i === n) .select('text') .attr(positionToShift, 0) .select('tspan') @@ -284,7 +284,7 @@ export function generateChart (gasPrices, estimatedTimes, gasPricesMax, estimate }) return text + '' + "
" }, - position: function (data) { + position: function () { if (d3.select('#overlayed-circle').empty()) { return { top: -100, left: -100 } } diff --git a/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js b/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js index 7dec7a85f..c960f49a7 100644 --- a/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js +++ b/ui/app/components/app/gas-customization/gas-price-chart/tests/gas-price-chart.component.test.js @@ -6,7 +6,7 @@ import shallow from '../../../../../../lib/shallow-with-context' import * as d3 from 'd3' function timeout (time) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(resolve, time) }) } diff --git a/ui/app/components/app/modals/deposit-ether-modal.js b/ui/app/components/app/modals/deposit-ether-modal.js index 8f7ef792c..f56069d65 100644 --- a/ui/app/components/app/modals/deposit-ether-modal.js +++ b/ui/app/components/app/modals/deposit-ether-modal.js @@ -48,7 +48,7 @@ function mapDispatchToProps (dispatch) { } inherits(DepositEtherModal, Component) -function DepositEtherModal (props, context) { +function DepositEtherModal (_, context) { Component.call(this) // need to set after i18n locale has loaded diff --git a/ui/app/components/app/modals/export-private-key-modal.js b/ui/app/components/app/modals/export-private-key-modal.js index 70987330a..c3098a16c 100644 --- a/ui/app/components/app/modals/export-private-key-modal.js +++ b/ui/app/components/app/modals/export-private-key-modal.js @@ -98,7 +98,7 @@ ExportPrivateKeyModal.prototype.renderPasswordInput = function (privateKey) { }) } -ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, address, hideModal) { +ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, address, hideModal) { return h('div.export-private-key-buttons', {}, [ !privateKey && h(Button, { type: 'default', @@ -171,7 +171,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.private-key-password-warning', this.context.t('privateKeyWarning')), - this.renderButtons(privateKey, this.state.password, address, hideModal), + this.renderButtons(privateKey, address, hideModal), ]) } diff --git a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js index 83595281f..ea7d71a73 100644 --- a/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js +++ b/ui/app/components/app/modals/metametrics-opt-in-modal/metametrics-opt-in-modal.container.js @@ -4,7 +4,7 @@ import MetaMetricsOptInModal from './metametrics-opt-in-modal.component' import withModalProps from '../../../../helpers/higher-order-components/with-modal-props' import { setParticipateInMetaMetrics } from '../../../../store/actions' -const mapStateToProps = (state, ownProps) => { +const mapStateToProps = (_, ownProps) => { const { unapprovedTxCount } = ownProps return { diff --git a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js index 20915b5f9..a83ba8f8e 100644 --- a/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/app/modals/qr-scanner/qr-scanner.component.js @@ -71,7 +71,7 @@ export default class QrScanner extends Component { initCamera () { this.codeReader = new BrowserQRCodeReader() this.codeReader.getVideoInputDevices() - .then(videoInputDevices => { + .then(() => { clearTimeout(this.permissionChecker) this.checkPermisisions() this.codeReader.decodeFromInputVideoDevice(undefined, 'video') diff --git a/ui/app/components/app/modals/reject-transactions/reject-transactions.container.js b/ui/app/components/app/modals/reject-transactions/reject-transactions.container.js index d2af05573..aa74fd800 100644 --- a/ui/app/components/app/modals/reject-transactions/reject-transactions.container.js +++ b/ui/app/components/app/modals/reject-transactions/reject-transactions.container.js @@ -3,7 +3,7 @@ import { compose } from 'recompose' import RejectTransactionsModal from './reject-transactions.component' import withModalProps from '../../../../helpers/higher-order-components/with-modal-props' -const mapStateToProps = (state, ownProps) => { +const mapStateToProps = (_, ownProps) => { const { unapprovedTxCount } = ownProps return { diff --git a/ui/app/components/app/token-cell.js b/ui/app/components/app/token-cell.js index cef809e8a..495b9502b 100644 --- a/ui/app/components/app/token-cell.js +++ b/ui/app/components/app/token-cell.js @@ -155,7 +155,7 @@ TokenCell.prototype.send = function (address, event) { } } -TokenCell.prototype.view = function (address, userAddress, network, event) { +TokenCell.prototype.view = function (address, userAddress, network) { const url = etherscanLinkFor(address, userAddress, network) if (url) { navigateTo(url) diff --git a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js index 88d63baae..4ecc0dabb 100644 --- a/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js +++ b/ui/app/components/app/user-preferenced-currency-display/tests/user-preferenced-currency-display.container.test.js @@ -5,7 +5,7 @@ let mapStateToProps, mergeProps proxyquire('../user-preferenced-currency-display.container.js', { 'react-redux': { - connect: (ms, md, mp) => { + connect: (ms, _, mp) => { mapStateToProps = ms mergeProps = mp return () => ({}) diff --git a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js index 42d156f92..2a4635955 100644 --- a/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js +++ b/ui/app/components/app/user-preferenced-currency-display/user-preferenced-currency-display.container.js @@ -3,7 +3,7 @@ import UserPreferencedCurrencyDisplay from './user-preferenced-currency-display. import { preferencesSelector, getIsMainnet } from '../../../selectors/selectors' import { ETH, PRIMARY, SECONDARY } from '../../../helpers/constants/common' -const mapStateToProps = (state, ownProps) => { +const mapStateToProps = (state) => { const { useNativeCurrencyAsPrimaryCurrency, showFiatInTestnets, diff --git a/ui/app/components/ui/alert/index.js b/ui/app/components/ui/alert/index.js index 5620d847a..b1229f502 100644 --- a/ui/app/components/ui/alert/index.js +++ b/ui/app/components/ui/alert/index.js @@ -18,7 +18,7 @@ class Alert extends Component { if (!this.props.visible && nextProps.visible) { this.animateIn(nextProps) } else if (this.props.visible && !nextProps.visible) { - this.animateOut(nextProps) + this.animateOut() } } @@ -30,7 +30,7 @@ class Alert extends Component { }) } - animateOut (props) { + animateOut () { this.setState({ msg: null, className: '.hidden', diff --git a/ui/app/components/ui/currency-display/tests/currency-display.container.test.js b/ui/app/components/ui/currency-display/tests/currency-display.container.test.js index 9888c366e..182524e59 100644 --- a/ui/app/components/ui/currency-display/tests/currency-display.container.test.js +++ b/ui/app/components/ui/currency-display/tests/currency-display.container.test.js @@ -5,7 +5,7 @@ let mapStateToProps, mergeProps proxyquire('../currency-display.container.js', { 'react-redux': { - connect: (ms, md, mp) => { + connect: (ms, _, mp) => { mapStateToProps = ms mergeProps = mp return () => ({}) diff --git a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js index 6109d29b6..259fe594a 100644 --- a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js +++ b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js @@ -5,7 +5,7 @@ let mapStateToProps, mergeProps proxyquire('../currency-input.container.js', { 'react-redux': { - connect: (ms, md, mp) => { + connect: (ms, _, mp) => { mapStateToProps = ms mergeProps = mp return () => ({}) diff --git a/ui/app/components/ui/token-input/tests/token-input.container.test.js b/ui/app/components/ui/token-input/tests/token-input.container.test.js index 2b1c102c8..6f87e64a5 100644 --- a/ui/app/components/ui/token-input/tests/token-input.container.test.js +++ b/ui/app/components/ui/token-input/tests/token-input.container.test.js @@ -5,7 +5,7 @@ let mapStateToProps, mergeProps proxyquire('../token-input.container.js', { 'react-redux': { - connect: (ms, md, mp) => { + connect: (ms, _, mp) => { mapStateToProps = ms mergeProps = mp return () => ({}) diff --git a/ui/app/components/ui/unit-input/unit-input.component.js b/ui/app/components/ui/unit-input/unit-input.component.js index c5f8350a6..6a53f4c6f 100644 --- a/ui/app/components/ui/unit-input/unit-input.component.js +++ b/ui/app/components/ui/unit-input/unit-input.component.js @@ -58,7 +58,7 @@ export default class UnitInput extends PureComponent { this.props.onChange(value) } - handleBlur = event => { + handleBlur = () => { const { onBlur } = this.props typeof onBlur === 'function' && onBlur(this.state.value) } diff --git a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js index 483f2f56d..d2e344663 100644 --- a/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js +++ b/ui/app/ducks/confirm-transaction/confirm-transaction.duck.test.js @@ -494,7 +494,7 @@ describe('Confirm Transaction Duck', () => { }) }) - describe('Thunk actions', done => { + describe('Thunk actions', () => { beforeEach(() => { global.eth = { getCode: sinon.stub().callsFake( diff --git a/ui/app/ducks/gas/gas-duck.test.js b/ui/app/ducks/gas/gas-duck.test.js index c0152c74f..b7e83a81c 100644 --- a/ui/app/ducks/gas/gas-duck.test.js +++ b/ui/app/ducks/gas/gas-duck.test.js @@ -461,8 +461,8 @@ describe('Gas Duck', () => { assert.equal(thirdDispatchCallType, SET_PRICE_AND_TIME_ESTIMATES) assert(priceAndTimeEstimateResult.length < mockPredictTableResponse.length * 3 - 2) assert(!priceAndTimeEstimateResult.find(d => d.expectedTime > 100)) - assert(!priceAndTimeEstimateResult.find((d, i, a) => a[a + 1] && d.expectedTime > a[a + 1].expectedTime)) - assert(!priceAndTimeEstimateResult.find((d, i, a) => a[a + 1] && d.gasprice > a[a + 1].gasprice)) + assert(!priceAndTimeEstimateResult.find((d, _, a) => a[a + 1] && d.expectedTime > a[a + 1].expectedTime)) + assert(!priceAndTimeEstimateResult.find((d, _, a) => a[a + 1] && d.gasprice > a[a + 1].gasprice)) assert.deepEqual( mockDistpatch.getCall(3).args, diff --git a/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js b/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js index 6086e03fb..6281ddcc6 100644 --- a/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js +++ b/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js @@ -42,7 +42,7 @@ class MetaMetricsProvider extends Component { currentPath: window.location.href, } - props.history.listen(locationObj => { + props.history.listen(() => { this.setState({ previousPath: this.state.currentPath, currentPath: window.location.href, diff --git a/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js b/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js index 654e7062a..81a3512d1 100644 --- a/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js +++ b/ui/app/helpers/higher-order-components/with-modal-props/tests/with-modal-props.test.js @@ -21,7 +21,7 @@ const mockState = { describe('withModalProps', () => { it('should return a component wrapped with modal state props', () => { - const TestComponent = props => ( + const TestComponent = () => (
Testing
) const WrappedComponent = withModalProps(TestComponent) diff --git a/ui/app/helpers/utils/conversion-util.js b/ui/app/helpers/utils/conversion-util.js index 8cc531773..affddade7 100644 --- a/ui/app/helpers/utils/conversion-util.js +++ b/ui/app/helpers/utils/conversion-util.js @@ -42,7 +42,7 @@ const convert = R.invoker(1, 'times') const round = R.invoker(2, 'round')(R.__, BigNumber.ROUND_HALF_DOWN) const roundDown = R.invoker(2, 'round')(R.__, BigNumber.ROUND_DOWN) const invertConversionRate = conversionRate => () => new BigNumber(1.0).div(conversionRate) -const decToBigNumberViaString = n => R.pipe(String, toBigNumber['dec']) +const decToBigNumberViaString = () => R.pipe(String, toBigNumber['dec']) // Setter Maps const toBigNumber = { diff --git a/ui/app/helpers/utils/metametrics.util.js b/ui/app/helpers/utils/metametrics.util.js index 62f5fd760..cafbd5c07 100644 --- a/ui/app/helpers/utils/metametrics.util.js +++ b/ui/app/helpers/utils/metametrics.util.js @@ -84,7 +84,7 @@ function composeParamAddition (paramValue, paramName) { : `&${paramName}=${paramValue}` } -function composeUrl (config, permissionPreferences = {}) { +function composeUrl (config) { const { eventOpts = {}, customVariables = '', diff --git a/ui/app/helpers/utils/util.js b/ui/app/helpers/utils/util.js index c50d7cbe5..94fa9ad42 100644 --- a/ui/app/helpers/utils/util.js +++ b/ui/app/helpers/utils/util.js @@ -92,7 +92,7 @@ function miniAddressSummary (address) { return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...' } -function isValidAddress (address, network) { +function isValidAddress (address) { var prefixed = ethUtil.addHexPrefix(address) if (address === '0x0000000000000000000000000000000000000000') return false return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed) @@ -268,7 +268,7 @@ function bnMultiplyByFraction (targetBN, numerator, denominator) { return targetBN.mul(numBN).div(denomBN) } -function getTxFeeBn (gas, gasPrice = MIN_GAS_PRICE_BN.toString(16), blockGasLimit) { +function getTxFeeBn (gas, gasPrice = MIN_GAS_PRICE_BN.toString(16)) { const gasBn = hexToBn(gas) const gasPriceBn = hexToBn(gasPrice) const txFeeBn = gasBn.mul(gasPriceBn) @@ -297,7 +297,7 @@ function exportAsFile (filename, data, type = 'text/csv') { } function allNull (obj) { - return Object.entries(obj).every(([key, value]) => value === null) + return Object.entries(obj).every(([_, value]) => value === null) } function getTokenAddressFromTokenObject (token) { @@ -308,11 +308,10 @@ function getTokenAddressFromTokenObject (token) { * Safely checksumms a potentially-null address * * @param {String} [address] - address to checksum - * @param {String} [network] - network id * @returns {String} - checksummed address * */ -function checksumAddress (address, network) { +function checksumAddress (address) { const checksummed = address ? ethUtil.toChecksumAddress(address) : '' return checksummed } diff --git a/ui/app/pages/create-account/connect-hardware/account-list.js b/ui/app/pages/create-account/connect-hardware/account-list.js index a521c7eaf..247c27a5d 100644 --- a/ui/app/pages/create-account/connect-hardware/account-list.js +++ b/ui/app/pages/create-account/connect-hardware/account-list.js @@ -6,10 +6,6 @@ const Select = require('react-select').default import Button from '../../../components/ui/button' class AccountList extends Component { - constructor (props, context) { - super(props) - } - getHdPaths () { return [ { diff --git a/ui/app/pages/create-account/connect-hardware/connect-screen.js b/ui/app/pages/create-account/connect-hardware/connect-screen.js index f5a83e6cf..a3b8ad246 100644 --- a/ui/app/pages/create-account/connect-hardware/connect-screen.js +++ b/ui/app/pages/create-account/connect-hardware/connect-screen.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') import Button from '../../../components/ui/button' class ConnectScreen extends Component { - constructor (props, context) { + constructor (props) { super(props) this.state = { selectedDevice: null, @@ -103,7 +103,7 @@ class ConnectScreen extends Component { } - scrollToTutorial = (e) => { + scrollToTutorial = () => { if (this.referenceNode) this.referenceNode.scrollIntoView({behavior: 'smooth'}) } diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index 1398fa680..5a91a2725 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -12,7 +12,7 @@ const { getPlatform } = require('../../../../../app/scripts/lib/util') const { PLATFORM_FIREFOX } = require('../../../../../app/scripts/lib/enums') class ConnectHardwareForm extends Component { - constructor (props, context) { + constructor (props) { super(props) this.state = { error: null, @@ -101,7 +101,7 @@ class ConnectHardwareForm extends Component { const newState = { unlocked: true, device, error: null } // Default to the first account if (this.state.selectedAccount === null) { - accounts.forEach((a, i) => { + accounts.forEach((a) => { if (a.address.toLowerCase() === this.props.address) { newState.selectedAccount = a.index.toString() } diff --git a/ui/app/pages/create-account/import-account/seed.js b/ui/app/pages/create-account/import-account/seed.js index d98909baa..73332f926 100644 --- a/ui/app/pages/create-account/import-account/seed.js +++ b/ui/app/pages/create-account/import-account/seed.js @@ -11,7 +11,7 @@ SeedImportSubview.contextTypes = { module.exports = connect(mapStateToProps)(SeedImportSubview) -function mapStateToProps (state) { +function mapStateToProps () { return {} } diff --git a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js index ffaff9acf..6b9d06cf9 100644 --- a/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js +++ b/ui/app/pages/first-time-flow/metametrics-opt-in/metametrics-opt-in.component.js @@ -119,7 +119,7 @@ export default class MetaMetricsOptIn extends Component { hideCancel={false} onSubmit={() => { setParticipateInMetaMetrics(true) - .then(([participateStatus, metaMetricsId]) => { + .then(([_, metaMetricsId]) => { const promise = participateInMetaMetrics !== true ? metricsEvent({ eventOpts: { diff --git a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js index 04fe651e6..4cfc38fdf 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js +++ b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/confirm-seed-phrase.component.js @@ -37,7 +37,7 @@ export default class ConfirmSeedPhrase extends PureComponent { isDragging: false, } - shouldComponentUpdate (nextProps, nextState, nextContext) { + shouldComponentUpdate (nextProps, nextState) { const { seedPhrase } = this.props const { selectedSeedIndices, @@ -108,7 +108,7 @@ export default class ConfirmSeedPhrase extends PureComponent { } } - handleSelectSeedWord = (word, shuffledIndex) => { + handleSelectSeedWord = (shuffledIndex) => { this.setState({ selectedSeedIndices: [...this.state.selectedSeedIndices, shuffledIndex], pendingSeedIndices: [...this.state.pendingSeedIndices, shuffledIndex], @@ -183,7 +183,7 @@ export default class ConfirmSeedPhrase extends PureComponent { selected={isSelected} onClick={() => { if (!isSelected) { - this.handleSelectSeedWord(word, index) + this.handleSelectSeedWord(index) } else { this.handleDeselectSeedWord(index) } diff --git a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js index 97dbd2a4b..cdb881921 100644 --- a/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js +++ b/ui/app/pages/first-time-flow/seed-phrase/confirm-seed-phrase/draggable-seed.component.js @@ -28,7 +28,7 @@ class DraggableSeed extends Component { onClick () {}, } - componentWillReceiveProps (nextProps, nextContext) { + componentWillReceiveProps (nextProps) { const { isOver, setHoveringIndex } = this.props if (isOver && !nextProps.isOver) { setHoveringIndex(-1) diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 7ff741405..9c30da086 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -438,7 +438,7 @@ function mapStateToProps (state) { } } -function mapDispatchToProps (dispatch, ownProps) { +function mapDispatchToProps (dispatch) { return { dispatch, hideSidebar: () => dispatch(actions.hideSidebar()), diff --git a/ui/app/pages/send/account-list-item/tests/account-list-item-container.test.js b/ui/app/pages/send/account-list-item/tests/account-list-item-container.test.js index 33f932daf..1580fd497 100644 --- a/ui/app/pages/send/account-list-item/tests/account-list-item-container.test.js +++ b/ui/app/pages/send/account-list-item/tests/account-list-item-container.test.js @@ -5,7 +5,7 @@ let mapStateToProps proxyquire('../account-list-item.container.js', { 'react-redux': { - connect: (ms, md) => { + connect: (ms) => { mapStateToProps = ms return () => ({}) }, diff --git a/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js b/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js index eecff165d..2013e3200 100644 --- a/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js +++ b/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/tests/send-row-error-message-container.test.js @@ -5,7 +5,7 @@ let mapStateToProps proxyquire('../send-row-error-message.container.js', { 'react-redux': { - connect: (ms, md) => { + connect: (ms) => { mapStateToProps = ms return () => ({}) }, diff --git a/ui/app/pages/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js b/ui/app/pages/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js index 225bf056c..6c0739f0e 100644 --- a/ui/app/pages/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js +++ b/ui/app/pages/send/send-content/send-row-wrapper/send-row-warning-message/tests/send-row-warning-message-container.test.js @@ -5,7 +5,7 @@ let mapStateToProps proxyquire('../send-row-warning-message.container.js', { 'react-redux': { - connect: (ms, md) => { + connect: (ms) => { mapStateToProps = ms return () => ({}) }, diff --git a/ui/app/pages/send/send-content/send-to-row/send-to-row.utils.js b/ui/app/pages/send/send-content/send-to-row/send-to-row.utils.js index 200a2e26a..b3b0d2da3 100644 --- a/ui/app/pages/send/send-content/send-to-row/send-to-row.utils.js +++ b/ui/app/pages/send/send-content/send-to-row/send-to-row.utils.js @@ -10,7 +10,7 @@ import { checkExistingAddresses } from '../../../add-token/util' const ethUtil = require('ethereumjs-util') const contractMap = require('eth-contract-metadata') -function getToErrorObject (to, toError = null, hasHexData = false, tokens = [], selectedToken = null, network) { +function getToErrorObject (to, toError = null, hasHexData = false, _, __, network) { if (!to) { if (!hasHexData) { toError = REQUIRED_ERROR diff --git a/ui/app/pages/send/tests/send-container.test.js b/ui/app/pages/send/tests/send-container.test.js index b3e202030..131c42f59 100644 --- a/ui/app/pages/send/tests/send-container.test.js +++ b/ui/app/pages/send/tests/send-container.test.js @@ -24,7 +24,7 @@ proxyquire('../send.container.js', { }, }, 'react-router-dom': { withRouter: () => {} }, - 'recompose': { compose: (arg1, arg2) => () => arg2() }, + 'recompose': { compose: (_, arg2) => () => arg2() }, './send.selectors': { getAmountConversionRate: (s) => `mockAmountConversionRate:${s}`, getBlockGasLimit: (s) => `mockBlockGasLimit:${s}`, diff --git a/ui/app/pages/send/tests/send-utils.test.js b/ui/app/pages/send/tests/send-utils.test.js index b19535b9e..bf9cba14a 100644 --- a/ui/app/pages/send/tests/send-utils.test.js +++ b/ui/app/pages/send/tests/send-utils.test.js @@ -17,12 +17,12 @@ const { } = require('../send.constants') const stubs = { - addCurrencies: sinon.stub().callsFake((a, b, obj) => { + addCurrencies: sinon.stub().callsFake((a, b) => { if (String(a).match(/^0x.+/)) a = Number(String(a).slice(2)) if (String(b).match(/^0x.+/)) b = Number(String(b).slice(2)) return a + b }), - conversionUtil: sinon.stub().callsFake((val, obj) => parseInt(val, 16)), + conversionUtil: sinon.stub().callsFake((val) => parseInt(val, 16)), conversionGTE: sinon.stub().callsFake((obj1, obj2) => obj1.value >= obj2.value), multiplyCurrencies: sinon.stub().callsFake((a, b) => `${a}x${b}`), calcTokenAmount: sinon.stub().callsFake((a, d) => 'calc:' + a + d), diff --git a/ui/app/pages/send/to-autocomplete/to-autocomplete.js b/ui/app/pages/send/to-autocomplete/to-autocomplete.js index b246413fb..328a5b62b 100644 --- a/ui/app/pages/send/to-autocomplete/to-autocomplete.js +++ b/ui/app/pages/send/to-autocomplete/to-autocomplete.js @@ -84,7 +84,7 @@ ToAutoComplete.prototype.handleInputEvent = function (event = {}, cb) { cb && cb(event.target.value) } -ToAutoComplete.prototype.componentDidUpdate = function (nextProps, nextState) { +ToAutoComplete.prototype.componentDidUpdate = function (nextProps) { if (this.props.to !== nextProps.to) { this.handleInputEvent() } diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index f2a9ed08f..95c6dbb77 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -762,7 +762,7 @@ function addNewAccount () { function checkHardwareStatus (deviceName, hdPath) { log.debug(`background.checkHardwareStatus`, deviceName, hdPath) - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { background.checkHardwareStatus(deviceName, hdPath, (err, unlocked) => { @@ -783,10 +783,10 @@ function checkHardwareStatus (deviceName, hdPath) { function forgetDevice (deviceName) { log.debug(`background.forgetDevice`, deviceName) - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { - background.forgetDevice(deviceName, (err, response) => { + background.forgetDevice(deviceName, (err) => { if (err) { log.error(err) dispatch(actions.displayWarning(err.message)) @@ -804,7 +804,7 @@ function forgetDevice (deviceName) { function connectHardware (deviceName, page, hdPath) { log.debug(`background.connectHardware`, deviceName, page, hdPath) - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { background.connectHardware(deviceName, page, hdPath, (err, accounts) => { @@ -825,10 +825,10 @@ function connectHardware (deviceName, page, hdPath) { function unlockHardwareWalletAccount (index, deviceName, hdPath) { log.debug(`background.unlockHardwareWalletAccount`, index, deviceName, hdPath) - return (dispatch, getState) => { + return (dispatch) => { dispatch(actions.showLoadingIndication()) return new Promise((resolve, reject) => { - background.unlockHardwareWalletAccount(index, deviceName, hdPath, (err, accounts) => { + background.unlockHardwareWalletAccount(index, deviceName, hdPath, (err) => { if (err) { log.error(err) dispatch(actions.displayWarning(err.message)) @@ -849,7 +849,7 @@ function showInfoPage () { } function showQrScanner (ROUTE) { - return (dispatch, getState) => { + return (dispatch) => { return WebcamUtils.checkStatus() .then(status => { if (!status.environmentReady) { @@ -988,7 +988,7 @@ function signTypedMsg (msgData) { function signTx (txData) { return (dispatch) => { - global.ethQuery.sendTransaction(txData, (err, data) => { + global.ethQuery.sendTransaction(txData, (err) => { if (err) { return dispatch(actions.displayWarning(err.message)) } @@ -1021,7 +1021,6 @@ function setGasTotal (gasTotal) { function updateGasData ({ gasPrice, blockGasLimit, - recentBlocks, selectedAddress, selectedToken, to, @@ -1403,7 +1402,7 @@ function cancelTx (txData) { * @return {function(*): Promise} */ function cancelTxs (txDataList) { - return async (dispatch, getState) => { + return async (dispatch) => { window.onbeforeunload = null dispatch(actions.showLoadingIndication()) const txIds = txDataList.map(({id}) => id) @@ -1808,7 +1807,7 @@ function removeSuggestedTokens () { return (dispatch) => { dispatch(actions.showLoadingIndication()) window.onbeforeunload = null - return new Promise((resolve, reject) => { + return new Promise((resolve) => { background.removeSuggestedTokens((err, suggestedTokens) => { dispatch(actions.hideLoadingIndication()) if (err) { @@ -1827,7 +1826,7 @@ function removeSuggestedTokens () { } function addKnownMethodData (fourBytePrefix, methodData) { - return (dispatch) => { + return () => { background.addKnownMethodData(fourBytePrefix, methodData) } } @@ -1932,7 +1931,7 @@ function setProviderType (type) { return (dispatch, getState) => { const { type: currentProviderType } = getState().metamask.provider log.debug(`background.setProviderType`, type) - background.setProviderType(type, (err, result) => { + background.setProviderType(type, (err) => { if (err) { log.error(err) return dispatch(actions.displayWarning('Had a problem changing networks!')) @@ -1962,7 +1961,7 @@ function setPreviousProvider (type) { function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname) { return (dispatch) => { log.debug(`background.updateAndSetCustomRpc: ${newRpc} ${chainId} ${ticker} ${nickname}`) - background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err, result) => { + background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err) => { if (err) { log.error(err) return dispatch(actions.displayWarning('Had a problem changing networks!')) @@ -1978,7 +1977,7 @@ function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname) { function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname) { return (dispatch) => { log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`) - background.setCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err, result) => { + background.setCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err) => { if (err) { log.error(err) return dispatch(actions.displayWarning('Had a problem changing networks!')) @@ -1991,7 +1990,7 @@ function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname) { function delRpcTarget (oldRpc) { return (dispatch) => { log.debug(`background.delRpcTarget: ${oldRpc}`) - background.delCustomRpc(oldRpc, (err, result) => { + background.delCustomRpc(oldRpc, (err) => { if (err) { log.error(err) return dispatch(self.displayWarning('Had a problem removing network!')) @@ -2005,7 +2004,7 @@ function delRpcTarget (oldRpc) { function addToAddressBook (recipient, nickname = '') { log.debug(`background.addToAddressBook`) return (dispatch) => { - background.setAddressBook(recipient, nickname, (err, result) => { + background.setAddressBook(recipient, nickname, (err) => { if (err) { log.error(err) return dispatch(self.displayWarning('Address book failed to update')) @@ -2274,7 +2273,7 @@ function pairUpdate (coin) { } } -function shapeShiftSubview (network) { +function shapeShiftSubview () { var pair = 'btc_eth' return (dispatch) => { dispatch(actions.showSubLoadingIndication()) @@ -2310,7 +2309,7 @@ function coinShiftRquest (data, marketData) { } function buyWithShapeShift (data) { - return dispatch => new Promise((resolve, reject) => { + return () => new Promise((resolve, reject) => { shapeShiftRequest('shift', { method: 'POST', data}, (response) => { if (response.error) { return reject(response.error) @@ -2357,7 +2356,7 @@ function shapeShiftRequest (query, options, cb) { !options ? options = {} : null options.method ? method = options.method : method = 'GET' - var requestListner = function (request) { + var requestListner = function () { try { queryResponse = JSON.parse(this.responseText) cb ? cb(queryResponse) : null @@ -2686,19 +2685,19 @@ function setPendingTokens (pendingTokens) { } function approveProviderRequestByOrigin (origin) { - return (dispatch) => { + return () => { background.approveProviderRequestByOrigin(origin) } } function rejectProviderRequestByOrigin (origin) { - return (dispatch) => { + return () => { background.rejectProviderRequestByOrigin(origin) } } function clearApprovedOrigins () { - return (dispatch) => { + return () => { background.clearApprovedOrigins() } } diff --git a/ui/example.js b/ui/example.js index 4627c0e9c..d940d3bc8 100644 --- a/ui/example.js +++ b/ui/example.js @@ -91,7 +91,7 @@ accountManager.setSelectedAccount = function (address, cb) { this._didUpdate() } -accountManager.signTransaction = function (txParams, cb) { +accountManager.signTransaction = function () { alert('signing tx....') } diff --git a/ui/lib/test-timeout.js b/ui/lib/test-timeout.js index 957b0fce2..7d825487f 100644 --- a/ui/lib/test-timeout.js +++ b/ui/lib/test-timeout.js @@ -1,5 +1,5 @@ export default function timeout (time) { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(resolve, time || 1500) }) } From 77d3bc252d5c4d223e9de3c6700750d1895bb257 Mon Sep 17 00:00:00 2001 From: bitpshr Date: Mon, 6 May 2019 12:12:52 -0400 Subject: [PATCH 62/87] feature: integrate gaba/PhishingController --- app/scripts/controllers/blacklist.js | 136 --- app/scripts/metamask-controller.js | 15 +- package-lock.json | 877 ++++++++++-------- package.json | 2 +- .../controllers/blacklist-controller-test.js | 56 -- .../controllers/metamask-controller-test.js | 3 +- 6 files changed, 524 insertions(+), 565 deletions(-) delete mode 100644 app/scripts/controllers/blacklist.js delete mode 100644 test/unit/app/controllers/blacklist-controller-test.js diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js deleted file mode 100644 index e55b09d03..000000000 --- a/app/scripts/controllers/blacklist.js +++ /dev/null @@ -1,136 +0,0 @@ -const ObservableStore = require('obs-store') -const extend = require('xtend') -const PhishingDetector = require('eth-phishing-detect/src/detector') -const log = require('loglevel') - -// compute phishing lists -const PHISHING_DETECTION_CONFIG = require('eth-phishing-detect/src/config.json') -// every four minutes -const POLLING_INTERVAL = 4 * 60 * 1000 - -class BlacklistController { - - /** - * Responsible for polling for and storing an up to date 'eth-phishing-detect' config.json file, while - * exposing a method that can check whether a given url is a phishing attempt. The 'eth-phishing-detect' - * config.json file contains a fuzzylist, whitelist and blacklist. - * - * - * @typedef {Object} BlacklistController - * @param {object} opts Overrides the defaults for the initial state of this.store - * @property {object} store The the store of the current phishing config - * @property {object} store.phishing Contains fuzzylist, whitelist and blacklist arrays. @see - * {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json} - * @property {object} _phishingDetector The PhishingDetector instantiated by passing store.phishing to - * PhishingDetector. - * @property {object} _phishingUpdateIntervalRef Id of the interval created to periodically update the blacklist - * - */ - constructor (opts = {}) { - const initState = extend({ - phishing: PHISHING_DETECTION_CONFIG, - whitelist: [], - }, opts.initState) - this.store = new ObservableStore(initState) - // phishing detector - this._phishingDetector = null - this._setupPhishingDetector(initState.phishing) - // polling references - this._phishingUpdateIntervalRef = null - } - - /** - * Adds the given hostname to the runtime whitelist - * @param {string} hostname the hostname to whitelist - */ - whitelistDomain (hostname) { - if (!hostname) { - return - } - - const { whitelist } = this.store.getState() - this.store.updateState({ - whitelist: [...new Set([hostname, ...whitelist])], - }) - } - - /** - * Given a url, returns the result of checking if that url is in the store.phishing blacklist - * - * @param {string} hostname The hostname portion of a url; the one that will be checked against the white and - * blacklists of store.phishing - * @returns {boolean} Whether or not the passed hostname is on our phishing blacklist - * - */ - checkForPhishing (hostname) { - if (!hostname) return false - - const { whitelist } = this.store.getState() - if (whitelist.some((e) => e === hostname)) { - return false - } - - const { result } = this._phishingDetector.check(hostname) - return result - } - - /** - * Queries `https://api.infura.io/v2/blacklist` for an updated blacklist config. This is passed to this._phishingDetector - * to update our phishing detector instance, and is updated in the store. The new phishing config is returned - * - * - * @returns {Promise} Promises the updated blacklist config for the phishingDetector - * - */ - async updatePhishingList () { - // make request - let response - try { - response = await fetch('https://api.infura.io/v2/blacklist') - } catch (err) { - log.error(new Error(`BlacklistController - failed to fetch blacklist:\n${err.stack}`)) - return - } - // parse response - let rawResponse - let phishing - try { - const rawResponse = await response.text() - phishing = JSON.parse(rawResponse) - } catch (err) { - log.error(new Error(`BlacklistController - failed to parse blacklist:\n${rawResponse}`)) - return - } - // update current blacklist - this.store.updateState({ phishing }) - this._setupPhishingDetector(phishing) - return phishing - } - - /** - * Initiates the updating of the local blacklist at a set interval. The update is done via this.updatePhishingList(). - * Also, this method store a reference to that interval at this._phishingUpdateIntervalRef - * - */ - scheduleUpdates () { - if (this._phishingUpdateIntervalRef) return - this.updatePhishingList() - this._phishingUpdateIntervalRef = setInterval(() => { - this.updatePhishingList() - }, POLLING_INTERVAL) - } - - /** - * Sets this._phishingDetector to a new PhishingDetector instance. - * @see {@link https://github.com/MetaMask/eth-phishing-detect} - * - * @private - * @param {object} config A config object like that found at {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json} - * - */ - _setupPhishingDetector (config) { - this._phishingDetector = new PhishingDetector(config) - } -} - -module.exports = BlacklistController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b190dd452..447d8b626 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -28,7 +28,6 @@ const PreferencesController = require('./controllers/preferences') const CurrencyController = require('./controllers/currency') const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') -const BlacklistController = require('./controllers/blacklist') const CachedBalancesController = require('./controllers/cached-balances') const RecentBlocksController = require('./controllers/recent-blocks') const MessageManager = require('./lib/message-manager') @@ -55,7 +54,10 @@ const HW_WALLETS_KEYRINGS = [TrezorKeyring.type, LedgerBridgeKeyring.type] const EthQuery = require('eth-query') const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') -const { AddressBookController } = require('gaba') +const { + AddressBookController, + PhishingController, +} = require('gaba') const backEndMetaMetricsEvent = require('./lib/backend-metametrics') @@ -112,8 +114,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.infuraController.scheduleInfuraNetworkCheck() - this.blacklistController = new BlacklistController() - this.blacklistController.scheduleUpdates() + this.phishingController = new PhishingController() // rpc provider this.initializeProvider() @@ -1301,7 +1302,7 @@ module.exports = class MetamaskController extends EventEmitter { */ setupUntrustedCommunication (connectionStream, originDomain) { // Check if new connection is blacklisted - if (this.blacklistController.checkForPhishing(originDomain)) { + if (this.phishingController.test(originDomain)) { log.debug('MetaMask - sending phishing warning for', originDomain) this.sendPhishingWarning(connectionStream, originDomain) return @@ -1781,11 +1782,11 @@ module.exports = class MetamaskController extends EventEmitter { */ /** - * Adds a domain to the {@link BlacklistController} whitelist + * Adds a domain to the PhishingController whitelist * @param {string} hostname the domain to whitelist */ whitelistPhishingDomain (hostname) { - return this.blacklistController.whitelistDomain(hostname) + return this.phishingController.bypass(hostname) } /** diff --git a/package-lock.json b/package-lock.json index e26c37150..8844b21a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1752,9 +1752,9 @@ "integrity": "sha512-lRVw09gOvgviOfeUrKc/pmTiRZ7g7oDOU6OAutyuSHpm1/o2RaBQvRhgK8QEdu+FFuw/wnWb29A/iuxv9i8OpQ==" }, "@types/lodash": { - "version": "4.14.123", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz", - "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==" + "version": "4.14.124", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.124.tgz", + "integrity": "sha512-6bKEUVbHJ8z34jisA7lseJZD2g31SIvee3cGX2KEZCS4XXWNbjPZpmO1/2rGNR9BhGtaYr6iYXPl1EzRrDAFTA==" }, "@types/node": { "version": "8.5.5", @@ -9863,12 +9863,12 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.11.8", @@ -9887,20 +9887,18 @@ "rlp": "^2.0.0", "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" - }, - "dependencies": { - "ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - } } } } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } } } }, @@ -9908,8 +9906,7 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -9980,7 +9977,7 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" } }, @@ -10174,12 +10171,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -10200,21 +10197,19 @@ "rlp": "^2.0.0", "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" - }, - "dependencies": { - "ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dev": true, - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - } } } } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } } } }, @@ -10222,14 +10217,14 @@ "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", @@ -10312,26 +10307,50 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -10379,8 +10398,34 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + } } }, "ethereum-common": { @@ -10622,26 +10667,50 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#2863c40e0982acfc0b7163f0285d4c56427c7799", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8" } }, "ethereumjs-util": { @@ -10831,8 +10900,34 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + } } }, "ethereum-common": { @@ -10947,7 +11042,7 @@ "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", "requires": { - "async-eventemitter": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "eth-query": "^2.1.0", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.1.3", @@ -11110,8 +11205,76 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" + }, + "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } } }, "ethereumjs-util": { @@ -13163,15 +13326,16 @@ "integrity": "sha1-8ESOgGmFW/Kj5oPNwdMg5+KgfvQ=" }, "gaba": { - "version": "1.0.0-beta.65", - "resolved": "https://registry.npmjs.org/gaba/-/gaba-1.0.0-beta.65.tgz", - "integrity": "sha512-pX9hMd4RR5AXe7bwIamQEXLJe26fNvjOf7PjkHGKlRjKzBYmxZ03Y/Pa9nklNlG2Shc9sSgB6GXZpYlXNlJRIg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gaba/-/gaba-1.0.1.tgz", + "integrity": "sha512-67Zoaq6wnaBASIXGfu2L+jzx8m+l1tfn6FAEIZI/pMvn/ymk4V9raeqz73QQKq1fF4WcRy2H1Ru1r45J1tDQoQ==", "dev": true, "requires": { "await-semaphore": "^0.1.3", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#faa4f56fb17b3ae8579df68708be59d617732f31", "eth-json-rpc-infura": "^3.1.2", "eth-keyring-controller": "^4.0.0", + "eth-method-registry": "1.1.0", "eth-phishing-detect": "^1.1.13", "eth-query": "^2.1.2", "eth-sig-util": "^2.1.0", @@ -13248,12 +13412,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -13290,6 +13454,15 @@ } } }, + "eth-method-registry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eth-method-registry/-/eth-method-registry-1.1.0.tgz", + "integrity": "sha512-jGbbGYd19XJCtoGFtUD2qJYWefKCCbFcu7F/AQ5sJXvqTIVAHnFn3paaV2zhN5t7iyKYp1qxc+ugOky+72xcbg==", + "dev": true, + "requires": { + "ethjs": "^0.3.0" + } + }, "eth-phishing-detect": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/eth-phishing-detect/-/eth-phishing-detect-1.1.13.tgz", @@ -13342,6 +13515,119 @@ "secp256k1": "^3.0.1" } }, + "ethjs": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/ethjs/-/ethjs-0.3.9.tgz", + "integrity": "sha512-gOQzA3tDUjoLpNONSOALJ/rUFtHi5tXl2mholHasF1cvXhoddqi06yU4OJFJu9AGd6n9v9ywzHlYeIKg1t1hdw==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "ethjs-abi": "0.2.1", + "ethjs-contract": "0.2.2", + "ethjs-filter": "0.1.8", + "ethjs-provider-http": "0.1.6", + "ethjs-query": "0.3.7", + "ethjs-unit": "0.1.6", + "ethjs-util": "0.1.3", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + }, + "ethjs-query": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.7.tgz", + "integrity": "sha512-TZnKUwfkWjy0SowFdPLtmsytCorHi0i4vvkQn7Jg8rZt33cRzKhuzOwKr/G3vdigCc+ePXOhUGMcJSAPlOG44A==", + "dev": true, + "requires": { + "ethjs-format": "0.2.7", + "ethjs-rpc": "0.2.0", + "promise-to-callback": "^1.0.0" + } + }, + "ethjs-util": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", + "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, + "ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha1-4KepOn6BFjqUR3utVu3lJKtt5TM=", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + } + } + }, + "ethjs-contract": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ethjs-contract/-/ethjs-contract-0.2.2.tgz", + "integrity": "sha512-xxPqEjsULQ/QNWuvX6Ako0PGs5RxALA8N/H3+boLvnaXDFZVGpD7H63H1gBCRTZyYqCldPpVlVHuw/rD45vazw==", + "dev": true, + "requires": { + "ethjs-abi": "0.2.0", + "ethjs-filter": "0.1.8", + "ethjs-util": "0.1.3", + "js-sha3": "0.5.5" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", + "dev": true + }, + "ethjs-abi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.0.tgz", + "integrity": "sha1-0+LCIQEVIPxJm3FoIDbBT8wvWyU=", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + } + }, + "ethjs-util": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", + "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, + "ethjs-filter": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/ethjs-filter/-/ethjs-filter-0.1.8.tgz", + "integrity": "sha512-qTDPskDL2UadHwjvM8A+WG9HwM4/FoSY3p3rMJORkHltYcAuiQZd2otzOYKcL5w2Q3sbAkW/E3yt/FPFL/AVXA==", + "dev": true + }, "ethjs-query": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.8.tgz", @@ -13363,6 +13649,12 @@ "promise-to-callback": "^1.0.0" } }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha1-uvDA6MVK1ZA0R9+Wreekobynmko=", + "dev": true + }, "obs-store": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", @@ -13400,7 +13692,7 @@ "integrity": "sha512-VU6/DSUX93d1fCzBz7WP/SGCQizO1rKZi4Px9j/3yRyfssHyFcZamMw2/sj4E8TlfMXONvZLoforR8B4bRoyTQ==", "dev": true, "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2-cookies": "^1.1.0", @@ -13492,7 +13784,6 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, - "optional": true, "requires": { "mime-types": "~2.1.18", "negotiator": "0.6.1" @@ -13533,15 +13824,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", - "dev": true, - "optional": true + "dev": true }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true, - "optional": true + "dev": true }, "asn1": { "version": "0.2.4", @@ -13557,7 +13846,6 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", "dev": true, - "optional": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -13685,7 +13973,7 @@ "dependencies": { "jsesc": { "version": "1.3.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -13854,13 +14142,13 @@ }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", "dev": true }, "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", - "resolved": "http://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", "dev": true }, @@ -14280,7 +14568,7 @@ }, "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "dev": true, "requires": { @@ -14323,8 +14611,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", - "dev": true, - "optional": true + "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -14368,10 +14655,9 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, - "optional": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -14405,7 +14691,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", "dev": true, - "optional": true, "requires": { "bytes": "3.0.0", "content-type": "~1.0.4", @@ -14424,7 +14709,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -14449,7 +14733,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -14488,10 +14772,9 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, - "optional": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -14560,7 +14843,6 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, - "optional": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -14571,7 +14853,6 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, - "optional": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -14581,8 +14862,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "dev": true, - "optional": true + "dev": true }, "buffer-crc32": { "version": "0.2.13", @@ -14595,8 +14875,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", - "dev": true, - "optional": true + "dev": true }, "buffer-from": { "version": "1.1.1", @@ -14608,8 +14887,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", "integrity": "sha1-YGSkD6dutDxyOrqe+PbhIW0QURo=", - "dev": true, - "optional": true + "dev": true }, "buffer-xor": { "version": "1.0.3", @@ -14621,8 +14899,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, - "optional": true + "dev": true }, "bytewise": { "version": "1.1.0", @@ -14684,7 +14961,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14768,10 +15045,9 @@ }, "commander": { "version": "2.8.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, - "optional": true, "requires": { "graceful-readlink": ">= 1.0.0" } @@ -14798,15 +15074,13 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true, - "optional": true + "dev": true }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "optional": true + "dev": true }, "convert-source-map": { "version": "1.6.0", @@ -14821,22 +15095,19 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true, - "optional": true + "dev": true }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true, - "optional": true + "dev": true }, "cookiejar": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true, - "optional": true + "dev": true }, "core-js": { "version": "2.6.5", @@ -14855,7 +15126,6 @@ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, - "optional": true, "requires": { "object-assign": "^4", "vary": "^1" @@ -14874,7 +15144,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -14887,7 +15157,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -14957,8 +15227,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true, - "optional": true + "dev": true }, "decompress": { "version": "4.2.0", @@ -14979,7 +15248,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "optional": true @@ -14991,7 +15260,6 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "dev": true, - "optional": true, "requires": { "mimic-response": "^1.0.0" } @@ -15001,7 +15269,6 @@ "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, - "optional": true, "requires": { "file-type": "^5.2.0", "is-stream": "^1.1.0", @@ -15058,14 +15325,14 @@ "dependencies": { "file-type": { "version": "3.9.0", - "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", "dev": true, "optional": true }, "get-stream": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, "optional": true, @@ -15076,7 +15343,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true, "optional": true @@ -15142,8 +15409,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "optional": true + "dev": true }, "des.js": { "version": "1.0.0", @@ -15160,8 +15426,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true, - "optional": true + "dev": true }, "detect-indent": { "version": "4.0.0", @@ -15174,7 +15439,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "optional": true, @@ -15205,8 +15470,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true, - "optional": true + "dev": true }, "ecc-jsbn": { "version": "0.1.2", @@ -15222,8 +15486,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true, - "optional": true + "dev": true }, "electron-to-chromium": { "version": "1.3.113", @@ -15250,8 +15513,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "optional": true + "dev": true }, "encoding": { "version": "0.1.12", @@ -15350,8 +15612,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true, - "optional": true + "dev": true }, "escape-string-regexp": { "version": "1.0.5", @@ -15369,8 +15630,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true, - "optional": true + "dev": true }, "eth-block-tracker": { "version": "3.0.1", @@ -15389,7 +15649,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -15410,7 +15670,7 @@ }, "eth-json-rpc-middleware": { "version": "1.6.0", - "resolved": "http://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", "dev": true, "requires": { @@ -15437,7 +15697,7 @@ }, "ethereumjs-block": { "version": "1.7.1", - "resolved": "http://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", "dev": true, "requires": { @@ -15455,7 +15715,6 @@ "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", "integrity": "sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA==", "dev": true, - "optional": true, "requires": { "bn.js": "^4.11.6", "elliptic": "^6.4.0", @@ -15539,7 +15798,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" } }, @@ -15554,13 +15813,13 @@ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-block": { "version": "1.7.1", - "resolved": "http://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", "dev": true, "requires": { @@ -15592,7 +15851,7 @@ }, "fs-extra": { "version": "0.30.0", - "resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", "dev": true, "requires": { @@ -15605,7 +15864,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -15630,7 +15889,7 @@ }, "web3-provider-engine": { "version": "13.8.0", - "resolved": "http://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", + "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", "dev": true, "requires": { @@ -15675,7 +15934,7 @@ "dependencies": { "ethereumjs-util": { "version": "4.5.0", - "resolved": "http://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-4.5.0.tgz", "integrity": "sha1-PpQosxfuvaPXJg2FT93alUsfG8Y=", "dev": true, "requires": { @@ -15906,7 +16165,6 @@ "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "number-to-bn": "1.7.0" @@ -15916,8 +16174,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -15935,8 +16192,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.1.1.tgz", "integrity": "sha1-R3hr2qCHyvext15zq8XH1UAVjNA=", - "dev": true, - "optional": true + "dev": true }, "events": { "version": "3.0.0", @@ -15959,7 +16215,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", "dev": true, - "optional": true, "requires": { "accepts": "~1.3.5", "array-flatten": "1.1.1", @@ -15998,7 +16253,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -16007,8 +16261,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -16080,8 +16333,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", - "dev": true, - "optional": true + "dev": true }, "file-uri-to-path": { "version": "1.0.0", @@ -16091,10 +16343,9 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "dev": true, - "optional": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -16110,7 +16361,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -16119,8 +16369,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -16164,29 +16413,25 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true, - "optional": true + "dev": true }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true, - "optional": true + "dev": true }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true + "dev": true }, "fs-extra": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0" @@ -16695,7 +16940,6 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "dev": true, - "optional": true, "requires": { "graceful-fs": "^4.1.2", "inherits": "~2.0.0", @@ -16723,10 +16967,9 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "dev": true, - "optional": true + "dev": true }, "getpass": { "version": "0.1.7", @@ -16772,7 +17015,6 @@ "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", "dev": true, - "optional": true, "requires": { "decompress-response": "^3.2.0", "duplexer3": "^0.1.4", @@ -16800,8 +17042,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true, - "optional": true + "dev": true }, "har-schema": { "version": "2.0.0", @@ -16841,8 +17082,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", - "dev": true, - "optional": true + "dev": true }, "has-symbols": { "version": "1.0.0", @@ -16855,7 +17095,6 @@ "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dev": true, - "optional": true, "requires": { "has-symbol-support-x": "^1.4.1" } @@ -16927,10 +17166,9 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, - "optional": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -16942,8 +17180,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=", - "dev": true, - "optional": true + "dev": true }, "http-signature": { "version": "1.2.0", @@ -16969,8 +17206,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", - "dev": true, - "optional": true + "dev": true }, "immediate": { "version": "3.2.3", @@ -17013,8 +17249,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=", - "dev": true, - "optional": true + "dev": true }, "is-arrayish": { "version": "0.2.1", @@ -17081,15 +17316,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", - "dev": true, - "optional": true + "dev": true }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", - "dev": true, - "optional": true + "dev": true }, "is-regex": { "version": "1.0.4", @@ -17104,8 +17337,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", - "dev": true, - "optional": true + "dev": true }, "is-stream": { "version": "1.1.0", @@ -17151,7 +17383,6 @@ "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, - "optional": true, "requires": { "has-to-string-tag-x": "^1.2.0", "is-object": "^1.0.1" @@ -17177,7 +17408,7 @@ }, "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, @@ -17239,13 +17470,13 @@ }, "json5": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "dev": true }, "jsonfile": { "version": "2.4.0", - "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { @@ -17327,7 +17558,7 @@ }, "level-iterator-stream": { "version": "1.3.1", - "resolved": "http://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", + "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz", "integrity": "sha1-5Dt4sagUPm+pek9IXrjqUwNS8u0=", "dev": true, "requires": { @@ -17348,7 +17579,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -17418,7 +17649,7 @@ "dependencies": { "readable-stream": { "version": "1.0.34", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", "dev": true, "requires": { @@ -17485,7 +17716,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -17498,7 +17729,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -17535,8 +17766,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "3.2.0", @@ -17585,10 +17815,9 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, - "optional": true + "dev": true }, "memdown": { "version": "1.4.1", @@ -17625,12 +17854,11 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true, - "optional": true + "dev": true }, "merkle-patricia-tree": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.1.tgz", "integrity": "sha512-Qp9Mpb3xazznXzzGQBqHbqCpT2AR9joUOHYYPiQjYCarrdCPCnLWXo4BFv77y4xN26KR224xoU1n/qYY7RYYgw==", "dev": true, "requires": { @@ -17646,7 +17874,7 @@ "dependencies": { "async": { "version": "1.5.2", - "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, @@ -17686,8 +17914,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true, - "optional": true + "dev": true }, "miller-rabin": { "version": "4.0.1", @@ -17704,8 +17931,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true, - "optional": true + "dev": true }, "mime-db": { "version": "1.38.0", @@ -17726,8 +17952,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "optional": true + "dev": true }, "min-document": { "version": "2.19.0", @@ -17761,13 +17986,13 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -17818,26 +18043,24 @@ }, "nan": { "version": "2.10.0", - "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nano-json-stream-parser": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=", - "dev": true, - "optional": true + "dev": true }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true, - "optional": true + "dev": true }, "node-fetch": { "version": "2.1.2", - "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", "dev": true }, @@ -17864,7 +18087,6 @@ "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "strip-hex-prefix": "1.0.0" @@ -17874,8 +18096,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -17908,7 +18129,6 @@ "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.3.tgz", "integrity": "sha1-K0hl29Rr6BIlcT9Om/5Lz09oCk8=", "dev": true, - "optional": true, "requires": { "http-https": "^1.0.0" } @@ -17918,7 +18138,6 @@ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dev": true, - "optional": true, "requires": { "ee-first": "1.1.1" } @@ -17934,13 +18153,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { @@ -17949,7 +18168,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -17957,22 +18176,19 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", - "dev": true, - "optional": true + "dev": true }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true, - "optional": true + "dev": true }, "p-timeout": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", "dev": true, - "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -17982,7 +18198,6 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "dev": true, - "optional": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -18015,8 +18230,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", - "dev": true, - "optional": true + "dev": true }, "path-exists": { "version": "2.1.0", @@ -18029,7 +18243,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -18043,8 +18257,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true, - "optional": true + "dev": true }, "path-type": { "version": "1.1.0", @@ -18059,7 +18272,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -18116,8 +18329,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true, - "optional": true + "dev": true }, "private": { "version": "0.1.8", @@ -18152,7 +18364,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", "dev": true, - "optional": true, "requires": { "forwarded": "~0.1.2", "ipaddr.js": "1.8.0" @@ -18263,10 +18474,9 @@ }, "query-string": { "version": "5.1.1", - "resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dev": true, - "optional": true, "requires": { "decode-uri-component": "^0.2.0", "object-assign": "^4.1.0", @@ -18297,22 +18507,19 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/randomhex/-/randomhex-0.1.5.tgz", "integrity": "sha1-us7vmCMpCRQA8qKRLGzQLxCU9YU=", - "dev": true, - "optional": true + "dev": true }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", - "dev": true, - "optional": true + "dev": true }, "raw-body": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", "dev": true, - "optional": true, "requires": { "bytes": "3.0.0", "http-errors": "1.6.3", @@ -18343,7 +18550,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -18409,7 +18616,7 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, @@ -18630,7 +18837,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "dev": true, - "optional": true, "requires": { "debug": "2.6.9", "depd": "~1.1.2", @@ -18652,7 +18858,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -18661,8 +18866,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", - "dev": true, - "optional": true + "dev": true } } }, @@ -18671,7 +18875,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "dev": true, - "optional": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -18684,7 +18887,6 @@ "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", "dev": true, - "optional": true, "requires": { "body-parser": "^1.16.0", "cors": "^2.8.1", @@ -18716,12 +18918,11 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "optional": true + "dev": true }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -18742,15 +18943,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", - "dev": true, - "optional": true + "dev": true }, "simple-get": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "dev": true, - "optional": true, "requires": { "decompress-response": "^3.3.0", "once": "^1.3.1", @@ -18832,8 +19031,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "optional": true + "dev": true }, "stream-to-pull-stream": { "version": "1.7.2", @@ -18857,8 +19055,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "dev": true, - "optional": true + "dev": true }, "string-width": { "version": "1.0.2", @@ -18890,7 +19087,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -18976,7 +19173,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -18984,7 +19181,7 @@ }, "tar": { "version": "2.2.1", - "resolved": "http://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "dev": true, "optional": true, @@ -18999,7 +19196,6 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, - "optional": true, "requires": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -19026,7 +19222,7 @@ "dependencies": { "bluebird": { "version": "2.11.0", - "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", "dev": true, "optional": true @@ -19038,7 +19234,6 @@ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", "dev": true, - "optional": true, "requires": { "any-promise": "^1.0.0" } @@ -19048,14 +19243,13 @@ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", "dev": true, - "optional": true, "requires": { "thenify": ">= 3.1.0 < 4" } }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -19073,8 +19267,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "dev": true, - "optional": true + "dev": true }, "tmp": { "version": "0.0.33", @@ -19089,8 +19282,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "dev": true, - "optional": true + "dev": true }, "to-fast-properties": { "version": "1.0.3", @@ -19148,7 +19340,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, - "optional": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.18" @@ -19194,8 +19385,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true, - "optional": true + "dev": true }, "unbzip2-stream": { "version": "1.3.3", @@ -19212,8 +19402,7 @@ "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", - "dev": true, - "optional": true + "dev": true }, "unorm": { "version": "1.5.0", @@ -19225,8 +19414,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true, - "optional": true + "dev": true }, "uri-js": { "version": "4.2.2", @@ -19242,7 +19430,6 @@ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "dev": true, - "optional": true, "requires": { "prepend-http": "^1.0.1" } @@ -19251,15 +19438,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", "integrity": "sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk=", - "dev": true, - "optional": true + "dev": true }, "url-to-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "dev": true, - "optional": true + "dev": true }, "utf8": { "version": "3.0.0", @@ -19278,8 +19463,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "optional": true + "dev": true }, "uuid": { "version": "3.3.2", @@ -19301,8 +19485,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "optional": true + "dev": true }, "verror": { "version": "1.10.0", @@ -19348,7 +19531,6 @@ "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.0.0-beta.35.tgz", "integrity": "sha512-ayGavbgVk4KL9Y88Uv411fBJ0SVgVfKhKEBweKYzmP0zOqneMzWt6YsyD1n6kRvjAbqA0AfUPEOKyMNjcx2tjw==", "dev": true, - "optional": true, "requires": { "web3-core-helpers": "1.0.0-beta.35", "web3-core-method": "1.0.0-beta.35", @@ -19361,7 +19543,6 @@ "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.0.0-beta.35.tgz", "integrity": "sha512-APOu3sEsamyqWt//8o4yq9KF25/uqGm+pQShson/sC4gKzmfJB07fLo2ond0X30E8fIqAPeVCotPXQxGciGUmA==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-eth-iban": "1.0.0-beta.35", @@ -19373,7 +19554,6 @@ "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.0.0-beta.35.tgz", "integrity": "sha512-jidImCide8q0GpfsO4L73qoHrbkeWgwU3uOH5DKtJtv0ccmG086knNMRgryb/o9ZgetDWLmDEsJnHjBSoIwcbA==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", @@ -19387,7 +19567,6 @@ "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.0.0-beta.35.tgz", "integrity": "sha512-GvqXqKq07OmHuVi5uNRg6k79a1/CI0ViCC+EtNv4CORHtDRmYEt5Bvdv6z6FJEiaaQkD0lKbFwNhLxutx7HItw==", "dev": true, - "optional": true, "requires": { "any-promise": "1.3.0", "eventemitter3": "1.1.1" @@ -19398,7 +19577,6 @@ "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.0.0-beta.35.tgz", "integrity": "sha512-S+zW2h17ZZQU9oe3yaCJE0E7aJS4C3Kf4kGPDv+nXjW0gKhQQhgVhw1Doq/aYQGqNSWJp7f1VHkz5gQWwg6RRg==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", @@ -19412,7 +19590,6 @@ "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.0.0-beta.35.tgz", "integrity": "sha512-gXzLrWvcGkGiWq1y33Z4Y80XI8XMrwowiQJkrPSjQ81K5PBKquOGwcMffLaKcwdmEy/NpsOXDeFo3eLE1Ghvvw==", "dev": true, - "optional": true, "requires": { "eventemitter3": "1.1.1", "underscore": "1.8.3", @@ -19445,7 +19622,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.0.0-beta.35.tgz", "integrity": "sha512-KUDC+EtFFYG8z01ZleKrASdjj327/rtWHzEt6RWsEj7bBa0bGp9nEh+nqdZx/Sdgz1O8tnfFzJlrRcXpfr1vGg==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "underscore": "1.8.3", @@ -19457,8 +19633,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19506,7 +19681,7 @@ }, "uuid": { "version": "2.0.1", - "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", "dev": true, "optional": true @@ -19535,7 +19710,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.0.0-beta.35.tgz", "integrity": "sha512-H5wkcNcAIc+h/WoDIKv7ZYmrM2Xqu3O7jBQl1IWo73EDVQji+AoB2i3J8tuwI1yZRInRwrfpI3Zuwuf54hXHmQ==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "web3-utils": "1.0.0-beta.35" @@ -19545,8 +19719,7 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19555,7 +19728,6 @@ "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.0.0-beta.35.tgz", "integrity": "sha512-AcM9nnlxu7ZRRxPvkrFB9eLxMM4A2cPfj2aCg21Wb2EpMnhR+b/O1cT33k7ApRowoMpM+T9M8vx2oPNwXfaCOQ==", "dev": true, - "optional": true, "requires": { "web3-core": "1.0.0-beta.35", "web3-core-helpers": "1.0.0-beta.35", @@ -19569,7 +19741,6 @@ "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.0.0-beta.35.tgz", "integrity": "sha512-bbwaQ/KohGjIJ6HAKbZ6KrklCAaG6/B7hIbAbVLSFLxF+Yz9lmAgQYaDInpidpC/NLb3WOmcbRF+P77J4qMVIA==", "dev": true, - "optional": true, "requires": { "web3-core": "1.0.0-beta.35", "web3-core-method": "1.0.0-beta.35", @@ -19610,7 +19781,7 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", "ethereumjs-util": "^5.1.1" } }, @@ -19625,8 +19796,8 @@ "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { - "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" } }, "ethereumjs-block": { @@ -19658,7 +19829,6 @@ "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.35.tgz", "integrity": "sha512-DcIMFq52Fb08UpWyZ3ZlES6NsNqJnco4hBS/Ej6eOcASfuUayPI+GLkYVZsnF3cBYqlH+DOKuArcKSuIxK7jIA==", "dev": true, - "optional": true, "requires": { "web3-core-helpers": "1.0.0-beta.35", "xhr2-cookies": "1.1.0" @@ -19669,7 +19839,6 @@ "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.0.0-beta.35.tgz", "integrity": "sha512-iB0FG0HcpUnayfa8pn4guqEQ4Y1nrroi/jffdtQgFkrNt0sD3fMSwwC0AbmECqj3tDLl0e1slBR0RENll+ZF0g==", "dev": true, - "optional": true, "requires": { "oboe": "2.1.3", "underscore": "1.8.3", @@ -19681,11 +19850,10 @@ "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.0.0-beta.35.tgz", "integrity": "sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ==", "dev": true, - "optional": true, "requires": { "underscore": "1.8.3", "web3-core-helpers": "1.0.0-beta.35", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible" + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { "debug": { @@ -19702,7 +19870,6 @@ "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", "dev": true, - "optional": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -19730,7 +19897,6 @@ "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.0.0-beta.35.tgz", "integrity": "sha512-Dq6f0SOKj3BDFRgOPnE6ALbzBDCKVIW8mKWVf7tGVhTDHf+wQaWwQSC3aArFSqdExB75BPBPyDpuMTNszhljpA==", "dev": true, - "optional": true, "requires": { "bn.js": "4.11.6", "eth-lib": "0.1.27", @@ -19745,15 +19911,13 @@ "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=", - "dev": true, - "optional": true + "dev": true }, "utf8": { "version": "2.1.1", - "resolved": "http://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.1.tgz", "integrity": "sha1-LgHbAvfY0JRPdxBPFgnrDDBM92g=", - "dev": true, - "optional": true + "dev": true } } }, @@ -19782,7 +19946,7 @@ }, "whatwg-fetch": { "version": "2.0.4", - "resolved": "http://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==", "dev": true }, @@ -19800,7 +19964,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -19819,7 +19983,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, - "optional": true, "requires": { "async-limiter": "~1.0.0", "safe-buffer": "~5.1.0", @@ -19843,7 +20006,6 @@ "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", "dev": true, - "optional": true, "requires": { "buffer-to-arraybuffer": "^0.0.5", "object-assign": "^4.1.1", @@ -19859,7 +20021,6 @@ "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.2.tgz", "integrity": "sha1-NDxE0e53JrhkgGloLQ+EDIO0Jh0=", "dev": true, - "optional": true, "requires": { "xhr-request": "^1.0.1" } @@ -19869,7 +20030,6 @@ "resolved": "https://registry.npmjs.org/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz", "integrity": "sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg=", "dev": true, - "optional": true, "requires": { "cookiejar": "^2.1.1" } @@ -19894,7 +20054,7 @@ }, "yargs": { "version": "4.8.1", - "resolved": "http://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", "dev": true, "requires": { @@ -19916,7 +20076,7 @@ }, "yargs-parser": { "version": "2.4.1", - "resolved": "http://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", "dev": true, "requires": { @@ -24267,7 +24427,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -24306,7 +24466,7 @@ }, "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -26732,7 +26892,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "requires": { "babel-core": "^6.0.14", @@ -27658,8 +27818,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "tar": { "version": "4.4.6", @@ -27679,8 +27838,7 @@ "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "optional": true + "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=" } } }, @@ -27927,7 +28085,6 @@ "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, - "optional": true, "requires": { "kind-of": "^3.0.2", "longest": "^1.0.1", @@ -28306,8 +28463,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true, - "optional": true + "dev": true }, "is-builtin-module": { "version": "1.0.0", @@ -28403,7 +28559,6 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, - "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -28446,8 +28601,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true, - "optional": true + "dev": true }, "lru-cache": { "version": "4.1.3", @@ -28677,8 +28831,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "optional": true + "dev": true }, "require-directory": { "version": "2.1.1", @@ -39122,7 +39275,7 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.3.tgz", "integrity": "sha1-yqRDc9yIFayHZ73ba6cwc5ZMqos=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git", + "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -39193,12 +39346,12 @@ "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "dev": true, "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "ethereumjs-util": "^5.1.1" } }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#d84a96796079c8595a0c78accd1e7709f2277215", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "dev": true, "requires": { @@ -39219,18 +39372,16 @@ "rlp": "^2.0.0", "safe-buffer": "^5.1.1", "secp256k1": "^3.0.1" - }, - "dependencies": { - "ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dev": true, - "requires": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - } - } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" } } } diff --git a/package.json b/package.json index 8d9da397d..0ae402600 100644 --- a/package.json +++ b/package.json @@ -228,7 +228,7 @@ "file-loader": "^1.1.11", "fs-extra": "^6.0.1", "fs-promise": "^2.0.3", - "gaba": "1.0.0-beta.65", + "gaba": "^1.0.1", "ganache-cli": "^6.1.0", "ganache-core": "^2.5.3", "geckodriver": "^1.14.1", diff --git a/test/unit/app/controllers/blacklist-controller-test.js b/test/unit/app/controllers/blacklist-controller-test.js deleted file mode 100644 index 7a14c02cc..000000000 --- a/test/unit/app/controllers/blacklist-controller-test.js +++ /dev/null @@ -1,56 +0,0 @@ -const assert = require('assert') -const BlacklistController = require('../../../../app/scripts/controllers/blacklist') - -describe('blacklist controller', function () { - let blacklistController - - before(() => { - blacklistController = new BlacklistController() - }) - - describe('whitelistDomain', function () { - it('should add hostname to the runtime whitelist', function () { - blacklistController.whitelistDomain('foo.com') - assert.deepEqual(blacklistController.store.getState().whitelist, ['foo.com']) - - blacklistController.whitelistDomain('bar.com') - assert.deepEqual(blacklistController.store.getState().whitelist, ['bar.com', 'foo.com']) - }) - }) - - describe('checkForPhishing', function () { - it('should not flag whitelisted values', function () { - const result = blacklistController.checkForPhishing('www.metamask.io') - assert.equal(result, false) - }) - it('should flag explicit values', function () { - const result = blacklistController.checkForPhishing('metamask.com') - assert.equal(result, true) - }) - it('should flag levenshtein values', function () { - const result = blacklistController.checkForPhishing('metmask.io') - assert.equal(result, true) - }) - it('should not flag not-even-close values', function () { - const result = blacklistController.checkForPhishing('example.com') - assert.equal(result, false) - }) - it('should not flag the ropsten faucet domains', function () { - const result = blacklistController.checkForPhishing('faucet.metamask.io') - assert.equal(result, false) - }) - it('should not flag the mascara domain', function () { - const result = blacklistController.checkForPhishing('zero.metamask.io') - assert.equal(result, false) - }) - it('should not flag the mascara-faucet domain', function () { - const result = blacklistController.checkForPhishing('zero-faucet.metamask.io') - assert.equal(result, false) - }) - it('should not flag whitelisted domain', function () { - blacklistController.whitelistDomain('metamask.com') - const result = blacklistController.checkForPhishing('metamask.com') - assert.equal(result, false) - }) - }) -}) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 0a1a85d5e..4768b7c64 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -752,8 +752,7 @@ describe('MetaMaskController', function () { }) it('sets up phishing stream for untrusted communication ', async () => { - await metamaskController.blacklistController.updatePhishingList() - console.log(blacklistJSON.blacklist.includes(phishingUrl)) + await metamaskController.phishingController.updatePhishingLists() const { promise, resolve } = deferredPromise() From 13be683701bc46d8f1bcbaa301e2b7f01a34e29c Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 9 May 2019 14:57:14 -0230 Subject: [PATCH 63/87] New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form. --- app/_locales/en/messages.json | 36 ++- app/scripts/controllers/network/network.js | 3 +- app/scripts/controllers/preferences.js | 32 +-- app/scripts/metamask-controller.js | 14 +- development/states/conf-tx.json | 3 +- development/states/confirm-new-ui.json | 3 +- development/states/confirm-sig-requests.json | 3 +- development/states/currency-localization.json | 3 +- development/states/send-edit.json | 3 +- development/states/send-new-ui.json | 3 +- development/states/send.json | 3 +- development/states/tx-list-items.json | 3 +- test/e2e/beta/metamask-beta-ui.spec.js | 7 +- .../preferences-controller-test.js | 6 +- .../app/dropdowns/account-details-dropdown.js | 17 +- .../app/dropdowns/network-dropdown.js | 10 +- .../app/modals/account-details-modal.js | 12 +- ...transaction-list-item-details.component.js | 15 +- .../transaction-list-item.component.js | 3 + .../transaction-list-item.container.js | 5 +- .../ui/text-field/text-field.component.js | 6 +- ui/app/ducks/app/app.js | 12 + ui/app/helpers/constants/routes.js | 2 + ui/app/helpers/utils/transactions.util.js | 16 ++ ui/app/pages/settings/index.scss | 36 ++- ui/app/pages/settings/networks-tab/index.js | 1 + ui/app/pages/settings/networks-tab/index.scss | 200 ++++++++++++++++ .../networks-tab/network-form/index.js | 1 + .../network-form/network-form.component.js | 225 ++++++++++++++++++ .../networks-tab/networks-tab.component.js | 214 +++++++++++++++++ .../networks-tab/networks-tab.constants.js | 50 ++++ .../networks-tab/networks-tab.container.js | 77 ++++++ ui/app/pages/settings/settings.component.js | 10 +- ui/app/selectors/selectors.js | 8 + ui/app/store/actions.js | 48 +++- ui/lib/account-link.js | 6 +- 36 files changed, 1028 insertions(+), 68 deletions(-) create mode 100644 ui/app/pages/settings/networks-tab/index.js create mode 100644 ui/app/pages/settings/networks-tab/index.scss create mode 100644 ui/app/pages/settings/networks-tab/network-form/index.js create mode 100644 ui/app/pages/settings/networks-tab/network-form/network-form.component.js create mode 100644 ui/app/pages/settings/networks-tab/networks-tab.component.js create mode 100644 ui/app/pages/settings/networks-tab/networks-tab.constants.js create mode 100644 ui/app/pages/settings/networks-tab/networks-tab.container.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7a5f9297c..254bfdfb9 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -83,6 +83,9 @@ "address": { "message": "Address" }, + "addNetwork": { + "message": "Add Network" + }, "advanced": { "message": "Advanced" }, @@ -191,6 +194,13 @@ "message": "must be greater than or equal to $1 and less than or equal to $2.", "description": "helper for inputting hex as decimal input" }, + "blockExplorerUrl": { + "message": "Block Explorer" + }, + "blockExplorerView": { + "message": "View account at $1", + "description": "$1 replaced by URL for custom block explorer" + }, "blockiesIdenticon": { "message": "Use Blockies Identicon" }, @@ -230,6 +240,9 @@ "ok": { "message": "Ok" }, + "optionalBlockExplorerUrl": { + "message": "Block Explorer URL (optional)" + }, "cancel": { "message": "Cancel" }, @@ -245,6 +258,9 @@ "cancelN": { "message": "Cancel all $1 transactions" }, + "chainId": { + "message": "Chain ID" + }, "classicInterface": { "message": "Use classic interface" }, @@ -502,6 +518,9 @@ "edit": { "message": "Edit" }, + "editNetwork": { + "message": "Edit Network" + }, "editAccountName": { "message": "Edit Account Name" }, @@ -934,9 +953,15 @@ "negativeETH": { "message": "Can not send negative amounts of ETH." }, + "networkName": { + "message": "Network Name" + }, "networks": { "message": "Networks" }, + "networkSettingsDescription": { + "message": "Add and edit custom RPC networks" + }, "nevermind": { "message": "Nevermind" }, @@ -977,7 +1002,7 @@ "protectYourKeysMessage2": { "message": "Keep your phrase safe. If you see something fishy, or you’re uncertain about a website, email support@metamask.io" }, - "rpcURL": { + "rpcUrl": { "message": "New RPC URL" }, "showAdvancedOptions": { @@ -1492,6 +1517,9 @@ "supportCenter": { "message": "Visit our Support Center" }, + "symbol": { + "message": "Symbol" + }, "symbolBetweenZeroTwelve": { "message": "Symbol must be between 0 and 12 characters." }, @@ -1714,9 +1742,15 @@ "viewAccount": { "message": "View Account" }, + "viewOnCustomBlockExplorer": { + "message": "View at $1" + }, "viewOnEtherscan": { "message": "View on Etherscan" }, + "viewNetworkInfo": { + "message": "View Network Info" + }, "visitWebSite": { "message": "Visit our web site" }, diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index fc8e0df5d..2c68e4378 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -129,13 +129,14 @@ module.exports = class NetworkController extends EventEmitter { }) } - setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '') { + setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs) { const providerConfig = { type: 'rpc', rpcTarget, chainId, ticker, nickname, + rpcPrefs, } this.providerConfig = providerConfig } diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index bbb13bd8e..acf952bb1 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -488,8 +488,8 @@ class PreferencesController { rpcList[index] = updatedRpc this.store.updateState({ frequentRpcListDetail: rpcList }) } else { - const { rpcUrl, chainId, ticker, nickname } = newRpcDetails - return this.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname) + const { rpcUrl, chainId, ticker, nickname, rpcPrefs = {} } = newRpcDetails + return this.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs) } return Promise.resolve(rpcList) } @@ -503,22 +503,22 @@ class PreferencesController { * @returns {Promise} Promise resolving to updated frequentRpcList. * */ - addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '') { - const rpcList = this.getFrequentRpcListDetail() - const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) - if (index !== -1) { - rpcList.splice(index, 1) - } - if (url !== 'http://localhost:8545') { - let checkedChainId - if (!!chainId && !Number.isNaN(parseInt(chainId))) { - checkedChainId = chainId + addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { + const rpcList = this.getFrequentRpcListDetail() + const index = rpcList.findIndex((element) => { return element.rpcUrl === url }) + if (index !== -1) { + rpcList.splice(index, 1) } - rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname }) + if (url !== 'http://localhost:8545') { + let checkedChainId + if (!!chainId && !Number.isNaN(parseInt(chainId))) { + checkedChainId = chainId + } + rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs }) + } + this.store.updateState({ frequentRpcListDetail: rpcList }) + return Promise.resolve(rpcList) } - this.store.updateState({ frequentRpcListDetail: rpcList }) - return Promise.resolve(rpcList) - } /** * Removes custom RPC url from state. diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b190dd452..cc9d51d3c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1633,9 +1633,9 @@ module.exports = class MetamaskController extends EventEmitter { * @returns {Promise} - The RPC Target URL confirmed. */ - async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname) { - await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname }) - this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname) + async updateAndSetCustomRpc (rpcUrl, chainId, ticker = 'ETH', nickname, rpcPrefs) { + await this.preferencesController.updateRpc({ rpcUrl, chainId, ticker, nickname, rpcPrefs }) + this.networkController.setRpcTarget(rpcUrl, chainId, ticker, nickname, rpcPrefs) return rpcUrl } @@ -1648,15 +1648,15 @@ module.exports = class MetamaskController extends EventEmitter { * @param {string} nickname - Optional nickname of the selected network. * @returns {Promise} - The RPC Target URL confirmed. */ - async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') { + async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) { const frequentRpcListDetail = this.preferencesController.getFrequentRpcListDetail() const rpcSettings = frequentRpcListDetail.find((rpc) => rpcTarget === rpc.rpcUrl) if (rpcSettings) { - this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname) + this.networkController.setRpcTarget(rpcSettings.rpcUrl, rpcSettings.chainId, rpcSettings.ticker, rpcSettings.nickname, rpcPrefs) } else { - this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname) - await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname) + this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname, rpcPrefs) + await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname, rpcPrefs) } return rpcTarget } diff --git a/development/states/conf-tx.json b/development/states/conf-tx.json index d47b26fd4..7b278f331 100644 --- a/development/states/conf-tx.json +++ b/development/states/conf-tx.json @@ -192,7 +192,8 @@ "type": "testnet" }, "shapeShiftTxList": [], - "lostAccounts": [] + "lostAccounts": [], + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-new-ui.json b/development/states/confirm-new-ui.json index 4019bede8..c9340fc8f 100644 --- a/development/states/confirm-new-ui.json +++ b/development/states/confirm-new-ui.json @@ -134,7 +134,8 @@ "useNativeCurrencyAsPrimaryCurrency": true, "showFiatInTestnets": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json index 9bf69c700..d531b2ef7 100644 --- a/development/states/confirm-sig-requests.json +++ b/development/states/confirm-sig-requests.json @@ -157,7 +157,8 @@ "preferences": { "useNativeCurrencyAsPrimaryCurrency": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/currency-localization.json b/development/states/currency-localization.json index faacb25de..a9a37ecd0 100644 --- a/development/states/currency-localization.json +++ b/development/states/currency-localization.json @@ -116,7 +116,8 @@ "useNativeCurrencyAsPrimaryCurrency": true, "showFiatInTestnets": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/send-edit.json b/development/states/send-edit.json index 71421d29f..7c7e8f097 100644 --- a/development/states/send-edit.json +++ b/development/states/send-edit.json @@ -138,7 +138,8 @@ "useNativeCurrencyAsPrimaryCurrency": true, "showFiatInTestnets": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json index 8709d096b..75982f318 100644 --- a/development/states/send-new-ui.json +++ b/development/states/send-new-ui.json @@ -117,7 +117,8 @@ "useNativeCurrencyAsPrimaryCurrency": true, "showFiatInTestnets": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/send.json b/development/states/send.json index 8ae385564..c71516edc 100644 --- a/development/states/send.json +++ b/development/states/send.json @@ -87,7 +87,8 @@ "type": "testnet" }, "shapeShiftTxList": [], - "lostAccounts": [] + "lostAccounts": [], + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/development/states/tx-list-items.json b/development/states/tx-list-items.json index 1f7539e7b..4190ee149 100644 --- a/development/states/tx-list-items.json +++ b/development/states/tx-list-items.json @@ -1059,7 +1059,8 @@ "preferences": { "useNativeCurrencyAsPrimaryCurrency": true }, - "completedUiMigration": true + "completedUiMigration": true, + "frequentRpcListDetail": [] }, "appState": { "menuOpen": false, diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 05ad84f24..7fb3de6e4 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -1341,11 +1341,14 @@ describe('MetaMask', function () { await customRpcButton.click() await delay(regularDelayMs) - const customRpcInput = await findElement(driver, By.css('input[placeholder="New RPC URL"]')) + await findElement(driver, By.css('.settings-page__sub-header-text')) + + const customRpcInputs = await findElements(driver, By.css('input[type="text"]')) + const customRpcInput = customRpcInputs[1] await customRpcInput.clear() await customRpcInput.sendKeys(customRpcUrl) - const customRpcSave = await findElement(driver, By.css('.settings-tab__rpc-save-button')) + const customRpcSave = await findElement(driver, By.css('.page-container__footer-button')) await customRpcSave.click() await delay(largeDelayMs * 2) }) diff --git a/test/unit/app/controllers/preferences-controller-test.js b/test/unit/app/controllers/preferences-controller-test.js index 558597ae7..81b152f3d 100644 --- a/test/unit/app/controllers/preferences-controller-test.js +++ b/test/unit/app/controllers/preferences-controller-test.js @@ -527,14 +527,14 @@ describe('preferences controller', function () { it('should add custom RPC url to state', function () { preferencesController.addToFrequentRpcList('rpc_url', 1) preferencesController.addToFrequentRpcList('http://localhost:8545', 1) - assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }]) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '', rpcPrefs: {} }]) preferencesController.addToFrequentRpcList('rpc_url', 1) - assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }]) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '', rpcPrefs: {} }]) }) it('should remove custom RPC url from state', function () { preferencesController.addToFrequentRpcList('rpc_url', 1) - assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }]) + assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '', rpcPrefs: {} }]) preferencesController.removeFromFrequentRpcList('other_rpc_url') preferencesController.removeFromFrequentRpcList('http://localhost:8545') preferencesController.removeFromFrequentRpcList('rpc_url') diff --git a/ui/app/components/app/dropdowns/account-details-dropdown.js b/ui/app/components/app/dropdowns/account-details-dropdown.js index 3d4598946..cbeccdd81 100644 --- a/ui/app/components/app/dropdowns/account-details-dropdown.js +++ b/ui/app/components/app/dropdowns/account-details-dropdown.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') -const { getSelectedIdentity } = require('../../../selectors/selectors') +const { getSelectedIdentity, getRpcPrefsForCurrentProvider } = require('../../../selectors/selectors') const genAccountLink = require('../../../../lib/account-link.js') const { Menu, Item, CloseArea } = require('./components/menu') @@ -20,6 +20,7 @@ function mapStateToProps (state) { selectedIdentity: getSelectedIdentity(state), network: state.metamask.network, keyrings: state.metamask.keyrings, + rpcPrefs: getRpcPrefsForCurrentProvider(state), } } @@ -28,8 +29,8 @@ function mapDispatchToProps (dispatch) { showAccountDetailModal: () => { dispatch(actions.showModal({ name: 'ACCOUNT_DETAILS' })) }, - viewOnEtherscan: (address, network) => { - global.platform.openWindow({ url: genAccountLink(address, network) }) + viewOnEtherscan: (address, network, rpcPrefs) => { + global.platform.openWindow({ url: genAccountLink(address, network, rpcPrefs) }) }, showRemoveAccountConfirmationModal: (identity) => { return dispatch(actions.showModal({ name: 'CONFIRM_REMOVE_ACCOUNT', identity })) @@ -56,7 +57,9 @@ AccountDetailsDropdown.prototype.render = function () { keyrings, showAccountDetailModal, viewOnEtherscan, - showRemoveAccountConfirmationModal } = this.props + showRemoveAccountConfirmationModal, + rpcPrefs, + } = this.props const address = selectedIdentity.address @@ -112,10 +115,12 @@ AccountDetailsDropdown.prototype.render = function () { name: 'Clicked View on Etherscan', }, }) - viewOnEtherscan(address, network) + viewOnEtherscan(address, network, rpcPrefs) this.props.onClose() }, - text: this.context.t('viewOnEtherscan'), + text: (rpcPrefs.blockExplorerUrl + ? this.context.t('blockExplorerView', [rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1]]) + : this.context.t('viewOnEtherscan')), icon: h(`img`, { src: 'images/open-etherscan.svg', style: { height: '15px' } }), }), isRemovable ? h(Item, { diff --git a/ui/app/components/app/dropdowns/network-dropdown.js b/ui/app/components/app/dropdowns/network-dropdown.js index dbe3f1bc8..378ad3ba6 100644 --- a/ui/app/components/app/dropdowns/network-dropdown.js +++ b/ui/app/components/app/dropdowns/network-dropdown.js @@ -10,7 +10,7 @@ const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') const R = require('ramda') -const { ADVANCED_ROUTE } = require('../../../helpers/constants/routes') +const { NETWORKS_ROUTE } = require('../../../helpers/constants/routes') // classes from nodes of the toggle element. const notToggleElementClassnames = [ @@ -49,6 +49,7 @@ function mapDispatchToProps (dispatch) { }, showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()), hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()), + setNetworksTabAddMode: isInAddMode => dispatch(actions.setNetworksTabAddMode(isInAddMode)), } } @@ -72,7 +73,7 @@ module.exports = compose( // TODO: specify default props and proptypes NetworkDropdown.prototype.render = function () { const props = this.props - const { provider: { type: providerType, rpcTarget: activeNetwork } } = props + const { provider: { type: providerType, rpcTarget: activeNetwork }, setNetworksTabAddMode } = props const rpcListDetail = props.frequentRpcListDetail const isOpen = this.props.networkDropdownOpen const dropdownMenuItemStyle = { @@ -255,7 +256,10 @@ NetworkDropdown.prototype.render = function () { DropdownMenuItem, { closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => this.props.history.push(ADVANCED_ROUTE), + onClick: () => { + setNetworksTabAddMode(true) + this.props.history.push(NETWORKS_ROUTE) + }, style: dropdownMenuItemStyle, }, [ diff --git a/ui/app/components/app/modals/account-details-modal.js b/ui/app/components/app/modals/account-details-modal.js index 1b1ca6b8e..6cffc918b 100644 --- a/ui/app/components/app/modals/account-details-modal.js +++ b/ui/app/components/app/modals/account-details-modal.js @@ -5,7 +5,7 @@ const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../../store/actions') const AccountModalContainer = require('./account-modal-container') -const { getSelectedIdentity } = require('../../../selectors/selectors') +const { getSelectedIdentity, getRpcPrefsForCurrentProvider } = require('../../../selectors/selectors') const genAccountLink = require('../../../../lib/account-link.js') const QrView = require('../../ui/qr-code') const EditableLabel = require('../../ui/editable-label') @@ -17,6 +17,7 @@ function mapStateToProps (state) { network: state.metamask.network, selectedIdentity: getSelectedIdentity(state), keyrings: state.metamask.keyrings, + rpcPrefs: getRpcPrefsForCurrentProvider(state), } } @@ -54,6 +55,7 @@ AccountDetailsModal.prototype.render = function () { showExportPrivateKeyModal, setAccountLabel, keyrings, + rpcPrefs, } = this.props const { name, address } = selectedIdentity @@ -86,8 +88,12 @@ AccountDetailsModal.prototype.render = function () { h(Button, { type: 'secondary', className: 'account-modal__button', - onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, this.context.t('etherscanView')), + onClick: () => { + global.platform.openWindow({ url: genAccountLink(address, network, rpcPrefs) }) + }, + }, (rpcPrefs.blockExplorerUrl + ? this.context.t('blockExplorerView', [rpcPrefs.blockExplorerUrl.match(/^https?:\/\/(.+)/)[1]]) + : this.context.t('viewOnEtherscan'))), // Holding on redesign for Export Private Key functionality diff --git a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 4a3b04998..72ca784e2 100644 --- a/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/app/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -1,13 +1,15 @@ import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import copyToClipboard from 'copy-to-clipboard' +import { + getBlockExplorerUrlForTx, +} from '../../../helpers/utils/transactions.util' import SenderToRecipient from '../../ui/sender-to-recipient' import { FLAT_VARIANT } from '../../ui/sender-to-recipient/sender-to-recipient.constants' import TransactionActivityLog from '../transaction-activity-log' import TransactionBreakdown from '../transaction-breakdown' import Button from '../../ui/button' import Tooltip from '../../ui/tooltip' -import prefixForNetwork from '../../../../lib/etherscan-prefix-for-network' export default class TransactionListItemDetails extends PureComponent { static contextTypes = { @@ -22,6 +24,7 @@ export default class TransactionListItemDetails extends PureComponent { showRetry: PropTypes.bool, cancelDisabled: PropTypes.bool, transactionGroup: PropTypes.object, + rpcPrefs: PropTypes.object, } state = { @@ -30,12 +33,9 @@ export default class TransactionListItemDetails extends PureComponent { } handleEtherscanClick = () => { - const { transactionGroup: { primaryTransaction } } = this.props + const { transactionGroup: { primaryTransaction }, rpcPrefs } = this.props const { hash, metamaskNetworkId } = primaryTransaction - const prefix = prefixForNetwork(metamaskNetworkId) - const etherscanUrl = `https://${prefix}etherscan.io/tx/${hash}` - this.context.metricsEvent({ eventOpts: { category: 'Navigation', @@ -44,7 +44,7 @@ export default class TransactionListItemDetails extends PureComponent { }, }) - global.platform.openWindow({ url: etherscanUrl }) + global.platform.openWindow({ url: getBlockExplorerUrlForTx(metamaskNetworkId, hash, rpcPrefs) }) } handleCancel = event => { @@ -125,6 +125,7 @@ export default class TransactionListItemDetails extends PureComponent { showRetry, onCancel, onRetry, + rpcPrefs: { blockExplorerUrl } = {}, } = this.props const { primaryTransaction: transaction } = transactionGroup const { txParams: { to, from } = {} } = transaction @@ -158,7 +159,7 @@ export default class TransactionListItemDetails extends PureComponent { /> - + + + + ) + } + + renderNetworkListItem (network, selectRpcUrl) { + const { + setSelectedSettingsRpcUrl, + setNetworksTabAddMode, + networkIsSelected, + providerUrl, + providerType, + networksTabIsInAddMode, + } = this.props + const { + border, + iconColor, + label, + labelKey, + rpcUrl, + providerType: currentProviderType, + } = network + + const listItemNetworkIsSelected = selectRpcUrl && selectRpcUrl === rpcUrl + const listItemUrlIsProviderUrl = rpcUrl === providerUrl + const listItemTypeIsProviderNonRpcType = providerType !== 'rpc' && currentProviderType === providerType + const listItemNetworkIsCurrentProvider = !networkIsSelected && !networksTabIsInAddMode && (listItemUrlIsProviderUrl || listItemTypeIsProviderNonRpcType) + const displayNetworkListItemAsSelected = listItemNetworkIsSelected || listItemNetworkIsCurrentProvider + + return ( +
{ + setNetworksTabAddMode(false) + setSelectedSettingsRpcUrl(rpcUrl) + }} + > + +
+ { label || this.context.t(labelKey) } +
+
+
+ ) + } + + renderNetworksList () { + const { networksToRender, selectedNetwork, networkIsSelected, networksTabIsInAddMode, networkDefaultedToProvider } = this.props + + return ( +
+ { networksToRender.map(network => this.renderNetworkListItem(network, selectedNetwork.rpcUrl)) } +
+ ) + } + + renderNetworksTabContent () { + const { + setRpcTarget, + setSelectedSettingsRpcUrl, + setNetworksTabAddMode, + selectedNetwork: { + labelKey, + label, + rpcUrl, + chainId, + ticker, + viewOnly, + rpcPrefs, + blockExplorerUrl, + }, + networksTabIsInAddMode, + editRpc, + networkDefaultedToProvider, + } = this.props + const envIsPopup = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP + + return ( +
+ {this.renderNetworksList()} + {networksTabIsInAddMode || !envIsPopup || (envIsPopup && !networkDefaultedToProvider) + ? { + setNetworksTabAddMode(false) + setSelectedSettingsRpcUrl(null) + }} + viewOnly={viewOnly} + networksTabIsInAddMode={networksTabIsInAddMode} + rpcPrefs={rpcPrefs} + blockExplorerUrl={blockExplorerUrl} + /> + : null + } +
+ ) + } + + renderContent () { + const { setNetworksTabAddMode, setSelectedSettingsRpcUrl, networkIsSelected, networksTabIsInAddMode } = this.props + + return ( +
+ {this.renderSubHeader()} + {this.renderNetworksTabContent()} + {!networkIsSelected && !networksTabIsInAddMode + ?
+ +
+ : null + } +
+ ) + } + + render () { + return this.renderContent() + } +} diff --git a/ui/app/pages/settings/networks-tab/networks-tab.constants.js b/ui/app/pages/settings/networks-tab/networks-tab.constants.js new file mode 100644 index 000000000..d3d1a01cc --- /dev/null +++ b/ui/app/pages/settings/networks-tab/networks-tab.constants.js @@ -0,0 +1,50 @@ +const defaultNetworksData = [ + { + labelKey: 'mainnet', + iconColor: '#29B6AF', + providerType: 'mainnet', + rpcUrl: 'https://api.infura.io/v1/jsonrpc/mainnet', + chainId: '1', + ticker: 'ETH', + blockExplorerUrl: 'https://etherscan.io', + }, + { + labelKey: 'ropsten', + iconColor: '#FF4A8D', + providerType: 'ropsten', + rpcUrl: 'https://api.infura.io/v1/jsonrpc/ropsten', + chainId: '3', + ticker: 'ETH', + blockExplorerUrl: 'https://ropsten.etherscan.io', + }, + { + labelKey: 'kovan', + iconColor: '#9064FF', + providerType: 'kovan', + rpcUrl: 'https://api.infura.io/v1/jsonrpc/kovan', + chainId: '4', + ticker: 'ETH', + blockExplorerUrl: 'https://etherscan.io', + }, + { + labelKey: 'rinkeby', + iconColor: '#F6C343', + providerType: 'rinkeby', + rpcUrl: 'https://api.infura.io/v1/jsonrpc/rinkeby', + chainId: '42', + ticker: 'ETH', + blockExplorerUrl: 'https://rinkeby.etherscan.io', + }, + { + labelKey: 'localhost', + iconColor: 'white', + border: '1px solid #6A737D', + providerType: 'localhost', + rpcUrl: 'http://localhost:8545/', + blockExplorerUrl: 'https://etherscan.io', + }, +] + +export { + defaultNetworksData, +} diff --git a/ui/app/pages/settings/networks-tab/networks-tab.container.js b/ui/app/pages/settings/networks-tab/networks-tab.container.js new file mode 100644 index 000000000..a5d71f714 --- /dev/null +++ b/ui/app/pages/settings/networks-tab/networks-tab.container.js @@ -0,0 +1,77 @@ +import NetworksTab from './networks-tab.component' +import { compose } from 'recompose' +import { connect } from 'react-redux' +import { withRouter } from 'react-router-dom' +import { + setSelectedSettingsRpcUrl, + updateAndSetCustomRpc, + displayWarning, + setNetworksTabAddMode, + editRpc, +} from '../../../store/actions' +import { defaultNetworksData } from './networks-tab.constants' +const defaultNetworks = defaultNetworksData.map(network => ({ ...network, viewOnly: true })) + +const mapStateToProps = state => { + const { + frequentRpcListDetail, + provider, + } = state.metamask + const { + networksTabSelectedRpcUrl, + networksTabIsInAddMode, + } = state.appState + + const frequentRpcNetworkListDetails = frequentRpcListDetail.map(rpc => { + return { + label: rpc.nickname, + iconColor: '#6A737D', + providerType: 'rpc', + rpcUrl: rpc.rpcUrl, + chainId: rpc.chainId, + ticker: rpc.ticker, + blockExplorerUrl: rpc.rpcPrefs && rpc.rpcPrefs.blockExplorerUrl || '', + } + }) + + const networksToRender = [ ...defaultNetworks, ...frequentRpcNetworkListDetails ] + let selectedNetwork = networksToRender.find(network => network.rpcUrl === networksTabSelectedRpcUrl) || {} + const networkIsSelected = Boolean(selectedNetwork.rpcUrl) + + let networkDefaultedToProvider = false + if (!networkIsSelected && !networksTabIsInAddMode) { + selectedNetwork = networksToRender.find(network => { + return network.rpcUrl === provider.rpcTarget || network.providerType !== 'rpc' && network.providerType === provider.type + }) || {} + networkDefaultedToProvider = true + } + + return { + selectedNetwork, + networksToRender, + networkIsSelected, + networksTabIsInAddMode, + providerType: provider.type, + providerUrl: provider.rpcTarget, + networkDefaultedToProvider, + } +} + +const mapDispatchToProps = dispatch => { + return { + setSelectedSettingsRpcUrl: newRpcUrl => dispatch(setSelectedSettingsRpcUrl(newRpcUrl)), + setRpcTarget: (newRpc, chainId, ticker, nickname, rpcPrefs) => { + dispatch(updateAndSetCustomRpc(newRpc, chainId, ticker, nickname, rpcPrefs)) + }, + displayWarning: warning => dispatch(displayWarning(warning)), + setNetworksTabAddMode: isInAddMode => dispatch(setNetworksTabAddMode(isInAddMode)), + editRpc: (oldRpc, newRpc, chainId, ticker, nickname, rpcPrefs) => { + dispatch(editRpc(oldRpc, newRpc, chainId, ticker, nickname, rpcPrefs)) + }, + } +} + +export default compose( + withRouter, + connect(mapStateToProps, mapDispatchToProps) +)(NetworksTab) diff --git a/ui/app/pages/settings/settings.component.js b/ui/app/pages/settings/settings.component.js index fe799a6e8..a2f137264 100644 --- a/ui/app/pages/settings/settings.component.js +++ b/ui/app/pages/settings/settings.component.js @@ -6,6 +6,7 @@ import { getEnvironmentType } from '../../../../app/scripts/lib/util' import TabBar from '../../components/app/tab-bar' import c from 'classnames' import SettingsTab from './settings-tab' +import NetworksTab from './networks-tab' import AdvancedTab from './advanced-tab' import InfoTab from './info-tab' import SecurityTab from './security-tab' @@ -16,6 +17,7 @@ import { GENERAL_ROUTE, ABOUT_US_ROUTE, SETTINGS_ROUTE, + NETWORKS_ROUTE, } from '../../helpers/constants/routes' const ROUTES_TO_I18N_KEYS = { @@ -55,7 +57,7 @@ class SettingsPage extends PureComponent { >
{ - !this.isCurrentPath(SETTINGS_ROUTE) && ( + !this.isCurrentPath(SETTINGS_ROUTE) && !this.isCurrentPath(NETWORKS_ROUTE) && (
history.push(SETTINGS_ROUTE)} @@ -104,6 +106,7 @@ class SettingsPage extends PureComponent { { content: t('general'), description: t('generalSettingsDescription'), key: GENERAL_ROUTE }, { content: t('advanced'), description: t('advancedSettingsDescription'), key: ADVANCED_ROUTE }, { content: t('securityAndPrivacy'), description: t('securitySettingsDescription'), key: SECURITY_ROUTE }, + { content: t('networks'), description: t('networkSettingsDescription'), key: NETWORKS_ROUTE }, { content: t('about'), description: t('aboutSettingsDescription'), key: ABOUT_US_ROUTE }, ]} isActive={key => { @@ -135,6 +138,11 @@ class SettingsPage extends PureComponent { path={ADVANCED_ROUTE} component={AdvancedTab} /> + rpcInfo.rpcUrl === provider.rpcTarget) + const { rpcPrefs = {} } = selectRpcInfo || {} + return rpcPrefs +} diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 95c6dbb77..7d45f0932 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -239,6 +239,7 @@ var actions = { updateAndSetCustomRpc: updateAndSetCustomRpc, setRpcTarget: setRpcTarget, delRpcTarget: delRpcTarget, + editRpc: editRpc, setProviderType: setProviderType, SET_HARDWARE_WALLET_DEFAULT_HD_PATH: 'SET_HARDWARE_WALLET_DEFAULT_HD_PATH', setHardwareWalletDefaultHdPath, @@ -350,6 +351,11 @@ var actions = { setFirstTimeFlowType, SET_FIRST_TIME_FLOW_TYPE: 'SET_FIRST_TIME_FLOW_TYPE', + + SET_SELECTED_SETTINGS_RPC_URL: 'SET_SELECTED_SETTINGS_RPC_URL', + setSelectedSettingsRpcUrl, + SET_NETWORKS_TAB_ADD_MODE: 'SET_NETWORKS_TAB_ADD_MODE', + setNetworksTabAddMode, } module.exports = actions @@ -1958,10 +1964,10 @@ function setPreviousProvider (type) { } } -function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname) { +function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname, rpcPrefs) { return (dispatch) => { log.debug(`background.updateAndSetCustomRpc: ${newRpc} ${chainId} ${ticker} ${nickname}`) - background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err) => { + background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, rpcPrefs, (err) => { if (err) { log.error(err) return dispatch(actions.displayWarning('Had a problem changing networks!')) @@ -1974,6 +1980,29 @@ function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname) { } } +function editRpc (oldRpc, newRpc, chainId, ticker = 'ETH', nickname, rpcPrefs) { + return (dispatch) => { + log.debug(`background.delRpcTarget: ${oldRpc}`) + background.delCustomRpc(oldRpc, (err) => { + if (err) { + log.error(err) + return dispatch(self.displayWarning('Had a problem removing network!')) + } + dispatch(actions.setSelectedToken()) + background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, rpcPrefs, (err) => { + if (err) { + log.error(err) + return dispatch(actions.displayWarning('Had a problem changing networks!')) + } + dispatch({ + type: actions.SET_RPC_TARGET, + value: newRpc, + }) + }) + }) + } +} + function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname) { return (dispatch) => { log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`) @@ -2000,6 +2029,7 @@ function delRpcTarget (oldRpc) { } } + // Calls the addressBookController to add a new address. function addToAddressBook (recipient, nickname = '') { log.debug(`background.addToAddressBook`) @@ -2716,3 +2746,17 @@ function setFirstTimeFlowType (type) { }) } } + +function setSelectedSettingsRpcUrl (newRpcUrl) { + return { + type: actions.SET_SELECTED_SETTINGS_RPC_URL, + value: newRpcUrl, + } +} + +function setNetworksTabAddMode (isInAddMode) { + return { + type: actions.SET_NETWORKS_TAB_ADD_MODE, + value: isInAddMode, + } +} diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index 3eaa7cf71..f1428ba92 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -1,4 +1,8 @@ -module.exports = function (address, network) { +module.exports = function (address, network, rpcPrefs) { + if (rpcPrefs.blockExplorerUrl) { + return `${rpcPrefs.blockExplorerUrl}/address/${address}` + } + const net = parseInt(network) let link switch (net) { From 0cdce533e2e9368b6aa9b37e85dd1f4cc33395aa Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Fri, 10 May 2019 11:54:53 -0230 Subject: [PATCH 64/87] Fix RPC URL message key casing (#6595) --- ui/app/pages/settings/advanced-tab/advanced-tab.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index 8d70cd2df..3d27fe349 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -51,7 +51,7 @@ export default class AdvancedTab extends PureComponent { this.setState({ newRpc: e.target.value })} onKeyPress={e => { From 25323c8e18b5f568737486bb2da4e8877df9a7b3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 10 May 2019 15:38:32 -0700 Subject: [PATCH 65/87] Version 6.5.0 RC1 --- CHANGELOG.md | 22 ++++++++++++++++++++++ app/manifest.json | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d62a32a25..7d2e4b06d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ ## Current Develop Branch +## 6.5.0 Fri May 10 2019 + +- [#6568](https://github.com/MetaMask/metamask-extension/pull/6568): feature: integrate gaba/PhishingController +- [#6595](https://github.com/MetaMask/metamask-extension/pull/6595): Fix RPC URL message key casing +- [#6490](https://github.com/MetaMask/metamask-extension/pull/6490): * Add networks tab to settings, with header. +- [#6583](https://github.com/MetaMask/metamask-extension/pull/6583): * eslint: Check for unused function arguments +- [#6567](https://github.com/MetaMask/metamask-extension/pull/6567): * Adds a transactionCategory to txMeta for use in UI +- [#6558](https://github.com/MetaMask/metamask-extension/pull/6558): * Add i18n strings +- [#6578](https://github.com/MetaMask/metamask-extension/pull/6578): * Remove KNOWN_ADDRESS_ERROR from error objects +- [#6581](https://github.com/MetaMask/metamask-extension/pull/6581): Bump eth-json-rpc-filters and eth-contract-metadata +- [#6577](https://github.com/MetaMask/metamask-extension/pull/6577): Fix integration tests: completedUiMigration state and fetch + ethquery mocking +- [#6575](https://github.com/MetaMask/metamask-extension/pull/6575): Fix nock usages in unit tests +- [#6557](https://github.com/MetaMask/metamask-extension/pull/6557): * Add basic drag and drop functionality to seed phrase entry. +- [#6543](https://github.com/MetaMask/metamask-extension/pull/6543): * i18n: Don't translate null or undefined key +- [#6565](https://github.com/MetaMask/metamask-extension/pull/6565): Adds NPM scripts for running a dapp, and dapp + chain, locally. +- [#6546](https://github.com/MetaMask/metamask-extension/pull/6546): Add suffix to title text only when it exists +- [#6410](https://github.com/MetaMask/metamask-extension/pull/6410): * Ensure home screen does not render if there are unapproved txs (#6501) +- [#6526](https://github.com/MetaMask/metamask-extension/pull/6526): Include token checksum address in prices lookup for token rates +- [#6500](https://github.com/MetaMask/metamask-extension/pull/6500): * Send metrics event from backend for on chain transaction failures +- [#6502](https://github.com/MetaMask/metamask-extension/pull/6502): * Add subheader to all settings subviews +- [#6501](https://github.com/MetaMask/metamask-extension/pull/6501): * Ensure that the confirm screen renders before the home screen if there are unapproved txs. + ## 6.4.1 Fri Apr 26 2019 - [#6521](https://github.com/MetaMask/metamask-extension/pull/6521): Revert "Adds 4byte registry fallback to getMethodData()" to fix stalling bug. diff --git a/app/manifest.json b/app/manifest.json index bd10f60da..1d194a154 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "6.4.1", + "version": "6.5.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 28c4001f5269eb170f14bd2829698ee402b2cfbf Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 13 May 2019 13:46:09 -0230 Subject: [PATCH 66/87] Update auto-logout to recognize idle time in background (#6593) * Fix wording of autoLogoutTimeLimitDescription * AppStateController and update auto-logout functionality --- app/_locales/en/messages.json | 2 +- app/scripts/controllers/app-state.js | 73 ++++++++++++++++++++++++++++ app/scripts/metamask-controller.js | 12 +++++ ui/app/pages/routes/index.js | 17 ++----- ui/app/store/actions.js | 14 ++++++ 5 files changed, 105 insertions(+), 13 deletions(-) create mode 100644 app/scripts/controllers/app-state.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 254bfdfb9..bef278f79 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -161,7 +161,7 @@ "message": "Auto-Logout Timer (minutes)" }, "autoLogoutTimeLimitDescription": { - "message": "Set the number of idle time in minutes before Metamask automatically log out" + "message": "Set the idle time in minutes before MetaMask will automatically log out" }, "available": { "message": "Available" diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js new file mode 100644 index 000000000..9533fd458 --- /dev/null +++ b/app/scripts/controllers/app-state.js @@ -0,0 +1,73 @@ +const ObservableStore = require('obs-store') +const extend = require('xtend') + +class AppStateController { + /** + * @constructor + * @param opts + */ + constructor (opts = {}) { + const {initState, onInactiveTimeout, preferencesStore} = opts + const {preferences} = preferencesStore.getState() + + this.onInactiveTimeout = onInactiveTimeout || (() => {}) + this.store = new ObservableStore(extend({ + timeoutMinutes: 0, + }, initState)) + this.timer = null + + preferencesStore.subscribe(state => { + this._setInactiveTimeout(state.preferences.autoLogoutTimeLimit) + }) + + this._setInactiveTimeout(preferences.autoLogoutTimeLimit) + } + + /** + * Sets the last active time to the current time + * @return {void} + */ + setLastActiveTime () { + this._resetTimer() + } + + /** + * Sets the inactive timeout for the app + * @param {number} timeoutMinutes the inactive timeout in minutes + * @return {void} + * @private + */ + _setInactiveTimeout (timeoutMinutes) { + this.store.putState({ + timeoutMinutes, + }) + + this._resetTimer() + } + + /** + * Resets the internal inactive timer + * + * If the {@code timeoutMinutes} state is falsy (i.e., zero) then a new + * timer will not be created. + * + * @return {void} + * @private + */ + _resetTimer () { + const {timeoutMinutes} = this.store.getState() + + if (this.timer) { + clearTimeout(this.timer) + } + + if (!timeoutMinutes) { + return + } + + this.timer = setTimeout(() => this.onInactiveTimeout(), timeoutMinutes * 60 * 1000) + } +} + +module.exports = AppStateController + diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bdfff9827..07054f84b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -25,6 +25,7 @@ const {setupMultiplex} = require('./lib/stream-utils.js') const KeyringController = require('eth-keyring-controller') const NetworkController = require('./controllers/network') const PreferencesController = require('./controllers/preferences') +const AppStateController = require('./controllers/app-state') const CurrencyController = require('./controllers/currency') const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') @@ -101,6 +102,12 @@ module.exports = class MetamaskController extends EventEmitter { network: this.networkController, }) + // app-state controller + this.appStateController = new AppStateController({ + preferencesStore: this.preferencesController.store, + onInactiveTimeout: () => this.setLocked(), + }) + // currency controller this.currencyController = new CurrencyController({ initState: initState.CurrencyController, @@ -252,6 +259,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.store.updateStructure({ + AppStateController: this.appStateController.store, TransactionController: this.txController.store, KeyringController: this.keyringController.store, PreferencesController: this.preferencesController.store, @@ -264,6 +272,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.memStore = new ComposableObservableStore(null, { + AppStateController: this.appStateController.store, NetworkController: this.networkController.store, AccountTracker: this.accountTracker.store, TxController: this.txController.memStore, @@ -462,6 +471,9 @@ module.exports = class MetamaskController extends EventEmitter { // AddressController setAddressBook: this.addressBookController.set.bind(this.addressBookController), + // AppStateController + setLastActiveTime: nodeify(this.appStateController.setLastActiveTime, this.appStateController), + // KeyringController setLocked: nodeify(this.setLocked, this), createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), diff --git a/ui/app/pages/routes/index.js b/ui/app/pages/routes/index.js index 9c30da086..9eeac2da2 100644 --- a/ui/app/pages/routes/index.js +++ b/ui/app/pages/routes/index.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import { connect } from 'react-redux' import { Route, Switch, withRouter, matchPath } from 'react-router-dom' import { compose } from 'recompose' -import actions, {hideSidebar, hideWarning, lockMetamask} from '../../store/actions' +import actions from '../../store/actions' import log from 'loglevel' import IdleTimer from 'react-idle-timer' import {getMetaMaskAccounts, getNetworkIdentifier, preferencesSelector} from '../../selectors/selectors' @@ -99,7 +99,7 @@ class Routes extends Component { } renderRoutes () { - const { autoLogoutTimeLimit, lockMetamask } = this.props + const { autoLogoutTimeLimit, setLastActiveTime } = this.props const routes = ( @@ -122,10 +122,7 @@ class Routes extends Component { if (autoLogoutTimeLimit > 0) { return ( - + {routes} ) @@ -338,7 +335,7 @@ Routes.propTypes = { networkDropdownOpen: PropTypes.bool, showNetworkDropdown: PropTypes.func, hideNetworkDropdown: PropTypes.func, - lockMetamask: PropTypes.func, + setLastActiveTime: PropTypes.func, history: PropTypes.object, location: PropTypes.object, dispatch: PropTypes.func, @@ -447,11 +444,7 @@ function mapDispatchToProps (dispatch) { setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('usd')), toggleAccountMenu: () => dispatch(actions.toggleAccountMenu()), setMouseUserState: (isMouseUser) => dispatch(actions.setMouseUserState(isMouseUser)), - lockMetamask: () => { - dispatch(lockMetamask()) - dispatch(hideWarning()) - dispatch(hideSidebar()) - }, + setLastActiveTime: () => dispatch(actions.setLastActiveTime()), } } diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 7d45f0932..7f6cbea1f 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -356,6 +356,10 @@ var actions = { setSelectedSettingsRpcUrl, SET_NETWORKS_TAB_ADD_MODE: 'SET_NETWORKS_TAB_ADD_MODE', setNetworksTabAddMode, + + // AppStateController-related actions + SET_LAST_ACTIVE_TIME: 'SET_LAST_ACTIVE_TIME', + setLastActiveTime, } module.exports = actions @@ -2760,3 +2764,13 @@ function setNetworksTabAddMode (isInAddMode) { value: isInAddMode, } } + +function setLastActiveTime () { + return (dispatch) => { + background.setLastActiveTime((err) => { + if (err) { + return dispatch(actions.displayWarning(err.message)) + } + }) + } +} From 55764b71bb850d53fc339dba32454ad28a616e43 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Mon, 13 May 2019 13:51:19 -0230 Subject: [PATCH 67/87] Improve changelog for 6.5.0 --- CHANGELOG.md | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d2e4b06d..46cb9e063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,24 +5,13 @@ ## 6.5.0 Fri May 10 2019 - [#6568](https://github.com/MetaMask/metamask-extension/pull/6568): feature: integrate gaba/PhishingController -- [#6595](https://github.com/MetaMask/metamask-extension/pull/6595): Fix RPC URL message key casing -- [#6490](https://github.com/MetaMask/metamask-extension/pull/6490): * Add networks tab to settings, with header. -- [#6583](https://github.com/MetaMask/metamask-extension/pull/6583): * eslint: Check for unused function arguments -- [#6567](https://github.com/MetaMask/metamask-extension/pull/6567): * Adds a transactionCategory to txMeta for use in UI -- [#6558](https://github.com/MetaMask/metamask-extension/pull/6558): * Add i18n strings -- [#6578](https://github.com/MetaMask/metamask-extension/pull/6578): * Remove KNOWN_ADDRESS_ERROR from error objects -- [#6581](https://github.com/MetaMask/metamask-extension/pull/6581): Bump eth-json-rpc-filters and eth-contract-metadata -- [#6577](https://github.com/MetaMask/metamask-extension/pull/6577): Fix integration tests: completedUiMigration state and fetch + ethquery mocking -- [#6575](https://github.com/MetaMask/metamask-extension/pull/6575): Fix nock usages in unit tests -- [#6557](https://github.com/MetaMask/metamask-extension/pull/6557): * Add basic drag and drop functionality to seed phrase entry. -- [#6543](https://github.com/MetaMask/metamask-extension/pull/6543): * i18n: Don't translate null or undefined key -- [#6565](https://github.com/MetaMask/metamask-extension/pull/6565): Adds NPM scripts for running a dapp, and dapp + chain, locally. -- [#6546](https://github.com/MetaMask/metamask-extension/pull/6546): Add suffix to title text only when it exists -- [#6410](https://github.com/MetaMask/metamask-extension/pull/6410): * Ensure home screen does not render if there are unapproved txs (#6501) +- [#6490](https://github.com/MetaMask/metamask-extension/pull/6490): Redesign custom RPC form +- [#6558](https://github.com/MetaMask/metamask-extension/pull/6558): Adds auto logout with customizable time frame +- [#6578](https://github.com/MetaMask/metamask-extension/pull/6578): Fixes ability to send to token contract addresses +- [#6557](https://github.com/MetaMask/metamask-extension/pull/6557): Adds drag and drop functionality to seed phrase entry. - [#6526](https://github.com/MetaMask/metamask-extension/pull/6526): Include token checksum address in prices lookup for token rates -- [#6500](https://github.com/MetaMask/metamask-extension/pull/6500): * Send metrics event from backend for on chain transaction failures -- [#6502](https://github.com/MetaMask/metamask-extension/pull/6502): * Add subheader to all settings subviews -- [#6501](https://github.com/MetaMask/metamask-extension/pull/6501): * Ensure that the confirm screen renders before the home screen if there are unapproved txs. +- [#6502](https://github.com/MetaMask/metamask-extension/pull/6502): Add subheader to all settings subviews +- [#6501](https://github.com/MetaMask/metamask-extension/pull/6501): Improve confirm screen loading performance by fixing home screen rendering bug ## 6.4.1 Fri Apr 26 2019 @@ -30,7 +19,7 @@ ## 6.4.0 Wed Apr 17 2019 -- [#6445](https://github.com/MetaMask/metamask-extension/pull/6445): * Move send to pages/ +- [#6445](https://github.com/MetaMask/metamask-extension/pull/6445): * Move send to pages/ - [#6470](https://github.com/MetaMask/metamask-extension/pull/6470): update publishing.md with dev diagram - [#6403](https://github.com/MetaMask/metamask-extension/pull/6403): Update to eth-method-registry@1.2.0 - [#6468](https://github.com/MetaMask/metamask-extension/pull/6468): Fix switcher height when Custom RPC is selected or loading From b81c4e5c98cdf3f5e6ebb05e57c2be993cdf5da0 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Tue, 14 May 2019 15:44:07 -0230 Subject: [PATCH 68/87] Set a default value for code in _determineTransactionCategory (#6604) * Set a default value for code in _determineTransactionCategory * Adds e2e tests that fail when token txs without gas param are not properly handled. * Adds unit tests for _determineTransactionCategory * Base error throwing and simple gas setting in estimateTxGas on transactionCategory --- app/scripts/controllers/transactions/index.js | 11 +- .../controllers/transactions/tx-gas-utils.js | 15 +- test/e2e/beta/contract-test/contract.js | 25 +++ test/e2e/beta/contract-test/index.html | 2 + test/e2e/beta/metamask-beta-ui.spec.js | 164 ++++++++++++++++-- .../transactions/tx-controller-test.js | 87 ++++++++++ 6 files changed, 274 insertions(+), 30 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index dc6a043e4..79dba7833 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -191,7 +191,7 @@ class TransactionController extends EventEmitter { } txUtils.validateTxParams(normalizedTxParams) // construct txMeta - const { transactionCategory, code } = await this._determineTransactionCategory(txParams) + const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams) let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams, type: TRANSACTION_TYPE_STANDARD, @@ -204,7 +204,7 @@ class TransactionController extends EventEmitter { // check whether recipient account is blacklisted recipientBlacklistChecker.checkAccount(txMeta.metamaskNetworkId, normalizedTxParams.to) // add default tx params - txMeta = await this.addTxGasDefaults(txMeta, code) + txMeta = await this.addTxGasDefaults(txMeta, getCodeResponse) } catch (error) { log.warn(error) txMeta.loadingDefaults = false @@ -224,7 +224,7 @@ class TransactionController extends EventEmitter { @param txMeta {Object} - the txMeta object @returns {Promise} resolves with txMeta */ - async addTxGasDefaults (txMeta, code) { + async addTxGasDefaults (txMeta, getCodeResponse) { const txParams = txMeta.txParams // ensure value txParams.value = txParams.value ? ethUtil.addHexPrefix(txParams.value) : '0x0' @@ -235,7 +235,7 @@ class TransactionController extends EventEmitter { } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) // set gasLimit - return await this.txGasUtil.analyzeGasUsage(txMeta, code) + return await this.txGasUtil.analyzeGasUsage(txMeta, getCodeResponse) } /** @@ -593,6 +593,7 @@ class TransactionController extends EventEmitter { try { code = await this.query.getCode(to) } catch (e) { + code = null log.warn(e) } // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0' @@ -601,7 +602,7 @@ class TransactionController extends EventEmitter { result = codeIsEmpty ? SEND_ETHER_ACTION_KEY : CONTRACT_INTERACTION_KEY } - return { transactionCategory: result, code } + return { transactionCategory: result, getCodeResponse: code } } /** diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 2dc461f48..287fb6f44 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -6,6 +6,7 @@ const { } = require('../../lib/util') const log = require('loglevel') const { addHexPrefix } = require('ethereumjs-util') +const { SEND_ETHER_ACTION_KEY } = require('../../../../ui/app/helpers/constants/transactions.js') const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys' @@ -25,14 +26,13 @@ class TxGasUtil { /** @param txMeta {Object} - the txMeta object - @param code {string} - the code at the txs address, as returned by this.query.getCode(to) @returns {object} the txMeta object with the gas written to the txParams */ - async analyzeGasUsage (txMeta, code) { + async analyzeGasUsage (txMeta, getCodeResponse) { const block = await this.query.getBlockByNumber('latest', false) let estimatedGasHex try { - estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit, code) + estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit, getCodeResponse) } catch (err) { log.warn(err) txMeta.simulationFails = { @@ -55,10 +55,9 @@ class TxGasUtil { Estimates the tx's gas usage @param txMeta {Object} - the txMeta object @param blockGasLimitHex {string} - hex string of the block's gas limit - @param code {string} - the code at the txs address, as returned by this.query.getCode(to) @returns {string} the estimated gas limit as a hex string */ - async estimateTxGas (txMeta, blockGasLimitHex, code) { + async estimateTxGas (txMeta, blockGasLimitHex, getCodeResponse) { const txParams = txMeta.txParams // check if gasLimit is already specified @@ -75,9 +74,9 @@ class TxGasUtil { // see if we can set the gas based on the recipient if (hasRecipient) { // For an address with no code, geth will return '0x', and ganache-core v2.2.1 will return '0x0' - const codeIsEmpty = !code || code === '0x' || code === '0x0' + const categorizedAsSimple = txMeta.transactionCategory === SEND_ETHER_ACTION_KEY - if (codeIsEmpty) { + if (categorizedAsSimple) { // if there's data in the params, but there's no contract code, it's not a valid transaction if (txParams.data) { const err = new Error('TxGasUtil - Trying to call a function on a non-contract address') @@ -85,7 +84,7 @@ class TxGasUtil { err.errorKey = TRANSACTION_NO_CONTRACT_ERROR_KEY // set the response on the error so that we can see in logs what the actual response was - err.getCodeResponse = code + err.getCodeResponse = getCodeResponse throw err } diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js index e247e26ea..e1f886c58 100644 --- a/test/e2e/beta/contract-test/contract.js +++ b/test/e2e/beta/contract-test/contract.js @@ -37,6 +37,8 @@ web3.currentProvider.enable().then(() => { const createToken = document.getElementById('createToken') const transferTokens = document.getElementById('transferTokens') const approveTokens = document.getElementById('approveTokens') + const transferTokensWithoutGas = document.getElementById('transferTokensWithoutGas') + const approveTokensWithoutGas = document.getElementById('approveTokensWithoutGas') deployButton.addEventListener('click', async function () { document.getElementById('contractStatus').innerHTML = 'Deploying' @@ -135,6 +137,29 @@ web3.currentProvider.enable().then(() => { console.log(result) }) }) + + transferTokensWithoutGas.addEventListener('click', function (event) { + console.log(`event`, event) + contract.transfer('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + gasPrice: '20000000000', + }, function (result) { + console.log('result', result) + }) + }) + + approveTokensWithoutGas.addEventListener('click', function () { + contract.approve('0x2f318C334780961FB129D2a6c30D0763d9a5C970', '7', { + from: web3.eth.accounts[0], + to: contract.address, + data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + gasPrice: '20000000000', + }, function (result) { + console.log(result) + }) + }) } }) diff --git a/test/e2e/beta/contract-test/index.html b/test/e2e/beta/contract-test/index.html index 0d422ef20..6e134dc36 100644 --- a/test/e2e/beta/contract-test/index.html +++ b/test/e2e/beta/contract-test/index.html @@ -27,6 +27,8 @@ + + diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 7fb3de6e4..06778ab99 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -812,10 +812,31 @@ describe('MetaMask', function () { await delay(regularDelayMs) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.advanced-tab__gas-edit-row__input')) - await gasPriceInput.clear() + await gasPriceInput.sendKeys(Key.chord(Key.CONTROL, 'a')) + await delay(50) + + await gasPriceInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasPriceInput.sendKeys(Key.BACK_SPACE) + await delay(50) await gasPriceInput.sendKeys('10') - await gasLimitInput.clear() + await delay(50) + await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a')) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) await gasLimitInput.sendKeys('60001') + await delay(50) + await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e')) + await delay(50) const save = await findElement(driver, By.xpath(`//button[contains(text(), 'Save')]`)) await save.click() @@ -1175,7 +1196,7 @@ describe('MetaMask', function () { const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Approve Tokens')]`)) await transferTokens.click() - await closeAllWindowHandlesExcept(driver, extension) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) await driver.switchTo().window(extension) await delay(regularDelayMs) @@ -1228,21 +1249,31 @@ describe('MetaMask', function () { await delay(regularDelayMs) const [gasPriceInput, gasLimitInput] = await findElements(driver, By.css('.advanced-tab__gas-edit-row__input')) - await gasPriceInput.clear() - await delay(tinyDelayMs) - await gasPriceInput.sendKeys('10') - await delay(tinyDelayMs) - await gasLimitInput.clear() - await delay(tinyDelayMs) - await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a')) - await gasLimitInput.sendKeys('60000') - await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e')) + await gasPriceInput.sendKeys(Key.chord(Key.CONTROL, 'a')) + await delay(50) - // Needed for different behaviour of input in different versions of firefox - const gasLimitInputValue = await gasLimitInput.getAttribute('value') - if (gasLimitInputValue === '600001') { - await gasLimitInput.sendKeys(Key.BACK_SPACE) - } + await gasPriceInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasPriceInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasPriceInput.sendKeys('10') + await delay(50) + await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'a')) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys(Key.BACK_SPACE) + await delay(50) + await gasLimitInput.sendKeys('60001') + await delay(50) + await gasLimitInput.sendKeys(Key.chord(Key.CONTROL, 'e')) + await delay(50) const save = await findElement(driver, By.css('.page-container__footer-button')) await save.click() @@ -1271,6 +1302,105 @@ describe('MetaMask', function () { }) }) + describe('Tranfers a custom token from dapp when no gas value is specified', () => { + it('transfers an already created token, without specifying gas', async () => { + const windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await delay(regularDelayMs) + + await driver.switchTo().window(dapp) + + const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Transfer Tokens Without Gas')]`)) + await transferTokens.click() + + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await driver.switchTo().window(extension) + await delay(regularDelayMs) + + await driver.wait(async () => { + const pendingTxes = await findElements(driver, By.css('.transaction-list__pending-transactions .transaction-list-item')) + return pendingTxes.length === 1 + }, 10000) + + const [txListItem] = await findElements(driver, By.css('.transaction-list-item')) + const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/)) + await txListItem.click() + await delay(regularDelayMs) + }) + + it('submits the transaction', async function () { + await delay(regularDelayMs) + const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) + await confirmButton.click() + await delay(regularDelayMs) + }) + + it('finds the transaction in the transactions list', async function () { + await driver.wait(async () => { + const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) + return confirmedTxes.length === 4 + }, 10000) + + const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) + const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) + await driver.wait(until.elementTextMatches(txStatuses[0], /Sent Tokens/)) + }) + }) + + describe('Approves a custom token from dapp when no gas value is specified', () => { + it('approves an already created token', async () => { + const windowHandles = await driver.getAllWindowHandles() + const extension = windowHandles[0] + const dapp = await switchToWindowWithTitle(driver, 'E2E Test Dapp', windowHandles) + await closeAllWindowHandlesExcept(driver, [extension, dapp]) + await delay(regularDelayMs) + + await driver.switchTo().window(dapp) + await delay(tinyDelayMs) + + const transferTokens = await findElement(driver, By.xpath(`//button[contains(text(), 'Approve Tokens Without Gas')]`)) + await transferTokens.click() + + await closeAllWindowHandlesExcept(driver, extension) + await driver.switchTo().window(extension) + await delay(regularDelayMs) + + await driver.wait(async () => { + const pendingTxes = await findElements(driver, By.css('.transaction-list__pending-transactions .transaction-list-item')) + return pendingTxes.length === 1 + }, 10000) + + const [txListItem] = await findElements(driver, By.css('.transaction-list-item')) + const [txListValue] = await findElements(driver, By.css('.transaction-list-item__amount--primary')) + await driver.wait(until.elementTextMatches(txListValue, /-7\s*TST/)) + await txListItem.click() + await delay(regularDelayMs) + }) + + it('submits the transaction', async function () { + await delay(regularDelayMs) + const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) + await confirmButton.click() + await delay(regularDelayMs) + }) + + it('finds the transaction in the transactions list', async function () { + await driver.wait(async () => { + const confirmedTxes = await findElements(driver, By.css('.transaction-list__completed-transactions .transaction-list-item')) + return confirmedTxes.length === 5 + }, 10000) + + const txValues = await findElements(driver, By.css('.transaction-list-item__amount--primary')) + await driver.wait(until.elementTextMatches(txValues[0], /-7\s*TST/)) + const txStatuses = await findElements(driver, By.css('.transaction-list-item__action')) + await driver.wait(until.elementTextMatches(txStatuses[0], /Approve/)) + }) + }) + describe('Hide token', () => { it('hides the token when clicked', async () => { const [hideTokenEllipsis] = await findElements(driver, By.css('.token-list-item__ellipsis')) diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index 9000cd364..8ff409207 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -8,6 +8,13 @@ const TransactionController = require('../../../../../app/scripts/controllers/tr const { TRANSACTION_TYPE_RETRY, } = require('../../../../../app/scripts/controllers/transactions/enums') +const { + TOKEN_METHOD_APPROVE, + TOKEN_METHOD_TRANSFER, + SEND_ETHER_ACTION_KEY, + DEPLOY_CONTRACT_ACTION_KEY, + CONTRACT_INTERACTION_KEY, +} = require('../../../../../ui/app/helpers/constants/transactions.js') const { createTestProviderTools, getTestAccounts } = require('../../../../stub/provider') const noop = () => true @@ -537,6 +544,86 @@ describe('Transaction Controller', function () { }) }) + describe('#_determineTransactionCategory', function () { + it('should return a simple send transactionCategory when to is truthy but data is falsey', async function () { + const result = await txController._determineTransactionCategory({ + to: '0xabc', + data: '', + }) + assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: undefined }) + }) + + it('should return a token transfer transactionCategory when data is for the respective method call', async function () { + const result = await txController._determineTransactionCategory({ + to: '0xabc', + data: '0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a', + }) + assert.deepEqual(result, { transactionCategory: TOKEN_METHOD_TRANSFER, getCodeResponse: undefined }) + }) + + it('should return a token approve transactionCategory when data is for the respective method call', async function () { + const result = await txController._determineTransactionCategory({ + to: '0xabc', + data: '0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005', + }) + assert.deepEqual(result, { transactionCategory: TOKEN_METHOD_APPROVE, getCodeResponse: undefined }) + }) + + it('should return a contract deployment transactionCategory when to is falsey and there is data', async function () { + const result = await txController._determineTransactionCategory({ + to: '', + data: '0xabd', + }) + assert.deepEqual(result, { transactionCategory: DEPLOY_CONTRACT_ACTION_KEY, getCodeResponse: undefined }) + }) + + it('should return a simple send transactionCategory with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () { + const result = await txController._determineTransactionCategory({ + to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', + data: '0xabd', + }) + assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: '0x' }) + }) + + it('should return a simple send transactionCategory with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () { + const result = await txController._determineTransactionCategory({ + to: '0xabc', + data: '0xabd', + }) + assert.deepEqual(result, { transactionCategory: SEND_ETHER_ACTION_KEY, getCodeResponse: null }) + }) + + it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () { + const _providerResultStub = { + // 1 gwei + eth_gasPrice: '0x0de0b6b3a7640000', + // by default, all accounts are external accounts (not contracts) + eth_getCode: '0xa', + } + const _provider = createTestProviderTools({ scaffold: _providerResultStub }).provider + const _fromAccount = getTestAccounts()[0] + const _blockTrackerStub = new EventEmitter() + _blockTrackerStub.getCurrentBlock = noop + _blockTrackerStub.getLatestBlock = noop + const _txController = new TransactionController({ + provider: _provider, + getGasPrice: function () { return '0xee6b2800' }, + networkStore: new ObservableStore(currentNetworkId), + txHistoryLimit: 10, + blockTracker: _blockTrackerStub, + signTransaction: (ethTx) => new Promise((resolve) => { + ethTx.sign(_fromAccount.key) + resolve() + }), + }) + const result = await _txController._determineTransactionCategory({ + to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9', + data: 'abd', + }) + assert.deepEqual(result, { transactionCategory: CONTRACT_INTERACTION_KEY, getCodeResponse: '0x0a' }) + }) + }) + describe('#getPendingTransactions', function () { beforeEach(function () { txController.txStateManager._saveTxList([ From 3d715e5cf935ba0e2ced7caa8d8d0b26d3c983d4 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 14 May 2019 09:40:03 -0700 Subject: [PATCH 69/87] Version 6.5.1 RC1 --- CHANGELOG.md | 5 +++++ app/manifest.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46cb9e063..d3e333e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Current Develop Branch +## 6.5.1 Tue May 14 2019 + +- Fix bug where approve method would show a warning. #6602 +- [#6593](https://github.com/MetaMask/metamask-extension/pull/6593): Fix wording of autoLogoutTimeLimitDescription + ## 6.5.0 Fri May 10 2019 - [#6568](https://github.com/MetaMask/metamask-extension/pull/6568): feature: integrate gaba/PhishingController diff --git a/app/manifest.json b/app/manifest.json index 1d194a154..570e5b6cb 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "6.5.0", + "version": "6.5.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From e57ffbed593599cbf84d91144c7f208ee1298226 Mon Sep 17 00:00:00 2001 From: Paul Bouchon Date: Tue, 14 May 2019 14:38:55 -0400 Subject: [PATCH 70/87] feature: integrate gaba/ShapeShiftController (#6569) --- app/scripts/controllers/shapeshift.js | 180 ------------------ app/scripts/metamask-controller.js | 12 +- .../controllers/metamask-controller-test.js | 2 +- 3 files changed, 6 insertions(+), 188 deletions(-) delete mode 100644 app/scripts/controllers/shapeshift.js diff --git a/app/scripts/controllers/shapeshift.js b/app/scripts/controllers/shapeshift.js deleted file mode 100644 index 9b0287007..000000000 --- a/app/scripts/controllers/shapeshift.js +++ /dev/null @@ -1,180 +0,0 @@ -const ObservableStore = require('obs-store') -const extend = require('xtend') -const log = require('loglevel') - -// every three seconds when an incomplete tx is waiting -const POLLING_INTERVAL = 3000 - -class ShapeshiftController { - - /** - * Controller responsible for managing the list of shapeshift transactions. On construction, it initiates a poll - * that queries a shapeshift.io API for updates to any pending shapeshift transactions - * - * @typedef {Object} ShapeshiftController - * @param {object} opts Overrides the defaults for the initial state of this.store - * @property {array} opts.initState initializes the the state of the ShapeshiftController. Can contain an - * shapeShiftTxList array. - * @property {array} shapeShiftTxList An array of ShapeShiftTx objects - * - */ - constructor (opts = {}) { - const initState = extend({ - shapeShiftTxList: [], - }, opts.initState) - this.store = new ObservableStore(initState) - this.pollForUpdates() - } - - /** - * Represents, and contains data about, a single shapeshift transaction. - * @typedef {Object} ShapeShiftTx - * @property {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the - * user's Metamask account - * @property {string} depositType - An abbreviation of the type of crypto currency to be deposited. - * @property {string} key - The 'shapeshift' key differentiates this from other types of txs in Metamask - * @property {number} time - The time at which the tx was created - * @property {object} response - Initiated as an empty object, which will be replaced by a Response object. @see {@link - * https://developer.mozilla.org/en-US/docs/Web/API/Response} - */ - - // - // PUBLIC METHODS - // - - /** - * A getter for the shapeShiftTxList property - * - * @returns {array} - * - */ - getShapeShiftTxList () { - const shapeShiftTxList = this.store.getState().shapeShiftTxList - return shapeShiftTxList - } - - /** - * A getter for all ShapeShiftTx in the shapeShiftTxList that have not successfully completed a deposit. - * - * @returns {array} Only includes ShapeShiftTx which has a response property with a status !== complete - * - */ - getPendingTxs () { - const txs = this.getShapeShiftTxList() - const pending = txs.filter(tx => tx.response && tx.response.status !== 'complete') - return pending - } - - /** - * A poll that exists as long as there are pending transactions. Each call attempts to update the data of any - * pendingTxs, and then calls itself again. If there are no pending txs, the recursive call is not made and - * the polling stops. - * - * this.updateTx is used to attempt the update to the pendingTxs in the ShapeShiftTxList, and that updated data - * is saved with saveTx. - * - */ - pollForUpdates () { - const pendingTxs = this.getPendingTxs() - - if (pendingTxs.length === 0) { - return - } - - Promise.all(pendingTxs.map((tx) => { - return this.updateTx(tx) - })) - .then((results) => { - results.forEach(tx => this.saveTx(tx)) - this.timeout = setTimeout(this.pollForUpdates.bind(this), POLLING_INTERVAL) - }) - } - - /** - * Attempts to update a ShapeShiftTx with data from a shapeshift.io API. Both the response and time properties - * can be updated. The response property is updated with every call, but the time property is only updated when - * the response status updates to 'complete'. This will occur once the user makes a deposit as the ShapeShiftTx - * depositAddress - * - * @param {ShapeShiftTx} tx The tx to update - * - */ - async updateTx (tx) { - try { - const url = `https://shapeshift.io/txStat/${tx.depositAddress}` - const response = await fetch(url) - const json = await response.json() - tx.response = json - if (tx.response.status === 'complete') { - tx.time = new Date().getTime() - } - return tx - } catch (err) { - log.warn(err) - } - } - - /** - * Saves an updated to a ShapeShiftTx in the shapeShiftTxList. If the passed ShapeShiftTx is not in the - * shapeShiftTxList, nothing happens. - * - * @param {ShapeShiftTx} tx The updated tx to save, if it exists in the current shapeShiftTxList - * - */ - saveTx (tx) { - const { shapeShiftTxList } = this.store.getState() - const index = shapeShiftTxList.indexOf(tx) - if (index !== -1) { - shapeShiftTxList[index] = tx - this.store.updateState({ shapeShiftTxList }) - } - } - - /** - * Removes a ShapeShiftTx from the shapeShiftTxList - * - * @param {ShapeShiftTx} tx The tx to remove - * - */ - removeShapeShiftTx () { - const { shapeShiftTxList } = this.store.getState() - const index = shapeShiftTxList.indexOf(index) - if (index !== -1) { - shapeShiftTxList.splice(index, 1) - } - this.updateState({ shapeShiftTxList }) - } - - /** - * Creates a new ShapeShiftTx, adds it to the shapeShiftTxList, and initiates a new poll for updates of pending txs - * - * @param {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the - * user's Metamask account - * @param {string} depositType - An abbreviation of the type of crypto currency to be deposited. - * - */ - createShapeShiftTx (depositAddress, depositType) { - const state = this.store.getState() - let { shapeShiftTxList } = state - - var shapeShiftTx = { - depositAddress, - depositType, - key: 'shapeshift', - time: new Date().getTime(), - response: {}, - } - - if (!shapeShiftTxList) { - shapeShiftTxList = [shapeShiftTx] - } else { - shapeShiftTxList.push(shapeShiftTx) - } - - this.store.updateState({ shapeShiftTxList }) - this.pollForUpdates() - } - -} - -module.exports = ShapeshiftController diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 07054f84b..55ca96ad4 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -27,7 +27,6 @@ const NetworkController = require('./controllers/network') const PreferencesController = require('./controllers/preferences') const AppStateController = require('./controllers/app-state') const CurrencyController = require('./controllers/currency') -const ShapeShiftController = require('./controllers/shapeshift') const InfuraController = require('./controllers/infura') const CachedBalancesController = require('./controllers/cached-balances') const RecentBlocksController = require('./controllers/recent-blocks') @@ -57,6 +56,7 @@ const ethUtil = require('ethereumjs-util') const sigUtil = require('eth-sig-util') const { AddressBookController, + ShapeShiftController, PhishingController, } = require('gaba') const backEndMetaMetricsEvent = require('./lib/backend-metametrics') @@ -237,9 +237,7 @@ module.exports = class MetamaskController extends EventEmitter { }) this.balancesController.updateAllBalances() - this.shapeshiftController = new ShapeShiftController({ - initState: initState.ShapeShiftController, - }) + this.shapeshiftController = new ShapeShiftController(undefined, initState.ShapeShiftController) this.networkController.lookupNetwork() this.messageManager = new MessageManager() @@ -265,7 +263,7 @@ module.exports = class MetamaskController extends EventEmitter { PreferencesController: this.preferencesController.store, AddressBookController: this.addressBookController, CurrencyController: this.currencyController.store, - ShapeShiftController: this.shapeshiftController.store, + ShapeShiftController: this.shapeshiftController, NetworkController: this.networkController.store, InfuraController: this.infuraController.store, CachedBalancesController: this.cachedBalancesController.store, @@ -287,7 +285,7 @@ module.exports = class MetamaskController extends EventEmitter { RecentBlocksController: this.recentBlocksController.store, AddressBookController: this.addressBookController, CurrencyController: this.currencyController.store, - ShapeshiftController: this.shapeshiftController.store, + ShapeshiftController: this.shapeshiftController, InfuraController: this.infuraController.store, ProviderApprovalController: this.providerApprovalController.store, }) @@ -1633,7 +1631,7 @@ module.exports = class MetamaskController extends EventEmitter { * @property {string} depositType - An abbreviation of the type of crypto currency to be deposited. */ createShapeShiftTx (depositAddress, depositType) { - this.shapeshiftController.createShapeShiftTx(depositAddress, depositType) + this.shapeshiftController.createTransaction(depositAddress, depositType) } // network diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 4768b7c64..a56b8adbd 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -464,7 +464,7 @@ describe('MetaMaskController', function () { depositAddress = '3EevLFfB4H4XMWQwYCgjLie1qCAGpd2WBc' depositType = 'ETH' - shapeShiftTxList = metamaskController.shapeshiftController.store.getState().shapeShiftTxList + shapeShiftTxList = metamaskController.shapeshiftController.state.shapeShiftTxList }) it('creates a shapeshift tx', async function () { From c8cb4ba3705478a16cd1e39f8edc1f277bb2ede6 Mon Sep 17 00:00:00 2001 From: Alex Ivasyuv Date: Tue, 14 May 2019 22:00:53 +0300 Subject: [PATCH 71/87] fixed #5524 --- ui/app/components/app/ens-input.js | 14 +++++-- ui/app/css/itcss/components/send.scss | 38 ++++++++++++++++++- .../send/to-autocomplete/to-autocomplete.js | 21 +++++++--- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/ui/app/components/app/ens-input.js b/ui/app/components/app/ens-input.js index 5eea0dd90..f17f6c3d6 100644 --- a/ui/app/components/app/ens-input.js +++ b/ui/app/components/app/ens-input.js @@ -41,12 +41,15 @@ EnsInput.prototype.onChange = function (recipient) { ensResolution: null, ensFailure: null, toError: null, + recipient, }) } this.setState({ loadingEns: true, + recipient, }) + this.checkName(recipient) } @@ -56,6 +59,7 @@ EnsInput.prototype.render = function () { list: 'addresses', onChange: this.onChange.bind(this), qrScanner: true, + recipient: (this.state || {}).recipient, }) return h('div', { style: { width: '100%', position: 'relative' }, @@ -79,19 +83,21 @@ EnsInput.prototype.componentDidMount = function () { EnsInput.prototype.lookupEnsName = function (recipient) { const { ensResolution } = this.state + recipient = recipient.trim() log.info(`ENS attempting to resolve name: ${recipient}`) - this.ens.lookup(recipient.trim()) + this.ens.lookup(recipient) .then((address) => { if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, - nickname: recipient.trim(), + nickname: recipient, hoverText: address + '\n' + this.context.t('clickCopy'), ensFailure: false, toError: null, + recipient, }) } }) @@ -101,11 +107,11 @@ EnsInput.prototype.lookupEnsName = function (recipient) { ensResolution: recipient, ensFailure: true, toError: null, + recipient: null, } if (isValidENSAddress(recipient) && reason.message === 'ENS name not defined.') { setStateObj.hoverText = this.context.t('ensNameNotFound') setStateObj.toError = 'ensNameNotFound' - setStateObj.ensFailure = false } else { log.error(reason) setStateObj.hoverText = reason.message @@ -128,7 +134,7 @@ EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) { } if (prevState && ensResolution && this.props.onChange && ensResolution !== prevState.ensResolution) { - this.props.onChange({ toAddress: ensResolution, nickname, toError: state.toError, toWarning: state.toWarning }) + this.props.onChange({ toAddress: ensResolution, recipient: state.recipient, nickname, toError: state.toError, toWarning: state.toWarning }) } } diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 927640f0b..2e76cc842 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -763,7 +763,43 @@ } } - &__to-autocomplete, &__memo-text-area, &__hex-data { + &__to-autocomplete { + display: flex; + flex-direction: column; + z-index: 1025; + position: relative; + height: 54px; + width: 100%; + border: 1px solid $alto; + border-radius: 4px; + background-color: $white; + color: $tundora; + padding: 0 10px; + font-family: Roboto; + line-height: 21px; + + &__input { + font-size: 16px; + height: 100%; + border: none; + } + + &__resolved { + font-size: 12px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + height: 30px; + cursor: pointer; + + + .send-v2__to-autocomplete__qr-code { + top: 2px; + right: 0; + } + } + } + + &__memo-text-area, &__hex-data { &__input { z-index: 1025; position: relative; diff --git a/ui/app/pages/send/to-autocomplete/to-autocomplete.js b/ui/app/pages/send/to-autocomplete/to-autocomplete.js index 328a5b62b..11f86acf3 100644 --- a/ui/app/pages/send/to-autocomplete/to-autocomplete.js +++ b/ui/app/pages/send/to-autocomplete/to-autocomplete.js @@ -1,6 +1,7 @@ const Component = require('react').Component const PropTypes = require('prop-types') const h = require('react-hyperscript') +const copyToClipboard = require('copy-to-clipboard') const inherits = require('util').inherits const AccountListItem = require('../account-list-item/account-list-item.component').default const connect = require('react-redux').connect @@ -93,24 +94,34 @@ ToAutoComplete.prototype.componentDidUpdate = function (nextProps) { ToAutoComplete.prototype.render = function () { const { to, + recipient, dropdownOpen, onChange, inError, qrScanner, } = this.props - return h('div.send-v2__to-autocomplete', {}, [ + const isRecipientToDiff = recipient && recipient !== to + + return h('div.send-v2__to-autocomplete', {style: { + borderColor: inError ? 'red' : null, + }}, [ h(`input.send-v2__to-autocomplete__input${qrScanner ? '.with-qr' : ''}`, { placeholder: this.context.t('recipientAddress'), className: inError ? `send-v2__error-border` : '', - value: to, + value: recipient, onChange: event => onChange(event.target.value), onFocus: event => this.handleInputEvent(event), - style: { - borderColor: inError ? 'red' : null, - }, }), + isRecipientToDiff && h(Tooltip, {title: this.context.t('copyToClipboard')}, + h('div.send-v2__to-autocomplete__resolved', { + onClick: (event) => { + event.preventDefault() + event.stopPropagation() + copyToClipboard(to) + }, + }, to)), qrScanner && h(Tooltip, { title: this.context.t('scanQrCode'), position: 'bottom', From 1d2cf52b649866a15ea00733739cc0212a53e509 Mon Sep 17 00:00:00 2001 From: Bruno Barbieri Date: Wed, 15 May 2019 04:53:09 -0400 Subject: [PATCH 72/87] Fixes bugs in 6.5.1 (#6613) * fix bg error * fix ui exception --- app/scripts/metamask-controller.js | 2 +- ui/lib/account-link.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 55ca96ad4..242028c92 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -343,7 +343,7 @@ module.exports = class MetamaskController extends EventEmitter { updatePublicConfigStore(this.getState()) publicConfigStore.destroy = () => { - this.removeEventListener('update', updatePublicConfigStore) + this.removeEventListener && this.removeEventListener('update', updatePublicConfigStore) } function updatePublicConfigStore (memState) { diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js index f1428ba92..f2e321991 100644 --- a/ui/lib/account-link.js +++ b/ui/lib/account-link.js @@ -1,5 +1,5 @@ module.exports = function (address, network, rpcPrefs) { - if (rpcPrefs.blockExplorerUrl) { + if (rpcPrefs && rpcPrefs.blockExplorerUrl) { return `${rpcPrefs.blockExplorerUrl}/address/${address}` } From 7ff1857156a166f1b2fba943e1676d986771c410 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Wed, 15 May 2019 02:16:05 -0700 Subject: [PATCH 73/87] Version Bump --- CHANGELOG.md | 3 +++ app/manifest.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3e333e23..129af1281 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Current Develop Branch +## 6.5.2 Wed May 15 2019 + +- [#6613](https://github.com/MetaMask/metamask-extension/pull/6613): Hardware Wallet Fix ## 6.5.1 Tue May 14 2019 - Fix bug where approve method would show a warning. #6602 diff --git a/app/manifest.json b/app/manifest.json index 570e5b6cb..2002dee76 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "6.5.1", + "version": "6.5.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From c043132b00801f81d467748bebe147cae6893719 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 15 May 2019 14:10:11 -0230 Subject: [PATCH 74/87] Adds e2e test for removing imported accounts. (#6615) --- app/_locales/en/messages.json | 2 +- test/e2e/beta/from-import-beta-ui.spec.js | 55 ++++++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index bef278f79..47c1cfde8 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1249,7 +1249,7 @@ "message": "Revert" }, "remove": { - "message": "remove" + "message": "Remove" }, "removeAccount": { "message": "Remove account" diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index a913caa79..625330dbb 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -27,6 +27,8 @@ describe('Using MetaMask with an existing account', function () { const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' const testAddress = '0x0Cc5261AB8cE458dc977078A3623E2BaDD27afD3' const testPrivateKey2 = '14abe6f4aab7f9f626fe981c864d0adeb5685f289ac9270c27b8fd790b4235d6' + const testPrivateKey3 = 'F4EC2590A0C10DE95FBF4547845178910E40F5035320C516A18C117DE02B5669' + const tinyDelayMs = 200 const regularDelayMs = 1000 const largeDelayMs = regularDelayMs * 2 @@ -323,11 +325,60 @@ describe('Using MetaMask with an existing account', function () { }) }) - describe('Connects to a Hardware wallet', () => { - it('choose Connect Hardware Wallet from the account menu', async () => { + describe('Imports and removes an account', () => { + it('choose Create Account from the account menu', async () => { await driver.findElement(By.css('.account-menu__icon')).click() await delay(regularDelayMs) + const [importAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Import Account')]`)) + await importAccount.click() + await delay(regularDelayMs) + }) + + it('enter private key', async () => { + const privateKeyInput = await findElement(driver, By.css('#private-key-box')) + await privateKeyInput.sendKeys(testPrivateKey3) + await delay(regularDelayMs) + const importButtons = await findElements(driver, By.xpath(`//button[contains(text(), 'Import')]`)) + await importButtons[0].click() + await delay(regularDelayMs) + }) + + it('should open the remove account modal', async () => { + const [accountName] = await findElements(driver, By.css('.account-name')) + assert.equal(await accountName.getText(), 'Account 5') + await delay(regularDelayMs) + + await driver.findElement(By.css('.account-menu__icon')).click() + await delay(regularDelayMs) + + const accountListItems = await findElements(driver, By.css('.account-menu__account')) + assert.equal(accountListItems.length, 5) + + const removeAccountIcons = await findElements(driver, By.css('.remove-account-icon')) + await removeAccountIcons[1].click() + await delay(tinyDelayMs) + + await findElement(driver, By.css('.confirm-remove-account__account')) + }) + + it('should remove the account', async () => { + const removeButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Remove')]`)) + await removeButton.click() + + await delay(regularDelayMs) + + const [accountName] = await findElements(driver, By.css('.account-name')) + assert.equal(await accountName.getText(), 'Account 1') + await delay(regularDelayMs) + + const accountListItems = await findElements(driver, By.css('.account-menu__account')) + assert.equal(accountListItems.length, 4) + }) + }) + + describe('Connects to a Hardware wallet', () => { + it('choose Connect Hardware Wallet from the account menu', async () => { const [connectAccount] = await findElements(driver, By.xpath(`//div[contains(text(), 'Connect Hardware Wallet')]`)) await connectAccount.click() await delay(regularDelayMs) From a34103987a5a3b75588eb23ab4e1a73d6669cbc2 Mon Sep 17 00:00:00 2001 From: Frankie Date: Thu, 16 May 2019 07:36:53 +0200 Subject: [PATCH 75/87] drop transactions who's nonce is lower then the known network nonce but were not included in a block (#6388) * transactions/pending - check nonce against the network and mark as dropped if not included in a block * transactions/pending - unifiy "dropped" txs * transactions/pending - test - fix for new expected behavior * fix comment * transactions/pending - clean up dropped event * fix spelling Co-Authored-By: frankiebee * nit fix * test/tx-pending - clarify test description --- app/scripts/controllers/transactions/index.js | 1 + .../transactions/pending-tx-tracker.js | 53 +++++++++++--- .../transactions/pending-tx-test.js | 72 +++++++++++++++++-- 3 files changed, 113 insertions(+), 13 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 79dba7833..dd497a11e 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -555,6 +555,7 @@ class TransactionController extends EventEmitter { }) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:confirmed', (txId) => this.confirmTransaction(txId)) + this.pendingTxTracker.on('tx:dropped', this.txStateManager.setTxStatusDropped.bind(this.txStateManager)) this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { txMeta.firstRetryBlockNumber = latestBlockNumber diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 4bf40b1db..bc11f6633 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -22,6 +22,7 @@ const EthQuery = require('ethjs-query') class PendingTransactionTracker extends EventEmitter { constructor (config) { super() + this.droppedBuffer = {} this.query = new EthQuery(config.provider) this.nonceTracker = config.nonceTracker this.getPendingTransactions = config.getPendingTransactions @@ -139,22 +140,42 @@ class PendingTransactionTracker extends EventEmitter { const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.') noTxHashErr.name = 'NoTxHashError' this.emit('tx:failed', txId, noTxHashErr) + return } - // If another tx with the same nonce is mined, set as failed. + // If another tx with the same nonce is mined, set as dropped. const taken = await this._checkIfNonceIsTaken(txMeta) - if (taken) { - const nonceTakenErr = new Error('Another transaction with this nonce has been mined.') - nonceTakenErr.name = 'NonceTakenErr' - return this.emit('tx:failed', txId, nonceTakenErr) + let dropped + try { + // check the network if the nonce is ahead the tx + // and the tx has not been mined into a block + + dropped = await this._checkIftxWasDropped(txMeta) + // the dropped buffer is in case we ask a node for the tx + // that is behind the node we asked for tx count + // IS A SECURITY FOR HITTING NODES IN INFURA THAT COULD GO OUT + // OF SYNC. + // on the next block event it will return fire as dropped + if (dropped && !this.droppedBuffer[txHash]) { + this.droppedBuffer[txHash] = true + dropped = false + } else if (dropped && this.droppedBuffer[txHash]) { + // clean up + delete this.droppedBuffer[txHash] + } + + } catch (e) { + log.error(e) + } + if (taken || dropped) { + return this.emit('tx:dropped', txId) } // get latest transaction status try { - const txParams = await this.query.getTransactionByHash(txHash) - if (!txParams) return - if (txParams.blockNumber) { + const { blockNumber } = await this.query.getTransactionByHash(txHash) || {} + if (blockNumber) { this.emit('tx:confirmed', txId) } } catch (err) { @@ -165,6 +186,22 @@ class PendingTransactionTracker extends EventEmitter { this.emit('tx:warning', txMeta, err) } } + /** + checks to see if if the tx's nonce has been used by another transaction + @param txMeta {Object} - txMeta object + @emits tx:dropped + @returns {boolean} + */ + + async _checkIftxWasDropped (txMeta) { + const { txParams: { nonce, from }, hash } = txMeta + const nextNonce = await this.query.getTransactionCount(from) + const { blockNumber } = await this.query.getTransactionByHash(hash) || {} + if (!blockNumber && parseInt(nextNonce) > parseInt(nonce)) { + return true + } + return false + } /** checks to see if a confirmed txMeta has the same nonce diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index 1c5f59f5a..b37ac2766 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -58,7 +58,7 @@ describe('PendingTransactionTracker', function () { } }) - it('should become failed if another tx with the same nonce succeeds', async function () { + it('should emit dropped if another tx with the same nonce succeeds', async function () { // SETUP const txGen = new MockTxGen() @@ -84,17 +84,16 @@ describe('PendingTransactionTracker', function () { // THE EXPECTATION const spy = sinon.spy() - pendingTxTracker.on('tx:failed', (txId, err) => { + pendingTxTracker.on('tx:dropped', (txId) => { assert.equal(txId, pending.id, 'should fail the pending tx') - assert.equal(err.name, 'NonceTakenErr', 'should emit a nonce taken error.') - spy(txId, err) + spy(txId) }) // THE METHOD await pendingTxTracker._checkPendingTx(pending) // THE ASSERTION - assert.ok(spy.calledWith(pending.id), 'tx failed should be emitted') + assert.ok(spy.calledWith(pending.id), 'tx dropped should be emitted') }) }) @@ -107,6 +106,38 @@ describe('PendingTransactionTracker', function () { pendingTxTracker._checkPendingTx(txMetaNoHash) }) + it('should emit tx:dropped with the txMetas id only after the second call', function (done) { + txMeta = { + id: 1, + hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'submitted', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + history: [{}], + rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + } + + providerResultStub['eth_getTransactionCount'] = '0x02' + providerResultStub['eth_getTransactionByHash'] = {} + pendingTxTracker.once('tx:dropped', (id) => { + if (id === txMeta.id) { + delete providerResultStub['eth_getTransactionCount'] + delete providerResultStub['eth_getTransactionByHash'] + return done() + } else { + done(new Error('wrong tx Id')) + } + }) + + pendingTxTracker._checkPendingTx(txMeta).then(() => { + pendingTxTracker._checkPendingTx(txMeta).catch(done) + }).catch(done) + }) + + it('should should return if query does not return txParams', function () { providerResultStub.eth_getTransactionByHash = null pendingTxTracker._checkPendingTx(txMeta) @@ -283,6 +314,37 @@ describe('PendingTransactionTracker', function () { }) }) + describe('#_checkIftxWasDropped', () => { + const txMeta = { + id: 1, + hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', + status: 'submitted', + txParams: { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + nonce: '0x1', + value: '0xfffff', + }, + rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', + } + it('should return false when the nonce is the suggested network nonce', (done) => { + providerResultStub['eth_getTransactionCount'] = '0x01' + providerResultStub['eth_getTransactionByHash'] = {} + pendingTxTracker._checkIftxWasDropped(txMeta).then((dropped) => { + assert(!dropped, 'should be false') + done() + }).catch(done) + }) + + it('should return true when the network nonce is higher then the txMeta nonce', function (done) { + providerResultStub['eth_getTransactionCount'] = '0x02' + providerResultStub['eth_getTransactionByHash'] = {} + pendingTxTracker._checkIftxWasDropped(txMeta).then((dropped) => { + assert(dropped, 'should be true') + done() + }).catch(done) + }) + }) + describe('#_checkIfNonceIsTaken', function () { beforeEach(function () { const confirmedTxList = [{ From 8c0bc7b3e2ecf945aa0a2de721a11e725e531a05 Mon Sep 17 00:00:00 2001 From: bitpshr Date: Thu, 16 May 2019 10:53:37 -0400 Subject: [PATCH 76/87] bugfix: show extension window if locked regardless of approval --- app/scripts/controllers/provider-approval.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/provider-approval.js b/app/scripts/controllers/provider-approval.js index 8206b2f8a..06c499780 100644 --- a/app/scripts/controllers/provider-approval.js +++ b/app/scripts/controllers/provider-approval.js @@ -38,7 +38,8 @@ class ProviderApprovalController extends SafeEventEmitter { // only handle requestAccounts if (req.method !== 'eth_requestAccounts') return next() // if already approved or privacy mode disabled, return early - if (this.shouldExposeAccounts(origin)) { + const isUnlocked = this.keyringController.memStore.getState().isUnlocked + if (this.shouldExposeAccounts(origin) && isUnlocked) { res.result = [this.preferencesController.getSelectedAddress()] return } From 8bd27f50b05541e15aa9e811a435d7f1d0539a55 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 16 May 2019 08:54:43 -0700 Subject: [PATCH 77/87] Version 6.5.3 RC1 --- CHANGELOG.md | 7 +++++++ app/manifest.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129af1281..875ad2bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## Current Develop Branch +## 6.5.3 Thu May 16 2019 + +- [#6619](https://github.com/MetaMask/metamask-extension/pull/6619): bugfix: show extension window if locked regardless of approval +- [#6388](https://github.com/MetaMask/metamask-extension/pull/6388): Transactions/pending - check nonce against the network and mark as dropped if not included in a block +- [#6606](https://github.com/MetaMask/metamask-extension/pull/6606): Improve ENS Address Input +- [#6615](https://github.com/MetaMask/metamask-extension/pull/6615): Adds e2e test for removing imported accounts. + ## 6.5.2 Wed May 15 2019 - [#6613](https://github.com/MetaMask/metamask-extension/pull/6613): Hardware Wallet Fix diff --git a/app/manifest.json b/app/manifest.json index 2002dee76..8471fffac 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "6.5.2", + "version": "6.5.3", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 0e9c8fb5ccb9b02a53879e8e676df2c7735a8c69 Mon Sep 17 00:00:00 2001 From: Etienne Dusseault Date: Tue, 21 May 2019 00:38:08 +0800 Subject: [PATCH 78/87] Improved UX for sweeping accounts (#6488) * Changed max button to checkbox, disabled input if max mode is on, recalculate price according to gas fee if max mode is on * Disabled insufficient funds message in the modal if max mode is on, displays proper amounts in modal when max mode is on, sets the send amount according to custom gas price after gas modal save, resets the send amount after resetting custom gas price * Disabled max mode checkbox if gas buttons are loading, refactored gas-modal-page-container * Implemented new max button & max mode message. Moved insufficient funds error to underneath the send amount field * Fixed existing integration test to pass, created new tests to ensure send amount field is disabled when max button is clicked and the amount changes when the gas price is changed. Refactored some components --- test/integration/lib/send-new-ui.js | 24 +++++++- .../gas-modal-page-container.container.js | 57 ++++++++++++++++--- ...gas-modal-page-container-container.test.js | 12 +++- .../currency-input.component.js | 4 +- .../currency-input.container.js | 3 + .../tests/currency-input.container.test.js | 16 ++++++ ui/app/components/ui/unit-input/index.scss | 9 +++ .../ui/unit-input/unit-input.component.js | 10 ++-- ui/app/css/itcss/components/send.scss | 55 ++++++++++++++++-- ui/app/helpers/utils/conversions.util.js | 11 +++- .../amount-max-button.component.js | 39 +++++++------ .../amount-max-button.container.js | 5 ++ .../tests/amount-max-button-component.test.js | 7 +-- .../tests/amount-max-button-container.test.js | 2 + .../send-amount-row.component.js | 2 +- .../send-gas-row/send-gas-row.component.js | 37 +++++++++++- .../send-gas-row/send-gas-row.container.js | 18 +++++- .../tests/send-gas-row-container.test.js | 9 +++ .../send-row-error-message.component.js | 3 +- .../send-row-wrapper.component.js | 46 ++++++++++++++- 20 files changed, 314 insertions(+), 55 deletions(-) diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index 78014feef..0cca9e959 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -71,11 +71,29 @@ async function runSendFlowTest (assert) { assert.equal(sendToAccountAddress, '0x2f8D4a878cFA04A6E60D46362f5644DeAb66572D', 'send to dropdown selects the correct address') const sendAmountField = await queryAsync($, '.send-v2__form-row:eq(3)') - sendAmountField.find('.unit-input')[0].click() - const sendAmountFieldInput = await findAsync(sendAmountField, '.unit-input__input') + + const amountMaxButton = await queryAsync($, '.send-v2__amount-max') + amountMaxButton.click() + reactTriggerChange(sendAmountField.find('input')[1]) + assert.equal(sendAmountFieldInput.is(':disabled'), true, 'disabled the send amount input when max mode is on') + + const gasPriceButtonGroup = await queryAsync($, '.gas-price-button-group--small') + const gasPriceButton = await gasPriceButtonGroup.find('button')[0] + const valueBeforeGasPriceChange = sendAmountFieldInput.prop('value') + gasPriceButton.click() + reactTriggerChange(sendAmountField.find('input')[1]) + + await timeout(1000) + + assert.notEqual(valueBeforeGasPriceChange, sendAmountFieldInput.prop('value'), 'send amount value changes when gas price changes') + + amountMaxButton.click() + reactTriggerChange(sendAmountField.find('input')[1]) + + sendAmountField.find('.unit-input').click() sendAmountFieldInput.val('5.1') - reactTriggerChange(sendAmountField.find('input')[0]) + reactTriggerChange(sendAmountField.find('input')[1]) let errorMessage = await queryAsync($, '.send-v2__error') assert.equal(errorMessage[0].textContent, 'Insufficient funds.', 'send should render an insufficient fund error message') diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index 0e7e30347..c3fdf51e5 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -7,6 +7,8 @@ import { setGasPrice, createSpeedUpTransaction, hideSidebar, + updateSendAmount, + setGasTotal, } from '../../../../store/actions' import { setCustomGasPrice, @@ -18,6 +20,7 @@ import { } from '../../../../ducks/gas/gas.duck' import { hideGasButtonGroup, + updateSendErrors, } from '../../../../ducks/send/send.duck' import { updateGasAndCalculate, @@ -45,6 +48,9 @@ import { getBasicGasEstimateBlockTime, isCustomPriceSafe, } from '../../../../selectors/custom-gas' +import { + getTokenBalance, +} from '../../../../pages/send/send.selectors' import { submittedPendingTransactionsSelector, } from '../../../../selectors/transactions' @@ -53,6 +59,7 @@ import { } from '../../../../helpers/utils/confirm-tx.util' import { addHexWEIsToDec, + subtractHexWEIsToDec, decEthToConvertedCurrency as ethTotalToConvertedCurrency, decGWEIToHexWEI, hexWEIToDecGWEI, @@ -66,6 +73,8 @@ import { } from '../../../../pages/send/send.utils' import { addHexPrefix } from 'ethereumjs-util' import { getAdjacentGasPrices, extrapolateY } from '../gas-price-chart/gas-price-chart.utils' +import { getMaxModeOn } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.selectors' +import { calcMaxAmount } from '../../../../pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils' const mapStateToProps = (state, ownProps) => { const { transaction = {} } = ownProps @@ -75,8 +84,6 @@ const mapStateToProps = (state, ownProps) => { const { gasPrice: currentGasPrice, gas: currentGasLimit, value } = getTxParams(state, transaction.id) const customModalGasPriceInHex = getCustomGasPrice(state) || currentGasPrice const customModalGasLimitInHex = getCustomGasLimit(state) || currentGasLimit - const gasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) - const customGasTotal = calcGasTotal(customModalGasLimitInHex, customModalGasPriceInHex) const gasButtonInfo = getRenderableBasicEstimateData(state, customModalGasLimitInHex) @@ -90,6 +97,8 @@ const mapStateToProps = (state, ownProps) => { const customGasPrice = calcCustomGasPrice(customModalGasPriceInHex) + const maxModeOn = getMaxModeOn(state) + const gasPrices = getEstimatedGasPrices(state) const estimatedTimes = getEstimatedGasTimes(state) const balance = getCurrentEthBalance(state) @@ -98,9 +107,13 @@ const mapStateToProps = (state, ownProps) => { const isMainnet = getIsMainnet(state) const showFiat = Boolean(isMainnet || showFiatInTestnets) - const insufficientBalance = !isBalanceSufficient({ + const newTotalEth = maxModeOn ? addHexWEIsToRenderableEth(balance, '0x0') : addHexWEIsToRenderableEth(value, customGasTotal) + + const sendAmount = maxModeOn ? subtractHexWEIsFromRenderableEth(balance, customGasTotal) : addHexWEIsToRenderableEth(value, '0x0') + + const insufficientBalance = maxModeOn ? false : !isBalanceSufficient({ amount: value, - gasTotal, + gasTotal: customGasTotal, balance, conversionRate, }) @@ -112,10 +125,12 @@ const mapStateToProps = (state, ownProps) => { customModalGasLimitInHex, customGasPrice, customGasLimit: calcCustomGasLimit(customModalGasLimitInHex), + customGasTotal, newTotalFiat, currentTimeEstimate: getRenderableTimeEstimate(customGasPrice, gasPrices, estimatedTimes), blockTime: getBasicGasEstimateBlockTime(state), customPriceIsSafe: isCustomPriceSafe(state), + maxModeOn, gasPriceButtonGroupProps: { buttonDataLoading, defaultActiveButtonIndex: getDefaultActiveButtonIndex(gasButtonInfo, customModalGasPriceInHex), @@ -129,12 +144,12 @@ const mapStateToProps = (state, ownProps) => { estimatedTimesMax: estimatedTimes[0], }, infoRowProps: { - originalTotalFiat: addHexWEIsToRenderableFiat(value, gasTotal, currentCurrency, conversionRate), - originalTotalEth: addHexWEIsToRenderableEth(value, gasTotal), + originalTotalFiat: addHexWEIsToRenderableFiat(value, customGasTotal, currentCurrency, conversionRate), + originalTotalEth: addHexWEIsToRenderableEth(value, customGasTotal), newTotalFiat: showFiat ? newTotalFiat : '', - newTotalEth: addHexWEIsToRenderableEth(value, customGasTotal), + newTotalEth, transactionFee: addHexWEIsToRenderableEth('0x0', customGasTotal), - sendAmount: addHexWEIsToRenderableEth(value, '0x0'), + sendAmount, }, isSpeedUp: transaction.status === 'submitted', txId: transaction.id, @@ -142,6 +157,9 @@ const mapStateToProps = (state, ownProps) => { gasEstimatesLoading, isMainnet, isEthereumNetwork: isEthereumNetwork(state), + selectedToken: getSelectedToken(state), + balance, + tokenBalance: getTokenBalance(state), } } @@ -174,11 +192,16 @@ const mapDispatchToProps = dispatch => { hideSidebar: () => dispatch(hideSidebar()), fetchGasEstimates: (blockTime) => dispatch(fetchGasEstimates(blockTime)), fetchBasicGasAndTimeEstimates: () => dispatch(fetchBasicGasAndTimeEstimates()), + setGasTotal: (total) => dispatch(setGasTotal(total)), + setAmountToMax: (maxAmountDataObject) => { + dispatch(updateSendErrors({ amount: null })) + dispatch(updateSendAmount(calcMaxAmount(maxAmountDataObject))) + }, } } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { gasPriceButtonGroupProps, isConfirm, txId, isSpeedUp, insufficientBalance, customGasPrice } = stateProps + const { gasPriceButtonGroupProps, isConfirm, txId, isSpeedUp, insufficientBalance, maxModeOn, customGasPrice, customGasTotal, balance, selectedToken, tokenBalance} = stateProps const { updateCustomGasPrice: dispatchUpdateCustomGasPrice, hideGasButtonGroup: dispatchHideGasButtonGroup, @@ -188,6 +211,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { hideSidebar: dispatchHideSidebar, cancelAndClose: dispatchCancelAndClose, hideModal: dispatchHideModal, + setAmountToMax: dispatchSetAmountToMax, ...otherDispatchProps } = dispatchProps @@ -208,6 +232,14 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { dispatchHideGasButtonGroup() dispatchCancelAndClose() } + if (maxModeOn) { + dispatchSetAmountToMax({ + balance, + gasTotal: customGasTotal, + selectedToken, + tokenBalance, + }) + } }, gasPriceButtonGroupProps: { ...gasPriceButtonGroupProps, @@ -258,6 +290,13 @@ function addHexWEIsToRenderableEth (aHexWEI, bHexWEI) { )(aHexWEI, bHexWEI) } +function subtractHexWEIsFromRenderableEth (aHexWEI, bHexWei) { + return pipe( + subtractHexWEIsToDec, + formatETHFee + )(aHexWEI, bHexWei) +} + function addHexWEIsToRenderableFiat (aHexWEI, bHexWEI, convertedCurrency, conversionRate) { return pipe( addHexWEIsToDec, diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js index ab24b9c0e..dbe61d5cf 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/tests/gas-modal-page-container-container.test.js @@ -46,6 +46,10 @@ proxyquire('../gas-modal-page-container.container.js', { '../../../../ducks/send/send.duck': sendActionSpies, '../../../../selectors/selectors.js': { getCurrentEthBalance: (state) => state.metamask.balance || '0x0', + getSelectedToken: () => null, + }, + '../../../../pages/send/send.selectors': { + getTokenBalance: (state) => state.metamask.send.tokenBalance || '0x0', }, }) @@ -68,6 +72,7 @@ describe('gas-modal-page-container container', () => { gasLimit: '16', gasPrice: '32', amount: '64', + maxModeOn: false, }, currentCurrency: 'abc', conversionRate: 50, @@ -106,6 +111,7 @@ describe('gas-modal-page-container container', () => { }, } const baseExpectedResult = { + balance: '0x0', isConfirm: true, customGasPrice: 4.294967295, customGasLimit: 2863311530, @@ -114,6 +120,7 @@ describe('gas-modal-page-container container', () => { blockTime: 12, customModalGasLimitInHex: 'aaaaaaaa', customModalGasPriceInHex: 'ffffffff', + customGasTotal: 'aaaaaaa955555556', customPriceIsSafe: true, gasChartProps: { 'currentPrice': 4.294967295, @@ -142,6 +149,9 @@ describe('gas-modal-page-container container', () => { txId: 34, isEthereumNetwork: true, isMainnet: true, + maxModeOn: false, + selectedToken: null, + tokenBalance: '0x0', } const baseMockOwnProps = { transaction: { id: 34 } } const tests = [ @@ -150,7 +160,7 @@ describe('gas-modal-page-container container', () => { mockState: Object.assign({}, baseMockState, { metamask: { ...baseMockState.metamask, balance: '0xfffffffffffffffffffff' }, }), - expectedResult: Object.assign({}, baseExpectedResult, { insufficientBalance: false }), + expectedResult: Object.assign({}, baseExpectedResult, { balance: '0xfffffffffffffffffffff', insufficientBalance: false }), mockOwnProps: baseMockOwnProps, }, { diff --git a/ui/app/components/ui/currency-input/currency-input.component.js b/ui/app/components/ui/currency-input/currency-input.component.js index b5be0972b..1876c9591 100644 --- a/ui/app/components/ui/currency-input/currency-input.component.js +++ b/ui/app/components/ui/currency-input/currency-input.component.js @@ -18,6 +18,7 @@ export default class CurrencyInput extends PureComponent { static propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, + maxModeOn: PropTypes.bool, nativeCurrency: PropTypes.string, onChange: PropTypes.func, onBlur: PropTypes.func, @@ -136,7 +137,7 @@ export default class CurrencyInput extends PureComponent { } render () { - const { fiatSuffix, nativeSuffix, ...restProps } = this.props + const { fiatSuffix, nativeSuffix, maxModeOn, ...restProps } = this.props const { decimalValue } = this.state return ( @@ -146,6 +147,7 @@ export default class CurrencyInput extends PureComponent { onChange={this.handleChange} onBlur={this.handleBlur} value={decimalValue} + maxModeOn={maxModeOn} actionComponent={(
{ const { metamask: { nativeCurrency, currentCurrency, conversionRate } } = state const { showFiatInTestnets } = preferencesSelector(state) const isMainnet = getIsMainnet(state) + const maxModeOn = getMaxModeOn(state) return { nativeCurrency, currentCurrency, conversionRate, hideFiat: (!isMainnet && !showFiatInTestnets), + maxModeOn, } } diff --git a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js index 259fe594a..f10abe09a 100644 --- a/ui/app/components/ui/currency-input/tests/currency-input.container.test.js +++ b/ui/app/components/ui/currency-input/tests/currency-input.container.test.js @@ -30,6 +30,9 @@ describe('CurrencyInput container', () => { provider: { type: 'mainnet', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -37,6 +40,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, // Test # 2 @@ -53,6 +57,9 @@ describe('CurrencyInput container', () => { provider: { type: 'rinkeby', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -60,6 +67,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: true, + maxModeOn: false, }, }, // Test # 3 @@ -76,6 +84,9 @@ describe('CurrencyInput container', () => { provider: { type: 'rinkeby', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -83,6 +94,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, // Test # 4 @@ -99,6 +111,9 @@ describe('CurrencyInput container', () => { provider: { type: 'mainnet', }, + send: { + maxModeOn: false, + }, }, }, expected: { @@ -106,6 +121,7 @@ describe('CurrencyInput container', () => { currentCurrency: 'usd', nativeCurrency: 'ETH', hideFiat: false, + maxModeOn: false, }, }, ] diff --git a/ui/app/components/ui/unit-input/index.scss b/ui/app/components/ui/unit-input/index.scss index adc4a3531..58a10c9a1 100644 --- a/ui/app/components/ui/unit-input/index.scss +++ b/ui/app/components/ui/unit-input/index.scss @@ -42,6 +42,10 @@ max-width: 22ch; height: 16px; line-height: 18px; + + &__disabled { + background-color: rgb(222, 222, 222); + } } &__input-container { @@ -59,4 +63,9 @@ &--error { border-color: $red; } + + &__disabled { + background-color: #F2F3F4; + } + } diff --git a/ui/app/components/ui/unit-input/unit-input.component.js b/ui/app/components/ui/unit-input/unit-input.component.js index 6a53f4c6f..9085a0677 100644 --- a/ui/app/components/ui/unit-input/unit-input.component.js +++ b/ui/app/components/ui/unit-input/unit-input.component.js @@ -13,6 +13,7 @@ export default class UnitInput extends PureComponent { children: PropTypes.node, actionComponent: PropTypes.node, error: PropTypes.bool, + maxModeOn: PropTypes.bool, onBlur: PropTypes.func, onChange: PropTypes.func, placeholder: PropTypes.string, @@ -71,25 +72,26 @@ export default class UnitInput extends PureComponent { } render () { - const { error, placeholder, suffix, actionComponent, children } = this.props + const { error, placeholder, suffix, actionComponent, children, maxModeOn } = this.props const { value } = this.state return (
{ this.unitInput = ref }} + disabled={maxModeOn} /> { suffix && ( diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 2e76cc842..e2f0f9b2f 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -520,6 +520,10 @@ color: $red; } + &__error-amount { + margin-top: 5px; + } + &__warning { font-size: 12px; line-height: 12px; @@ -557,6 +561,12 @@ justify-content: space-between; } + &__form-field-container { + display: flex; + flex-direction: column; + width: 277px; + } + &__form-field { flex: 1 1 auto; min-width: 0; @@ -817,12 +827,47 @@ } &__amount-max { - color: $curious-blue; font-family: Roboto; font-size: 12px; - left: 8px; - border: none; - cursor: pointer; + position: relative; + display: inline-block; + width: 56px; + height: 20px; + margin-top: 5px; + + &__button { + width: 56px; + height: 20px; + position: absolute; + border: 2px solid #B0D7F2; + border-radius: 6px; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + color: #2f9ae0; + + &__disabled { + color: #B0D7F2; + cursor: auto; + } + } + + input:checked + &__button { + background-color: #037DD6; + border: 2px solid #037DD6; + color: #fff; + } + } + + &__amount-max input { + opacity: 0; + width: 0; + height: 0; } &__gas-fee-display { @@ -1077,7 +1122,7 @@ font-size: 14px; color: #2f9ae0; cursor: pointer; - margin-top: 16px; + margin-top: 5px; } .sliders-icon-container { diff --git a/ui/app/helpers/utils/conversions.util.js b/ui/app/helpers/utils/conversions.util.js index b4ec50626..5e1c21ff7 100644 --- a/ui/app/helpers/utils/conversions.util.js +++ b/ui/app/helpers/utils/conversions.util.js @@ -1,6 +1,6 @@ import ethUtil from 'ethereumjs-util' import { ETH, GWEI, WEI } from '../constants/common' -import { conversionUtil, addCurrencies } from './conversion-util' +import { conversionUtil, addCurrencies, subtractCurrencies } from './conversion-util' export function bnToHex (inputBn) { return ethUtil.addHexPrefix(inputBn.toString(16)) @@ -92,6 +92,15 @@ export function addHexWEIsToDec (aHexWEI, bHexWEI) { }) } +export function subtractHexWEIsToDec (aHexWEI, bHexWEI) { + return subtractCurrencies(aHexWEI, bHexWEI, { + aBase: 16, + bBase: 16, + fromDenomination: 'WEI', + numberOfDecimals: 6, + }) +} + export function decEthToConvertedCurrency (ethTotal, convertedCurrency, conversionRate) { return conversionUtil(ethTotal, { fromNumericBase: 'dec', diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js index e256d1442..249703763 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js @@ -1,16 +1,21 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' export default class AmountMaxButton extends Component { static propTypes = { balance: PropTypes.string, + buttonDataLoading: PropTypes.bool, + clearMaxAmount: PropTypes.func, + inError: PropTypes.bool, gasTotal: PropTypes.string, maxModeOn: PropTypes.bool, selectedToken: PropTypes.object, setAmountToMax: PropTypes.func, setMaxModeTo: PropTypes.func, tokenBalance: PropTypes.string, + } static contextTypes = { @@ -36,7 +41,7 @@ export default class AmountMaxButton extends Component { } onMaxClick = (event) => { - const { setMaxModeTo } = this.props + const { setMaxModeTo, clearMaxAmount, maxModeOn } = this.props const { metricsEvent } = this.context metricsEvent({ @@ -46,25 +51,25 @@ export default class AmountMaxButton extends Component { name: 'Clicked "Amount Max"', }, }) - - event.preventDefault() - setMaxModeTo(true) - this.setMaxAmount() + if (!maxModeOn) { + setMaxModeTo(true) + this.setMaxAmount() + } else { + setMaxModeTo(false) + clearMaxAmount() + } } render () { - return this.props.maxModeOn - ? null - : ( -
- - {this.context.t('max')} - -
+ const { maxModeOn, buttonDataLoading, inError } = this.props + + return ( +
+ +
+ {this.context.t('max')} +
+
) } - } diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js index cd48a105f..e444589a1 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.container.js @@ -5,6 +5,7 @@ import { getSendFromBalance, getTokenBalance, } from '../../../send.selectors.js' +import { getBasicGasEstimateLoadingStatus } from '../../../../../selectors/custom-gas' import { getMaxModeOn } from './amount-max-button.selectors.js' import { calcMaxAmount } from './amount-max-button.utils.js' import { @@ -22,6 +23,7 @@ function mapStateToProps (state) { return { balance: getSendFromBalance(state), + buttonDataLoading: getBasicGasEstimateLoadingStatus(state), gasTotal: getGasTotal(state), maxModeOn: getMaxModeOn(state), selectedToken: getSelectedToken(state), @@ -35,6 +37,9 @@ function mapDispatchToProps (dispatch) { dispatch(updateSendErrors({ amount: null })) dispatch(updateSendAmount(calcMaxAmount(maxAmountDataObject))) }, + clearMaxAmount: () => { + dispatch(updateSendAmount('0')) + }, setMaxModeTo: bool => dispatch(setMaxModeTo(bool)), } } diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js index a6cb29d4c..f986b26bb 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-component.test.js @@ -65,7 +65,7 @@ describe('AmountMaxButton Component', function () { assert(wrapper.exists('.send-v2__amount-max')) }) - it('should call setMaxModeTo and setMaxAmount when the send-v2__amount-max div is clicked', () => { + it('should call setMaxModeTo and setMaxAmount when the checkbox is checked', () => { const { onClick, } = wrapper.find('.send-v2__amount-max').props() @@ -81,11 +81,6 @@ describe('AmountMaxButton Component', function () { ) }) - it('should not render anything when maxModeOn is true', () => { - wrapper.setProps({ maxModeOn: true }) - assert.ok(!wrapper.exists('.send-v2__amount-max')) - }) - it('should render the expected text when maxModeOn is false', () => { wrapper.setProps({ maxModeOn: false }) assert.equal(wrapper.find('.send-v2__amount-max').text(), 'max_t') diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js index a75ed5e8f..dcee8fda0 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-container.test.js @@ -29,6 +29,7 @@ proxyquire('../amount-max-button.container.js', { }, './amount-max-button.selectors.js': { getMaxModeOn: (s) => `mockMaxModeOn:${s}` }, './amount-max-button.utils.js': { calcMaxAmount: (mockObj) => mockObj.val + 1 }, + '../../../../../selectors/custom-gas': { getBasicGasEstimateLoadingStatus: (s) => `mockButtonDataLoading:${s}`}, '../../../../../store/actions': actionSpies, '../../../../../ducks/send/send.duck': duckActionSpies, }) @@ -40,6 +41,7 @@ describe('amount-max-button container', () => { it('should map the correct properties to props', () => { assert.deepEqual(mapStateToProps('mockState'), { balance: 'mockBalance:mockState', + buttonDataLoading: 'mockButtonDataLoading:mockState', gasTotal: 'mockGasTotal:mockState', maxModeOn: 'mockMaxModeOn:mockState', selectedToken: 'mockSelectedToken:mockState', diff --git a/ui/app/pages/send/send-content/send-amount-row/send-amount-row.component.js b/ui/app/pages/send/send-content/send-amount-row/send-amount-row.component.js index c0241ea91..10e90c419 100644 --- a/ui/app/pages/send/send-content/send-amount-row/send-amount-row.component.js +++ b/ui/app/pages/send/send-content/send-amount-row/send-amount-row.component.js @@ -110,7 +110,7 @@ export default class SendAmountRow extends Component { showError={inError} errorType={'amount'} > - {!inError && gasTotal && } + {gasTotal && } { this.renderInput() } ) diff --git a/ui/app/pages/send/send-content/send-gas-row/send-gas-row.component.js b/ui/app/pages/send/send-content/send-gas-row/send-gas-row.component.js index 1b850ac57..4c09ed564 100644 --- a/ui/app/pages/send/send-content/send-gas-row/send-gas-row.component.js +++ b/ui/app/pages/send/send-content/send-gas-row/send-gas-row.component.js @@ -8,14 +8,19 @@ import AdvancedGasInputs from '../../../../components/app/gas-customization/adva export default class SendGasRow extends Component { static propTypes = { + balance: PropTypes.string, conversionRate: PropTypes.number, convertedCurrency: PropTypes.string, gasFeeError: PropTypes.bool, gasLoadingError: PropTypes.bool, gasTotal: PropTypes.string, + maxModeOn: PropTypes.bool, showCustomizeGasModal: PropTypes.func, + selectedToken: PropTypes.object, + setAmountToMax: PropTypes.func, setGasPrice: PropTypes.func, setGasLimit: PropTypes.func, + tokenBalance: PropTypes.string, gasPriceButtonGroupProps: PropTypes.object, gasButtonGroupShown: PropTypes.bool, advancedInlineGasShown: PropTypes.bool, @@ -47,6 +52,23 @@ export default class SendGasRow extends Component {
} + setMaxAmount () { + const { + balance, + gasTotal, + selectedToken, + setAmountToMax, + tokenBalance, + } = this.props + + setAmountToMax({ + balance, + gasTotal, + selectedToken, + tokenBalance, + }) + } + renderContent () { const { conversionRate, @@ -57,6 +79,7 @@ export default class SendGasRow extends Component { gasPriceButtonGroupProps, gasButtonGroupShown, advancedInlineGasShown, + maxModeOn, resetGasButtons, setGasPrice, setGasLimit, @@ -71,7 +94,7 @@ export default class SendGasRow extends Component { className="gas-price-button-group--small" showCheck={false} {...gasPriceButtonGroupProps} - handleGasPriceSelection={(...args) => { + handleGasPriceSelection={async (...args) => { metricsEvent({ eventOpts: { category: 'Transactions', @@ -79,7 +102,10 @@ export default class SendGasRow extends Component { name: 'Changed Gas Button', }, }) - gasPriceButtonGroupProps.handleGasPriceSelection(...args) + await gasPriceButtonGroupProps.handleGasPriceSelection(...args) + if (maxModeOn) { + this.setMaxAmount() + } }} /> { this.renderAdvancedOptionsButton() } @@ -89,7 +115,12 @@ export default class SendGasRow extends Component { convertedCurrency={convertedCurrency} gasLoadingError={gasLoadingError} gasTotal={gasTotal} - onReset={resetGasButtons} + onReset={() => { + resetGasButtons() + if (maxModeOn) { + this.setMaxAmount() + } + }} onClick={() => showCustomizeGasModal()} /> const advancedGasInputs =
diff --git a/ui/app/pages/send/send-content/send-gas-row/send-gas-row.container.js b/ui/app/pages/send/send-content/send-gas-row/send-gas-row.container.js index c4daa98af..10eaa50b8 100644 --- a/ui/app/pages/send/send-content/send-gas-row/send-gas-row.container.js +++ b/ui/app/pages/send/send-content/send-gas-row/send-gas-row.container.js @@ -6,11 +6,17 @@ import { getGasPrice, getGasLimit, getSendAmount, + getSendFromBalance, + getTokenBalance, } from '../../send.selectors.js' +import { + getMaxModeOn, +} from '../send-amount-row/amount-max-button/amount-max-button.selectors' import { isBalanceSufficient, calcGasTotal, } from '../../send.utils.js' +import { calcMaxAmount } from '../send-amount-row/amount-max-button/amount-max-button.utils' import { getBasicGasEstimateLoadingStatus, getRenderableEstimateDataForSmallButtonsFromGWEI, @@ -18,6 +24,7 @@ import { } from '../../../../selectors/custom-gas' import { showGasButtonGroup, + updateSendErrors, } from '../../../../ducks/send/send.duck' import { resetCustomData, @@ -25,10 +32,11 @@ import { setCustomGasLimit, } from '../../../../ducks/gas/gas.duck' import { getGasLoadingError, gasFeeIsInError, getGasButtonGroupShown } from './send-gas-row.selectors.js' -import { showModal, setGasPrice, setGasLimit, setGasTotal } from '../../../../store/actions' +import { showModal, setGasPrice, setGasLimit, setGasTotal, updateSendAmount } from '../../../../store/actions' import { getAdvancedInlineGasShown, getCurrentEthBalance, getSelectedToken } from '../../../../selectors/selectors' import SendGasRow from './send-gas-row.component' + export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(SendGasRow) function mapStateToProps (state) { @@ -49,6 +57,7 @@ function mapStateToProps (state) { }) return { + balance: getSendFromBalance(state), conversionRate, convertedCurrency: getCurrentCurrency(state), gasTotal, @@ -65,6 +74,9 @@ function mapStateToProps (state) { gasPrice, gasLimit, insufficientBalance, + maxModeOn: getMaxModeOn(state), + selectedToken: getSelectedToken(state), + tokenBalance: getTokenBalance(state), } } @@ -85,6 +97,10 @@ function mapDispatchToProps (dispatch) { dispatch(setGasTotal(calcGasTotal(newLimit, gasPrice))) } }, + setAmountToMax: maxAmountDataObject => { + dispatch(updateSendErrors({ amount: null })) + dispatch(updateSendAmount(calcMaxAmount(maxAmountDataObject))) + }, showGasButtonGroup: () => dispatch(showGasButtonGroup()), resetCustomData: () => dispatch(resetCustomData()), } diff --git a/ui/app/pages/send/send-content/send-gas-row/tests/send-gas-row-container.test.js b/ui/app/pages/send/send-content/send-gas-row/tests/send-gas-row-container.test.js index ddc6ea985..4acb310f8 100644 --- a/ui/app/pages/send/send-content/send-gas-row/tests/send-gas-row-container.test.js +++ b/ui/app/pages/send/send-content/send-gas-row/tests/send-gas-row-container.test.js @@ -44,6 +44,11 @@ proxyquire('../send-gas-row.container.js', { getGasPrice: (s) => `mockGasPrice:${s}`, getGasLimit: (s) => `mockGasLimit:${s}`, getSendAmount: (s) => `mockSendAmount:${s}`, + getSendFromBalance: (s) => `mockBalance:${s}`, + getTokenBalance: (s) => `mockTokenBalance:${s}`, + }, + '../send-amount-row/amount-max-button/amount-max-button.selectors': { + getMaxModeOn: (s) => `mockMaxModeOn:${s}`, }, '../../send.utils.js': { isBalanceSufficient: ({ @@ -75,6 +80,7 @@ describe('send-gas-row container', () => { it('should map the correct properties to props', () => { assert.deepEqual(mapStateToProps('mockState'), { + balance: 'mockBalance:mockState', conversionRate: 'mockConversionRate:mockState', convertedCurrency: 'mockConvertedCurrency:mockState', gasTotal: 'mockGasTotal:mockState', @@ -91,6 +97,9 @@ describe('send-gas-row container', () => { gasLimit: 'mockGasLimit:mockState', gasPrice: 'mockGasPrice:mockState', insufficientBalance: false, + maxModeOn: 'mockMaxModeOn:mockState', + selectedToken: false, + tokenBalance: 'mockTokenBalance:mockState', }) }) diff --git a/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js b/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js index 61bc7bab7..0be01996a 100644 --- a/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js +++ b/ui/app/pages/send/send-content/send-row-wrapper/send-row-error-message/send-row-error-message.component.js @@ -1,5 +1,6 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' export default class SendRowErrorMessage extends Component { @@ -19,7 +20,7 @@ export default class SendRowErrorMessage extends Component { return ( errorMessage - ?
{this.context.t(errorMessage)}
+ ?
{this.context.t(errorMessage)}
: null ) } diff --git a/ui/app/pages/send/send-content/send-row-wrapper/send-row-wrapper.component.js b/ui/app/pages/send/send-content/send-row-wrapper/send-row-wrapper.component.js index 94309bd96..075b86633 100644 --- a/ui/app/pages/send/send-content/send-row-wrapper/send-row-wrapper.component.js +++ b/ui/app/pages/send/send-content/send-row-wrapper/send-row-wrapper.component.js @@ -18,7 +18,7 @@ export default class SendRowWrapper extends Component { t: PropTypes.func, }; - render () { + renderAmountFormRow () { const { children, errorType = '', @@ -34,7 +34,39 @@ export default class SendRowWrapper extends Component {
{label} - {showError && } + {customLabelContent} +
+
+
+ {formField} +
+
+ {showError && } + {!showError && showWarning && } +
+
+
+ ) + } + + renderFormRow () { + const { + children, + errorType = '', + label, + showError = false, + showWarning = false, + warningType = '', + } = this.props + + const formField = Array.isArray(children) ? children[1] || children[0] : children + const customLabelContent = (Array.isArray(children) && children.length) > 1 ? children[0] : null + + return ( +
+
+ {label} + {showError && } {!showError && showWarning && } {customLabelContent}
@@ -45,4 +77,14 @@ export default class SendRowWrapper extends Component { ) } + render () { + const { + errorType = '', + } = this.props + + return ( + errorType === 'amount' ? this.renderAmountFormRow() : this.renderFormRow() + ) + } + } From cfee7e8bb4ebccc6806ec766b09a4edae81133ee Mon Sep 17 00:00:00 2001 From: matteopey Date: Mon, 20 May 2019 18:52:05 +0200 Subject: [PATCH 79/87] Update translation (#6628) --- app/_locales/it/messages.json | 234 +++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 4 deletions(-) diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 9e0f1f06d..09ba045b9 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -11,6 +11,9 @@ "exposeDescription": { "message": "Esporre gli account al sito Web corrente. Utile per dapps legacy." }, + "chartOnlyAvailableEth": { + "message": "Grafico disponibile solo per le reti Ethereum." + }, "confirmExpose": { "message": "Sei sicuro di voler esporre i tuoi account al sito web corrente?" }, @@ -41,6 +44,15 @@ "providerRequestInfo": { "message": "Il dominio elencato di seguito sta tentando di richiedere l'accesso all'API Ethereum in modo che possa interagire con la blockchain di Ethereum. Controlla sempre di essere sul sito corretto prima di approvare l'accesso a Ethereum." }, + "about": { + "message": "Informazioni" + }, + "aboutSettingsDescription": { + "message": "Version, centro di supporto e contatti." + }, + "aboutUs": { + "message": "Chi siamo" + }, "accept": { "message": "Accetta" }, @@ -71,6 +83,15 @@ "address": { "message": "Indirizzo" }, + "addNetwork": { + "message": "Aggiungi Rete" + }, + "advanced": { + "message": "Avanzate" + }, + "advancedSettingsDescription": { + "message": "Accedi alle funzionalità sviluppatore, download dei log di Stato, Reset Account, imposta reti di test e RPC personalizzata." + }, "advancedOptions": { "message": "Opzioni Avanzate" }, @@ -89,8 +110,14 @@ "addAcquiredTokens": { "message": "Aggiungi i token che hai acquistato usando MetaMask" }, - "advanced": { - "message": "Avanzato" + "agreeTermsOfService": { + "message": "Accetto i termini di servizio" + }, + "allDone": { + "message": "Tutto Fatto" + }, + "alreadyHaveSeedPhrase": { + "message": "No, ho già una frase seed" }, "amount": { "message": "Importo" @@ -115,6 +142,9 @@ "approved": { "message": "Approvato" }, + "asset": { + "message": "Asset" + }, "attemptingConnect": { "message": "Tentativo di connessione alla blockchain." }, @@ -127,6 +157,12 @@ "attributions": { "message": "Attribuzioni" }, + "autoLogoutTimeLimit": { + "message": "Timer di Logout Automatico (minuti)" + }, + "autoLogoutTimeLimitDescription": { + "message": "Imposta il tempo di inattività dopo il quale MetaMask fa il log out automaticamente" + }, "available": { "message": "Disponibile" }, @@ -158,6 +194,13 @@ "message": "deve essere maggiore o uguale a $1 e minore o uguale a $2.", "description": "aiuto per inserire un input esadecimale come decimale" }, + "blockExplorerUrl": { + "message": "Block Explorer" + }, + "blockExplorerView": { + "message": "Visualizza account su $1", + "description": "$1 replaced by URL for custom block explorer" + }, "blockiesIdenticon": { "message": "Usa le icone Blockie" }, @@ -179,6 +222,12 @@ "buyCoinbaseExplainer": { "message": "Coinbase è il servizio più popolare al mondo per comprare e vendere Bitcoin, Ethereum e Litecoin." }, + "buyWithWyre": { + "message": "Compra ETH con Wyre" + }, + "buyWithWyreDescription": { + "message": "Wyre ti consente di usare la carta di credito per depositare ETH direttamente nel tuo account MetaMask." + }, "buyCoinSwitch": { "message": "Compra su CoinSwitch" }, @@ -191,6 +240,9 @@ "ok": { "message": "Ok" }, + "optionalBlockExplorerUrl": { + "message": "URL del Block Explorer (opzionale)" + }, "cancel": { "message": "Annulla" }, @@ -206,6 +258,9 @@ "cancelN": { "message": "Annulla tutte le transazioni relative a $1" }, + "chainId": { + "message": "Chain ID" + }, "classicInterface": { "message": "Usa l'interfaccia classica" }, @@ -224,6 +279,9 @@ "chromeRequiredForHardwareWallets": { "message": "Devi usare MetaMask con Google Chrome per connettere il tuo Portafoglio Hardware" }, + "company": { + "message": "Azienda" + }, "confirm": { "message": "Conferma" }, @@ -245,6 +303,9 @@ "confirmTransaction": { "message": "Conferma Transazione" }, + "congratulations": { + "message": "Congratulazioni" + }, "connectHardwareWallet": { "message": "Connetti Portafoglio Hardware" }, @@ -272,6 +333,12 @@ "connectingToRinkeby": { "message": "Connessione alla Rete di test Rinkeby" }, + "connectingToLocalhost": { + "message": "Connessione a Localhost 8545" + }, + "connectingToGoerli": { + "message": "Connessione alla Rete di Test Goerli" + }, "connectingToUnknown": { "message": "Connessione ad una Rete Sconosciuta" }, @@ -287,6 +354,9 @@ "continueToCoinbase": { "message": "Continua su Coinbase" }, + "continueToWyre": { + "message": "Continua su Wyre" + }, "continueToCoinSwitch": { "message": "Continua su CoinSwitch" }, @@ -314,6 +384,12 @@ "copyAddress": { "message": "Copia l'indirizzo" }, + "copyTransactionId": { + "message": "Copia ID Transazione" + }, + "copiedTransactionId": { + "message": "ID Transazione Copiato" + }, "copyToClipboard": { "message": "Copia negli appunti" }, @@ -329,6 +405,9 @@ "createAccount": { "message": "Crea Account" }, + "createAWallet": { + "message": "Crea un Wallet" + }, "createDen": { "message": "Crea" }, @@ -439,6 +518,9 @@ "edit": { "message": "Modifica" }, + "editNetwork": { + "message": "Modifica Rete" + }, "editAccountName": { "message": "Modifica Nome Account" }, @@ -451,6 +533,30 @@ "encryptNewDen": { "message": "Cripta il tuo nuovo DEN" }, + "endOfFlowMessage1": { + "message": "Hai passato il test - tieni la tua frase seed al sicuro, è tua responsabilità!" + }, + "endOfFlowMessage2": { + "message": "Suggerimenti su come tenerla al sicuro" + }, + "endOfFlowMessage3": { + "message": "Salva un backup in più di un posto." + }, + "endOfFlowMessage4": { + "message": "Non condividerla mai con nessuno." + }, + "endOfFlowMessage5": { + "message": "Stai attento al phishing! MetaMask non ti chiederà mai spontaneamente la tua frase seed." + }, + "endOfFlowMessage6": { + "message": "Se vorrai fare nuovamente un backup della frase, la puoi trovare in Impostazioni -> Sicurezza & Privacy." + }, + "endOfFlowMessage7": { + "message": "Se hai delle domande o vedi delle attività sospette, manda una mail a support@metamask.io." + }, + "endOfFlowMessage8": { + "message": "MetaMask non può recuperare la tua frase seed. Impara di più." + }, "ensNameNotFound": { "message": "Nome ENS non trovato" }, @@ -571,6 +677,12 @@ "gasPriceRequired": { "message": "Prezzo Gas Richiesto" }, + "general": { + "message": "Generale" + }, + "generalSettingsDescription": { + "message": "Conversione moneta, moneta primaria, lingua, icone blockie" + }, "generatingTransaction": { "message": "Generando la transazione" }, @@ -584,10 +696,16 @@ "getHelp": { "message": "Aiuto." }, + "getStarted": { + "message": "Inizia" + }, "greaterThanMin": { "message": "deve essere maggiore o uguale a $1.", "description": "aiuto per inserire un input esadecimale come decimale" }, + "happyToSeeYou": { + "message": "Siamo contenti di vederti." + }, "hardware": { "message": "hardware" }, @@ -650,6 +768,12 @@ "importDen": { "message": "Importa un DEN Esistente" }, + "importWallet": { + "message": "Importa Portafoglio" + }, + "importYourExisting": { + "message": "Importa il tuo portafoglio esistente usando la tua frase seed a 12 parole" + }, "imported": { "message": "Importato", "description": "stato che conferma che un account è stato totalmente caricato nel portachiavi" @@ -687,6 +811,9 @@ "knownAddressRecipient": { "message": "Indirizzo del contratto conosciuto." }, + "invalidAddressRecipientNotEthNetwork": { + "message": "Non rete ETH, inserisci caratteri minuscoli" + }, "invalidGasParams": { "message": "Parametri del Gas non validi" }, @@ -727,10 +854,16 @@ "ledgerAccountRestriction": { "message": "E' necessario utilizzare l'ultimo account prima di poterne aggiungere uno nuovo." }, + "legal": { + "message": "Informazioni Legali" + }, "lessThanMax": { "message": "deve essere minore o uguale a $1.", "description": "aiuto per inserire un input esadecimale come decimale" }, + "letsGoSetUp": { + "message": "Si, iniziamo!" + }, "likeToAddTokens": { "message": "Vorresti aggiungere questi token?" }, @@ -794,6 +927,12 @@ "minutesShorthand": { "message": "Min" }, + "mobileSyncTitle": { + "message": "Sincronizza account con il dispositivo mobile" + }, + "mobileSyncText": { + "message": "Per favore inserisci la password per confermare che sei te!" + }, "myAccounts": { "message": "Miei Account" }, @@ -814,9 +953,15 @@ "negativeETH": { "message": "Non puoi inviare una quantità di ETH negativa." }, + "networkName": { + "message": "Nome Rete" + }, "networks": { "message": "Reti" }, + "networkSettingsDescription": { + "message": "Aggiungi e modifica reti RPC personalizzate" + }, "nevermind": { "message": "Non importa" }, @@ -842,7 +987,22 @@ "newNetwork": { "message": "Nuova Rete" }, - "rpcURL": { + "newToMetaMask": { + "message": "Nuovo a MetaMask?" + }, + "noAlreadyHaveSeed": { + "message": "No, ho già una frase seed" + }, + "protectYourKeys": { + "message": "Proteggi le tue chiavi!" + }, + "protectYourKeysMessage1": { + "message": "Stai attento con la tua frase seed - ci sono stati report di siti web che hanno tentato di imitare MetaMask. MetaMask non ti chiederà mai la tua frase seed!" + }, + "protectYourKeysMessage2": { + "message": "Tieni la tua frase al sicuro. Se vedi qualcosa di sospetto, o non sei sicuro di un sito web, manda una mail a support@metamask.io" + }, + "rpcUrl": { "message": "Nuovo URL RPC" }, "showAdvancedOptions": { @@ -884,6 +1044,9 @@ "noTransactions": { "message": "Nessuna Transazione" }, + "notEnoughGas": { + "message": "Gas Non Sufficiente" + }, "notFound": { "message": "Non Trovata" }, @@ -934,6 +1097,12 @@ "originalTotal": { "message": "Totale Precedente" }, + "participateInMetaMetrics": { + "message": "Participa in MetaMetrics" + }, + "participateInMetaMetricsDescription": { + "message": "Participa in MetaMetrics per aiutarci a rendere MetaMask migliore" + }, "password": { "message": "Password" }, @@ -1097,6 +1266,9 @@ "ropsten": { "message": "Rete di test Ropsten" }, + "goerli": { + "message": "Rete di test Goerli" + }, "rpc": { "message": "RPC Personalizzata" }, @@ -1147,6 +1319,12 @@ "secretPhrase": { "message": "Inserisci la tua frase segreta di dodici parole per ripristinare la cassaforte." }, + "securityAndPrivacy": { + "message": "Sicurezza & Privacy" + }, + "securitySettingsDescription": { + "message": "Impostazioni sulla Privacy e sulla frase seed del portafoglio" + }, "secondsShorthand": { "message": "Sec" }, @@ -1207,6 +1385,9 @@ "selectAnAccountHelp": { "message": "Selezione l'account da visualizzare in MetaMask" }, + "selectAnAsset": { + "message": "Seleziona un Asset" + }, "selectAHigherGasFee": { "message": "Seleziona un costo in gas maggiore per accelerare l'elaborazione della transazione.*" }, @@ -1229,7 +1410,13 @@ "message": "Controlli gas avanzati" }, "showAdvancedGasInlineDescription": { - "message": "Seleziona qui per visualizzare i controlli su prezzo e limite del gas nelle schermate di invio e conferma." + "message": "Seleziona per visualizzare i controlli su prezzo e limite del gas nelle schermate di invio e conferma." + }, + "showFiatConversionInTestnets": { + "message": "Mostra conversione nelle reti di test" + }, + "showFiatConversionInTestnetsDescription": { + "message": "Seleziona se vuoi vedere la conversione in valuta fiat nelle reti di test" }, "showPrivateKeys": { "message": "Mostra Chiave Privata" @@ -1330,9 +1517,33 @@ "supportCenter": { "message": "Visita il nostro Centro di Supporto" }, + "symbol": { + "message": "Simbolo" + }, "symbolBetweenZeroTwelve": { "message": "Il simbolo deve essere lungo tra 0 e 12 caratteri." }, + "syncWithMobile": { + "message": "Sincronizza con dispositivo mobile" + }, + "syncWithMobileTitle": { + "message": "Sincronizza con dispositivo mobile" + }, + "syncWithMobileDesc": { + "message": "Puoi sincronizzare i tuoi account e le tue informazioni con il tuo dispositivo mobile. Apri l'app di MetaMask, vai su \"Impostazioni\" e tocca \"Sincronizza da Estensione sul Browser\"" + }, + "syncWithMobileDescNewUsers": { + "message": "Se hai appena aperto l'app di MetaMask per la prima volta, segui i passaggi sul tuo telefono." + }, + "syncWithMobileScanThisCode": { + "message": "Scansiona questo codice con l'app di MetaMask" + }, + "syncWithMobileBeCareful": { + "message": "Assicurati che nessun'altro stia guardando al tuo schermo quando scansioni questo codice" + }, + "syncWithMobileComplete": { + "message": "I tuoi dati sono stati sincronizzati con successo. Goditi l'app di MetaMask!" + }, "takesTooLong": { "message": "Ci sta mettendo troppo?" }, @@ -1342,6 +1553,9 @@ "testFaucet": { "message": "Prova Faucet" }, + "thisWillCreate": { + "message": "Questo creerà un nuovo portafoglio e frase seed" + }, "tips": { "message": "Suggerimenti" }, @@ -1364,6 +1578,9 @@ "tokenBalance": { "message": "Bilancio Token:" }, + "tokenContractAddress": { + "message": "Indirizzo Contratto Token" + }, "tokenSelection": { "message": "Cerca un token o seleziona dalla lista di token più popolari." }, @@ -1525,9 +1742,15 @@ "viewAccount": { "message": "Vedi Account" }, + "viewOnCustomBlockExplorer": { + "message": "Vedi su $1" + }, "viewOnEtherscan": { "message": "Vedi su Etherscan" }, + "viewNetworkInfo": { + "message": "Visualizza Informazioni Rete" + }, "visitWebSite": { "message": "Visita il nostro sito web" }, @@ -1573,6 +1796,9 @@ "yourUniqueAccountImageDescription2": { "message": "Vedrai questa immagine ogni volta che dovrai confermare una transazione." }, + "yourUniqueAccountImageDescription3": { + "message": "MetaMask non ti chiederà mai la tua frase seed!" + }, "zeroGasPriceOnSpeedUpError": { "message": "Prezzo del gas maggiore di zero" } From 32547383603b24849db8f83103ec72c0b3dc29ed Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Mon, 20 May 2019 15:02:26 -0230 Subject: [PATCH 80/87] MetaMetrics documentation (#6624) --- docs/creating-metrics-events.md | 71 ++++++++++++++++++++++++ ui/app/helpers/utils/metametrics.util.js | 63 ++++++++++++++++----- 2 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 docs/creating-metrics-events.md diff --git a/docs/creating-metrics-events.md b/docs/creating-metrics-events.md new file mode 100644 index 000000000..7e7f2d77d --- /dev/null +++ b/docs/creating-metrics-events.md @@ -0,0 +1,71 @@ +## Creating Metrics Events + +The `metricsEvent` method is made available to all components via context. This is done in `metamask-extension/ui/app/helpers/higher-order-components/metametrics/metametrics.provider.js`. As such, it can be called in all components by first adding it to the context proptypes: + +``` +static contextTypes = { + t: PropTypes.func, + metricsEvent: PropTypes.func, +} +``` + +and then accessing it on `this.context`. + +Below is an example of a metrics event call: + +``` +this.context.metricsEvent({ + eventOpts: { + category: 'Navigation', + action: 'Main Menu', + name: 'Switched Account', + }, +}) +``` + +### Base Schema + +Every `metricsEvent` call is passed an object that must have an `eventOpts` property. This property is an object that itself must have three properties: +- category: categorizes events according to the schema we have set up in our matomo.org instance +- action: usually describes the page on which the event takes place, or sometimes a significant subsections of a page +- name: a very specific descriptor of the event + +### Implicit properties + +All metrics events send the following data when called: +- network +- environmentType +- activeCurrency +- accountType +- numberOfTokens +- numberOfAccounts + +These are added to the metrics event via the metametrics provider. + +### Custom Variables + +Metrics events can include custom variables. These are included within the `customVariables` property that is a first-level property within first param passed to `metricsEvent`. + +For example: +``` +this.context.metricsEvent({ + eventOpts: { + category: 'Settings', + action: 'Custom RPC', + name: 'Error', + }, + customVariables: { + networkId: newRpc, + chainId, + }, +}) +``` + +Custom variables can have custom property names and values can be strings or numbers. + +**To include a custom variable, there are a set of necessary steps you must take.** + +1. First you must declare a constant equal to the desired name of the custom variable property in `metamask-extension/ui/app/helpers/utils/metametrics.util.js` under `//Custom Variable Declarations` +1. Then you must add that name to the `customVariableNameIdMap` declaration + 1. The id must be between 1 and 5 + 1. There can be no more than 5 custom variables assigned ids on a given url diff --git a/ui/app/helpers/utils/metametrics.util.js b/ui/app/helpers/utils/metametrics.util.js index cafbd5c07..50270c6a8 100644 --- a/ui/app/helpers/utils/metametrics.util.js +++ b/ui/app/helpers/utils/metametrics.util.js @@ -12,6 +12,8 @@ const METAMETRICS_TRACKING_URL = inDevelopment ? 'http://www.metamask.io/metametrics' : 'http://www.metamask.io/metametrics-prod' +/** ***************Custom variables*************** **/ +// Custon variable declarations const METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE = 'gasLimitChange' const METAMETRICS_CUSTOM_GAS_PRICE_CHANGE = 'gasPriceChange' const METAMETRICS_CUSTOM_FUNCTION_TYPE = 'functionType' @@ -24,6 +26,28 @@ const METAMETRICS_CUSTOM_ERROR_MESSAGE = 'errorMessage' const METAMETRICS_CUSTOM_RPC_NETWORK_ID = 'networkId' const METAMETRICS_CUSTOM_RPC_CHAIN_ID = 'chainId' const METAMETRICS_CUSTOM_GAS_CHANGED = 'gasChanged' +const METAMETRICS_CUSTOM_ASSET_SELECTED = 'assetSelected' + +const customVariableNameIdMap = { + [METAMETRICS_CUSTOM_FUNCTION_TYPE]: 1, + [METAMETRICS_CUSTOM_RECIPIENT_KNOWN]: 2, + [METAMETRICS_CUSTOM_CONFIRM_SCREEN_ORIGIN]: 3, + [METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE]: 4, + [METAMETRICS_CUSTOM_GAS_PRICE_CHANGE]: 5, + + [METAMETRICS_CUSTOM_FROM_NETWORK]: 1, + [METAMETRICS_CUSTOM_TO_NETWORK]: 2, + + [METAMETRICS_CUSTOM_RPC_NETWORK_ID]: 1, + [METAMETRICS_CUSTOM_RPC_CHAIN_ID]: 2, + + [METAMETRICS_CUSTOM_ERROR_FIELD]: 3, + [METAMETRICS_CUSTOM_ERROR_MESSAGE]: 4, + + [METAMETRICS_CUSTOM_GAS_CHANGED]: 1, + [METAMETRICS_CUSTOM_ASSET_SELECTED]: 2, +} +/** ********************************************************** **/ const METAMETRICS_CUSTOM_NETWORK = 'network' const METAMETRICS_CUSTOM_ENVIRONMENT_TYPE = 'environmentType' @@ -32,20 +56,6 @@ const METAMETRICS_CUSTOM_ACCOUNT_TYPE = 'accountType' const METAMETRICS_CUSTOM_NUMBER_OF_TOKENS = 'numberOfTokens' const METAMETRICS_CUSTOM_NUMBER_OF_ACCOUNTS = 'numberOfAccounts' -const customVariableNameIdMap = { - [METAMETRICS_CUSTOM_FUNCTION_TYPE]: 1, - [METAMETRICS_CUSTOM_RECIPIENT_KNOWN]: 2, - [METAMETRICS_CUSTOM_CONFIRM_SCREEN_ORIGIN]: 3, - [METAMETRICS_CUSTOM_GAS_LIMIT_CHANGE]: 4, - [METAMETRICS_CUSTOM_GAS_PRICE_CHANGE]: 5, - [METAMETRICS_CUSTOM_FROM_NETWORK]: 1, - [METAMETRICS_CUSTOM_TO_NETWORK]: 2, - [METAMETRICS_CUSTOM_RPC_NETWORK_ID]: 1, - [METAMETRICS_CUSTOM_RPC_CHAIN_ID]: 2, - [METAMETRICS_CUSTOM_ERROR_FIELD]: 1, - [METAMETRICS_CUSTOM_ERROR_MESSAGE]: 2, - [METAMETRICS_CUSTOM_GAS_CHANGED]: 1, -} const customDimensionsNameIdMap = { [METAMETRICS_CUSTOM_NETWORK]: 5, @@ -61,6 +71,7 @@ function composeUrlRefParamAddition (previousPath, confirmTransactionOrigin) { return `&urlref=${externalOrigin ? 'EXTERNAL' : encodeURIComponent(previousPath.replace(/chrome-extension:\/\/\w+/, METAMETRICS_TRACKING_URL))}` } +// composes query params of the form &dimension[0-999]=[value] function composeCustomDimensionParamAddition (customDimensions) { const customDimensionParamStrings = Object.keys(customDimensions).reduce((acc, name) => { return [...acc, `dimension${customDimensionsNameIdMap[name]}=${customDimensions[name]}`] @@ -68,6 +79,8 @@ function composeCustomDimensionParamAddition (customDimensions) { return `&${customDimensionParamStrings.join('&')}` } +// composes query params in form: &cvar={[id]:[[name],[value]]} +// Example: &cvar={"1":["OS","iphone 5.0"],"2":["Matomo Mobile Version","1.6.2"],"3":["Locale","en::en"],"4":["Num Accounts","2"]} function composeCustomVarParamAddition (customVariables) { const customVariableIdValuePairs = Object.keys(customVariables).reduce((acc, name) => { return { @@ -84,6 +97,28 @@ function composeParamAddition (paramValue, paramName) { : `&${paramName}=${paramValue}` } +/** + * @name composeUrl + * @param {Object} config - configuration object for composing the metametrics url + * @property {object} config.eventOpts Object containing event category, action and name descriptors + * @property {object} config.customVariables Object containing custom properties with values relevant to a specific event + * @property {object} config.pageOpts Objects containing information about a page/route the event is dispatched from + * @property {number} config.network The selected network of the user when the event occurs + * @property {string} config.environmentType The "environment" the user is using the app from: 'popup', 'notification' or 'fullscreen' + * @property {string} config.activeCurrency The current the user has select as their primary currency at the time of the event + * @property {string} config.accountType The account type being used at the time of the event: 'hardware', 'imported' or 'default' + * @property {number} config.numberOfTokens The number of tokens that the user has added at the time of the event + * @property {number} config.numberOfAccounts The number of accounts the user has added at the time of the event + * @property {string} config.previousPath The location path the user was on prior to the path they are on at the time of the event + * @property {string} config.currentPath The location path the user is on at the time of the event + * @property {string} config.metaMetricsId A random id assigned to a user at the time of opting in to metametrics. A hexadecimal number + * @property {string} config.confirmTransactionOrigin The origin on a transaction + * @property {string} config.url The url to track an event at. Overrides `currentPath` + * @property {boolean} config.excludeMetaMetricsId Whether or not the tracked event data should be associated with a metametrics id + * @property {boolean} config.isNewVisit Whether or not the event should be tracked as a new visit/user sessions + * @returns {String} Returns a url to be passed to fetch to make the appropriate request to matomo. + * Example: https://chromeextensionmm.innocraft.cloud/piwik.php?idsite=1&rec=1&apiv=1&e_c=Navigation&e_a=Home&e_n=Clicked%20Send:%20Eth&urlref=http%3A%2F%2Fwww.metamask.io%2Fmetametrics%2Fhome.html%23send&dimension5=3&dimension6=fullscreen&dimension7=ETH&dimension8=default&dimension9=0&dimension10=3&url=http%3A%2F%2Fwww.metamask.io%2Fmetametrics%2Fhome.html%23&_id=49c10aff19795e9a&rand=7906028754863992&pv_id=53acad&uid=49c1 + */ function composeUrl (config) { const { eventOpts = {}, From 5f307040f28e0f1617028397f7978bb9ec38044e Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Mon, 20 May 2019 15:06:28 -0230 Subject: [PATCH 81/87] Remove unused fn arguments in AmountMaxButton --- .../amount-max-button/amount-max-button.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js index 249703763..7901ccef6 100644 --- a/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js +++ b/ui/app/pages/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js @@ -40,7 +40,7 @@ export default class AmountMaxButton extends Component { }) } - onMaxClick = (event) => { + onMaxClick = () => { const { setMaxModeTo, clearMaxAmount, maxModeOn } = this.props const { metricsEvent } = this.context From e0c11371a9d5f419d91a6d30d2cfda1743d2a967 Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Tue, 21 May 2019 05:59:09 -0700 Subject: [PATCH 82/87] Fix grammatical error in i18n endOfFlowMessage6 (#6633) --- app/_locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 47c1cfde8..41ba7ef7a 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -549,7 +549,7 @@ "message": "Be careful of phishing! MetaMask will never spontaneously ask for your seed phrase." }, "endOfFlowMessage6": { - "message": "If you need to back your up seed phrase again, you can find it in Settings -> Security." + "message": "If you need to back up your seed phrase again, you can find it in Settings -> Security." }, "endOfFlowMessage7": { "message": "If you ever have questions or see something fishy, email support@metamask.io." From 2b5c7b82a95dea4ddb50917daa52fae07715e210 Mon Sep 17 00:00:00 2001 From: Frankie Date: Tue, 21 May 2019 17:17:09 +0200 Subject: [PATCH 83/87] transactions/deps - use broken out nonce-tracker module (#6555) --- app/scripts/controllers/transactions/index.js | 2 +- .../controllers/transactions/nonce-tracker.js | 161 ------------ package-lock.json | 79 +++++- package.json | 1 + .../transactions/nonce-tracker-test.js | 238 ------------------ 5 files changed, 74 insertions(+), 407 deletions(-) delete mode 100644 app/scripts/controllers/transactions/nonce-tracker.js delete mode 100644 test/unit/app/controllers/transactions/nonce-tracker-test.js diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index dd497a11e..1ae925835 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -17,7 +17,7 @@ const { const TransactionStateManager = require('./tx-state-manager') const TxGasUtil = require('./tx-gas-utils') const PendingTransactionTracker = require('./pending-tx-tracker') -const NonceTracker = require('./nonce-tracker') +const NonceTracker = require('nonce-tracker') const txUtils = require('./lib/util') const cleanErrorStack = require('../../lib/cleanErrorStack') const log = require('loglevel') diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js deleted file mode 100644 index 421036368..000000000 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ /dev/null @@ -1,161 +0,0 @@ -const EthQuery = require('ethjs-query') -const assert = require('assert') -const Mutex = require('await-semaphore').Mutex -/** - @param opts {Object} - @param {Object} opts.provider a ethereum provider - @param {Function} opts.getPendingTransactions a function that returns an array of txMeta - whosee status is `submitted` - @param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta - whose status is `confirmed` - @class -*/ -class NonceTracker { - - constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) { - this.provider = provider - this.blockTracker = blockTracker - this.ethQuery = new EthQuery(provider) - this.getPendingTransactions = getPendingTransactions - this.getConfirmedTransactions = getConfirmedTransactions - this.lockMap = {} - } - - /** - @returns {Promise} with the key releaseLock (the gloabl mutex) - */ - async getGlobalLock () { - const globalMutex = this._lookupMutex('global') - // await global mutex free - const releaseLock = await globalMutex.acquire() - return { releaseLock } - } - - /** - * @typedef NonceDetails - * @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction. - * @property {number} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method. - * @property {number} highestSuggested - The maximum between the other two, the number returned. - */ - - /** - this will return an object with the `nextNonce` `nonceDetails` of type NonceDetails, and the releaseLock - Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding). - - @param address {string} the hex string for the address whose nonce we are calculating - @returns {Promise} - */ - async getNonceLock (address) { - // await global mutex free - await this._globalMutexFree() - // await lock free, then take lock - const releaseLock = await this._takeMutex(address) - try { - // evaluate multiple nextNonce strategies - const nonceDetails = {} - const networkNonceResult = await this._getNetworkNextNonce(address) - const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) - const nextNetworkNonce = networkNonceResult.nonce - const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) - - const pendingTxs = this.getPendingTransactions(address) - const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 - - nonceDetails.params = { - highestLocallyConfirmed, - highestSuggested, - nextNetworkNonce, - } - nonceDetails.local = localNonceResult - nonceDetails.network = networkNonceResult - - const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce) - assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) - - // return nonce and release cb - return { nextNonce, nonceDetails, releaseLock } - } catch (err) { - // release lock if we encounter an error - releaseLock() - throw err - } - } - - async _globalMutexFree () { - const globalMutex = this._lookupMutex('global') - const releaseLock = await globalMutex.acquire() - releaseLock() - } - - async _takeMutex (lockId) { - const mutex = this._lookupMutex(lockId) - const releaseLock = await mutex.acquire() - return releaseLock - } - - _lookupMutex (lockId) { - let mutex = this.lockMap[lockId] - if (!mutex) { - mutex = new Mutex() - this.lockMap[lockId] = mutex - } - return mutex - } - - async _getNetworkNextNonce (address) { - // calculate next nonce - // we need to make sure our base count - // and pending count are from the same block - const blockNumber = await this.blockTracker.getLatestBlock() - const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber) - const baseCount = baseCountBN.toNumber() - assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) - const nonceDetails = { blockNumber, baseCount } - return { name: 'network', nonce: baseCount, details: nonceDetails } - } - - _getHighestLocallyConfirmed (address) { - const confirmedTransactions = this.getConfirmedTransactions(address) - const highest = this._getHighestNonce(confirmedTransactions) - return Number.isInteger(highest) ? highest + 1 : 0 - } - - _getHighestNonce (txList) { - const nonces = txList.map((txMeta) => { - const nonce = txMeta.txParams.nonce - assert(typeof nonce, 'string', 'nonces should be hex strings') - return parseInt(nonce, 16) - }) - const highestNonce = Math.max.apply(null, nonces) - return highestNonce - } - - /** - @typedef {object} highestContinuousFrom - @property {string} - name the name for how the nonce was calculated based on the data used - @property {number} - nonce the next suggested nonce - @property {object} - details the provided starting nonce that was used (for debugging) - */ - /** - @param txList {array} - list of txMeta's - @param startPoint {number} - the highest known locally confirmed nonce - @returns {highestContinuousFrom} - */ - _getHighestContinuousFrom (txList, startPoint) { - const nonces = txList.map((txMeta) => { - const nonce = txMeta.txParams.nonce - assert(typeof nonce, 'string', 'nonces should be hex strings') - return parseInt(nonce, 16) - }) - - let highest = startPoint - while (nonces.includes(highest)) { - highest++ - } - - return { name: 'local', nonce: highest, details: { startPoint, highest } } - } - -} - -module.exports = NonceTracker diff --git a/package-lock.json b/package-lock.json index 8844b21a5..526420356 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8854,7 +8854,7 @@ }, "engine.io-client": { "version": "3.2.1", - "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", "dev": true, "requires": { @@ -9473,7 +9473,7 @@ }, "inquirer": { "version": "0.12.0", - "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "dev": true, "requires": { @@ -9566,7 +9566,7 @@ }, "table": { "version": "3.8.3", - "resolved": "http://registry.npmjs.org/table/-/table-3.8.3.tgz", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "dev": true, "requires": { @@ -10157,7 +10157,7 @@ "dependencies": { "babelify": { "version": "7.3.0", - "resolved": "http://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", "dev": true, "requires": { @@ -15815,6 +15815,23 @@ "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } } }, "ethereumjs-block": { @@ -19798,6 +19815,23 @@ "requires": { "bn.js": "^4.11.8", "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.1.0.tgz", + "integrity": "sha512-URESKMFbDeJxnAxPppnk2fN6Y3BIatn9fwn76Lm8bQlt+s52TpG8dN9M66MLPuRAiAOIqL3dfwqWJf0sd0fL0Q==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "0.1.6", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } } }, "ethereumjs-block": { @@ -20952,7 +20986,7 @@ }, "got": { "version": "5.6.0", - "resolved": "http://registry.npmjs.org/got/-/got-5.6.0.tgz", + "resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz", "integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=", "dev": true, "requires": { @@ -27909,6 +27943,37 @@ "underscore": "~1.4.4" } }, + "nonce-tracker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nonce-tracker/-/nonce-tracker-1.0.0.tgz", + "integrity": "sha512-hxKokxgLvOZx9A5qPQKwL34G1/YwMC5xJWZHFUKfvwxypkn2nP0KVJjbcoXwY6pXsRRa11KdFEPW61N4YCGnWQ==", + "requires": { + "assert": "^1.4.1", + "await-semaphore": "^0.1.3", + "ethjs-query": "^0.3.8" + }, + "dependencies": { + "ethjs-query": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.8.tgz", + "integrity": "sha512-/J5JydqrOzU8O7VBOwZKUWXxHDGr46VqNjBCJgBVNNda+tv7Xc8Y2uJc6aMHHVbeN3YOQ7YRElgIc0q1CI02lQ==", + "requires": { + "babel-runtime": "^6.26.0", + "ethjs-format": "0.2.7", + "ethjs-rpc": "0.2.0", + "promise-to-callback": "^1.0.0" + } + }, + "ethjs-rpc": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.2.0.tgz", + "integrity": "sha512-RINulkNZTKnj4R/cjYYtYMnFFaBcVALzbtEJEONrrka8IeoarNB9Jbzn+2rT00Cv8y/CxAI+GgY1d0/i2iQeOg==", + "requires": { + "promise-to-callback": "^1.0.0" + } + } + } + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -30423,7 +30488,7 @@ }, "po2json": { "version": "0.4.5", - "resolved": "http://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", + "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", "integrity": "sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=", "dev": true, "requires": { @@ -35856,7 +35921,7 @@ }, "socket.io-parser": { "version": "3.2.0", - "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", "dev": true, "requires": { diff --git a/package.json b/package.json index 0ae402600..89e0388d4 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "mkdirp": "^0.5.1", "multihashes": "^0.4.12", "multiplex": "^6.7.0", + "nonce-tracker": "^1.0.0", "number-to-bn": "^1.7.0", "obj-multiplex": "^1.0.0", "obs-store": "^3.0.2", diff --git a/test/unit/app/controllers/transactions/nonce-tracker-test.js b/test/unit/app/controllers/transactions/nonce-tracker-test.js deleted file mode 100644 index 51ac390e9..000000000 --- a/test/unit/app/controllers/transactions/nonce-tracker-test.js +++ /dev/null @@ -1,238 +0,0 @@ -const assert = require('assert') -const NonceTracker = require('../../../../../app/scripts/controllers/transactions/nonce-tracker') -const MockTxGen = require('../../../../lib/mock-tx-gen') -const providerResultStub = {} - -describe('Nonce Tracker', function () { - let nonceTracker, pendingTxs, confirmedTxs - - describe('#getNonceLock', function () { - - describe('with 3 confirmed and 1 pending', function () { - beforeEach(function () { - const txGen = new MockTxGen() - confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) - pendingTxs = txGen.generate({ status: 'submitted' }, { count: 1 }) - nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x1') - }) - - it('should return 4', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '4', `nonce should be 4 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - - it('should use localNonce if network returns a nonce lower then a confirmed tx in state', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '4', 'nonce should be 4') - await nonceLock.releaseLock() - }) - }) - - describe('sentry issue 476304902', function () { - beforeEach(function () { - const txGen = new MockTxGen() - pendingTxs = txGen.generate({ status: 'submitted' }, { - fromNonce: 3, - count: 29, - }) - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x3') - }) - - it('should return 9', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '32', `nonce should be 32 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('issue 3670', function () { - beforeEach(function () { - const txGen = new MockTxGen() - pendingTxs = txGen.generate({ status: 'submitted' }, { - fromNonce: 6, - count: 3, - }) - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x6') - }) - - it('should return 9', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('with no previous txs', function () { - beforeEach(function () { - nonceTracker = generateNonceTrackerWith([], []) - }) - - it('should return 0', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 returned ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('with multiple previous txs with same nonce', function () { - beforeEach(function () { - const txGen = new MockTxGen() - confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 1 }) - pendingTxs = txGen.generate({ - status: 'submitted', - txParams: { nonce: '0x01' }, - }, { count: 5 }) - - nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x0') - }) - - it('should return nonce after those', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('when local confirmed count is higher than network nonce', function () { - beforeEach(function () { - const txGen = new MockTxGen() - confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 3 }) - nonceTracker = generateNonceTrackerWith([], confirmedTxs, '0x1') - }) - - it('should return nonce after those', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '3', `nonce should be 3 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('when local pending count is higher than other metrics', function () { - beforeEach(function () { - const txGen = new MockTxGen() - pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) - nonceTracker = generateNonceTrackerWith(pendingTxs, []) - }) - - it('should return nonce after those', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '2', `nonce should be 2 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('when provider nonce is higher than other metrics', function () { - beforeEach(function () { - const txGen = new MockTxGen() - pendingTxs = txGen.generate({ status: 'submitted' }, { count: 2 }) - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x05') - }) - - it('should return nonce after those', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('when there are some pending nonces below the remote one and some over.', function () { - beforeEach(function () { - const txGen = new MockTxGen() - pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x03') - }) - - it('should return nonce after those', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '5', `nonce should be 5 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('when there are pending nonces non sequentially over the network nonce.', function () { - beforeEach(function () { - const txGen = new MockTxGen() - txGen.generate({ status: 'submitted' }, { count: 5 }) - // 5 over that number - pendingTxs = txGen.generate({ status: 'submitted' }, { count: 5 }) - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x00') - }) - - it('should return nonce after network nonce', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '0', `nonce should be 0 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('When all three return different values', function () { - beforeEach(function () { - const txGen = new MockTxGen() - confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 10 }) - pendingTxs = txGen.generate({ - status: 'submitted', - nonce: 100, - }, { count: 1 }) - // 0x32 is 50 in hex: - nonceTracker = generateNonceTrackerWith(pendingTxs, confirmedTxs, '0x32') - }) - - it('should return nonce after network nonce', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '50', `nonce should be 50 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - - describe('Faq issue 67', function () { - beforeEach(function () { - const txGen = new MockTxGen() - confirmedTxs = txGen.generate({ status: 'confirmed' }, { count: 64 }) - pendingTxs = txGen.generate({ - status: 'submitted', - }, { count: 10 }) - // 0x40 is 64 in hex: - nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x40') - }) - - it('should return nonce after network nonce', async function () { - this.timeout(15000) - const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') - assert.equal(nonceLock.nextNonce, '74', `nonce should be 74 got ${nonceLock.nextNonce}`) - await nonceLock.releaseLock() - }) - }) - }) -}) - -function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') { - const getPendingTransactions = () => pending - const getConfirmedTransactions = () => confirmed - providerResultStub.result = providerStub - const provider = { - sendAsync: (_, cb) => { cb(undefined, providerResultStub) }, - } - const blockTracker = { - getCurrentBlock: () => '0x11b568', - getLatestBlock: async () => '0x11b568', - } - return new NonceTracker({ - provider, - blockTracker, - getPendingTransactions, - getConfirmedTransactions, - }) -} From c0607bf2609c35e70e271078997387c33c22aa40 Mon Sep 17 00:00:00 2001 From: Whymarrh Whitby Date: Tue, 21 May 2019 11:37:27 -0230 Subject: [PATCH 84/87] Clean EditorConfig file --- .editorconfig | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.editorconfig b/.editorconfig index 609f684a0..c6c8b3621 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,24 +1,9 @@ -# EditorConfig helps developers define and maintain consistent -# coding styles between different editors and IDEs -# editorconfig.org - root = true - [*] - -# Change these settings to your own preference indent_style = space indent_size = 2 - -[*.json] -indent_size = 2 - -# We recommend you to keep these unchanged end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false From 5e2fd8ae868f1f61096b97ea72afd52651fc925d Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Thu, 23 May 2019 11:26:40 -0230 Subject: [PATCH 85/87] Ensures that transactions cannot be confirmed if gas limit is below 21000. (#6625) --- .../gas-modal-page-container.container.js | 17 +++++++++++++++-- .../confirm-transaction-base.component.js | 9 +++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js index c3fdf51e5..9da9a2ef6 100644 --- a/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js +++ b/ui/app/components/app/gas-customization/gas-modal-page-container/gas-modal-page-container.container.js @@ -201,7 +201,20 @@ const mapDispatchToProps = dispatch => { } const mergeProps = (stateProps, dispatchProps, ownProps) => { - const { gasPriceButtonGroupProps, isConfirm, txId, isSpeedUp, insufficientBalance, maxModeOn, customGasPrice, customGasTotal, balance, selectedToken, tokenBalance} = stateProps + const { + gasPriceButtonGroupProps, + isConfirm, + txId, + isSpeedUp, + insufficientBalance, + maxModeOn, + customGasPrice, + customGasTotal, + balance, + selectedToken, + tokenBalance, + customGasLimit, + } = stateProps const { updateCustomGasPrice: dispatchUpdateCustomGasPrice, hideGasButtonGroup: dispatchHideGasButtonGroup, @@ -251,7 +264,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => { dispatchHideSidebar() } }, - disableSave: insufficientBalance || (isSpeedUp && customGasPrice === 0), + disableSave: insufficientBalance || (isSpeedUp && customGasPrice === 0) || customGasLimit < 21000, } } diff --git a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js index 3c4e6dcac..c6a05cf0f 100644 --- a/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/app/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -9,6 +9,7 @@ import { DEFAULT_ROUTE, CONFIRM_TRANSACTION_ROUTE } from '../../helpers/constant import { INSUFFICIENT_FUNDS_ERROR_KEY, TRANSACTION_ERROR_KEY, + GAS_LIMIT_TOO_LOW_ERROR_KEY, } from '../../helpers/constants/error-keys' import { CONFIRMED_STATUS, DROPPED_STATUS } from '../../helpers/constants/transactions' import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display' @@ -134,6 +135,7 @@ export default class ConfirmTransactionBase extends Component { value: amount, } = {}, } = {}, + customGas, } = this.props const insufficientBalance = balance && !isBalanceSufficient({ @@ -150,6 +152,13 @@ export default class ConfirmTransactionBase extends Component { } } + if (customGas.gasLimit < 21000) { + return { + valid: false, + errorKey: GAS_LIMIT_TOO_LOW_ERROR_KEY, + } + } + if (simulationFails) { return { valid: true, From c7266067cecf2fe7ab4ba40e112bf93baea1f618 Mon Sep 17 00:00:00 2001 From: Mathew Kamkar Date: Fri, 24 May 2019 21:42:48 -0700 Subject: [PATCH 86/87] Enable Ledger hardware wallet support on Firefox Firefox 67 support U2F by default --- ui/app/pages/create-account/connect-hardware/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index 5a91a2725..68b932935 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -51,12 +51,6 @@ class ConnectHardwareForm extends Component { } connectToHardwareWallet = (device) => { - // Ledger hardware wallets are not supported on firefox - if (getPlatform() === PLATFORM_FIREFOX && device === 'ledger') { - this.setState({ browserSupported: false, error: null}) - return null - } - if (this.state.accounts.length) { return null } From 79d2eaffac37495dd113672f2638baa19f59223a Mon Sep 17 00:00:00 2001 From: Mathew Kamkar Date: Fri, 24 May 2019 22:16:56 -0700 Subject: [PATCH 87/87] lint cleanup --- ui/app/pages/create-account/connect-hardware/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui/app/pages/create-account/connect-hardware/index.js b/ui/app/pages/create-account/connect-hardware/index.js index 68b932935..80a160205 100644 --- a/ui/app/pages/create-account/connect-hardware/index.js +++ b/ui/app/pages/create-account/connect-hardware/index.js @@ -8,8 +8,6 @@ const ConnectScreen = require('./connect-screen') const AccountList = require('./account-list') const { DEFAULT_ROUTE } = require('../../../helpers/constants/routes') const { formatBalance } = require('../../../helpers/utils/util') -const { getPlatform } = require('../../../../../app/scripts/lib/util') -const { PLATFORM_FIREFOX } = require('../../../../../app/scripts/lib/enums') class ConnectHardwareForm extends Component { constructor (props) {