From 088d7930e0895ef1802823c5fc843dd1c19b9661 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 20:46:34 -0700 Subject: [PATCH 001/183] network - create provider and block-tracker via json-rpc-engine --- .../controllers/network/createInfuraClient.js | 34 +++++ .../network/createJsonRpcClient.js | 35 ++++++ .../network/createLocalhostClient.js | 33 +++++ .../network/createMetamaskMiddleware.js | 43 +++++++ app/scripts/controllers/network/network.js | 116 ++++++++++-------- app/scripts/controllers/transactions/index.js | 1 + .../controllers/transactions/nonce-tracker.js | 18 +-- app/scripts/metamask-controller.js | 7 +- package.json | 4 +- test/unit/nonce-tracker-test.js | 8 +- 10 files changed, 224 insertions(+), 75 deletions(-) create mode 100644 app/scripts/controllers/network/createInfuraClient.js create mode 100644 app/scripts/controllers/network/createJsonRpcClient.js create mode 100644 app/scripts/controllers/network/createLocalhostClient.js create mode 100644 app/scripts/controllers/network/createMetamaskMiddleware.js diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js new file mode 100644 index 000000000..e346f4bcb --- /dev/null +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -0,0 +1,34 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createInfuraClient + +function createInfuraClient({ network }) { + const infuraMiddleware = createInfuraMiddleware({ network }) + const blockProvider = providerFromMiddleware(infuraMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockCacheMiddleware({ blockTracker }), + createInflightMiddleware(), + createBlockTrackerInspectorMiddleware({ blockTracker }), + infuraMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js new file mode 100644 index 000000000..5a8e85c23 --- /dev/null +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -0,0 +1,35 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createJsonRpcClient + +function createJsonRpcClient({ rpcUrl }) { + const fetchMiddleware = createFetchMiddleware({ rpcUrl }) + const blockProvider = providerFromMiddleware(fetchMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockCacheMiddleware({ blockTracker }), + createInflightMiddleware(), + createBlockTrackerInspectorMiddleware({ blockTracker }), + fetchMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js new file mode 100644 index 000000000..404415532 --- /dev/null +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -0,0 +1,33 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createLocalhostClient + +function createLocalhostClient() { + const fetchMiddleware = createFetchMiddleware({ rpcUrl: 'http://localhost:8545/' }) + const blockProvider = providerFromMiddleware(fetchMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider, pollingInterval: 1000 }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockTrackerInspectorMiddleware({ blockTracker }), + fetchMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js new file mode 100644 index 000000000..1974c231d --- /dev/null +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -0,0 +1,43 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createScaffoldMiddleware = require('json-rpc-engine/src/scaffold') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') + +module.exports = createMetamaskMiddleware + +function createMetamaskMiddleware({ + version, + getAccounts, + processTransaction, + processEthSignMessage, + processTypedMessage, + processPersonalMessage, + getPendingNonce +}) { + const metamaskMiddleware = mergeMiddleware([ + createScaffoldMiddleware({ + // staticSubprovider + eth_syncing: false, + web3_clientVersion: `MetaMask/v${version}`, + }), + createWalletSubprovider({ + getAccounts, + processTransaction, + processEthSignMessage, + processTypedMessage, + processPersonalMessage, + }), + createPendingNonceMiddleware({ getPendingNonce }), + }) + return metamaskMiddleware +} + +function createPendingNonceMiddleware ({ getPendingNonce }) { + return createAsyncMiddleware(async (req, res, next) => { + if (req.method !== 'eth_getTransactionCount') return next() + const address = req.params[0] + const blockRef = req.params[1] + if (blockRef !== 'pending') return next() + req.result = await getPendingNonce(address) + }) +} diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 93fde7c57..c882c7d75 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -1,14 +1,17 @@ const assert = require('assert') const EventEmitter = require('events') -const createMetamaskProvider = require('web3-provider-engine/zero.js') -const SubproviderFromProvider = require('web3-provider-engine/subproviders/provider.js') -const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider') const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') const extend = require('xtend') const EthQuery = require('eth-query') -const createEventEmitterProxy = require('../../lib/events-proxy.js') const log = require('loglevel') +const createMetamaskMiddleware = require('./createMetamaskMiddleware') +const createInfuraClient = require('./createInfuraClient') +const createJsonRpcClient = require('./createJsonRpcClient') +const createLocalhostClient = require('./createLocalhostClient') +// const createEventEmitterProxy = require('../../lib/events-proxy.js') +const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') + const { ROPSTEN, RINKEBY, @@ -38,21 +41,27 @@ module.exports = class NetworkController extends EventEmitter { this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) - // create event emitter proxy - this._proxy = createEventEmitterProxy() - this.on('networkDidChange', this.lookupNetwork) + // provider and block tracker + this._provider = null + this._blockTracker = null + // provider and block tracker proxies - because the network changes + this._providerProxy = null + this._blockTrackerProxy = null } - initializeProvider (_providerParams) { - this._baseProviderParams = _providerParams + initializeProvider (providerParams) { + this._baseProviderParams = providerParams const { type, rpcTarget } = this.providerStore.getState() this._configureProvider({ type, rpcTarget }) - this._proxy.on('block', this._logBlock.bind(this)) - this._proxy.on('error', this.verifyNetwork.bind(this)) - this.ethQuery = new EthQuery(this._proxy) this.lookupNetwork() - return this._proxy + } + + // return the proxies so the references will always be good + getProviderAndBlockTracker() { + const provider = this._providerProxy + const blockTracker = this._blockTracker + return { provider, blockTracker } } verifyNetwork () { @@ -74,10 +83,11 @@ module.exports = class NetworkController extends EventEmitter { lookupNetwork () { // Prevent firing when provider is not defined. - if (!this.ethQuery || !this.ethQuery.sendAsync) { - return log.warn('NetworkController - lookupNetwork aborted due to missing ethQuery') + if (!this._provider) { + return log.warn('NetworkController - lookupNetwork aborted due to missing provider') } - this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { + const ethQuery = new EthQuery(this._provider) + ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) this.setNetworkState(network) @@ -123,7 +133,7 @@ module.exports = class NetworkController extends EventEmitter { this._configureInfuraProvider(opts) // other type-based rpc endpoints } else if (type === LOCALHOST) { - this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL }) + this._configureLocalhostProvider() // url-based rpc endpoints } else if (type === 'rpc'){ this._configureStandardProvider({ rpcUrl: rpcTarget }) @@ -133,47 +143,47 @@ module.exports = class NetworkController extends EventEmitter { } _configureInfuraProvider ({ type }) { - log.info('_configureInfuraProvider', type) - const infuraProvider = createInfuraProvider({ network: type }) - const infuraSubprovider = new SubproviderFromProvider(infuraProvider) - const providerParams = extend(this._baseProviderParams, { - engineParams: { - pollingInterval: 8000, - blockTrackerProvider: infuraProvider, - }, - dataSubprovider: infuraSubprovider, - }) - const provider = createMetamaskProvider(providerParams) - this._setProvider(provider) + log.info('NetworkController - configureInfuraProvider', type) + const networkClient = createInfuraClient({ network: type }) + this._setNetworkClient(networkClient) + } + + _configureLocalhostProvider () { + log.info('NetworkController - configureLocalhostProvider') + const networkClient = createLocalhostClient() + this._setNetworkClient(networkClient) } _configureStandardProvider ({ rpcUrl }) { - const providerParams = extend(this._baseProviderParams, { - rpcUrl, - engineParams: { - pollingInterval: 8000, - }, - }) - const provider = createMetamaskProvider(providerParams) - this._setProvider(provider) - } - - _setProvider (provider) { - // collect old block tracker events - const oldProvider = this._provider - let blockTrackerHandlers - if (oldProvider) { - // capture old block handlers - blockTrackerHandlers = oldProvider._blockTracker.proxyEventHandlers - // tear down - oldProvider.removeAllListeners() - oldProvider.stop() + log.info('NetworkController - configureStandardProvider', rpcUrl) + const networkClient = createJsonRpcClient({ rpcUrl }) + this._setNetworkClient(networkClient) + } + + _setNetworkClient ({ networkMiddleware, blockTracker }) { + const metamaskMiddleware = createMetamaskMiddleware(this._baseProviderParams) + const engine = new JsonRpcEngine() + engine.push(metamaskMiddleware) + engine.push(networkMiddleware) + const provider = providerFromEngine(engine) + this._setProviderAndBlockTracker({ provider, blockTracker }) + } + + _setProviderAndBlockTracker ({ provider, blockTracker }) { + // update or intialize proxies + if (this._providerProxy) { + this._providerProxy.setTarget(provider) + } else { + this._providerProxy = createSwappableProxy(provider) + } + if (this._blockTrackerProxy) { + this._blockTrackerProxy.setTarget(blockTracker) + } else { + this._blockTrackerProxy = createEventEmitterProxy(blockTracker) } - // override block tracler - provider._blockTracker = createEventEmitterProxy(provider._blockTracker, blockTrackerHandlers) - // set as new provider + // set new provider and blockTracker this._provider = provider - this._proxy.setTarget(provider) + this._blockTracker = blockTracker } _logBlock (block) { diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 3886db104..cb3d28f1d 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -63,6 +63,7 @@ class TransactionController extends EventEmitter { this.store = this.txStateManager.store this.nonceTracker = new NonceTracker({ provider: this.provider, + blockTracker: this.blockTracker, getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager), getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager), }) diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index f8cdc5523..490118c89 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -12,8 +12,9 @@ const Mutex = require('await-semaphore').Mutex */ class NonceTracker { - constructor ({ provider, getPendingTransactions, getConfirmedTransactions }) { + constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) { this.provider = provider + this.blockTracker = blockTracker this.ethQuery = new EthQuery(provider) this.getPendingTransactions = getPendingTransactions this.getConfirmedTransactions = getConfirmedTransactions @@ -75,11 +76,10 @@ class NonceTracker { } async _getCurrentBlock () { - const blockTracker = this._getBlockTracker() - const currentBlock = blockTracker.getCurrentBlock() + const currentBlock = this.blockTracker.getCurrentBlock() if (currentBlock) return currentBlock return await new Promise((reject, resolve) => { - blockTracker.once('latest', resolve) + this.blockTracker.once('latest', resolve) }) } @@ -171,16 +171,6 @@ class NonceTracker { return { name: 'local', nonce: highest, details: { startPoint, highest } } } - - // this is a hotfix for the fact that the blockTracker will - // change when the network changes - - /** - @returns {Object} the current blockTracker - */ - _getBlockTracker () { - return this.provider._blockTracker - } } module.exports = NonceTracker diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a6b5d3453..7f4f2fc9b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -103,8 +103,9 @@ module.exports = class MetamaskController extends EventEmitter { this.blacklistController.scheduleUpdates() // rpc provider - this.provider = this.initializeProvider() - this.blockTracker = this.provider._blockTracker + this.initializeProvider() + this.provider = this.networkController.getProviderAndBlockTracker().provider + this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker // token exchange rate tracker this.tokenRatesController = new TokenRatesController({ @@ -1033,7 +1034,7 @@ module.exports = class MetamaskController extends EventEmitter { // create filter polyfill middleware const filterMiddleware = createFilterMiddleware({ provider: this.provider, - blockTracker: this.provider._blockTracker, + blockTracker: this.blockTracker, }) engine.push(createOriginMiddleware({ origin })) diff --git a/package.json b/package.json index f6338c542..4580d0722 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "ensnare": "^1.0.0", "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", + "eth-block-tracker": "github:metamask/eth-block-tracker#acbcfda348c309ece0fb96fad78d4861d08f5a91", "eth-contract-metadata": "^1.1.5", "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.6", @@ -129,7 +130,7 @@ "iframe-stream": "^3.0.0", "inject-css": "^0.1.1", "jazzicon": "^1.2.0", - "json-rpc-engine": "^3.6.1", + "json-rpc-engine": "^3.7.0", "json-rpc-middleware-stream": "^1.0.1", "lodash.debounce": "^4.0.8", "lodash.memoize": "^4.1.2", @@ -185,6 +186,7 @@ "shallow-copy": "0.0.1", "sw-controller": "^1.0.3", "sw-stream": "^2.0.2", + "swappable-obj-proxy": "^1.0.0", "textarea-caret": "^3.0.1", "through2": "^2.0.3", "valid-url": "^1.0.9", diff --git a/test/unit/nonce-tracker-test.js b/test/unit/nonce-tracker-test.js index cf26945d3..b9e6a5947 100644 --- a/test/unit/nonce-tracker-test.js +++ b/test/unit/nonce-tracker-test.js @@ -226,14 +226,14 @@ function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') { providerResultStub.result = providerStub const provider = { sendAsync: (_, cb) => { cb(undefined, providerResultStub) }, - _blockTracker: { - getCurrentBlock: () => '0x11b568', - }, + } + const blockTracker = { + getCurrentBlock: () => '0x11b568', } return new NonceTracker({ provider, + blockTracker, getPendingTransactions, getConfirmedTransactions, }) } - From b6eff15bd25ca30ba8a746eff2beec1c820b8855 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:08:19 -0700 Subject: [PATCH 002/183] lint fix --- app/scripts/controllers/network/createInfuraClient.js | 7 +++++-- app/scripts/controllers/network/createJsonRpcClient.js | 6 ++++-- app/scripts/controllers/network/createLocalhostClient.js | 4 ++-- .../controllers/network/createMetamaskMiddleware.js | 6 +++--- app/scripts/controllers/network/network.js | 8 ++++---- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index e346f4bcb..528be80ce 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,12 +1,15 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') +const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') module.exports = createInfuraClient -function createInfuraClient({ network }) { +function createInfuraClient ({ network }) { const infuraMiddleware = createInfuraMiddleware({ network }) const blockProvider = providerFromMiddleware(infuraMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider }) diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index 5a8e85c23..f8b67aa26 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -2,12 +2,14 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') module.exports = createJsonRpcClient -function createJsonRpcClient({ rpcUrl }) { +function createJsonRpcClient ({ rpcUrl }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }) const blockProvider = providerFromMiddleware(fetchMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider }) diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index 404415532..990dc6a95 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -2,12 +2,12 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') module.exports = createLocalhostClient -function createLocalhostClient() { +function createLocalhostClient () { const fetchMiddleware = createFetchMiddleware({ rpcUrl: 'http://localhost:8545/' }) const blockProvider = providerFromMiddleware(fetchMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider, pollingInterval: 1000 }) diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 1974c231d..7dbd90d7f 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -5,14 +5,14 @@ const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') module.exports = createMetamaskMiddleware -function createMetamaskMiddleware({ +function createMetamaskMiddleware ({ version, getAccounts, processTransaction, processEthSignMessage, processTypedMessage, processPersonalMessage, - getPendingNonce + getPendingNonce, }) { const metamaskMiddleware = mergeMiddleware([ createScaffoldMiddleware({ @@ -28,7 +28,7 @@ function createMetamaskMiddleware({ processPersonalMessage, }), createPendingNonceMiddleware({ getPendingNonce }), - }) + ]) return metamaskMiddleware } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index c882c7d75..a8c45a79c 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -2,8 +2,9 @@ const assert = require('assert') const EventEmitter = require('events') const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') -const extend = require('xtend') const EthQuery = require('eth-query') +const JsonRpcEngine = require('json-rpc-engine') +const providerFromEngine = require('eth-json-rpc-middle/providerFromEngine') const log = require('loglevel') const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') @@ -19,7 +20,6 @@ const { MAINNET, LOCALHOST, } = require('./enums') -const LOCALHOST_RPC_URL = 'http://localhost:8545' const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] const env = process.env.METAMASK_ENV @@ -58,7 +58,7 @@ module.exports = class NetworkController extends EventEmitter { } // return the proxies so the references will always be good - getProviderAndBlockTracker() { + getProviderAndBlockTracker () { const provider = this._providerProxy const blockTracker = this._blockTracker return { provider, blockTracker } @@ -135,7 +135,7 @@ module.exports = class NetworkController extends EventEmitter { } else if (type === LOCALHOST) { this._configureLocalhostProvider() // url-based rpc endpoints - } else if (type === 'rpc'){ + } else if (type === 'rpc') { this._configureStandardProvider({ rpcUrl: rpcTarget }) } else { throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) From 3e04840a7104849e9329b8faa4730554b2438217 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:10:41 -0700 Subject: [PATCH 003/183] remove unused events-proxy, was replaced with module swappable-obj-proxy --- app/scripts/controllers/network/network.js | 1 - app/scripts/lib/events-proxy.js | 42 ---------------------- 2 files changed, 43 deletions(-) delete mode 100644 app/scripts/lib/events-proxy.js diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index a8c45a79c..213013cca 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -10,7 +10,6 @@ const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') -// const createEventEmitterProxy = require('../../lib/events-proxy.js') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') const { diff --git a/app/scripts/lib/events-proxy.js b/app/scripts/lib/events-proxy.js deleted file mode 100644 index f83773ccc..000000000 --- a/app/scripts/lib/events-proxy.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Returns an EventEmitter that proxies events from the given event emitter - * @param {any} eventEmitter - * @param {object} listeners - The listeners to proxy to - * @returns {any} - */ -module.exports = function createEventEmitterProxy (eventEmitter, listeners) { - let target = eventEmitter - const eventHandlers = listeners || {} - const proxy = /** @type {any} */ (new Proxy({}, { - get: (_, name) => { - // intercept listeners - if (name === 'on') return addListener - if (name === 'setTarget') return setTarget - if (name === 'proxyEventHandlers') return eventHandlers - return (/** @type {any} */ (target))[name] - }, - set: (_, name, value) => { - target[name] = value - return true - }, - })) - function setTarget (/** @type {EventEmitter} */ eventEmitter) { - target = eventEmitter - // migrate listeners - Object.keys(eventHandlers).forEach((name) => { - /** @type {Array} */ (eventHandlers[name]).forEach((handler) => target.on(name, handler)) - }) - } - /** - * Attaches a function to be called whenever the specified event is emitted - * @param {string} name - * @param {Function} handler - */ - function addListener (name, handler) { - if (!eventHandlers[name]) eventHandlers[name] = [] - eventHandlers[name].push(handler) - target.on(name, handler) - } - if (listeners) proxy.setTarget(eventEmitter) - return proxy -} From 623533ab1508c93f0c347f0c4a1002ce93ff1ae2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:13:53 -0700 Subject: [PATCH 004/183] recent-blocks - update for eth-block-tracker@4 --- app/scripts/controllers/recent-blocks.js | 41 ++++++++---------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 1377c1ba9..4101814eb 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -3,6 +3,8 @@ const extend = require('xtend') const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') +const pify = require('pify') +const timeout = (duration) => new Promise(resolve => setTimeout(duration, resolve)) class RecentBlocksController { @@ -34,7 +36,7 @@ class RecentBlocksController { }, opts.initState) this.store = new ObservableStore(initState) - this.blockTracker.on('block', this.processBlock.bind(this)) + this.blockTracker.on('latest', this.processBlock.bind(this)) this.backfill() } @@ -55,7 +57,10 @@ class RecentBlocksController { * @param {object} newBlock The new block to modify and add to the recentBlocks array * */ - processBlock (newBlock) { + async processBlock (newBlockNumberHex) { + const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) + const newBlock = await this.getBlockByNumber(newBlockNumber) + const block = this.mapTransactionsToPrices(newBlock) const state = this.store.getState() @@ -118,17 +123,16 @@ class RecentBlocksController { * @returns {Promise} Promises undefined */ async backfill() { - this.blockTracker.once('block', async (block) => { - let blockNum = block.number + this.blockTracker.once('latest', async (blockNumberHex) => { let recentBlocks + const blockNumber = Number.parseInt(blockNumberHex, 16) let state = this.store.getState() recentBlocks = state.recentBlocks while (recentBlocks.length < this.historyLength) { try { - let blockNumBn = new BN(blockNum.substr(2), 16) - const newNum = blockNumBn.subn(1).toString(10) - const newBlock = await this.getBlockByNumber(newNum) + const prevBlockNumber = blockNumber - 1 + const newBlock = await this.getBlockByNumber(prevBlockNumber) if (newBlock) { this.backfillBlock(newBlock) @@ -140,23 +144,11 @@ class RecentBlocksController { } catch (e) { log.error(e) } - await this.wait() + await timeout(100) } }) } - /** - * A helper for this.backfill. Provides an easy way to ensure a 100 millisecond delay using await - * - * @returns {Promise} Promises undefined - * - */ - async wait () { - return new Promise((resolve) => { - setTimeout(resolve, 100) - }) - } - /** * Uses EthQuery to get a block that has a given block number. * @@ -165,13 +157,8 @@ class RecentBlocksController { * */ async getBlockByNumber (number) { - const bn = new BN(number) - return new Promise((resolve, reject) => { - this.ethQuery.getBlockByNumber('0x' + bn.toString(16), true, (err, block) => { - if (err) reject(err) - resolve(block) - }) - }) + const blockNumberHex = '0x' + number.toString(16) + return await pify(this.ethQuery.getBlockByNumber).call(this.ethQuery, blockNumberHex, true) } } From 32b3b8f2a76b4a67fde2a3af2ddd239998c5dfcd Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:16:05 -0700 Subject: [PATCH 005/183] controllers - balance - update for eth-block-tracker@4 --- app/scripts/controllers/balance.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/balance.js b/app/scripts/controllers/balance.js index 86619fce1..465751e61 100644 --- a/app/scripts/controllers/balance.js +++ b/app/scripts/controllers/balance.js @@ -60,7 +60,7 @@ class BalanceController { * Sets up listeners and subscriptions which should trigger an update of ethBalance. These updates include: * - when a transaction changes state to 'submitted', 'confirmed' or 'failed' * - when the current account changes (i.e. a new account is selected) - * - when there is a block update + * - when there is a block update * * @private * @@ -80,7 +80,7 @@ class BalanceController { } }) this.accountTracker.store.subscribe(update) - this.blockTracker.on('block', update) + this.blockTracker.on('latest', update) } /** @@ -100,7 +100,7 @@ class BalanceController { /** * Gets the pending transactions (i.e. those with a 'submitted' status). These are accessed from the - * TransactionController passed to this BalanceController during construction. + * TransactionController passed to this BalanceController during construction. * * @private * @returns {Promise} Promises an array of transaction objects. From c2a685eb2f5973081863109a9f26433650726713 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:20:35 -0700 Subject: [PATCH 006/183] deps - remove web3-provider-engine --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 4580d0722..c26b45202 100644 --- a/package.json +++ b/package.json @@ -192,7 +192,6 @@ "valid-url": "^1.0.9", "vreme": "^3.0.2", "web3": "^0.20.1", - "web3-provider-engine": "^14.0.5", "web3-stream-provider": "^3.0.1", "xtend": "^4.0.1" }, From f9074a57211277f740d1eef0f0599381df958c84 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:20:50 -0700 Subject: [PATCH 007/183] docs - remove references to web3-provider-engine --- docs/developing-on-deps.md | 3 +-- docs/porting_to_new_environment.md | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/developing-on-deps.md b/docs/developing-on-deps.md index 7de3f67a8..e2e07cb4e 100644 --- a/docs/developing-on-deps.md +++ b/docs/developing-on-deps.md @@ -1,10 +1,9 @@ ### Developing on Dependencies -To enjoy the live-reloading that `gulp dev` offers while working on the `web3-provider-engine` or other dependencies: +To enjoy the live-reloading that `gulp dev` offers while working on the dependencies: 1. Clone the dependency locally. 2. `npm install` in its folder. 3. Run `npm link` in its folder. 4. Run `npm link $DEP_NAME` in this project folder. 5. Next time you `npm start` it will watch the dependency for changes as well! - diff --git a/docs/porting_to_new_environment.md b/docs/porting_to_new_environment.md index 729a28e5d..454337d2a 100644 --- a/docs/porting_to_new_environment.md +++ b/docs/porting_to_new_environment.md @@ -79,8 +79,6 @@ 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 make this as easy as possible, we use one of our favorite internal tools, [web3-provider-engine](https://www.npmjs.com/package/web3-provider-engine) to construct a custom web3 provider object whose source of truth is a stream that we connect to remotely. - 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. 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 08dc238c9fdb23997a7fbdf57de5305455d1d930 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 22:46:11 -0700 Subject: [PATCH 008/183] deps - fix incorrect dep paths and versions --- app/scripts/controllers/network/createInfuraClient.js | 2 +- app/scripts/controllers/network/createJsonRpcClient.js | 2 +- app/scripts/controllers/network/createMetamaskMiddleware.js | 2 +- app/scripts/controllers/network/network.js | 2 +- package.json | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 528be80ce..adbf4c001 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -2,7 +2,7 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') -const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index f8b67aa26..d712ed135 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -3,7 +3,7 @@ const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') -const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 7dbd90d7f..8b17829b7 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -1,5 +1,5 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createScaffoldMiddleware = require('json-rpc-engine/src/scaffold') +const createScaffoldMiddleware = require('json-rpc-engine/src/createScaffoldMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 213013cca..9e622981b 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -4,7 +4,7 @@ const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') const EthQuery = require('eth-query') const JsonRpcEngine = require('json-rpc-engine') -const providerFromEngine = require('eth-json-rpc-middle/providerFromEngine') +const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine') const log = require('loglevel') const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') diff --git a/package.json b/package.json index c26b45202..4a9b9ae8b 100644 --- a/package.json +++ b/package.json @@ -94,8 +94,9 @@ "eth-block-tracker": "github:metamask/eth-block-tracker#acbcfda348c309ece0fb96fad78d4861d08f5a91", "eth-contract-metadata": "^1.1.5", "eth-hd-keyring": "^1.2.1", - "eth-json-rpc-filters": "^1.2.6", + "eth-json-rpc-filters": "^1.2.8", "eth-json-rpc-infura": "^3.0.0", + "eth-json-rpc-middleware": "^2.1.0", "eth-keyring-controller": "^2.2.0", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", @@ -186,7 +187,7 @@ "shallow-copy": "0.0.1", "sw-controller": "^1.0.3", "sw-stream": "^2.0.2", - "swappable-obj-proxy": "^1.0.0", + "swappable-obj-proxy": "^1.0.1", "textarea-caret": "^3.0.1", "through2": "^2.0.3", "valid-url": "^1.0.9", @@ -227,7 +228,6 @@ "eslint-plugin-json": "^1.2.0", "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", - "eth-json-rpc-middleware": "^1.6.0", "file-loader": "^1.1.11", "fs-promise": "^2.0.3", "ganache-cli": "^6.1.0", From 41c04ef7219eafeca71bcd577abe6bca3a637a89 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 23:13:25 -0700 Subject: [PATCH 009/183] controllers - recent-blocks - fix pifyd setTimeout args --- app/scripts/controllers/recent-blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 4101814eb..28eba0f26 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -4,7 +4,7 @@ const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') const pify = require('pify') -const timeout = (duration) => new Promise(resolve => setTimeout(duration, resolve)) +const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) class RecentBlocksController { From ae53fa09b4f01820dfe3820233d32ac03bfdada0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 23:53:36 -0700 Subject: [PATCH 010/183] deps - bump some bugfixes --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4a9b9ae8b..4b9149025 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "iframe-stream": "^3.0.0", "inject-css": "^0.1.1", "jazzicon": "^1.2.0", - "json-rpc-engine": "^3.7.0", + "json-rpc-engine": "^3.7.1", "json-rpc-middleware-stream": "^1.0.1", "lodash.debounce": "^4.0.8", "lodash.memoize": "^4.1.2", @@ -187,7 +187,7 @@ "shallow-copy": "0.0.1", "sw-controller": "^1.0.3", "sw-stream": "^2.0.2", - "swappable-obj-proxy": "^1.0.1", + "swappable-obj-proxy": "^1.0.2", "textarea-caret": "^3.0.1", "through2": "^2.0.3", "valid-url": "^1.0.9", From eaa5a48c918b6d647c9dc75d8769a5e0ff6c42bb Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 23:54:17 -0700 Subject: [PATCH 011/183] test - unit - network - get providerProxy via public method --- test/unit/network-contoller-test.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js index 2d590a3f6..54cd3c7f4 100644 --- a/test/unit/network-contoller-test.js +++ b/test/unit/network-contoller-test.js @@ -33,11 +33,12 @@ describe('# Network Controller', function () { describe('network', function () { describe('#provider', function () { - it('provider should be updatable without reassignment', function () { + it.only('provider should be updatable without reassignment', function () { networkController.initializeProvider(networkControllerProviderConfig) - const proxy = networkController._proxy - proxy.setTarget({ test: true, on: () => {} }) - assert.ok(proxy.test) + const providerProxy = networkController.getProviderAndBlockTracker().provider + assert.equal(providerProxy.test, undefined) + providerProxy.setTarget({ test: true }) + assert.equal(providerProxy.test, true) }) }) describe('#getNetworkState', function () { From 3084dc47d10e3e455c924e5aad0b0961c500ec8d Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 17 May 2018 00:13:20 -0700 Subject: [PATCH 012/183] recent-blocks - fix backfill blockNumber tracking --- app/scripts/controllers/recent-blocks.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 28eba0f26..9a215d0e5 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -1,6 +1,5 @@ const ObservableStore = require('obs-store') const extend = require('xtend') -const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') const pify = require('pify') @@ -125,7 +124,7 @@ class RecentBlocksController { async backfill() { this.blockTracker.once('latest', async (blockNumberHex) => { let recentBlocks - const blockNumber = Number.parseInt(blockNumberHex, 16) + let blockNumber = Number.parseInt(blockNumberHex, 16) let state = this.store.getState() recentBlocks = state.recentBlocks @@ -136,7 +135,7 @@ class RecentBlocksController { if (newBlock) { this.backfillBlock(newBlock) - blockNum = newBlock.number + blockNumber = Number.parseInt(newBlock.number, 16) } state = this.store.getState() From ee280de3d07990817ec99138190d5da876708d24 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 22 May 2018 13:35:52 -0700 Subject: [PATCH 013/183] deps - eth-block-tracker@4.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5df405b27..ffdd78f82 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "ensnare": "^1.0.0", "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", - "eth-block-tracker": "github:metamask/eth-block-tracker#acbcfda348c309ece0fb96fad78d4861d08f5a91", + "eth-block-tracker": "^4.0.1", "eth-contract-metadata": "^1.1.5", "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^1.2.8", From 9e7a9e47bd36feb1ea2179dca6c2740ba6eb2ab1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 22 May 2018 16:02:26 -0700 Subject: [PATCH 014/183] deps - eth-json-rpc-filters@2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffdd78f82..06173bbcd 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "eth-block-tracker": "^4.0.1", "eth-contract-metadata": "^1.1.5", "eth-hd-keyring": "^1.2.1", - "eth-json-rpc-filters": "^1.2.8", + "eth-json-rpc-filters": "^2.0.0", "eth-json-rpc-infura": "^3.0.0", "eth-json-rpc-middleware": "^2.1.0", "eth-keyring-controller": "^3.1.1", From 60bc28bf3c75135bd751852e32ff98b7b6181249 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 22 May 2018 16:37:30 -0700 Subject: [PATCH 015/183] test pending-tx-tracker - update tests to reflect new block tracker behavior and remove tx:confirmed event tests --- test/unit/pending-tx-test.js | 53 ++++++++++++++---------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js index 001b86dd1..ffd9a7154 100644 --- a/test/unit/pending-tx-test.js +++ b/test/unit/pending-tx-test.js @@ -13,7 +13,7 @@ const otherNetworkId = 36 const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex') -describe('PendingTransactionTracker', function () { +describe.only('PendingTransactionTracker', function () { let pendingTxTracker, txMeta, txMetaNoHash, txMetaNoRawTx, providerResultStub, provider, txMeta3, txList, knownErrors this.timeout(10000) @@ -52,7 +52,10 @@ describe('PendingTransactionTracker', function () { getPendingTransactions: () => {return []}, getCompletedTransactions: () => {return []}, publishTransaction: () => {}, + confirmTransaction: () => {}, }) + + pendingTxTracker._getBlock = (blockNumber) => { return {number: blockNumber, transactions: []} } }) describe('_checkPendingTx state management', function () { @@ -120,40 +123,36 @@ describe('PendingTransactionTracker', function () { }) pendingTxTracker.checkForTxInBlock(block) }) - it('should emit \'txConfirmed\' if the tx is in the block', function (done) { - const block = { transactions: [txMeta]} - pendingTxTracker.getPendingTransactions = () => [txMeta] - pendingTxTracker.once('tx:confirmed', (txId) => { - assert(txId, txMeta.id, 'should pass txId') - done() - }) - pendingTxTracker.once('tx:failed', (_, err) => { done(err) }) - pendingTxTracker.checkForTxInBlock(block) - }) }) describe('#queryPendingTxs', function () { it('should call #_checkPendingTxs if their is no oldBlock', function (done) { let newBlock, oldBlock - newBlock = { number: '0x01' } - pendingTxTracker._checkPendingTxs = done + newBlock = '0x01' + const originalFunction = pendingTxTracker._checkPendingTxs + pendingTxTracker._checkPendingTxs = () => { done() } pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) + pendingTxTracker._checkPendingTxs = originalFunction }) it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) { let newBlock, oldBlock - oldBlock = { number: '0x01' } - newBlock = { number: '0x03' } - pendingTxTracker._checkPendingTxs = done + oldBlock = '0x01' + newBlock = '0x03' + const originalFunction = pendingTxTracker._checkPendingTxs + pendingTxTracker._checkPendingTxs = () => { done() } pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) + pendingTxTracker._checkPendingTxs = originalFunction }) it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) { let newBlock, oldBlock - oldBlock = { number: '0x1' } - newBlock = { number: '0x2' } + oldBlock = '0x1' + newBlock = '0x2' + const originalFunction = pendingTxTracker._checkPendingTxs pendingTxTracker._checkPendingTxs = () => { const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less') done(err) } pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) + pendingTxTracker._checkPendingTxs = originalFunction done() }) }) @@ -171,16 +170,6 @@ describe('PendingTransactionTracker', function () { providerResultStub.eth_getTransactionByHash = null pendingTxTracker._checkPendingTx(txMeta) }) - - it('should emit \'txConfirmed\'', function (done) { - providerResultStub.eth_getTransactionByHash = {blockNumber: '0x01'} - pendingTxTracker.once('tx:confirmed', (txId) => { - assert(txId, txMeta.id, 'should pass txId') - done() - }) - pendingTxTracker.once('tx:failed', (_, err) => { done(err) }) - pendingTxTracker._checkPendingTx(txMeta) - }) }) describe('#_checkPendingTxs', function () { @@ -207,7 +196,7 @@ describe('PendingTransactionTracker', function () { }) describe('#resubmitPendingTxs', function () { - const blockStub = { number: '0x0' }; + const blockNuberStub = '0x0' beforeEach(function () { const txMeta2 = txMeta3 = txMeta txList = [txMeta, txMeta2, txMeta3].map((tx) => { @@ -225,7 +214,7 @@ describe('PendingTransactionTracker', function () { Promise.all(txList.map((tx) => tx.processed)) .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs(blockStub) + pendingTxTracker.resubmitPendingTxs(blockNuberStub) }) it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) { knownErrors =[ @@ -252,7 +241,7 @@ describe('PendingTransactionTracker', function () { .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs(blockStub) + pendingTxTracker.resubmitPendingTxs(blockNuberStub) }) it('should emit \'tx:warning\' if it encountered a real error', function (done) { pendingTxTracker.once('tx:warning', (txMeta, err) => { @@ -270,7 +259,7 @@ describe('PendingTransactionTracker', function () { .then((txCompletedList) => done()) .catch(done) - pendingTxTracker.resubmitPendingTxs(blockStub) + pendingTxTracker.resubmitPendingTxs(blockNuberStub) }) }) describe('#_resubmitTx', function () { From 10aecf49227098fb7fdbd7db193a9dcc6fecf5af Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 22 May 2018 16:40:01 -0700 Subject: [PATCH 016/183] remove dependance on the even tx:confirmed --- app/scripts/controllers/transactions/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index cb3d28f1d..313b20675 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -57,6 +57,7 @@ class TransactionController extends EventEmitter { initState: opts.initState, txHistoryLimit: opts.txHistoryLimit, getNetwork: this.getNetwork.bind(this), + confirmTransaction: this.confirmTransaction.bind(this), }) this._onBootCleanUp() @@ -316,6 +317,11 @@ class TransactionController extends EventEmitter { this.txStateManager.setTxStatusSubmitted(txId) } + confirmTransaction (txId) { + this.txStateManager.setTxStatusConfirmed(txId) + this._markNonceDuplicatesDropped(txId) + } + /** Convenience method for the ui thats sets the transaction to rejected @param txId {number} - the tx's Id @@ -396,8 +402,6 @@ class TransactionController extends EventEmitter { this.pendingTxTracker.on('tx:warning', (txMeta) => { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) - this.pendingTxTracker.on('tx:confirmed', (txId) => this.txStateManager.setTxStatusConfirmed(txId)) - this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId)) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { From c4b09da34e9950ea485dfecb810726e49b683dcd Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 22 May 2018 16:41:00 -0700 Subject: [PATCH 017/183] transactions - update pending-tx-tracker to use the new block tracker --- .../transactions/pending-tx-tracker.js | 25 +++++++++++++------ test/unit/pending-tx-test.js | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 6e2fcb40b..bd26a72d9 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -27,6 +27,7 @@ class PendingTransactionTracker extends EventEmitter { this.getPendingTransactions = config.getPendingTransactions this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction + this.confirmTransaction = config.confirmTransaction this._checkPendingTxs() } @@ -37,7 +38,8 @@ class PendingTransactionTracker extends EventEmitter { @emits tx:confirmed @emits tx:failed */ - checkForTxInBlock (block) { + async checkForTxInBlock (blockNumber) { + const block = await this._getBlock(blockNumber) const signedTxList = this.getPendingTransactions() if (!signedTxList.length) return signedTxList.forEach((txMeta) => { @@ -51,9 +53,12 @@ class PendingTransactionTracker extends EventEmitter { return } + if (!block.transactions.length) return - block.transactions.forEach((tx) => { - if (tx.hash === txHash) this.emit('tx:confirmed', txId) + block.transactions.forEach((hash) => { + if (hash === txHash) { + this.confirmTransaction(txId) + } }) }) } @@ -70,7 +75,7 @@ class PendingTransactionTracker extends EventEmitter { return } // if we synced by more than one block, check for missed pending transactions - const diff = Number.parseInt(newBlock.number, 16) - Number.parseInt(oldBlock.number, 16) + const diff = Number.parseInt(newBlock, 16) - Number.parseInt(oldBlock, 16) if (diff > 1) this._checkPendingTxs() } @@ -79,11 +84,11 @@ class PendingTransactionTracker extends EventEmitter { @param block {object} - a block object @emits tx:warning */ - resubmitPendingTxs (block) { + resubmitPendingTxs (blockNumber) { const pending = this.getPendingTransactions() // only try resubmitting if their are transactions to resubmit if (!pending.length) return - pending.forEach((txMeta) => this._resubmitTx(txMeta, block.number).catch((err) => { + pending.forEach((txMeta) => this._resubmitTx(txMeta, blockNumber).catch((err) => { /* Dont marked as failed if the error is a "known" transaction warning "there is already a transaction with the same sender-nonce @@ -179,7 +184,7 @@ class PendingTransactionTracker extends EventEmitter { txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { - this.emit('tx:confirmed', txId) + this.confirmTransaction(txId) } } catch (err) { txMeta.warning = { @@ -206,11 +211,17 @@ class PendingTransactionTracker extends EventEmitter { nonceGlobalLock.releaseLock() } + async _getBlock (blockNumber) { + return await this.query.getBlockByNumber(blockNumber, false) + } + /** checks to see if a confirmed txMeta has the same nonce @param txMeta {Object} - txMeta object @returns {boolean} */ + + async _checkIfNonceIsTaken (txMeta) { const address = txMeta.txParams.from const completed = this.getCompletedTransactions(address) diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js index ffd9a7154..07029e0f7 100644 --- a/test/unit/pending-tx-test.js +++ b/test/unit/pending-tx-test.js @@ -13,7 +13,7 @@ const otherNetworkId = 36 const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex') -describe.only('PendingTransactionTracker', function () { +describe('PendingTransactionTracker', function () { let pendingTxTracker, txMeta, txMetaNoHash, txMetaNoRawTx, providerResultStub, provider, txMeta3, txList, knownErrors this.timeout(10000) From 53b946362a59fbaea1a3ae3a7e7af97f427afed4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 16:20:35 -0700 Subject: [PATCH 018/183] controllers - recent-blocks - doc update --- app/scripts/controllers/recent-blocks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index a6208b89c..e0b5551dd 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -8,7 +8,7 @@ class RecentBlocksController { /** * Controller responsible for storing, updating and managing the recent history of blocks. Blocks are back filled - * upon the controller's construction and then the list is updated when the given block tracker gets a 'block' event + * upon the controller's construction and then the list is updated when the given block tracker gets a 'latest' event * (indicating that there is a new block to process). * * @typedef {Object} RecentBlocksController @@ -16,7 +16,7 @@ class RecentBlocksController { * @param {BlockTracker} opts.blockTracker Contains objects necessary for tracking blocks and querying the blockchain * @param {BlockTracker} opts.provider The provider used to create a new EthQuery instance. * @property {BlockTracker} blockTracker Points to the passed BlockTracker. On RecentBlocksController construction, - * listens for 'block' events so that new blocks can be processed and added to storage. + * listens for 'latest' events so that new blocks can be processed and added to storage. * @property {EthQuery} ethQuery Points to the EthQuery instance created with the passed provider * @property {number} historyLength The maximum length of blocks to track * @property {object} store Stores the recentBlocks @@ -111,9 +111,9 @@ class RecentBlocksController { } /** - * On this.blockTracker's first 'block' event after this RecentBlocksController's instantiation, the store.recentBlocks + * On this.blockTracker's first 'latest' event after this RecentBlocksController's instantiation, the store.recentBlocks * array is populated with this.historyLength number of blocks. The block number of the this.blockTracker's first - * 'block' event is used to iteratively generate all the numbers of the previous blocks, which are obtained by querying + * 'latest' event is used to iteratively generate all the numbers of the previous blocks, which are obtained by querying * the blockchain. These blocks are backfilled so that the recentBlocks array is ordered from oldest to newest. * * Each iteration over the block numbers is delayed by 100 milliseconds. From eb2423799d472863b5a74443ac32b5c1d59ce9fc Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 16:22:40 -0700 Subject: [PATCH 019/183] controllers - account-tracker - refactor + update for eth-block-tracker@4 --- app/scripts/lib/account-tracker.js | 123 +++++++++++++---------------- 1 file changed, 56 insertions(+), 67 deletions(-) diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index 0f7b3d865..c9db65710 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -7,14 +7,13 @@ * on each new block. */ -const async = require('async') const EthQuery = require('eth-query') const ObservableStore = require('obs-store') -const EventEmitter = require('events').EventEmitter -function noop () {} +const log = require('loglevel') +const pify = require('pify') -class AccountTracker extends EventEmitter { +class AccountTracker { /** * This module is responsible for tracking any number of accounts and caching their current balances & transaction @@ -35,8 +34,6 @@ class AccountTracker extends EventEmitter { * */ constructor (opts = {}) { - super() - const initState = { accounts: {}, currentBlockGasLimit: '', @@ -44,12 +41,12 @@ class AccountTracker extends EventEmitter { this.store = new ObservableStore(initState) this._provider = opts.provider - this._query = new EthQuery(this._provider) + this._query = pify(new EthQuery(this._provider)) this._blockTracker = opts.blockTracker // subscribe to latest block - this._blockTracker.on('block', this._updateForBlock.bind(this)) + this._blockTracker.on('latest', this._updateForBlock.bind(this)) // blockTracker.currentBlock may be null - this._currentBlockNumber = this._blockTracker.currentBlock + this._currentBlockNumber = this._blockTracker.getCurrentBlock() } /** @@ -67,49 +64,57 @@ class AccountTracker extends EventEmitter { const accounts = this.store.getState().accounts const locals = Object.keys(accounts) - const toAdd = [] + const accountsToAdd = [] addresses.forEach((upstream) => { if (!locals.includes(upstream)) { - toAdd.push(upstream) + accountsToAdd.push(upstream) } }) - const toRemove = [] + const accountsToRemove = [] locals.forEach((local) => { if (!addresses.includes(local)) { - toRemove.push(local) + accountsToRemove.push(local) } }) - toAdd.forEach(upstream => this.addAccount(upstream)) - toRemove.forEach(local => this.removeAccount(local)) - this._updateAccounts() + this.addAccounts(accountsToAdd) + this.removeAccounts(accountsToRemove) } /** - * Adds a new address to this AccountTracker's accounts object, which points to an empty object. This object will be + * Adds new addresses to track the balances of * given a balance as long this._currentBlockNumber is defined. * - * @param {string} address A hex address of a new account to store in this AccountTracker's accounts object + * @param {array} addresses An array of hex addresses of new accounts to track * */ - addAccount (address) { + addAccounts (addresses) { const accounts = this.store.getState().accounts - accounts[address] = {} + // add initial state for addresses + addresses.forEach(address => { + accounts[address] = {} + }) + // save accounts state this.store.updateState({ accounts }) + // fetch balances for the accounts if there is block number ready if (!this._currentBlockNumber) return - this._updateAccount(address) + addresses.forEach(address => this._updateAccount(address)) } /** - * Removes an account from this AccountTracker's accounts object + * Removes accounts from being tracked * - * @param {string} address A hex address of a the account to remove + * @param {array} an array of hex addresses to stop tracking * */ - removeAccount (address) { + removeAccounts (addresses) { const accounts = this.store.getState().accounts - delete accounts[address] + // remove each state object + addresses.forEach(address => { + delete accounts[address] + }) + // save accounts state this.store.updateState({ accounts }) } @@ -118,71 +123,55 @@ class AccountTracker extends EventEmitter { * via EthQuery * * @private - * @param {object} block Data about the block that contains the data to update to. + * @param {number} blockNumber the block number to update to. * @fires 'block' The updated state, if all account updates are successful * */ - _updateForBlock (block) { - this._currentBlockNumber = block.number - const currentBlockGasLimit = block.gasLimit + async _updateForBlock (blockNumber) { + this._currentBlockNumber = blockNumber + // this shouldn't be here... + const currentBlock = await this._query.getBlockByNumber(blockNumber, false) + const currentBlockGasLimit = currentBlock.gasLimit this.store.updateState({ currentBlockGasLimit }) - async.parallel([ - this._updateAccounts.bind(this), - ], (err) => { - if (err) return console.error(err) - this.emit('block', this.store.getState()) - }) + try { + await this._updateAccounts() + } catch (err) { + log.error(err) + } } /** * Calls this._updateAccount for each account in this.store * - * @param {Function} cb A callback to pass to this._updateAccount, called after each account is successfully updated + * @returns {Promise} after all account balances updated * */ - _updateAccounts (cb = noop) { + async _updateAccounts () { const accounts = this.store.getState().accounts const addresses = Object.keys(accounts) - async.each(addresses, this._updateAccount.bind(this), cb) + await Promise.all(addresses.map(this._updateAccount.bind(this))) } /** - * Updates the current balance of an account. Gets an updated balance via this._getAccount. + * Updates the current balance of an account. * * @private * @param {string} address A hex address of a the account to be updated - * @param {Function} cb A callback to call once the account at address is successfully update + * @returns {Promise} after the account balance is updated * */ - _updateAccount (address, cb = noop) { - this._getAccount(address, (err, result) => { - if (err) return cb(err) - result.address = address - const accounts = this.store.getState().accounts - // only populate if the entry is still present - if (accounts[address]) { - accounts[address] = result - this.store.updateState({ accounts }) - } - cb(null, result) - }) - } - - /** - * Gets the current balance of an account via EthQuery. - * - * @private - * @param {string} address A hex address of a the account to query - * @param {Function} cb A callback to call once the account at address is successfully update - * - */ - _getAccount (address, cb = noop) { - const query = this._query - async.parallel({ - balance: query.getBalance.bind(query, address), - }, cb) + async _updateAccount (address) { + // query balance + const balance = await this._query.getBalance(address) + const result = { address, balance } + // update accounts state + const { accounts } = this.store.getState() + // only populate if the entry is still present + if (!accounts[address]) return + accounts[address] = result + this.store.updateState({ accounts }) } } From 22e59af741a43ab9a9dc8e96415788f681a8efda Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:32:33 -0700 Subject: [PATCH 020/183] controllers - recent-blocks - ensure full blocks --- app/scripts/controllers/recent-blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index e0b5551dd..215638666 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -57,7 +57,7 @@ class RecentBlocksController { */ async processBlock (newBlockNumberHex) { const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) - const newBlock = await this.getBlockByNumber(newBlockNumber) + const newBlock = await this.getBlockByNumber(newBlockNumber, true) const block = this.mapTransactionsToPrices(newBlock) @@ -128,7 +128,7 @@ class RecentBlocksController { const targetBlockNumbers = Array(blocksToFetch).fill().map((_, index) => prevBlockNumber - index) await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => { try { - const newBlock = await this.getBlockByNumber(targetBlockNumber) + const newBlock = await this.getBlockByNumber(targetBlockNumber, true) if (newBlock) { this.backfillBlock(newBlock) From f41198fbb6f4e72e331bb4e3d326534f90000ce9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:33:02 -0700 Subject: [PATCH 021/183] sentry - setupRaven - ensure message is truthy --- app/scripts/lib/setupRaven.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index d164827ab..30d0a3680 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -66,11 +66,11 @@ function simplifyErrorMessages(report) { function rewriteErrorMessages(report, rewriteFn) { // rewrite top level message - report.message = rewriteFn(report.message) + if (typeof report.message === 'string') report.message = rewriteFn(report.message) // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { - item.value = rewriteFn(item.value) + if (typeof item.value === 'string') item.value = rewriteFn(item.value) }) } } From 90327195986c953df40a10a6556ad9f133165712 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:33:43 -0700 Subject: [PATCH 022/183] deps - bump eth-block-tracker for bugfix --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06173bbcd..522f84159 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "eth-block-tracker": "^4.0.1", "eth-contract-metadata": "^1.1.5", "eth-hd-keyring": "^1.2.1", - "eth-json-rpc-filters": "^2.0.0", + "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", "eth-json-rpc-middleware": "^2.1.0", "eth-keyring-controller": "^3.1.1", From ee800de025397af7958d8e8e382b31b1d09c338c Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:46:20 -0700 Subject: [PATCH 023/183] controllers - recent-blocks - wrap block-tracker event in try-catch --- app/scripts/controllers/recent-blocks.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 215638666..e256c62e0 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -34,7 +34,13 @@ class RecentBlocksController { }, opts.initState) this.store = new ObservableStore(initState) - this.blockTracker.on('latest', this.processBlock.bind(this)) + this.blockTracker.on('latest', async (newBlockNumberHex) => { + try { + await this.processBlock(newBlockNumberHex) + } catch (err) { + log.error(err) + } + }) this.backfill() } From 49ef93b99158b9fae21d841828d7e7d105f837df Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:43:16 -0700 Subject: [PATCH 024/183] controllers - recent-blocks - guard against empty block --- app/scripts/controllers/recent-blocks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index e256c62e0..4009c35ae 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -64,6 +64,7 @@ class RecentBlocksController { async processBlock (newBlockNumberHex) { const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) const newBlock = await this.getBlockByNumber(newBlockNumber, true) + if (!newBlock) return const block = this.mapTransactionsToPrices(newBlock) @@ -135,10 +136,9 @@ class RecentBlocksController { await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => { try { const newBlock = await this.getBlockByNumber(targetBlockNumber, true) + if (!newBlock) return - if (newBlock) { - this.backfillBlock(newBlock) - } + this.backfillBlock(newBlock) } catch (e) { log.error(e) } From 91accee2c65e2b9c9e278451f1d6794f74b27c24 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:43:36 -0700 Subject: [PATCH 025/183] account-tracker - guard against empty block --- app/scripts/lib/account-tracker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index c9db65710..1a2354463 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -130,8 +130,9 @@ class AccountTracker { async _updateForBlock (blockNumber) { this._currentBlockNumber = blockNumber - // this shouldn't be here... + // block gasLimit polling shouldn't be in account-tracker shouldn't be here... const currentBlock = await this._query.getBlockByNumber(blockNumber, false) + if (!currentBlock) return const currentBlockGasLimit = currentBlock.gasLimit this.store.updateState({ currentBlockGasLimit }) From 66a62dfd0c2efbb9596bdc4b4befe03b25fbd7e9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:44:33 -0700 Subject: [PATCH 026/183] metamask-controller - fix account lookup hook --- app/scripts/metamask-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 14eb749e7..152ad13a0 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -241,7 +241,7 @@ module.exports = class MetamaskController extends EventEmitter { }, }, // account mgmt - getAccounts: (cb) => { + getAccounts: async () => { const isUnlocked = this.keyringController.memStore.getState().isUnlocked const result = [] const selectedAddress = this.preferencesController.getSelectedAddress() @@ -250,7 +250,7 @@ module.exports = class MetamaskController extends EventEmitter { if (isUnlocked && selectedAddress) { result.push(selectedAddress) } - cb(null, result) + return result }, // tx signing // old style msg signing From 68aa1cce5f4a1e502cccfba29c3f17f3b29b1527 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:46:16 -0700 Subject: [PATCH 027/183] deps - bump json-rpc modules for bugfixes --- package-lock.json | 586 +++++++++++++++++++++++++++++++--------------- package.json | 4 +- 2 files changed, 403 insertions(+), 187 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1fdf0059..f7a35dcc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -309,7 +309,7 @@ }, "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { @@ -1934,6 +1934,12 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, + "arch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.0.tgz", + "integrity": "sha1-NhOqRhSQZLPB8GB5Gb8dR4boKIk=", + "dev": true + }, "archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", @@ -3727,14 +3733,6 @@ "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", "dev": true }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", - "requires": { - "precond": "0.2.3" - } - }, "bail": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.2.tgz", @@ -3793,6 +3791,12 @@ "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", "dev": true }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=", + "dev": true + }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", @@ -5141,6 +5145,33 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, + "clipboardy": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz", + "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==", + "dev": true, + "requires": { + "arch": "2.1.0", + "execa": "0.8.0" + }, + "dependencies": { + "execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + } + } + }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -5808,22 +5839,6 @@ "is-windows": "1.0.2" } }, - "cross-fetch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.1.0.tgz", - "integrity": "sha512-FTIt2WK44RiafWQ62xIvd+oBoVd392abh1lF872trLlA74JCR1s4oTHlixwoIKy44ehn8WbQ0Ds2P16sw7ZQxg==", - "requires": { - "node-fetch": "2.1.1", - "whatwg-fetch": "2.0.3" - }, - "dependencies": { - "node-fetch": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.1.tgz", - "integrity": "sha1-NpynC4L1DIZJYQSmx3bSdPTkotQ=" - } - } - }, "cross-spawn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", @@ -7952,39 +7967,62 @@ } }, "eth-block-tracker": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.0.tgz", - "integrity": "sha512-yrNyBIBKC7WfUjrXSG/CZVy0gW2aF8+MnjnrkOxkZOR+BAtL6JgYOnzVnrU8KE6mKJETlA/1dYMygvLXWyJGGw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.1.tgz", + "integrity": "sha512-ytJxddJ0TMcJHYxPlgGhMyr5EH6/Kyp3bg0WsjXgY9X0uYX3xVHTTeU5WVX6KX+9oJ37ZLUjh5PZ6VYnF1Fx/Q==", "requires": { - "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-json-rpc-infura": "3.1.2", "eth-query": "2.1.2", - "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.1.3", - "ethjs-util": "0.1.4", - "json-rpc-engine": "3.6.0", - "pify": "2.3.0", - "tape": "4.8.0" + "pify": "3.0.0" }, "dependencies": { - "async-eventemitter": { - "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "cross-fetch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.0.tgz", + "integrity": "sha512-P0tdN3ZcwhZQsqUiBnyH02mduL2sBIG1lESy+rUALVDXobpSxNzJhzx4cbzRcSsy3FcJ40Ogc9sjIYrrPs3BVg==", "requires": { - "async": "2.6.0" + "node-fetch": "2.1.2", + "whatwg-fetch": "2.0.4" } }, - "babelify": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", - "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "eth-json-rpc-infura": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.1.2.tgz", + "integrity": "sha512-IuK5Iowfs6taluA/3Okmu6EfZcFMq6MQuyrUL1PrCoJstuuBr3TvVeSy3keDyxfbrjFB34nCo538I8G+qMtsbw==", "requires": { - "babel-core": "6.26.0", - "object-assign": "4.1.1" + "cross-fetch": "2.2.0", + "eth-json-rpc-middleware": "1.6.0", + "json-rpc-engine": "3.7.3", + "json-rpc-error": "2.0.0", + "tape": "4.8.0" + }, + "dependencies": { + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "2.6.0", + "eth-query": "2.1.2", + "eth-tx-summary": "3.2.1", + "ethereumjs-block": "1.7.0", + "ethereumjs-tx": "1.3.3", + "ethereumjs-util": "5.2.0", + "ethereumjs-vm": "2.3.2", + "fetch-ponyfill": "4.1.0", + "json-rpc-engine": "3.7.3", + "json-rpc-error": "2.0.0", + "json-stable-stringify": "1.0.1", + "promise-to-callback": "1.0.0", + "tape": "4.8.0" + } + } } }, "ethereumjs-util": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.3.tgz", - "integrity": "sha512-U/wmHagElZVxnpo3bFsvk5beFADegUcEzqtA/NfQbitAPOs6JoYq8M4SY9NfH4HD8236i63UOkkXafd7bqBL9A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -7995,22 +8033,15 @@ "secp256k1": "3.4.0" } }, - "json-rpc-engine": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.0.tgz", - "integrity": "sha512-QGEIIPMaG4lQ8iKQgzKq7Ra6hscqSL+6S+xiUFbNAoVaZII8iyN1l6tJHmUWIdbnl2o0rbwCnOPFAhTn9AJObw==", - "requires": { - "async": "2.6.0", - "babel-preset-env": "1.6.1", - "babelify": "7.3.0", - "json-rpc-error": "2.0.0", - "promise-to-callback": "1.0.0" - } + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" } } }, @@ -8065,13 +8096,70 @@ } }, "eth-json-rpc-filters": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-1.2.6.tgz", - "integrity": "sha512-6G9t43s3lxJckeSfNduc3Ww/40BGm1Cf8MU1nL8rrumZbEg44ZSexWUowB00D4kJ9qSOH+CbzdI+m3oVMi4xFw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-2.1.1.tgz", + "integrity": "sha512-FSFcCMJ1lRS8az1LhIK5Klima8Hyfv4keKSdW2MA3zwiN/wX1NKb/sQSEFO3nstPUqR2Aa02lVokp85UnnrBlA==", "requires": { "await-semaphore": "0.1.3", - "json-rpc-engine": "3.6.1", + "eth-json-rpc-middleware": "1.6.0", + "ethjs-query": "0.3.8", + "json-rpc-engine": "3.7.3", "lodash.flatmap": "4.5.0" + }, + "dependencies": { + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "2.6.0", + "eth-query": "2.1.2", + "eth-tx-summary": "3.2.1", + "ethereumjs-block": "1.7.0", + "ethereumjs-tx": "1.3.3", + "ethereumjs-util": "5.2.0", + "ethereumjs-vm": "2.3.2", + "fetch-ponyfill": "4.1.0", + "json-rpc-engine": "3.7.3", + "json-rpc-error": "2.0.0", + "json-stable-stringify": "1.0.1", + "promise-to-callback": "1.0.0", + "tape": "4.8.0" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "4.11.8", + "create-hash": "1.1.3", + "ethjs-util": "0.1.4", + "keccak": "1.4.0", + "rlp": "2.0.0", + "safe-buffer": "5.1.1", + "secp256k1": "3.4.0" + } + }, + "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" + } + } } }, "eth-json-rpc-infura": { @@ -8080,27 +8168,65 @@ "integrity": "sha512-Ab6170AxlF4DK+HDImh52+AetwHPHstgg8uWtX4im26rqK7u4ziSfvUIUK2+/LK0pi0wbIFb8hZm5jPKAXDmBA==", "requires": { "eth-json-rpc-middleware": "1.6.0", - "json-rpc-engine": "3.6.1", + "json-rpc-engine": "3.7.3", "json-rpc-error": "2.0.0", "tape": "4.8.0" + }, + "dependencies": { + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "2.6.0", + "eth-query": "2.1.2", + "eth-tx-summary": "3.2.1", + "ethereumjs-block": "1.7.0", + "ethereumjs-tx": "1.3.3", + "ethereumjs-util": "5.2.0", + "ethereumjs-vm": "2.3.2", + "fetch-ponyfill": "4.1.0", + "json-rpc-engine": "3.7.3", + "json-rpc-error": "2.0.0", + "json-stable-stringify": "1.0.1", + "promise-to-callback": "1.0.0", + "tape": "4.8.0" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "4.11.8", + "create-hash": "1.1.3", + "ethjs-util": "0.1.4", + "keccak": "1.4.0", + "rlp": "2.0.0", + "safe-buffer": "5.1.1", + "secp256k1": "3.4.0" + } + } } }, "eth-json-rpc-middleware": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", - "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.1.1.tgz", + "integrity": "sha512-uIMBZXMVN/ntnvNAN/o20gOFR7Ya23gg7S3jytdejpt/F6FKl25Y4zbyFrGhbt0oCKiYfECGln8pOlu6Zc8znw==", "requires": { "async": "2.6.0", "eth-query": "2.1.2", + "eth-sig-util": "1.4.2", "eth-tx-summary": "3.2.1", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", "ethereumjs-util": "5.2.0", "ethereumjs-vm": "2.3.2", "fetch-ponyfill": "4.1.0", - "json-rpc-engine": "3.6.1", + "json-rpc-engine": "3.7.3", "json-rpc-error": "2.0.0", "json-stable-stringify": "1.0.1", + "pify": "3.0.0", "promise-to-callback": "1.0.0", "tape": "4.8.0" }, @@ -8488,48 +8614,6 @@ } } } - }, - "web3-provider-engine": { - "version": "13.8.0", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", - "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", - "requires": { - "async": "2.6.0", - "clone": "2.1.1", - "eth-block-tracker": "2.3.0", - "eth-sig-util": "1.4.2", - "ethereumjs-block": "1.7.0", - "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.2.0", - "ethereumjs-vm": "2.3.5", - "fetch-ponyfill": "4.1.0", - "json-rpc-error": "2.0.0", - "json-stable-stringify": "1.0.1", - "promise-to-callback": "1.0.0", - "readable-stream": "2.3.3", - "request": "2.83.0", - "semaphore": "1.1.0", - "solc": "0.4.23", - "tape": "4.8.0", - "xhr": "2.4.1", - "xtend": "4.0.1" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "requires": { - "bn.js": "4.11.8", - "create-hash": "1.1.3", - "ethjs-util": "0.1.4", - "keccak": "1.4.0", - "rlp": "2.0.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.4.0" - } - } - } } } }, @@ -8895,6 +8979,35 @@ "resolved": "https://registry.npmjs.org/ethjs-filter/-/ethjs-filter-0.1.5.tgz", "integrity": "sha1-ARKvYBfCRnfjK4/esg5hlgGbdZg=" }, + "ethjs-format": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.7.tgz", + "integrity": "sha512-uNYAi+r3/mvR3xYu2AfSXx5teP4ovy9z2FrRsblU+h2logsaIKZPi9V3bn3V7wuRcnG0HZ3QydgZuVaRo06C4Q==", + "requires": { + "bn.js": "4.11.6", + "ethjs-schema": "0.2.1", + "ethjs-util": "0.1.3", + "is-hex-prefixed": "1.0.0", + "number-to-bn": "1.7.0", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + }, + "ethjs-util": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.3.tgz", + "integrity": "sha1-39XqSkANxeQhqInK9H4IGtp4u1U=", + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + } + } + }, "ethjs-provider-http": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-provider-http/-/ethjs-provider-http-0.1.6.tgz", @@ -8956,6 +9069,11 @@ "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.5.tgz", "integrity": "sha1-CZ4i8n3EwYtpeKSF/DaxsPeWkIA=" }, + "ethjs-schema": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.2.1.tgz", + "integrity": "sha512-DXd8lwNrhT9sjsh/Vd2Z+4pfyGxhc0POVnLBUfwk5udtdoBzADyq+sK39dcb48+ZU+2VgtwHxtGWnLnCfmfW5g==" + }, "ethjs-unit": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", @@ -8997,7 +9115,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -11028,7 +11146,7 @@ "requires": { "async": "2.6.0", "clone": "2.1.1", - "eth-block-tracker": "2.3.0", + "eth-block-tracker": "2.3.1", "eth-sig-util": "1.4.2", "ethereumjs-block": "1.2.2", "ethereumjs-tx": "1.3.3", @@ -11045,6 +11163,34 @@ "tape": "4.8.0", "xhr": "2.4.1", "xtend": "4.0.1" + }, + "dependencies": { + "async-eventemitter": { + "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "requires": { + "async": "2.6.0" + } + }, + "eth-block-tracker": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", + "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", + "requires": { + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-query": "2.1.2", + "ethereumjs-tx": "1.3.3", + "ethereumjs-util": "5.2.0", + "ethjs-util": "0.1.4", + "json-rpc-engine": "3.7.3", + "pify": "2.3.0", + "tape": "4.8.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "yargs": { @@ -11347,6 +11493,62 @@ } } }, + "gh-pages": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-1.1.0.tgz", + "integrity": "sha512-ZpDkeOVmIrN5mz+sBWDz5zmTqcbNJzI/updCwEv/7rrSdpTNlj1B5GhBqG7f4Q8p5sJOdnBV0SIqxJrxtZQ9FA==", + "dev": true, + "requires": { + "async": "2.6.0", + "base64url": "2.0.0", + "commander": "2.11.0", + "fs-extra": "4.0.3", + "globby": "6.1.0", + "graceful-fs": "4.1.11", + "rimraf": "2.6.2" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "gifencoder": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/gifencoder/-/gifencoder-1.1.0.tgz", @@ -15261,13 +15463,14 @@ "dev": true }, "json-rpc-engine": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz", - "integrity": "sha512-xYuD9M1pcld5OKPzVAoEG5MKtnR8iKMyNzRpeS3/mCJ7dcAcS67vqfOmYLoaIQfVRU5uClThbjri3VFR0vEwYg==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", "requires": { "async": "2.6.0", "babel-preset-env": "1.6.1", "babelify": "7.3.0", + "clone": "2.1.1", "json-rpc-error": "2.0.0", "promise-to-callback": "1.0.0" }, @@ -15297,17 +15500,52 @@ "integrity": "sha512-IR6cOO6B21NdLpiYblueB3O+g3UAYLIZd6ZgZfddVPl0z6vSECcpuiYnV5MmIMJY3D0fLYpJqOxYaEmLYQqTtA==", "requires": { "end-of-stream": "1.4.0", - "eth-block-tracker": "2.3.0", + "eth-block-tracker": "2.3.1", "ethjs-query": "0.2.9", - "json-rpc-engine": "3.6.1", + "json-rpc-engine": "3.7.3", "readable-stream": "2.3.3" }, "dependencies": { + "async-eventemitter": { + "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "requires": { + "async": "2.6.0" + } + }, "bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, + "eth-block-tracker": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", + "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", + "requires": { + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-query": "2.1.2", + "ethereumjs-tx": "1.3.3", + "ethereumjs-util": "5.2.0", + "ethjs-util": "0.1.3", + "json-rpc-engine": "3.7.3", + "pify": "2.3.0", + "tape": "4.8.0" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "4.11.6", + "create-hash": "1.1.3", + "ethjs-util": "0.1.3", + "keccak": "1.4.0", + "rlp": "2.0.0", + "safe-buffer": "5.1.1", + "secp256k1": "3.4.0" + } + }, "ethjs-format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.2.tgz", @@ -15343,6 +15581,11 @@ "is-hex-prefixed": "1.0.0", "strip-hex-prefix": "1.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -18067,7 +18310,7 @@ "requires": { "iframe": "1.0.0", "iframe-stream": "3.0.0", - "json-rpc-engine": "3.6.1", + "json-rpc-engine": "3.7.3", "json-rpc-middleware-stream": "1.0.1", "obj-multiplex": "1.0.0", "obs-store": "2.4.1", @@ -24111,11 +24354,6 @@ } } }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -27399,9 +27637,9 @@ } }, "solc": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.23.tgz", - "integrity": "sha512-AT7anLHY6uIRg2It6N0UlCHeZ7YeecIkUhnlirrCgCPCUevtnoN48BxvgigN/4jJTRljv5oFhAJtI6gvHzT5DQ==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", + "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", "requires": { "fs-extra": "0.30.0", "memorystream": "0.3.1", @@ -28856,6 +29094,11 @@ } } }, + "swappable-obj-proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/swappable-obj-proxy/-/swappable-obj-proxy-1.0.2.tgz", + "integrity": "sha512-IDrfIgZr09yK9j8XSoeHACf9IaM03izjIiNBq7lZrXQYr2eXwjcRXJUcUmkOkTs3QrXigAGbVgaq86hsRH9DAg==" + }, "swarm-js": { "version": "0.1.37", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.37.tgz", @@ -30195,6 +30438,12 @@ "unist-util-is": "2.1.1" } }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, "unorm": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz", @@ -31386,63 +31635,56 @@ } }, "web3-provider-engine": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-14.0.5.tgz", - "integrity": "sha512-1W/ue7VOwOMnmKgMY3HCpbixi6qhfl4r1dK8W597AwJLbrQ+twJKwWlFAedDpJjCc9MwRCCB3pyexW4HJVSiBg==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", + "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", "requires": { "async": "2.6.0", - "backoff": "2.5.0", "clone": "2.1.1", - "cross-fetch": "2.1.0", - "eth-block-tracker": "3.0.0", - "eth-json-rpc-infura": "3.1.0", + "eth-block-tracker": "2.3.1", "eth-sig-util": "1.4.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.1.5", - "ethereumjs-vm": "2.3.5", + "ethereumjs-util": "5.2.0", + "ethereumjs-vm": "2.3.2", + "fetch-ponyfill": "4.1.0", "json-rpc-error": "2.0.0", "json-stable-stringify": "1.0.1", "promise-to-callback": "1.0.0", "readable-stream": "2.3.3", "request": "2.83.0", "semaphore": "1.1.0", + "solc": "0.4.24", "tape": "4.8.0", - "ws": "5.1.1", "xhr": "2.4.1", "xtend": "4.0.1" }, "dependencies": { + "async-eventemitter": { + "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "requires": { + "async": "2.6.0" + } + }, "eth-block-tracker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.0.tgz", - "integrity": "sha512-Lhhu/+1GOeekMRDRhUcM7VSJRmX279DByrwzEbmG0JL1tcT3xRo6GLNXnidyJ7ahHJm+0JFhw/RqtTeIxagQwA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", + "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", "requires": { + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", "eth-query": "2.1.2", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.1.5", + "ethereumjs-util": "5.2.0", "ethjs-util": "0.1.4", - "json-rpc-engine": "3.6.1", + "json-rpc-engine": "3.7.3", "pify": "2.3.0", "tape": "4.8.0" } }, - "eth-json-rpc-infura": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.1.0.tgz", - "integrity": "sha512-uMYkEP6fga8CyNo8TMoA/7cxi6bL3V8pTvjKQikOi9iYl6/AO5xlfgniyAMElSiq2mmXz3lYa/9VYDMzt/J5aA==", - "requires": { - "cross-fetch": "2.1.0", - "eth-json-rpc-middleware": "1.6.0", - "json-rpc-engine": "3.6.1", - "json-rpc-error": "2.0.0", - "tape": "4.8.0" - } - }, "ethereumjs-util": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz", - "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -31453,36 +31695,10 @@ "secp256k1": "3.4.0" } }, - "ethereumjs-vm": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz", - "integrity": "sha512-AJ7x44+xqyE5+UO3Nns19WkTdZfyqFZ+sEjIEpvme7Ipbe3iBU1uwCcHEdiu/yY9bdhr3IfSa/NfIKNeXPaRVQ==", - "requires": { - "async": "2.6.0", - "async-eventemitter": "0.2.4", - "ethereum-common": "0.2.0", - "ethereumjs-account": "2.0.4", - "ethereumjs-block": "1.7.0", - "ethereumjs-util": "5.1.5", - "fake-merkle-patricia-tree": "1.0.1", - "functional-red-black-tree": "1.0.1", - "merkle-patricia-tree": "2.3.0", - "rustbn.js": "0.1.1", - "safe-buffer": "5.1.1" - } - }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "ws": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.1.1.tgz", - "integrity": "sha512-bOusvpCb09TOBLbpMKszd45WKC2KPtxiyiHanv+H2DE3Az+1db5a/L7sVJZVDPUC1Br8f0SKRr1KjLpD1U/IAw==", - "requires": { - "async-limiter": "1.0.0" - } } } }, diff --git a/package.json b/package.json index 522f84159..fdb032741 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", - "eth-json-rpc-middleware": "^2.1.0", + "eth-json-rpc-middleware": "^2.1.1", "eth-keyring-controller": "^3.1.1", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", @@ -132,7 +132,7 @@ "iframe-stream": "^3.0.0", "inject-css": "^0.1.1", "jazzicon": "^1.2.0", - "json-rpc-engine": "^3.7.1", + "json-rpc-engine": "^3.7.3", "json-rpc-middleware-stream": "^1.0.1", "lodash.debounce": "^4.0.8", "lodash.memoize": "^4.1.2", From aab9691c42184b81cdf7086d389bb74279e867bf Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 15:51:46 -0700 Subject: [PATCH 028/183] provider - update wallet hooks for new wallet middleware --- app/scripts/lib/message-manager.js | 31 ++++++++- app/scripts/lib/personal-message-manager.js | 35 +++++++++- app/scripts/lib/typed-message-manager.js | 31 ++++++++- app/scripts/metamask-controller.js | 77 +++++---------------- package-lock.json | 6 +- package.json | 2 +- 6 files changed, 114 insertions(+), 68 deletions(-) diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 901367f04..47925b94b 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -69,10 +69,39 @@ module.exports = class MessageManager extends EventEmitter { * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} after signature has been + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + const msgId = this.addUnapprovedMessage(msgParams, req) + // await finished + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the + * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object where the origin may be specificied * @returns {number} The id of the newly created message. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { + // add origin from request + if (req) msgParams.origin = req.origin msgParams.data = normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index e96ced1f2..fc2cccdf1 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -73,11 +73,43 @@ module.exports = class PersonalMessageManager extends EventEmitter { * this.memStore. * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} When the message has been signed or rejected + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + if (!msgParams.from) { + reject(new Error('MetaMask Message Signature: from field is required.')) + } + const msgId = this.addUnapprovedMessage(msgParams, req) + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new PersonalMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add + * the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to + * this.memStore. + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin * @returns {number} The id of the newly created PersonalMessage. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { log.debug(`PersonalMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) + // add origin from request + if (req) msgParams.origin = req.origin msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() @@ -257,4 +289,3 @@ module.exports = class PersonalMessageManager extends EventEmitter { } } - diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index c58921610..e5e1c94b3 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -72,11 +72,40 @@ module.exports = class TypedMessageManager extends EventEmitter { * this.memStore. Before any of this is done, msgParams are validated * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} When the message has been signed or rejected + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + const msgId = this.addUnapprovedMessage(msgParams, req) + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new TypedMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add + * the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to + * this.memStore. Before any of this is done, msgParams are validated + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin * @returns {number} The id of the newly created TypedMessage. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { this.validateParams(msgParams) + // add origin from request + if (req) msgParams.origin = req.origin log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) // create txData obj with parameters and meta data diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 152ad13a0..8c3c70c5c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -234,28 +234,22 @@ module.exports = class MetamaskController extends EventEmitter { static: { eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, - eth_sendTransaction: (payload, next, end) => { - const origin = payload.origin - const txParams = payload.params[0] - nodeify(this.txController.newUnapprovedTransaction, this.txController)(txParams, { origin }, end) - }, }, // account mgmt getAccounts: async () => { const isUnlocked = this.keyringController.memStore.getState().isUnlocked - const result = [] const selectedAddress = this.preferencesController.getSelectedAddress() - // only show address if account is unlocked if (isUnlocked && selectedAddress) { - result.push(selectedAddress) + return [selectedAddress] + } else { + return [] } - return result }, // tx signing - // old style msg signing - processMessage: this.newUnsignedMessage.bind(this), - // personal_sign msg signing + processTransaction: this.txController.newUnapprovedTransaction.bind(this.txController), + // msg signing + processEthSignMessage: this.newUnsignedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), processTypedMessage: this.newUnsignedTypedMessage.bind(this), } @@ -634,20 +628,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_sign. * @param {Function} cb = The callback function called with the signature. */ - newUnsignedMessage (msgParams, cb) { - const msgId = this.messageManager.addUnapprovedMessage(msgParams) + newUnsignedMessage (msgParams, req) { + const promise = this.messageManager.addUnapprovedMessageAsync(msgParams, req) this.sendUpdate() this.opts.showUnconfirmedMessage() - this.messageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + return promise } /** @@ -701,24 +686,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Function} cb - The callback function called with the signature. * Passed back to the requesting Dapp. */ - newUnsignedPersonalMessage (msgParams, cb) { - if (!msgParams.from) { - return cb(new Error('MetaMask Message Signature: from field is required.')) - } - - const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams) + async newUnsignedPersonalMessage (msgParams, req) { + const promise = this.personalMessageManager.addUnapprovedMessageAsync(msgParams, req) this.sendUpdate() this.opts.showUnconfirmedMessage() - this.personalMessageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + return promise } /** @@ -767,26 +739,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @param {Function} cb - The callback function, called with the signature. */ - newUnsignedTypedMessage (msgParams, cb) { - let msgId - try { - msgId = this.typedMessageManager.addUnapprovedMessage(msgParams) - this.sendUpdate() - this.opts.showUnconfirmedMessage() - } catch (e) { - return cb(e) - } - - this.typedMessageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + newUnsignedTypedMessage (msgParams, req) { + const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + return promise } /** diff --git a/package-lock.json b/package-lock.json index f7a35dcc6..1640f831b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8210,9 +8210,9 @@ } }, "eth-json-rpc-middleware": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.1.1.tgz", - "integrity": "sha512-uIMBZXMVN/ntnvNAN/o20gOFR7Ya23gg7S3jytdejpt/F6FKl25Y4zbyFrGhbt0oCKiYfECGln8pOlu6Zc8znw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.2.0.tgz", + "integrity": "sha512-P5TRtVRWYIVdhGFzLZoUFwOoS2r4rGhh2qxwPpeI8AcF+qj0EqgFHn22ts20XXqALTq+f7bmkwGEIE75e83pcw==", "requires": { "async": "2.6.0", "eth-query": "2.1.2", diff --git a/package.json b/package.json index fdb032741..908ee23bd 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", - "eth-json-rpc-middleware": "^2.1.1", + "eth-json-rpc-middleware": "^2.2.0", "eth-keyring-controller": "^3.1.1", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", From 2b54d948da80e5ef90b81f140b72df8a3547d0d1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 15:53:06 -0700 Subject: [PATCH 029/183] test - remove .only from unit tests --- test/unit/app/controllers/network-contoller-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js index 701eb5718..a87ffb904 100644 --- a/test/unit/app/controllers/network-contoller-test.js +++ b/test/unit/app/controllers/network-contoller-test.js @@ -33,7 +33,7 @@ describe('# Network Controller', function () { describe('network', function () { describe('#provider', function () { - it.only('provider should be updatable without reassignment', function () { + it('provider should be updatable without reassignment', function () { networkController.initializeProvider(networkControllerProviderConfig) const providerProxy = networkController.getProviderAndBlockTracker().provider assert.equal(providerProxy.test, undefined) From 76cfb10864364d53efcdfa5f646f9947c83b6fb2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 16:05:07 -0700 Subject: [PATCH 030/183] metamask-controller - wrap txController.addUnapprovedTx for wallet middleware reference before txController is instantiated --- app/scripts/metamask-controller.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8c3c70c5c..796c9385a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -247,7 +247,7 @@ module.exports = class MetamaskController extends EventEmitter { } }, // tx signing - processTransaction: this.txController.newUnapprovedTransaction.bind(this.txController), + processTransaction: this.newUnapprovedTransaction.bind(this), // msg signing processEthSignMessage: this.newUnsignedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), @@ -617,6 +617,18 @@ module.exports = class MetamaskController extends EventEmitter { // --------------------------------------------------------------------------- // Identity Management (signature operations) + /** + * Called when a Dapp suggests a new tx to be signed. + * this wrapper needs to exist so we can provide a reference to + * "newUnapprovedTransaction" before "txController" is instantiated + * + * @param {Object} msgParams - The params passed to eth_sign. + * @param {Object} req - (optional) the original request, containing the origin + */ + async newUnapprovedTransaction(txParams, req) { + return await this.txController.newUnapprovedTransaction(txParams, req) + } + // eth_sign methods: /** From 41e4d27cafc3e5fa5f295552ff7d395719d5cc3f Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 16:51:47 -0700 Subject: [PATCH 031/183] deps - bump eth-json-rpc-middleware for fetch bugfix --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1640f831b..24e766334 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8210,9 +8210,9 @@ } }, "eth-json-rpc-middleware": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.2.0.tgz", - "integrity": "sha512-P5TRtVRWYIVdhGFzLZoUFwOoS2r4rGhh2qxwPpeI8AcF+qj0EqgFHn22ts20XXqALTq+f7bmkwGEIE75e83pcw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.2.2.tgz", + "integrity": "sha512-ZyFnMxjYKucDC8GHIIE7Fhwj4psdRr7xrGONHolH3uqV+4V1iE8VJphlQpDkRTx2Ar1oM2gKJCQsZCuhG8Wucw==", "requires": { "async": "2.6.0", "eth-query": "2.1.2", diff --git a/package.json b/package.json index 908ee23bd..1c4d64cc9 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", - "eth-json-rpc-middleware": "^2.2.0", + "eth-json-rpc-middleware": "^2.2.2", "eth-keyring-controller": "^3.1.1", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", From 380964a68728b557a892d4b2e7175f45afe8222a Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 21:17:56 -0700 Subject: [PATCH 032/183] test - unit - metamask-controller - polyfill global.fetch --- test/unit/app/controllers/metamask-controller-test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 4bc16e65e..101fdfdc1 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -1,3 +1,5 @@ +global.fetch = global.fetch || require('isomorphic-fetch') + const assert = require('assert') const sinon = require('sinon') const clone = require('clone') @@ -479,7 +481,7 @@ describe('MetaMaskController', function () { it('errors when signing a message', async function () { await metamaskController.signPersonalMessage(personalMessages[0].msgParams) assert.equal(metamaskPersonalMsgs[msgId].status, 'signed') - assert.equal(metamaskPersonalMsgs[msgId].rawSig, '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b') + assert.equal(metamaskPersonalMsgs[msgId].rawSig, '0x6a1b65e2b8ed53cf398a769fad24738f9fbe29841fe6854e226953542c4b6a173473cb152b6b1ae5f06d601d45dd699a129b0a8ca84e78b423031db5baa734741b') }) }) @@ -513,7 +515,7 @@ describe('MetaMaskController', function () { }) it('sets up controller dnode api for trusted communication', function (done) { - streamTest = createThoughStream((chunk, enc, cb) => { + streamTest = createThoughStream((chunk, enc, cb) => { assert.equal(chunk.name, 'controller') cb() done() From 630e2300f4c2377bf14931964cfe9542910292db Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 22:10:17 -0700 Subject: [PATCH 033/183] test - unit - move fetch polyfill to helper --- test/helper.js | 3 +++ test/unit/app/controllers/currency-controller-test.js | 3 --- test/unit/config-manager-test.js | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/helper.js b/test/helper.js index a3abbebf2..6f1bc051f 100644 --- a/test/helper.js +++ b/test/helper.js @@ -14,6 +14,9 @@ global.log = log // polyfills // +// fetch +global.fetch = require('isomorphic-fetch') + // dom require('jsdom-global')() diff --git a/test/unit/app/controllers/currency-controller-test.js b/test/unit/app/controllers/currency-controller-test.js index 1941d1c43..7c4644d9f 100644 --- a/test/unit/app/controllers/currency-controller-test.js +++ b/test/unit/app/controllers/currency-controller-test.js @@ -1,6 +1,3 @@ -// polyfill fetch -global.fetch = global.fetch || require('isomorphic-fetch') - const assert = require('assert') const nock = require('nock') const CurrencyController = require('../../../../app/scripts/controllers/currency') diff --git a/test/unit/config-manager-test.js b/test/unit/config-manager-test.js index b710e2dfb..df0c549d0 100644 --- a/test/unit/config-manager-test.js +++ b/test/unit/config-manager-test.js @@ -1,6 +1,3 @@ -// polyfill fetch -global.fetch = global.fetch || require('isomorphic-fetch') - const assert = require('assert') const configManagerGen = require('../lib/mock-config-manager') From afdefc58e99a14b26911fc5badcf983629b33179 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 22:41:09 -0700 Subject: [PATCH 034/183] test - unit - tx-controller-test - add history object to txMeta when using internal calls --- .../transactions/tx-controller-test.js | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index 1f32a0f37..c450ed3ed 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -53,9 +53,9 @@ describe('Transaction Controller', function () { describe('#getUnapprovedTxCount', function () { it('should return the number of unapproved txs', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, - { id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, - { id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, + { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, + { id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, + { id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, ]) const unapprovedTxCount = txController.getUnapprovedTxCount() assert.equal(unapprovedTxCount, 3, 'should be 3') @@ -65,9 +65,9 @@ describe('Transaction Controller', function () { describe('#getPendingTxCount', function () { it('should return the number of pending txs', function () { txController.txStateManager._saveTxList([ - { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {} }, - { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {} }, - { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {} }, + { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, + { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, + { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, ]) const pendingTxCount = txController.getPendingTxCount() assert.equal(pendingTxCount, 3, 'should be 3') @@ -83,15 +83,15 @@ describe('Transaction Controller', function () { 'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d', } txController.txStateManager._saveTxList([ - {id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams}, - {id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams}, - {id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams}, - {id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams}, - {id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams}, - {id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams}, - {id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams}, - {id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams}, - {id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams}, + {id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] }, + {id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, ]) }) @@ -188,24 +188,22 @@ describe('Transaction Controller', function () { }) describe('#addTxGasDefaults', function () { - it('should add the tx defaults if their are none', function (done) { + it('should add the tx defaults if their are none', async () => { const txMeta = { - 'txParams': { - 'from': '0xc684832530fcbddae4b4230a47e991ddcec2831d', - 'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d', + txParams: { + from: '0xc684832530fcbddae4b4230a47e991ddcec2831d', + to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', }, + history: [], } - providerResultStub.eth_gasPrice = '4a817c800' - providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' } - providerResultStub.eth_estimateGas = '5209' - txController.addTxGasDefaults(txMeta) - .then((txMetaWithDefaults) => { - assert(txMetaWithDefaults.txParams.value, '0x0', 'should have added 0x0 as the value') - assert(txMetaWithDefaults.txParams.gasPrice, 'should have added the gas price') - assert(txMetaWithDefaults.txParams.gas, 'should have added the gas field') - done() - }) - .catch(done) + providerResultStub.eth_gasPrice = '4a817c800' + providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' } + providerResultStub.eth_estimateGas = '5209' + + const txMetaWithDefaults = await txController.addTxGasDefaults(txMeta) + assert(txMetaWithDefaults.txParams.value, '0x0', 'should have added 0x0 as the value') + assert(txMetaWithDefaults.txParams.gasPrice, 'should have added the gas price') + assert(txMetaWithDefaults.txParams.gas, 'should have added the gas field') }) }) @@ -378,7 +376,7 @@ describe('Transaction Controller', function () { data: '0x0', } txController.txStateManager._saveTxList([ - { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams }, + { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] }, ]) txController.retryTransaction(1) .then((txMeta) => { From 0b45810d4cdb6f5cfcf875b916b7dc52c4c6ef51 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 23:18:11 -0700 Subject: [PATCH 035/183] test - unit - run ganache-server in background --- test/helper.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/helper.js b/test/helper.js index 6f1bc051f..2225be37a 100644 --- a/test/helper.js +++ b/test/helper.js @@ -1,3 +1,4 @@ +const Ganache = require('ganache-core') import Enzyme from 'enzyme' import Adapter from 'enzyme-adapter-react-15' @@ -5,6 +6,12 @@ Enzyme.configure({ adapter: new Adapter() }) // disallow promises from swallowing errors enableFailureOnUnhandledPromiseRejection() +// ganache server +const server = Ganache.server() +server.listen(8545, () => { + console.log('Ganache Testrpc is running on "http://localhost:8545"') +}) + // logging util var log = require('loglevel') log.setDefaultLevel(5) From da5be0812aed74548f1107a9f1ce3a2abc479076 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 23:19:39 -0700 Subject: [PATCH 036/183] test - unit - metamask-controller - fix many bugs in tests --- test/lib/createTxMeta.js | 16 ++++ .../controllers/metamask-controller-test.js | 78 +++++++++++-------- 2 files changed, 61 insertions(+), 33 deletions(-) create mode 100644 test/lib/createTxMeta.js diff --git a/test/lib/createTxMeta.js b/test/lib/createTxMeta.js new file mode 100644 index 000000000..246ea58a5 --- /dev/null +++ b/test/lib/createTxMeta.js @@ -0,0 +1,16 @@ +const txStateHistoryHelper = require('../../app/scripts/controllers/transactions/lib/tx-state-history-helper') + +module.exports = createTxMeta + +function createTxMeta(partialMeta) { + const txMeta = Object.assign({ + status: 'unapproved', + txParams: {}, + }, partialMeta) + // initialize history + txMeta.history = [] + // capture initial snapshot of txMeta for history + const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta) + txMeta.history.push(snapshot) + return txMeta +} diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 101fdfdc1..0deaaac62 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -1,13 +1,12 @@ -global.fetch = global.fetch || require('isomorphic-fetch') - const assert = require('assert') const sinon = require('sinon') const clone = require('clone') const nock = require('nock') const createThoughStream = require('through2').obj -const MetaMaskController = require('../../../../app/scripts/metamask-controller') const blacklistJSON = require('eth-phishing-detect/src/config') +const MetaMaskController = require('../../../../app/scripts/metamask-controller') const firstTimeState = require('../../../../app/scripts/first-time-state') +const createTxMeta = require('../../../lib/createTxMeta') const currentNetworkId = 42 const DEFAULT_LABEL = 'Account 1' @@ -15,6 +14,7 @@ const TEST_SEED = 'debris dizzy just program just float decrease vacant alarm re const TEST_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc' const TEST_SEED_ALT = 'setup olympic issue mobile velvet surge alcohol burger horse view reopen gentle' const TEST_ADDRESS_ALT = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' +const CUSTOM_RPC_URL = 'http://localhost:8545' describe('MetaMaskController', function () { let metamaskController @@ -197,29 +197,19 @@ describe('MetaMaskController', function () { }) describe('#setCustomRpc', function () { - const customRPC = 'https://custom.rpc/' let rpcTarget beforeEach(function () { - - nock('https://custom.rpc') - .post('/') - .reply(200) - - rpcTarget = metamaskController.setCustomRpc(customRPC) - }) - - afterEach(function () { - nock.cleanAll() + rpcTarget = metamaskController.setCustomRpc(CUSTOM_RPC_URL) }) it('returns custom RPC that when called', async function () { - assert.equal(await rpcTarget, customRPC) + assert.equal(await rpcTarget, CUSTOM_RPC_URL) }) it('changes the network controller rpc', function () { const networkControllerState = metamaskController.networkController.store.getState() - assert.equal(networkControllerState.provider.rpcTarget, customRPC) + assert.equal(networkControllerState.provider.rpcTarget, CUSTOM_RPC_URL) }) }) @@ -324,9 +314,10 @@ describe('MetaMaskController', function () { getNetworkstub.returns(42) metamaskController.txController.txStateManager._saveTxList([ - { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'} }, - { id: 2, status: 'rejected', metamaskNetworkId: 32, txParams: {} }, - { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4'} }, + createTxMeta({ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'} }), + createTxMeta({ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'} }), + createTxMeta({ id: 2, status: 'rejected', metamaskNetworkId: 32 }), + createTxMeta({ id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {from: '0xB09d8505E1F4EF1CeA089D47094f5DD3464083d4'} }), ]) }) @@ -370,14 +361,14 @@ describe('MetaMaskController', function () { }) - describe('#newUnsignedMessage', function () { + describe('#newUnsignedMessage', () => { let msgParams, metamaskMsgs, messages, msgId const address = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' const data = '0x43727970746f6b697474696573' - beforeEach(async function () { + beforeEach(async () => { await metamaskController.createNewVaultAndRestore('foobar1337', TEST_SEED_ALT) @@ -386,7 +377,10 @@ describe('MetaMaskController', function () { 'data': data, } - metamaskController.newUnsignedMessage(msgParams, noop) + const promise = metamaskController.newUnsignedMessage(msgParams) + // handle the promise so it doesn't throw an unhandledRejection + promise.then(noop).catch(noop) + metamaskMsgs = metamaskController.messageManager.getUnapprovedMsgs() messages = metamaskController.messageManager.messages msgId = Object.keys(metamaskMsgs)[0] @@ -426,13 +420,16 @@ describe('MetaMaskController', function () { describe('#newUnsignedPersonalMessage', function () { - it('errors with no from in msgParams', function () { + it('errors with no from in msgParams', async () => { const msgParams = { 'data': data, } - metamaskController.newUnsignedPersonalMessage(msgParams, function (error) { + try { + await metamaskController.newUnsignedPersonalMessage(msgParams) + assert.fail('should have thrown') + } catch (error) { assert.equal(error.message, 'MetaMask Message Signature: from field is required.') - }) + } }) let msgParams, metamaskPersonalMsgs, personalMessages, msgId @@ -449,7 +446,10 @@ describe('MetaMaskController', function () { 'data': data, } - metamaskController.newUnsignedPersonalMessage(msgParams, noop) + const promise = metamaskController.newUnsignedPersonalMessage(msgParams) + // handle the promise so it doesn't throw an unhandledRejection + promise.then(noop).catch(noop) + metamaskPersonalMsgs = metamaskController.personalMessageManager.getUnapprovedMsgs() personalMessages = metamaskController.personalMessageManager.messages msgId = Object.keys(metamaskPersonalMsgs)[0] @@ -488,22 +488,28 @@ describe('MetaMaskController', function () { describe('#setupUntrustedCommunication', function () { let streamTest - const phishingUrl = 'decentral.market' + const phishingUrl = 'myethereumwalletntw.com' afterEach(function () { streamTest.end() }) - it('sets up phishing stream for untrusted communication ', async function () { + it('sets up phishing stream for untrusted communication ', async () => { await metamaskController.blacklistController.updatePhishingList() + console.log(blacklistJSON.blacklist.includes(phishingUrl)) + + const { promise, resolve } = deferredPromise() streamTest = createThoughStream((chunk, enc, cb) => { - assert.equal(chunk.name, 'phishing') + console.log('createThoughStream', chunk) + if (chunk.name !== 'phishing') return cb() assert.equal(chunk.data.hostname, phishingUrl) - cb() - }) - // console.log(streamTest) - metamaskController.setupUntrustedCommunication(streamTest, phishingUrl) + resolve() + cb() + }) + metamaskController.setupUntrustedCommunication(streamTest, phishingUrl) + + await promise }) }) @@ -550,3 +556,9 @@ describe('MetaMaskController', function () { }) }) + +function deferredPromise () { + let resolve + const promise = new Promise(_resolve => { resolve = _resolve }) + return { promise, resolve } +} From deab195772d4566effa7e052b5594032a92c4246 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 23:19:54 -0700 Subject: [PATCH 037/183] test - unit - code style nitpick --- test/unit/app/controllers/transactions/pending-tx-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index 672856afe..c0d033007 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -17,6 +17,7 @@ describe('PendingTransactionTracker', function () { let pendingTxTracker, txMeta, txMetaNoHash, txMetaNoRawTx, providerResultStub, provider, txMeta3, txList, knownErrors this.timeout(10000) + beforeEach(function () { txMeta = { id: 1, @@ -331,7 +332,7 @@ describe('PendingTransactionTracker', function () { }) describe('#_checkIfNonceIsTaken', function () { - beforeEach ( function () { + beforeEach(function () { let confirmedTxList = [{ id: 1, hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb', From a0fe5b9190a4991c93ba99dd7e65d154b80b4702 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 11:09:19 -0700 Subject: [PATCH 038/183] test - unit - metamask-controller - remove log --- test/unit/app/controllers/metamask-controller-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js index 0deaaac62..1b2c95f48 100644 --- a/test/unit/app/controllers/metamask-controller-test.js +++ b/test/unit/app/controllers/metamask-controller-test.js @@ -501,7 +501,6 @@ describe('MetaMaskController', function () { const { promise, resolve } = deferredPromise() streamTest = createThoughStream((chunk, enc, cb) => { - console.log('createThoughStream', chunk) if (chunk.name !== 'phishing') return cb() assert.equal(chunk.data.hostname, phishingUrl) resolve() From 61ef4f1f29169c553b6a8fc36803e6f7596fc9ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 13:21:42 -0700 Subject: [PATCH 039/183] tx-gas-utils - query for block without tx bodies --- app/scripts/controllers/transactions/tx-gas-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 36b5cdbc9..9bf2ae1e2 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -25,7 +25,7 @@ class TxGasUtil { @returns {object} the txMeta object with the gas written to the txParams */ async analyzeGasUsage (txMeta) { - const block = await this.query.getBlockByNumber('latest', true) + const block = await this.query.getBlockByNumber('latest', false) let estimatedGasHex try { estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit) @@ -126,4 +126,4 @@ class TxGasUtil { } } -module.exports = TxGasUtil \ No newline at end of file +module.exports = TxGasUtil From 9f8d5f05470d68a7a9a5474a5b1f4587398e94a3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 13:30:26 -0700 Subject: [PATCH 040/183] controllers - transactions - pending-tx-tracker - _getBlock - poll until block is truthy --- .../controllers/transactions/pending-tx-tracker.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index bd26a72d9..e1bb67c90 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -1,6 +1,7 @@ const EventEmitter = require('events') const log = require('loglevel') const EthQuery = require('ethjs-query') +const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) /** Event emitter utility class for tracking the transactions as they
@@ -212,7 +213,15 @@ class PendingTransactionTracker extends EventEmitter { } async _getBlock (blockNumber) { - return await this.query.getBlockByNumber(blockNumber, false) + let block + while (!block) { + // block requests will sometimes return null due do the infura api + // being backed by multiple out-of-sync clients + block = await this.query.getBlockByNumber(blockNumber, false) + // if block is null, wait 1 sec then try again + if (!block) await timeout(1000) + } + return block } /** From 5be154ea2035810462ff0e7051e537870bfc1afb Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 14:29:31 -0700 Subject: [PATCH 041/183] controllers - transactions - merge @frankiebee's work with mine --- .gitignore | 3 +- app/scripts/controllers/transactions/index.js | 46 ++++++++-- .../controllers/transactions/nonce-tracker.js | 16 +--- .../transactions/pending-tx-tracker.js | 89 +++---------------- app/scripts/lib/util.js | 14 +++ .../transactions/pending-tx-test.js | 57 +----------- .../transactions/tx-controller-test.js | 6 +- 7 files changed, 78 insertions(+), 153 deletions(-) diff --git a/.gitignore b/.gitignore index 0e91a7d04..21a13c904 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ package # IDEs .idea .vscode +.sublime-project temp .tmp @@ -37,4 +38,4 @@ ui/app/css/output/ notes.txt .coveralls.yml -.nyc_output +.nyc_output \ No newline at end of file diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 7cb8af3a8..f84fd95ff 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -78,7 +78,7 @@ class TransactionController extends EventEmitter { }) this.txStateManager.store.subscribe(() => this.emit('update:badge')) - this._setupListners() + this._setupListeners() // memstore is computed from a few different stores this._updateMemstore() this.txStateManager.store.subscribe(() => this._updateMemstore()) @@ -382,8 +382,9 @@ class TransactionController extends EventEmitter { is called in constructor applies the listeners for pendingTxTracker txStateManager and blockTracker */ - _setupListners () { + _setupListeners () { this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update')) + this._setupBlockTrackerListener() this.pendingTxTracker.on('tx:warning', (txMeta) => { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) @@ -399,13 +400,6 @@ class TransactionController extends EventEmitter { txMeta.retryCount++ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') }) - - this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker)) - // this is a little messy but until ethstore has been either - // removed or redone this is to guard against the race condition - this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker)) - this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker)) - } /** @@ -429,6 +423,40 @@ class TransactionController extends EventEmitter { }) } + _setupBlockTrackerListener () { + let listenersAreActive = false + const latestBlockHandler = this._onLatestBlock.bind(this) + const blockTracker = this.blockTracker + const txStateManager = this.txStateManager + + txStateManager.on('tx:status-update', updateSubscription) + updateSubscription() + + function updateSubscription() { + const pendingTxs = txStateManager.getPendingTransactions() + if (!listenersAreActive && pendingTxs.length > 0) { + blockTracker.on('latest', latestBlockHandler) + listenersAreActive = true + } else if (listenersAreActive && !pendingTxs.length) { + blockTracker.removeListener('latest', latestBlockHandler) + listenersAreActive = false + } + } + } + + async _onLatestBlock (blockNumber) { + try { + await this.pendingTxTracker.updatePendingTxs() + } catch (err) { + log.error(err) + } + try { + await this.pendingTxTracker.resubmitPendingTxs(blockNumber) + } catch (err) { + log.error(err) + } + } + /** Updates the memStore in transaction controller */ diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index 490118c89..fe2d25fca 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -35,7 +35,7 @@ class NonceTracker { * @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} highetSuggested - The maximum between the other two, the number returned. + * @property {number} highestSuggested - The maximum between the other two, the number returned. */ /** @@ -75,14 +75,6 @@ class NonceTracker { return { nextNonce, nonceDetails, releaseLock } } - async _getCurrentBlock () { - const currentBlock = this.blockTracker.getCurrentBlock() - if (currentBlock) return currentBlock - return await new Promise((reject, resolve) => { - this.blockTracker.once('latest', resolve) - }) - } - async _globalMutexFree () { const globalMutex = this._lookupMutex('global') const release = await globalMutex.acquire() @@ -108,9 +100,8 @@ class NonceTracker { // calculate next nonce // we need to make sure our base count // and pending count are from the same block - const currentBlock = await this._getCurrentBlock() - const blockNumber = currentBlock.blockNumber - const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest') + 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 } @@ -171,6 +162,7 @@ class NonceTracker { return { name: 'local', nonce: highest, details: { startPoint, highest } } } + } module.exports = NonceTracker diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index e1bb67c90..e981e2991 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -24,60 +24,27 @@ class PendingTransactionTracker extends EventEmitter { super() this.query = new EthQuery(config.provider) this.nonceTracker = config.nonceTracker - // default is one day this.getPendingTransactions = config.getPendingTransactions this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction this.confirmTransaction = config.confirmTransaction - this._checkPendingTxs() + this.updatePendingTxs() } /** - checks if a signed tx is in a block and - if it is included emits tx status as 'confirmed' - @param block {object}, a full block - @emits tx:confirmed - @emits tx:failed - */ - async checkForTxInBlock (blockNumber) { - const block = await this._getBlock(blockNumber) - const signedTxList = this.getPendingTransactions() - if (!signedTxList.length) return - signedTxList.forEach((txMeta) => { - const txHash = txMeta.hash - const txId = txMeta.id - - if (!txHash) { - 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 (!block.transactions.length) return - - block.transactions.forEach((hash) => { - if (hash === txHash) { - this.confirmTransaction(txId) - } - }) - }) - } - - /** - asks the network for the transaction to see if a block number is included on it - if we have skipped/missed blocks - @param object - oldBlock newBlock + checks the network for signed txs and releases the nonce global lock if it is */ - queryPendingTxs ({ oldBlock, newBlock }) { - // check pending transactions on start - if (!oldBlock) { - this._checkPendingTxs() - return + async updatePendingTxs () { + const pendingTxs = this.getPendingTransactions() + // in order to keep the nonceTracker accurate we block it while updating pending transactions + const nonceGlobalLock = await this.nonceTracker.getGlobalLock() + try { + await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) + } catch (err) { + log.error('PendingTransactionTracker - Error updating pending transactions') + log.error(err) } - // if we synced by more than one block, check for missed pending transactions - const diff = Number.parseInt(newBlock, 16) - Number.parseInt(oldBlock, 16) - if (diff > 1) this._checkPendingTxs() + nonceGlobalLock.releaseLock() } /** @@ -151,6 +118,7 @@ class PendingTransactionTracker extends EventEmitter { this.emit('tx:retry', txMeta) return txHash } + /** Ask the network for the transaction to see if it has been include in a block @param txMeta {Object} - the txMeta object @@ -180,9 +148,8 @@ class PendingTransactionTracker extends EventEmitter { } // get latest transaction status - let txParams try { - txParams = await this.query.getTransactionByHash(txHash) + const txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { this.confirmTransaction(txId) @@ -196,34 +163,6 @@ class PendingTransactionTracker extends EventEmitter { } } - /** - checks the network for signed txs and releases the nonce global lock if it is - */ - async _checkPendingTxs () { - const signedTxList = this.getPendingTransactions() - // in order to keep the nonceTracker accurate we block it while updating pending transactions - const nonceGlobalLock = await this.nonceTracker.getGlobalLock() - try { - await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta))) - } catch (err) { - log.error('PendingTransactionWatcher - Error updating pending transactions') - log.error(err) - } - nonceGlobalLock.releaseLock() - } - - async _getBlock (blockNumber) { - let block - while (!block) { - // block requests will sometimes return null due do the infura api - // being backed by multiple out-of-sync clients - block = await this.query.getBlockByNumber(blockNumber, false) - // if block is null, wait 1 sec then try again - if (!block) await timeout(1000) - } - return block - } - /** checks to see if a confirmed txMeta has the same nonce @param txMeta {Object} - txMeta object diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index 431d1e59c..7ceb9da3c 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -99,7 +99,21 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) { return targetBN.mul(numBN).div(denomBN) } +function applyListeners (listeners, emitter) { + Object.keys(listeners).forEach((key) => { + emitter.on(key, listeners[key]) + }) +} + +function removeListeners (listeners, emitter) { + Object.keys(listeners).forEach((key) => { + emitter.removeListener(key, listeners[key]) + }) +} + module.exports = { + removeListeners, + applyListeners, getStack, getEnvironmentType, sufficientBalance, diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index c0d033007..f06f1c0dd 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -7,7 +7,7 @@ const { createTestProviderTools } = require('../../../../stub/provider') const PendingTransactionTracker = require('../../../../../app/scripts/controllers/transactions/pending-tx-tracker') const MockTxGen = require('../../../../lib/mock-tx-gen') const sinon = require('sinon') -const noop = () => true +const noop =()=>true const currentNetworkId = 42 const otherNetworkId = 36 const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex') @@ -108,56 +108,6 @@ describe('PendingTransactionTracker', function () { }) }) - describe('#checkForTxInBlock', function () { - it('should return if no pending transactions', function () { - // throw a type error if it trys to do anything on the block - // thus failing the test - const block = Proxy.revocable({}, {}).revoke() - pendingTxTracker.checkForTxInBlock(block) - }) - it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { - const block = Proxy.revocable({}, {}).revoke() - pendingTxTracker.getPendingTransactions = () => [txMetaNoHash] - pendingTxTracker.once('tx:failed', (txId, err) => { - assert(txId, txMetaNoHash.id, 'should pass txId') - done() - }) - pendingTxTracker.checkForTxInBlock(block) - }) - }) - describe('#queryPendingTxs', function () { - it('should call #_checkPendingTxs if their is no oldBlock', function (done) { - let newBlock, oldBlock - newBlock = '0x01' - const originalFunction = pendingTxTracker._checkPendingTxs - pendingTxTracker._checkPendingTxs = () => { done() } - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - pendingTxTracker._checkPendingTxs = originalFunction - }) - it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) { - let newBlock, oldBlock - oldBlock = '0x01' - newBlock = '0x03' - const originalFunction = pendingTxTracker._checkPendingTxs - pendingTxTracker._checkPendingTxs = () => { done() } - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - pendingTxTracker._checkPendingTxs = originalFunction - }) - it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) { - let newBlock, oldBlock - oldBlock = '0x1' - newBlock = '0x2' - const originalFunction = pendingTxTracker._checkPendingTxs - pendingTxTracker._checkPendingTxs = () => { - const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less') - done(err) - } - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - pendingTxTracker._checkPendingTxs = originalFunction - done() - }) - }) - describe('#_checkPendingTx', function () { it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { pendingTxTracker.once('tx:failed', (txId, err) => { @@ -187,7 +137,6 @@ describe('PendingTransactionTracker', function () { it('should warp all txMeta\'s in #_checkPendingTx', function (done) { pendingTxTracker.getPendingTransactions = () => txList pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) } - const list = txList.map Promise.all(txList.map((tx) => tx.processed)) .then((txCompletedList) => done()) .catch(done) @@ -201,7 +150,7 @@ describe('PendingTransactionTracker', function () { beforeEach(function () { const txMeta2 = txMeta3 = txMeta txList = [txMeta, txMeta2, txMeta3].map((tx) => { - tx.processed = new Promise ((resolve) => { tx.resolve = resolve }) + tx.processed = new Promise((resolve) => { tx.resolve = resolve }) return tx }) }) @@ -218,7 +167,7 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.resubmitPendingTxs(blockNuberStub) }) it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) { - knownErrors =[ + knownErrors = [ // geth ' Replacement transaction Underpriced ', ' known transaction', diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index c450ed3ed..b0cc0acda 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -1,4 +1,5 @@ const assert = require('assert') +const EventEmitter = require('events') const ethUtil = require('ethereumjs-util') const EthTx = require('ethereumjs-tx') const EthjsQuery = require('ethjs-query') @@ -26,12 +27,13 @@ describe('Transaction Controller', function () { provider = createTestProviderTools({ scaffold: providerResultStub }).provider query = new EthjsQuery(provider) fromAccount = getTestAccounts()[0] - + const blockTrackerStub = new EventEmitter() + blockTrackerStub.getCurrentBlock = noop txController = new TransactionController({ provider, networkStore: new ObservableStore(currentNetworkId), txHistoryLimit: 10, - blockTracker: { getCurrentBlock: noop, on: noop, once: noop }, + blockTracker: blockTrackerStub, signTransaction: (ethTx) => new Promise((resolve) => { ethTx.sign(fromAccount.key) resolve() From 1b3fedd10d6209fe4c7dfcdc9e90a23c3972bf16 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 15:54:47 -0700 Subject: [PATCH 042/183] controllers - transaction - pending-tx-tracker - lint fix --- app/scripts/controllers/transactions/pending-tx-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index e981e2991..68f016d79 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -1,7 +1,7 @@ const EventEmitter = require('events') const log = require('loglevel') const EthQuery = require('ethjs-query') -const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) + /** Event emitter utility class for tracking the transactions as they
From 686d5cf825b8f6312c351103d5cae15af1ff9b8e Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 15:59:34 -0700 Subject: [PATCH 043/183] test - unit - nonce-tracker - fix blockTracker stub --- test/unit/app/controllers/transactions/nonce-tracker-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/app/controllers/transactions/nonce-tracker-test.js b/test/unit/app/controllers/transactions/nonce-tracker-test.js index 78d637706..aef606bab 100644 --- a/test/unit/app/controllers/transactions/nonce-tracker-test.js +++ b/test/unit/app/controllers/transactions/nonce-tracker-test.js @@ -229,6 +229,7 @@ function generateNonceTrackerWith (pending, confirmed, providerStub = '0x0') { } const blockTracker = { getCurrentBlock: () => '0x11b568', + getLatestBlock: async () => '0x11b568', } return new NonceTracker({ provider, From 31f47a7a426fc623a9b760127f802983b497ff77 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 16:00:35 -0700 Subject: [PATCH 044/183] test - unit - pending-tx-tracker - update method name --- test/unit/app/controllers/transactions/pending-tx-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index f06f1c0dd..f0096dadd 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -134,14 +134,14 @@ describe('PendingTransactionTracker', function () { }) }) - it('should warp all txMeta\'s in #_checkPendingTx', function (done) { + it('should warp all txMeta\'s in #updatePendingTxs', function (done) { pendingTxTracker.getPendingTransactions = () => txList pendingTxTracker._checkPendingTx = (tx) => { tx.resolve(tx) } Promise.all(txList.map((tx) => tx.processed)) .then((txCompletedList) => done()) .catch(done) - pendingTxTracker._checkPendingTxs() + pendingTxTracker.updatePendingTxs() }) }) From fe42de46422c89156e91fb08ee06f50511c8601f Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 22:58:14 -0700 Subject: [PATCH 045/183] metamask-controller - update preferences controller addresses after import account --- app/scripts/metamask-controller.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 796c9385a..ed606d4ab 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -345,7 +345,7 @@ module.exports = class MetamaskController extends EventEmitter { verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: nodeify(this.resetAccount, this), - importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), // vault management submitPassword: nodeify(keyringController.submitPassword, keyringController), @@ -603,15 +603,15 @@ module.exports = class MetamaskController extends EventEmitter { * @param {any} args - The data required by that strategy to import an account. * @param {Function} cb - A callback function called with a state update on success. */ - importAccountWithStrategy (strategy, args, cb) { - accountImporter.importAccount(strategy, args) - .then((privateKey) => { - return this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) - }) - .then(keyring => keyring.getAccounts()) - .then((accounts) => this.preferencesController.setSelectedAddress(accounts[0])) - .then(() => { cb(null, this.keyringController.fullUpdate()) }) - .catch((reason) => { cb(reason) }) + async importAccountWithStrategy (strategy, args) { + const privateKey = await accountImporter.importAccount(strategy, args) + const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) + const accounts = await keyring.getAccounts() + // update accounts in preferences controller + const allAccounts = await keyringController.getAccounts() + this.preferencesController.setAddresses(allAccounts) + // set new account as selected + await this.preferencesController.setSelectedAddress(accounts[0]) } // --------------------------------------------------------------------------- From c9f3404ca5b04df859f765f9f8e90f21737142c1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 23:14:38 -0700 Subject: [PATCH 046/183] metamask-controller - lint fix --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ed606d4ab..2e74b3a20 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -608,7 +608,7 @@ module.exports = class MetamaskController extends EventEmitter { const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) const accounts = await keyring.getAccounts() // update accounts in preferences controller - const allAccounts = await keyringController.getAccounts() + const allAccounts = await this.keyringController.getAccounts() this.preferencesController.setAddresses(allAccounts) // set new account as selected await this.preferencesController.setSelectedAddress(accounts[0]) From 7d449e974ddd5412581fe00976429c2ebb9ab644 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 23:34:40 -0700 Subject: [PATCH 047/183] newui - unlock - dont catch errors unrelated to tryUnlockMetamask --- ui/app/components/pages/unlock-page/unlock-page.component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/components/pages/unlock-page/unlock-page.component.js b/ui/app/components/pages/unlock-page/unlock-page.component.js index a2f009d8f..b6384b32d 100644 --- a/ui/app/components/pages/unlock-page/unlock-page.component.js +++ b/ui/app/components/pages/unlock-page/unlock-page.component.js @@ -37,8 +37,8 @@ class UnlockPage extends Component { tryUnlockMetamask (password) { const { tryUnlockMetamask, history } = this.props tryUnlockMetamask(password) - .then(() => history.push(DEFAULT_ROUTE)) .catch(({ message }) => this.setState({ error: message })) + .then(() => history.push(DEFAULT_ROUTE)) } handleSubmit (event) { @@ -55,8 +55,8 @@ class UnlockPage extends Component { this.setState({ error: null }) tryUnlockMetamask(password) - .then(() => history.push(DEFAULT_ROUTE)) .catch(({ message }) => this.setState({ error: message })) + .then(() => history.push(DEFAULT_ROUTE)) } handleInputChange ({ target }) { From 16d0db15e05ec97adfcb050901d84a5130e88892 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 00:41:28 -0700 Subject: [PATCH 048/183] controllers - transactions - fix tx confirmation --- app/scripts/controllers/transactions/index.js | 2 +- app/scripts/controllers/transactions/pending-tx-tracker.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index f84fd95ff..6266fea16 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -57,7 +57,6 @@ class TransactionController extends EventEmitter { initState: opts.initState, txHistoryLimit: opts.txHistoryLimit, getNetwork: this.getNetwork.bind(this), - confirmTransaction: this.confirmTransaction.bind(this), }) this._onBootCleanUp() @@ -389,6 +388,7 @@ class TransactionController extends EventEmitter { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) + this.pendingTxTracker.on('tx:confirmed', (txId) => this.confirmTransaction(txId)) 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 68f016d79..9a764b962 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -28,7 +28,6 @@ class PendingTransactionTracker extends EventEmitter { this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction this.confirmTransaction = config.confirmTransaction - this.updatePendingTxs() } /** @@ -37,6 +36,7 @@ class PendingTransactionTracker extends EventEmitter { async updatePendingTxs () { const pendingTxs = this.getPendingTransactions() // in order to keep the nonceTracker accurate we block it while updating pending transactions + console.log('updating pending txs....', pendingTxs) const nonceGlobalLock = await this.nonceTracker.getGlobalLock() try { await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) @@ -152,7 +152,7 @@ class PendingTransactionTracker extends EventEmitter { const txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { - this.confirmTransaction(txId) + this.emit('tx:confirmed', txId) } } catch (err) { txMeta.warning = { From 58de5671cc26a8848b9e0e02bcd6d18bdfcd3ea8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 00:53:44 -0700 Subject: [PATCH 049/183] controllers - transactions - fix tx status update on boot --- app/scripts/controllers/transactions/index.js | 12 ++++++++++++ .../controllers/transactions/pending-tx-tracker.js | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 6266fea16..71e7ea920 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -83,7 +83,11 @@ class TransactionController extends EventEmitter { this.txStateManager.store.subscribe(() => this._updateMemstore()) this.networkStore.subscribe(() => this._updateMemstore()) this.preferencesStore.subscribe(() => this._updateMemstore()) + + // request state update to finalize initialization + this._updatePendingTxsAfterFirstBlock() } + /** @returns {number} the chainId*/ getChainId () { const networkState = this.networkStore.getState() @@ -349,6 +353,14 @@ class TransactionController extends EventEmitter { this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts) } + // called once on startup + async _updatePendingTxsAfterFirstBlock () { + // wait for first block so we know we're ready + await this.blockTracker.getLatestBlock() + // get status update for all pending transactions (for the current network) + await this.pendingTxTracker.updatePendingTxs() + } + /** If transaction controller was rebooted with transactions that are uncompleted in steps of the transaction signing or user confirmation process it will either diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 9a764b962..70cac096b 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -34,11 +34,10 @@ class PendingTransactionTracker extends EventEmitter { checks the network for signed txs and releases the nonce global lock if it is */ async updatePendingTxs () { - const pendingTxs = this.getPendingTransactions() // in order to keep the nonceTracker accurate we block it while updating pending transactions - console.log('updating pending txs....', pendingTxs) const nonceGlobalLock = await this.nonceTracker.getGlobalLock() try { + const pendingTxs = this.getPendingTransactions() await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) } catch (err) { log.error('PendingTransactionTracker - Error updating pending transactions') From 32293a959c367ce5dd585111d4ee0d873072c830 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 01:08:55 -0700 Subject: [PATCH 050/183] test - unit - tx-controller - fix blockTracker stub --- test/unit/app/controllers/transactions/tx-controller-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index b0cc0acda..559c4011b 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -29,6 +29,7 @@ describe('Transaction Controller', function () { fromAccount = getTestAccounts()[0] const blockTrackerStub = new EventEmitter() blockTrackerStub.getCurrentBlock = noop + blockTrackerStub.getLatestBlock = noop txController = new TransactionController({ provider, networkStore: new ObservableStore(currentNetworkId), From ffb8fa16497d0c4a48e3bd4b918dde1ac3adcd5d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 6 Jun 2018 11:17:52 -0700 Subject: [PATCH 051/183] lint - remove unused require --- app/scripts/metamask-controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b206c6b67..b1d0217fd 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -45,7 +45,6 @@ const BN = require('ethereumjs-util').BN const GWEI_BN = new BN('1000000000') const percentile = require('percentile') const seedPhraseVerifier = require('./lib/seed-phrase-verifier') -const cleanErrorStack = require('./lib/cleanErrorStack') const DiagnosticsReporter = require('./lib/diagnostics-reporter') const log = require('loglevel') From 3ce83570ee336524e1ab0da50a9f47744cddb193 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 7 Jun 2018 12:26:37 -0700 Subject: [PATCH 052/183] network - provider - infura - use block-reemit middleware --- .../controllers/network/createInfuraClient.js | 4 +- package-lock.json | 51 ++++++++++--------- package.json | 2 +- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index adbf4c001..663a2595a 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,6 +1,6 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') @@ -15,7 +15,7 @@ function createInfuraClient ({ network }) { const blockTracker = new BlockTracker({ provider: blockProvider }) const networkMiddleware = mergeMiddleware([ - createBlockRefMiddleware({ blockTracker }), + createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockCacheMiddleware({ blockTracker }), createInflightMiddleware(), createBlockTrackerInspectorMiddleware({ blockTracker }), diff --git a/package-lock.json b/package-lock.json index a32b86e4d..f59eaf017 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8217,25 +8217,26 @@ } }, "eth-json-rpc-middleware": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.2.2.tgz", - "integrity": "sha512-ZyFnMxjYKucDC8GHIIE7Fhwj4psdRr7xrGONHolH3uqV+4V1iE8VJphlQpDkRTx2Ar1oM2gKJCQsZCuhG8Wucw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.3.0.tgz", + "integrity": "sha512-pMG8pDbmipPIellAoAz494ShJ/vLiCy0QOOLXPv2IwTtrdnpr04Zj9NTVxPhg6F+c87cyiUgHi6zOgoZQKvaGQ==", "requires": { - "async": "2.6.0", - "eth-query": "2.1.2", - "eth-sig-util": "1.4.2", - "eth-tx-summary": "3.2.1", - "ethereumjs-block": "1.7.0", - "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.2.0", - "ethereumjs-vm": "2.3.2", - "fetch-ponyfill": "4.1.0", - "json-rpc-engine": "3.7.3", - "json-rpc-error": "2.0.0", - "json-stable-stringify": "1.0.1", - "pify": "3.0.0", - "promise-to-callback": "1.0.0", - "tape": "4.8.0" + "async": "^2.5.0", + "clone": "^2.1.1", + "eth-query": "^2.1.2", + "eth-sig-util": "^1.4.2", + "eth-tx-summary": "^3.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.1.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^3.6.3", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "pify": "^3.0.0", + "promise-to-callback": "^1.0.0", + "tape": "^4.6.3" }, "dependencies": { "ethereumjs-util": { @@ -8243,13 +8244,13 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "4.11.8", - "create-hash": "1.1.3", - "ethjs-util": "0.1.4", - "keccak": "1.4.0", - "rlp": "2.0.0", - "safe-buffer": "5.1.1", - "secp256k1": "3.4.0" + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" } } } diff --git a/package.json b/package.json index 707a90ffe..564db99c9 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", - "eth-json-rpc-middleware": "^2.2.2", + "eth-json-rpc-middleware": "^2.3.0", "eth-keyring-controller": "^3.1.4", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", From 0fa90149868d5c21bca75e318a392e1ecb77c6f0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 09:37:08 -0700 Subject: [PATCH 053/183] test - e2e - reduce browser-specific code --- test/e2e/metamask.spec.js | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index a08a34d96..f993f3fca 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -8,31 +8,33 @@ const { By, Key } = webdriver const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func') describe('Metamask popup page', function () { - let driver, accountAddress, tokenAddress, extensionId + const browser = process.env.SELENIUM_BROWSER + let driver, accountAddress, tokenAddress, extensionId, extensionUri this.timeout(0) before(async function () { - if (process.env.SELENIUM_BROWSER === 'chrome') { - const extPath = path.resolve('dist/chrome') + const extPath = path.resolve(`dist/${browser}`) + if (browser === 'chrome') { driver = buildChromeWebDriver(extPath) extensionId = await getExtensionIdChrome(driver) - await driver.get(`chrome-extension://${extensionId}/popup.html`) - - } else if (process.env.SELENIUM_BROWSER === 'firefox') { - const extPath = path.resolve('dist/firefox') + extensionUri = `chrome-extension://${extensionId}/popup.html` + } else if (browser === 'firefox') { driver = buildFirefoxWebdriver() await installWebExt(driver, extPath) await delay(700) extensionId = await getExtensionIdFirefox(driver) - await driver.get(`moz-extension://${extensionId}/popup.html`) + extensionUri = `moz-extension://${extensionId}/popup.html` + } else { + throw new Error(`Unknown Browser "${browser}"`) } + await driver.get(extensionUri) }) afterEach(async function () { // logs command not supported in firefox // https://github.com/SeleniumHQ/selenium/issues/2910 - if (process.env.SELENIUM_BROWSER === 'chrome') { + if (browser === 'chrome') { // check for console errors const errors = await checkBrowserForConsoleErrors() if (errors.length) { @@ -272,11 +274,7 @@ describe('Metamask popup page', function () { }) it('navigates back to MetaMask popup in the tab', async function () { - if (process.env.SELENIUM_BROWSER === 'chrome') { - await driver.get(`chrome-extension://${extensionId}/popup.html`) - } else if (process.env.SELENIUM_BROWSER === 'firefox') { - await driver.get(`moz-extension://${extensionId}/popup.html`) - } + await driver.get(extensionUri) await delay(700) }) }) @@ -340,12 +338,7 @@ describe('Metamask popup page', function () { } async function verboseReportOnFailure (test) { - let artifactDir - if (process.env.SELENIUM_BROWSER === 'chrome') { - artifactDir = `./test-artifacts/chrome/${test.title}` - } else if (process.env.SELENIUM_BROWSER === 'firefox') { - artifactDir = `./test-artifacts/firefox/${test.title}` - } + const artifactDir = `./test-artifacts/${browser}/${test.title}` const filepathBase = `${artifactDir}/test-failure` await pify(mkdirp)(artifactDir) // capture screenshot From 0db776c3cc58e817d108d38ca389893cb13e3f92 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 10:17:09 -0700 Subject: [PATCH 054/183] lint - controllers - whitepace fix --- app/scripts/controllers/currency.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 480c08b1c..d5bc5fe2b 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -1,4 +1,4 @@ - const ObservableStore = require('obs-store') +const ObservableStore = require('obs-store') const extend = require('xtend') const log = require('loglevel') @@ -16,9 +16,9 @@ class CurrencyController { * currentCurrency, conversionRate and conversionDate properties * @property {string} currentCurrency A 2-4 character shorthand that describes a specific currency, currently * selected by the user - * @property {number} conversionRate The conversion rate from ETH to the selected currency. + * @property {number} conversionRate The conversion rate from ETH to the selected currency. * @property {string} conversionDate The date at which the conversion rate was set. Expressed in in milliseconds - * since midnight of January 1, 1970 + * since midnight of January 1, 1970 * @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method. * Used to clear an existing interval on subsequent calls of that method. * @@ -59,7 +59,7 @@ class CurrencyController { /** * A getter for the conversionRate property * - * @returns {string} The conversion rate from ETH to the selected currency. + * @returns {string} The conversion rate from ETH to the selected currency. * */ getConversionRate () { @@ -80,7 +80,7 @@ class CurrencyController { * A getter for the conversionDate property * * @returns {string} The date at which the conversion rate was set. Expressed in milliseconds since midnight of - * January 1, 1970 + * January 1, 1970 * */ getConversionDate () { From 02f5502e16fefc8d92392e614861e3f672c4f909 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 11:04:28 -0700 Subject: [PATCH 055/183] test - e2e - inject metamask config to point at localhost --- .gitignore | 3 ++- app/scripts/background.js | 4 ++- package-lock.json | 54 +++++++++++++++++++++++++++++++-------- package.json | 2 ++ test/e2e/metamask.spec.js | 21 ++++++++------- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 21a13c904..fcf520641 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ test/bundle.js test/test-bundle.js test-artifacts +test-builds #ignore css output and sourcemaps ui/app/css/output/ @@ -38,4 +39,4 @@ ui/app/css/output/ notes.txt .coveralls.yml -.nyc_output \ No newline at end of file +.nyc_output diff --git a/app/scripts/background.js b/app/scripts/background.js index 56e190f97..41fd89016 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -18,7 +18,7 @@ const migrations = require('./migrations/') const PortStream = require('./lib/port-stream.js') const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') -const firstTimeState = require('./first-time-state') +const rawFirstTimeState = require('./first-time-state') const setupRaven = require('./lib/setupRaven') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') @@ -31,6 +31,8 @@ const { ENVIRONMENT_TYPE_FULLSCREEN, } = require('./lib/enums') +const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_CONFIG) + const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = process.env.METAMASK_DEBUG diff --git a/package-lock.json b/package-lock.json index f59eaf017..56de846d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10241,15 +10241,25 @@ "dev": true }, "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "2.4.0", - "klaw": "1.3.1", - "path-is-absolute": "1.0.1", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "dependencies": { + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "fs-mkdirp-stream": { @@ -11126,6 +11136,18 @@ "yargs": "4.8.1" }, "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", @@ -16291,7 +16313,7 @@ "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.9" } }, "known-css-properties": { @@ -24426,7 +24448,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.1" } } } @@ -27736,6 +27758,18 @@ "yargs": "4.8.1" }, "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", diff --git a/package.json b/package.json index 564db99c9..94f4b1950 100644 --- a/package.json +++ b/package.json @@ -232,6 +232,7 @@ "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "file-loader": "^1.1.11", + "fs-extra": "^6.0.1", "fs-promise": "^2.0.3", "ganache-cli": "^6.1.0", "ganache-core": "^2.1.0", @@ -276,6 +277,7 @@ "open": "0.0.5", "path": "^0.12.7", "png-file-stream": "^1.0.0", + "prepend-file": "^1.3.1", "prompt": "^1.0.0", "proxyquire": "2.0.1", "qs": "^6.2.0", diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index f993f3fca..06c13b3d0 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -1,8 +1,9 @@ -const fs = require('fs') +const fs = require('fs-extra') const mkdirp = require('mkdirp') const path = require('path') const assert = require('assert') const pify = require('pify') +const prependFile = pify(require('prepend-file')) const webdriver = require('selenium-webdriver') const { By, Key } = webdriver const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func') @@ -14,7 +15,13 @@ describe('Metamask popup page', function () { this.timeout(0) before(async function () { - const extPath = path.resolve(`dist/${browser}`) + const srcPath = path.resolve(`dist/${browser}`) + const extPath = path.resolve(`test-builds/${browser}`) + await fs.ensureDir(extPath) + await fs.copy(srcPath, extPath) + const config = { NetworkController: { provider: { type: 'localhost' } } } + await prependFile(`${extPath}/background.js`, `window.METAMASK_CONFIG=${JSON.stringify(config)};\n`) + if (browser === 'chrome') { driver = buildChromeWebDriver(extPath) extensionId = await getExtensionIdChrome(driver) @@ -46,6 +53,7 @@ describe('Metamask popup page', function () { // gather extra data if test failed if (this.currentTest.state === 'failed') { await verboseReportOnFailure(this.currentTest) + await delay(1000000) } }) @@ -61,11 +69,6 @@ describe('Metamask popup page', function () { await driver.switchTo().window(windowHandles[0]) }) - it('sets provider type to localhost', async function () { - await delay(300) - await setProviderType('localhost') - }) - }) describe('Account Creation', () => { @@ -313,10 +316,6 @@ describe('Metamask popup page', function () { }) }) - async function setProviderType (type) { - await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) - } - async function checkBrowserForConsoleErrors() { const ignoredLogTypes = ['WARNING'] const ignoredErrorMessages = [ From ebb9447593a877cd299e701ddfcb217070068fac Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 14:25:49 -0700 Subject: [PATCH 056/183] test - e2e - factor out setup phase + rename METAMASK_CONFIG to METAMASK_TEST_CONFIG --- app/scripts/background.js | 3 ++- test/e2e/beta/metamask-beta-ui.spec.js | 32 +++++++----------------- test/e2e/func.js | 34 ++++++++++++++++++++++++++ test/e2e/metamask.spec.js | 29 +++++----------------- 4 files changed, 51 insertions(+), 47 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 41fd89016..9866ff0b0 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -31,7 +31,8 @@ const { ENVIRONMENT_TYPE_FULLSCREEN, } = require('./lib/enums') -const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_CONFIG) +// METAMASK_TEST_CONFIG is used in e2e tests to set the default network to localhost +const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_TEST_CONFIG) const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = process.env.METAMASK_DEBUG diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index ceeea31a5..8960e7e79 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -4,11 +4,8 @@ const webdriver = require('selenium-webdriver') const { By, Key, until } = webdriver const { delay, - buildChromeWebDriver, - buildFirefoxWebdriver, - installWebExt, - getExtensionIdChrome, - getExtensionIdFirefox, + createModifiedTestBuild, + setupBrowserAndExtension, } = require('../func') const { findElement, @@ -19,6 +16,7 @@ const { } = require('./helpers') describe('MetaMask', function () { + const browser = process.env.SELENIUM_BROWSER let extensionId let driver let tokenAddress @@ -33,27 +31,15 @@ describe('MetaMask', function () { this.bail(true) before(async function () { - switch (process.env.SELENIUM_BROWSER) { - case 'chrome': { - const extPath = path.resolve('dist/chrome') - driver = buildChromeWebDriver(extPath) - extensionId = await getExtensionIdChrome(driver) - await driver.get(`chrome-extension://${extensionId}/popup.html`) - break - } - case 'firefox': { - const extPath = path.resolve('dist/firefox') - driver = buildFirefoxWebdriver() - await installWebExt(driver, extPath) - await delay(700) - extensionId = await getExtensionIdFirefox(driver) - await driver.get(`moz-extension://${extensionId}/popup.html`) - } - } + const srcPath = path.resolve(`dist/${browser}`) + const { extPath } = await createModifiedTestBuild({ browser, srcPath }) + const installResult = await setupBrowserAndExtension({ browser, extPath }) + driver = installResult.driver + extensionUri = installResult.extensionUri }) afterEach(async function () { - if (process.env.SELENIUM_BROWSER === 'chrome') { + if (browser === 'chrome') { const errors = await checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map(err => err.message) diff --git a/test/e2e/func.js b/test/e2e/func.js index 9f06e7f37..60e02a296 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -3,12 +3,15 @@ require('geckodriver') const fs = require('fs') const os = require('os') const path = require('path') +const pify = require('pify') +const prependFile = pify(require('prepend-file')) const webdriver = require('selenium-webdriver') const Command = require('selenium-webdriver/lib/command').Command const By = webdriver.By module.exports = { delay, + createModifiedTestBuild, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, @@ -20,6 +23,37 @@ function delay (time) { return new Promise(resolve => setTimeout(resolve, time)) } +async function createModifiedTestBuild ({ browser, srcPath }) { + // copy build to test-builds directory + const extPath = path.resolve(`test-builds/${browser}`) + await fs.ensureDir(extPath) + await fs.copy(srcPath, extPath) + // inject METAMASK_TEST_CONFIG setting default test network + const config = { NetworkController: { provider: { type: 'localhost' } } } + await prependFile(`${extPath}/background.js`, `window.METAMASK_TEST_CONFIG=${JSON.stringify(config)};\n`) + return { extPath } +} + +async function setupBrowserAndExtension ({ browser, extPath }) { + let drive, extensionId, extensionUri + + if (browser === 'chrome') { + driver = buildChromeWebDriver(extPath) + extensionId = await getExtensionIdChrome(driver) + extensionUri = `chrome-extension://${extensionId}/popup.html` + } else if (browser === 'firefox') { + driver = buildFirefoxWebdriver() + await installWebExt(driver, extPath) + await delay(700) + extensionId = await getExtensionIdFirefox(driver) + extensionUri = `moz-extension://${extensionId}/popup.html` + } else { + throw new Error(`Unknown Browser "${browser}"`) + } + + return { driver, extensionId, extensionUri } +} + function buildChromeWebDriver (extPath) { const tmpProfile = path.join(os.tmpdir(), fs.mkdtempSync('mm-chrome-profile')); return new webdriver.Builder() diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 06c13b3d0..0d6ab9b35 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -3,10 +3,8 @@ const mkdirp = require('mkdirp') const path = require('path') const assert = require('assert') const pify = require('pify') -const prependFile = pify(require('prepend-file')) -const webdriver = require('selenium-webdriver') -const { By, Key } = webdriver -const { delay, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, getExtensionIdChrome, getExtensionIdFirefox } = require('./func') +const { By, Key } = require('selenium-webdriver') +const { delay, createModifiedTestBuild, setupBrowserAndExtension } = require('./func') describe('Metamask popup page', function () { const browser = process.env.SELENIUM_BROWSER @@ -16,25 +14,11 @@ describe('Metamask popup page', function () { before(async function () { const srcPath = path.resolve(`dist/${browser}`) - const extPath = path.resolve(`test-builds/${browser}`) - await fs.ensureDir(extPath) - await fs.copy(srcPath, extPath) - const config = { NetworkController: { provider: { type: 'localhost' } } } - await prependFile(`${extPath}/background.js`, `window.METAMASK_CONFIG=${JSON.stringify(config)};\n`) + const { extPath } = await createModifiedTestBuild({ browser, srcPath }) + const installResult = await setupBrowserAndExtension({ browser, extPath }) + driver = installResult.driver + extensionUri = installResult.extensionUri - if (browser === 'chrome') { - driver = buildChromeWebDriver(extPath) - extensionId = await getExtensionIdChrome(driver) - extensionUri = `chrome-extension://${extensionId}/popup.html` - } else if (browser === 'firefox') { - driver = buildFirefoxWebdriver() - await installWebExt(driver, extPath) - await delay(700) - extensionId = await getExtensionIdFirefox(driver) - extensionUri = `moz-extension://${extensionId}/popup.html` - } else { - throw new Error(`Unknown Browser "${browser}"`) - } await driver.get(extensionUri) }) @@ -53,7 +37,6 @@ describe('Metamask popup page', function () { // gather extra data if test failed if (this.currentTest.state === 'failed') { await verboseReportOnFailure(this.currentTest) - await delay(1000000) } }) From 907594463dc7fdbf62a350f64d7212be59a0355f Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 14:35:20 -0700 Subject: [PATCH 057/183] test - e2e - use fs-extra instead of fs --- test/e2e/func.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/func.js b/test/e2e/func.js index 60e02a296..ca590d84a 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -1,6 +1,6 @@ require('chromedriver') require('geckodriver') -const fs = require('fs') +const fs = require('fs-extra') const os = require('os') const path = require('path') const pify = require('pify') From 8a0961b4a8bd7eef50b8d8e45d73390f43795a14 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 14:46:45 -0700 Subject: [PATCH 058/183] test - e2e - more factoring of test setup --- test/e2e/beta/from-import-beta-ui.spec.js | 39 +++++++---------------- test/e2e/beta/helpers.js | 21 +----------- test/e2e/beta/metamask-beta-ui.spec.js | 4 +-- test/e2e/func.js | 11 +++++++ test/e2e/metamask.spec.js | 16 ++-------- 5 files changed, 27 insertions(+), 64 deletions(-) diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index efae948f9..d6e976dea 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -4,22 +4,20 @@ const webdriver = require('selenium-webdriver') const { By, Key, until } = webdriver const { delay, - buildChromeWebDriver, - buildFirefoxWebdriver, - installWebExt, - getExtensionIdChrome, - getExtensionIdFirefox, + createModifiedTestBuild, + setupBrowserAndExtension, + verboseReportOnFailure, } = require('../func') const { checkBrowserForConsoleErrors, loadExtension, - verboseReportOnFailure, findElement, findElements, } = require('./helpers') describe('Using MetaMask with an existing account', function () { + const browser = process.env.SELENIUM_BROWSER let extensionId let driver let tokenAddress @@ -34,30 +32,15 @@ describe('Using MetaMask with an existing account', function () { this.bail(true) before(async function () { - switch (process.env.SELENIUM_BROWSER) { - case 'chrome': { - const extensionPath = path.resolve('dist/chrome') - driver = buildChromeWebDriver(extensionPath) - extensionId = await getExtensionIdChrome(driver) - await driver.get(`chrome-extension://${extensionId}/popup.html`) - await delay(regularDelayMs) - break - } - case 'firefox': { - const extensionPath = path.resolve('dist/firefox') - driver = buildFirefoxWebdriver() - await installWebExt(driver, extensionPath) - await delay(regularDelayMs) - extensionId = await getExtensionIdFirefox(driver) - await driver.get(`moz-extension://${extensionId}/popup.html`) - await delay(regularDelayMs) - break - } - } + const srcPath = path.resolve(`dist/${browser}`) + const { extPath } = await createModifiedTestBuild({ browser, srcPath }) + const installResult = await setupBrowserAndExtension({ browser, extPath }) + driver = installResult.driver + extensionUri = installResult.extensionUri }) afterEach(async function () { - if (process.env.SELENIUM_BROWSER === 'chrome') { + if (browser === 'chrome') { const errors = await checkBrowserForConsoleErrors(driver) if (errors.length) { const errorReports = errors.map(err => err.message) @@ -66,7 +49,7 @@ describe('Using MetaMask with an existing account', function () { } } if (this.currentTest.state === 'failed') { - await verboseReportOnFailure(driver, this.currentTest) + await verboseReportOnFailure({ browser, driver, title: this.currentTest.title }) } }) diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js index 31c41d8b7..5951ea79b 100644 --- a/test/e2e/beta/helpers.js +++ b/test/e2e/beta/helpers.js @@ -1,12 +1,8 @@ -const fs = require('fs') -const mkdirp = require('mkdirp') -const pify = require('pify') -const {until} = require('selenium-webdriver') +const { until } = require('selenium-webdriver') module.exports = { checkBrowserForConsoleErrors, loadExtension, - verboseReportOnFailure, findElement, findElements, } @@ -42,21 +38,6 @@ async function checkBrowserForConsoleErrors (driver) { return errorObjects.filter(entry => !ignoredErrorMessages.some(message => entry.message.includes(message))) } -async function verboseReportOnFailure (driver, test) { - let artifactDir - if (process.env.SELENIUM_BROWSER === 'chrome') { - artifactDir = `./test-artifacts/chrome/${test.title}` - } else if (process.env.SELENIUM_BROWSER === 'firefox') { - artifactDir = `./test-artifacts/firefox/${test.title}` - } - const filepathBase = `${artifactDir}/test-failure` - await pify(mkdirp)(artifactDir) - const screenshot = await driver.takeScreenshot() - await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) - const htmlSource = await driver.getPageSource() - await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) -} - async function findElement (driver, by, timeout = 10000) { return driver.wait(until.elementLocated(by), timeout) } diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 8960e7e79..14ea5b0a5 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -6,13 +6,13 @@ const { delay, createModifiedTestBuild, setupBrowserAndExtension, + verboseReportOnFailure, } = require('../func') const { findElement, findElements, checkBrowserForConsoleErrors, loadExtension, - verboseReportOnFailure, } = require('./helpers') describe('MetaMask', function () { @@ -48,7 +48,7 @@ describe('MetaMask', function () { } } if (this.currentTest.state === 'failed') { - await verboseReportOnFailure(this.currentTest) + await verboseReportOnFailure({ browser, driver, title: this.currentTest.tile }) } }) diff --git a/test/e2e/func.js b/test/e2e/func.js index ca590d84a..ca8d05b18 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -12,6 +12,7 @@ const By = webdriver.By module.exports = { delay, createModifiedTestBuild, + verboseReportOnFailure, buildChromeWebDriver, buildFirefoxWebdriver, installWebExt, @@ -95,3 +96,13 @@ async function installWebExt (driver, extension) { return await driver.schedule(cmd, 'installWebExt(' + extension + ')') } + +async function verboseReportOnFailure ({ browser, driver, title }) { + const artifactDir = `./test-artifacts/${browser}/${title}` + const filepathBase = `${artifactDir}/test-failure` + await fs.ensureDir(artifactDir) + const screenshot = await driver.takeScreenshot() + await fs.writeFile(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + const htmlSource = await driver.getPageSource() + await fs.writeFile(`${filepathBase}-dom.html`, htmlSource) +} diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 0d6ab9b35..5153c0ee5 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -4,7 +4,7 @@ const path = require('path') const assert = require('assert') const pify = require('pify') const { By, Key } = require('selenium-webdriver') -const { delay, createModifiedTestBuild, setupBrowserAndExtension } = require('./func') +const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportOnFailure } = require('./func') describe('Metamask popup page', function () { const browser = process.env.SELENIUM_BROWSER @@ -36,7 +36,7 @@ describe('Metamask popup page', function () { } // gather extra data if test failed if (this.currentTest.state === 'failed') { - await verboseReportOnFailure(this.currentTest) + await verboseReportOnFailure({ browser, driver, title: this.currentTest.title }) } }) @@ -319,16 +319,4 @@ describe('Metamask popup page', function () { return matchedErrorObjects } - async function verboseReportOnFailure (test) { - const artifactDir = `./test-artifacts/${browser}/${test.title}` - const filepathBase = `${artifactDir}/test-failure` - await pify(mkdirp)(artifactDir) - // capture screenshot - const screenshot = await driver.takeScreenshot() - await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) - // capture dom source - const htmlSource = await driver.getPageSource() - await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) - } - }) From 2e3f421b7343911b84138b5de5a68aad00b01d48 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 14:55:50 -0700 Subject: [PATCH 059/183] test - e2e - properly export setupBrowserAndExtension --- test/e2e/func.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/func.js b/test/e2e/func.js index ca8d05b18..c100680d8 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -12,6 +12,7 @@ const By = webdriver.By module.exports = { delay, createModifiedTestBuild, + setupBrowserAndExtension, verboseReportOnFailure, buildChromeWebDriver, buildFirefoxWebdriver, From ab0e60e802b500460d919825971deb7c5ef4bc1b Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 15:34:54 -0700 Subject: [PATCH 060/183] test - e2e - fix incomplete setup phase --- test/e2e/beta/metamask-beta-ui.spec.js | 5 ++++- test/e2e/metamask.spec.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 14ea5b0a5..3cc9f6a2a 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -36,6 +36,9 @@ describe('MetaMask', function () { const installResult = await setupBrowserAndExtension({ browser, extPath }) driver = installResult.driver extensionUri = installResult.extensionUri + + await driver.get(extensionUri) + await delay(tinyDelayMs) }) afterEach(async function () { @@ -48,7 +51,7 @@ describe('MetaMask', function () { } } if (this.currentTest.state === 'failed') { - await verboseReportOnFailure({ browser, driver, title: this.currentTest.tile }) + await verboseReportOnFailure({ browser, driver, title: this.currentTest.title }) } }) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 5153c0ee5..6243bf8d6 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -20,6 +20,7 @@ describe('Metamask popup page', function () { extensionUri = installResult.extensionUri await driver.get(extensionUri) + await delay(300) }) afterEach(async function () { @@ -47,7 +48,6 @@ describe('Metamask popup page', function () { describe('Setup', function () { it('switches to Chrome extensions list', async function () { - await delay(300) const windowHandles = await driver.getAllWindowHandles() await driver.switchTo().window(windowHandles[0]) }) From 93a2e287058205dbc14448d2c50e3ba4dab005c7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 16:45:29 -0700 Subject: [PATCH 061/183] test - e2e - remove usage of extensionId from tests --- test/e2e/beta/from-import-beta-ui.spec.js | 13 ++++++------- test/e2e/beta/helpers.js | 14 -------------- test/e2e/beta/metamask-beta-ui.spec.js | 11 +++++------ test/e2e/metamask.spec.js | 2 +- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index d6e976dea..cd7d90e95 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -9,17 +9,16 @@ const { verboseReportOnFailure, } = require('../func') const { - checkBrowserForConsoleErrors, - loadExtension, findElement, findElements, + checkBrowserForConsoleErrors, } = require('./helpers') describe('Using MetaMask with an existing account', function () { const browser = process.env.SELENIUM_BROWSER - let extensionId let driver + let extensionUri let tokenAddress const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' @@ -273,7 +272,7 @@ describe('Using MetaMask with an existing account', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000) @@ -286,7 +285,7 @@ describe('Using MetaMask with an existing account', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) await delay(regularDelayMs) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) }) }) @@ -348,7 +347,7 @@ describe('Using MetaMask with an existing account', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) @@ -361,7 +360,7 @@ describe('Using MetaMask with an existing account', function () { tokenAddress = await tokenContactAddress.getText() await driver.close() await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) }) diff --git a/test/e2e/beta/helpers.js b/test/e2e/beta/helpers.js index 5951ea79b..eaf2e0ade 100644 --- a/test/e2e/beta/helpers.js +++ b/test/e2e/beta/helpers.js @@ -2,24 +2,10 @@ const { until } = require('selenium-webdriver') module.exports = { checkBrowserForConsoleErrors, - loadExtension, findElement, findElements, } -async function loadExtension (driver, extensionId) { - switch (process.env.SELENIUM_BROWSER) { - case 'chrome': { - await driver.get(`chrome-extension://${extensionId}/home.html`) - break - } - case 'firefox': { - await driver.get(`moz-extension://${extensionId}/home.html`) - break - } - } -} - async function checkBrowserForConsoleErrors (driver) { const ignoredLogTypes = ['WARNING'] const ignoredErrorMessages = [ diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 3cc9f6a2a..efd116c97 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -12,13 +12,12 @@ const { findElement, findElements, checkBrowserForConsoleErrors, - loadExtension, } = require('./helpers') describe('MetaMask', function () { const browser = process.env.SELENIUM_BROWSER - let extensionId let driver + let extensionUri let tokenAddress const testSeedPhrase = 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent' @@ -361,7 +360,7 @@ describe('MetaMask', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`), 14000) @@ -374,7 +373,7 @@ describe('MetaMask', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) await delay(regularDelayMs) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) }) }) @@ -437,7 +436,7 @@ describe('MetaMask', function () { await delay(regularDelayMs) await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) const confirmButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Confirm')]`)) @@ -450,7 +449,7 @@ describe('MetaMask', function () { tokenAddress = await tokenContactAddress.getText() await driver.close() await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await delay(regularDelayMs) }) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 6243bf8d6..30b077cde 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -8,7 +8,7 @@ const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportO describe('Metamask popup page', function () { const browser = process.env.SELENIUM_BROWSER - let driver, accountAddress, tokenAddress, extensionId, extensionUri + let driver, accountAddress, tokenAddress, extensionUri this.timeout(0) From 4773a7f3ec4537ddc73ddf85cc48ac1d19f4fe86 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 18:56:59 -0700 Subject: [PATCH 062/183] test - e2e - extensionUri should point to home.html --- test/e2e/func.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/func.js b/test/e2e/func.js index c100680d8..34c64709a 100644 --- a/test/e2e/func.js +++ b/test/e2e/func.js @@ -42,13 +42,13 @@ async function setupBrowserAndExtension ({ browser, extPath }) { if (browser === 'chrome') { driver = buildChromeWebDriver(extPath) extensionId = await getExtensionIdChrome(driver) - extensionUri = `chrome-extension://${extensionId}/popup.html` + extensionUri = `chrome-extension://${extensionId}/home.html` } else if (browser === 'firefox') { driver = buildFirefoxWebdriver() await installWebExt(driver, extPath) await delay(700) extensionId = await getExtensionIdFirefox(driver) - extensionUri = `moz-extension://${extensionId}/popup.html` + extensionUri = `moz-extension://${extensionId}/home.html` } else { throw new Error(`Unknown Browser "${browser}"`) } From 9d1b4cc1d720335855c2b53f01df8366a018d99c Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 08:19:57 -0700 Subject: [PATCH 063/183] test - e2e - beta - dont select localhost as it is already set --- test/e2e/beta/from-import-beta-ui.spec.js | 10 ---------- test/e2e/beta/metamask-beta-ui.spec.js | 11 +---------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index cd7d90e95..c56471680 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -63,16 +63,6 @@ describe('Using MetaMask with an existing account', function () { await delay(regularDelayMs) }) - it('use the local network', async function () { - const networkSelector = await findElement(driver, By.css('#network_component')) - await networkSelector.click() - await delay(regularDelayMs) - - const [localhost] = await findElements(driver, By.xpath(`//li[contains(text(), 'Localhost')]`)) - await localhost.click() - await delay(regularDelayMs) - }) - it('selects the new UI option', async () => { const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]")) await button.click() diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index efd116c97..afd0e9496 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -51,6 +51,7 @@ describe('MetaMask', function () { } if (this.currentTest.state === 'failed') { await verboseReportOnFailure({ browser, driver, title: this.currentTest.title }) + await delay(1000000) } }) @@ -65,16 +66,6 @@ describe('MetaMask', function () { await delay(regularDelayMs) }) - it('use the local network', async function () { - const networkSelector = await findElement(driver, By.css('#network_component')) - await networkSelector.click() - await delay(regularDelayMs) - - const localhost = await findElement(driver, By.xpath(`//li[contains(text(), 'Localhost')]`)) - await localhost.click() - await delay(regularDelayMs) - }) - it('selects the new UI option', async () => { const button = await findElement(driver, By.xpath("//p[contains(text(), 'Try Beta Version')]")) await button.click() From 030fea71369411d96a670bde53c40ffa9bb89ec5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 08:35:45 -0700 Subject: [PATCH 064/183] test - e2e - beta - from import - fix missing startup phase --- test/e2e/beta/from-import-beta-ui.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/e2e/beta/from-import-beta-ui.spec.js b/test/e2e/beta/from-import-beta-ui.spec.js index c56471680..f2feefa49 100644 --- a/test/e2e/beta/from-import-beta-ui.spec.js +++ b/test/e2e/beta/from-import-beta-ui.spec.js @@ -36,6 +36,9 @@ describe('Using MetaMask with an existing account', function () { const installResult = await setupBrowserAndExtension({ browser, extPath }) driver = installResult.driver extensionUri = installResult.extensionUri + + await driver.get(extensionUri) + await delay(300) }) afterEach(async function () { From c86f93588965291837ae905632ba9a8855f496f2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 10:55:54 -0700 Subject: [PATCH 065/183] nonce-tracker - wrap nonce calculations in try-catch and release lock on error --- .../controllers/transactions/nonce-tracker.js | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index fe2d25fca..14581c998 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -50,29 +50,35 @@ class NonceTracker { await this._globalMutexFree() // await lock free, then take lock const releaseLock = await this._takeMutex(address) - // 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, + 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 } - 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 } } async _globalMutexFree () { From 6a2649a90f5147b505ebc33b97a75d2e90956fca Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 11:12:32 -0700 Subject: [PATCH 066/183] network - import createBlockTrackerInspectorMiddleware and rearrange cache middleware order --- .../controllers/network/createInfuraClient.js | 15 ++------------- .../controllers/network/createJsonRpcClient.js | 13 +------------ .../controllers/network/createLocalhostClient.js | 13 +------------ package-lock.json | 6 +++--- package.json | 2 +- 5 files changed, 8 insertions(+), 41 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 663a2595a..6976e6022 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -3,6 +3,7 @@ const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') @@ -15,23 +16,11 @@ function createInfuraClient ({ network }) { const blockTracker = new BlockTracker({ provider: blockProvider }) const networkMiddleware = mergeMiddleware([ - createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockCacheMiddleware({ blockTracker }), createInflightMiddleware(), + createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockTrackerInspectorMiddleware({ blockTracker }), infuraMiddleware, ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index d712ed135..b9aca0bcf 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -4,6 +4,7 @@ const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') @@ -23,15 +24,3 @@ function createJsonRpcClient ({ rpcUrl }) { ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index 990dc6a95..ae42ac48b 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -2,6 +2,7 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') @@ -19,15 +20,3 @@ function createLocalhostClient () { ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} diff --git a/package-lock.json b/package-lock.json index 56de846d4..5c8ddbdb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8217,9 +8217,9 @@ } }, "eth-json-rpc-middleware": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.3.0.tgz", - "integrity": "sha512-pMG8pDbmipPIellAoAz494ShJ/vLiCy0QOOLXPv2IwTtrdnpr04Zj9NTVxPhg6F+c87cyiUgHi6zOgoZQKvaGQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.4.0.tgz", + "integrity": "sha512-KUxyz7pr6MZmFlsym8EObWwrFHVxRCLHGfl8H2V7D4ZjK0yhoPaA94jSXAumUbfx2AmyYEtG9j2xmU1P83m7OQ==", "requires": { "async": "^2.5.0", "clone": "^2.1.1", diff --git a/package.json b/package.json index 94f4b1950..0332f06b8 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "eth-hd-keyring": "^1.2.1", "eth-json-rpc-filters": "^2.1.1", "eth-json-rpc-infura": "^3.0.0", - "eth-json-rpc-middleware": "^2.3.0", + "eth-json-rpc-middleware": "^2.4.0", "eth-keyring-controller": "^3.1.4", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", From 055346843bc90a5168151ba2adc9deacedf8afd4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 11:27:32 -0700 Subject: [PATCH 067/183] lint - fix lint for network --- app/scripts/controllers/network/createInfuraClient.js | 1 - app/scripts/controllers/network/createJsonRpcClient.js | 1 - app/scripts/controllers/network/createLocalhostClient.js | 1 - 3 files changed, 3 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 6976e6022..41af4d9f9 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index b9aca0bcf..40c353f7f 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index ae42ac48b..fecc512e8 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') From 3163090e0bde8bbf2799ed2e6041df84fb65304b Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Jul 2018 13:55:54 -0700 Subject: [PATCH 068/183] deps - update package-lock --- package-lock.json | 526 +++++++++++++++++++++++++++++----------------- 1 file changed, 336 insertions(+), 190 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25ab491e3..957792a6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2425,7 +2425,8 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true }, "async-reduce": { "version": "0.0.1", @@ -3908,6 +3909,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=", + "dev": true, "requires": { "precond": "0.2" } @@ -6128,6 +6130,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.1.0.tgz", "integrity": "sha512-FTIt2WK44RiafWQ62xIvd+oBoVd392abh1lF872trLlA74JCR1s4oTHlixwoIKy44ehn8WbQ0Ds2P16sw7ZQxg==", + "dev": true, "requires": { "node-fetch": "2.1.1", "whatwg-fetch": "2.0.3" @@ -6136,7 +6139,8 @@ "node-fetch": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.1.tgz", - "integrity": "sha1-NpynC4L1DIZJYQSmx3bSdPTkotQ=" + "integrity": "sha1-NpynC4L1DIZJYQSmx3bSdPTkotQ=", + "dev": true } } }, @@ -8284,42 +8288,62 @@ } }, "eth-block-tracker": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.0.tgz", - "integrity": "sha512-yrNyBIBKC7WfUjrXSG/CZVy0gW2aF8+MnjnrkOxkZOR+BAtL6JgYOnzVnrU8KE6mKJETlA/1dYMygvLXWyJGGw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.0.1.tgz", + "integrity": "sha512-ytJxddJ0TMcJHYxPlgGhMyr5EH6/Kyp3bg0WsjXgY9X0uYX3xVHTTeU5WVX6KX+9oJ37ZLUjh5PZ6VYnF1Fx/Q==", "requires": { - "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-json-rpc-infura": "^3.1.0", "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" + "pify": "^3.0.0" }, "dependencies": { - "async-eventemitter": { - "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", - "from": "async-eventemitter@github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "cross-fetch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-2.2.2.tgz", + "integrity": "sha1-pH/09/xxLauo9qaVoRyUhEDUVyM=", "requires": { - "async": "^2.4.0" + "node-fetch": "2.1.2", + "whatwg-fetch": "2.0.4" } }, - "babelify": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", - "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "eth-json-rpc-infura": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.1.2.tgz", + "integrity": "sha512-IuK5Iowfs6taluA/3Okmu6EfZcFMq6MQuyrUL1PrCoJstuuBr3TvVeSy3keDyxfbrjFB34nCo538I8G+qMtsbw==", "requires": { - "babel-core": "^6.0.14", - "object-assign": "^4.0.0" + "cross-fetch": "^2.1.1", + "eth-json-rpc-middleware": "^1.5.0", + "json-rpc-engine": "^3.4.0", + "json-rpc-error": "^2.0.0", + "tape": "^4.8.0" + } + }, + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "^2.5.0", + "eth-query": "^2.1.2", + "eth-tx-summary": "^3.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.1.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^3.6.0", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "tape": "^4.6.3" } }, "ethereumjs-util": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.3.tgz", - "integrity": "sha512-U/wmHagElZVxnpo3bFsvk5beFADegUcEzqtA/NfQbitAPOs6JoYq8M4SY9NfH4HD8236i63UOkkXafd7bqBL9A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", "requires": { - "bn.js": "^4.8.0", + "bn.js": "^4.11.0", "create-hash": "^1.1.2", "ethjs-util": "^0.1.3", "keccak": "^1.0.2", @@ -8328,22 +8352,15 @@ "secp256k1": "^3.0.1" } }, - "json-rpc-engine": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.0.tgz", - "integrity": "sha512-QGEIIPMaG4lQ8iKQgzKq7Ra6hscqSL+6S+xiUFbNAoVaZII8iyN1l6tJHmUWIdbnl2o0rbwCnOPFAhTn9AJObw==", - "requires": { - "async": "^2.0.1", - "babel-preset-env": "^1.3.2", - "babelify": "^7.3.0", - "json-rpc-error": "^2.0.0", - "promise-to-callback": "^1.0.0" - } + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "whatwg-fetch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", + "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" } } }, @@ -8398,13 +8415,70 @@ } }, "eth-json-rpc-filters": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-1.2.6.tgz", - "integrity": "sha512-6G9t43s3lxJckeSfNduc3Ww/40BGm1Cf8MU1nL8rrumZbEg44ZSexWUowB00D4kJ9qSOH+CbzdI+m3oVMi4xFw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-2.1.1.tgz", + "integrity": "sha512-FSFcCMJ1lRS8az1LhIK5Klima8Hyfv4keKSdW2MA3zwiN/wX1NKb/sQSEFO3nstPUqR2Aa02lVokp85UnnrBlA==", "requires": { "await-semaphore": "^0.1.1", + "eth-json-rpc-middleware": "^1.6.0", + "ethjs-query": "^0.3.6", "json-rpc-engine": "^3.4.0", "lodash.flatmap": "^4.5.0" + }, + "dependencies": { + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "^2.5.0", + "eth-query": "^2.1.2", + "eth-tx-summary": "^3.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.1.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^3.6.0", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "tape": "^4.6.3" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, + "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" + } + } } }, "eth-json-rpc-infura": { @@ -8416,24 +8490,63 @@ "json-rpc-engine": "^3.4.0", "json-rpc-error": "^2.0.0", "tape": "^4.8.0" + }, + "dependencies": { + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "requires": { + "async": "^2.5.0", + "eth-query": "^2.1.2", + "eth-tx-summary": "^3.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.1.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^3.6.0", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "tape": "^4.6.3" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } } }, "eth-json-rpc-middleware": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", - "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-2.4.0.tgz", + "integrity": "sha512-KUxyz7pr6MZmFlsym8EObWwrFHVxRCLHGfl8H2V7D4ZjK0yhoPaA94jSXAumUbfx2AmyYEtG9j2xmU1P83m7OQ==", "requires": { "async": "^2.5.0", + "clone": "^2.1.1", "eth-query": "^2.1.2", + "eth-sig-util": "^1.4.2", "eth-tx-summary": "^3.1.2", "ethereumjs-block": "^1.6.0", "ethereumjs-tx": "^1.3.3", "ethereumjs-util": "^5.1.2", "ethereumjs-vm": "^2.1.0", "fetch-ponyfill": "^4.0.0", - "json-rpc-engine": "^3.6.0", + "json-rpc-engine": "^3.6.3", "json-rpc-error": "^2.0.0", "json-stable-stringify": "^1.0.1", + "pify": "^3.0.0", "promise-to-callback": "^1.0.0", "tape": "^4.6.3" }, @@ -8458,7 +8571,6 @@ "version": "3.1.4", "resolved": "https://registry.npmjs.org/eth-keyring-controller/-/eth-keyring-controller-3.1.4.tgz", "integrity": "sha512-NNlVB/TBc8p9CblwECjPlUR+7MNQKiBa7tEFxIzZ9MjjNCEYPWDXTm0vJZzuDtVmFxYwIA53UD0QEn0QNxWNEQ==", - "dev": true, "requires": { "bip39": "^2.4.0", "bluebird": "^3.5.0", @@ -8476,7 +8588,6 @@ "version": "7.3.0", "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", - "dev": true, "requires": { "babel-core": "^6.0.14", "object-assign": "^4.0.0" @@ -8486,7 +8597,6 @@ "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", @@ -8501,7 +8611,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-2.4.1.tgz", "integrity": "sha512-wpA8G4uSn8cnCKZ0pFTvqsamvy0Sm1hR2ot0Qonbfj5yBMwdAp/eD4vDI+U/ZCbV1hb2V5GapL8YKUdGCvahgg==", - "dev": true, "requires": { "babel-preset-es2015": "^6.22.0", "babelify": "^7.3.0", @@ -8581,7 +8690,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/eth-simple-keyring/-/eth-simple-keyring-1.2.2.tgz", "integrity": "sha512-uQVBYshHUOaXVoat1BpLA/QNMCr4hgdFBgwIB7rRmQ+m3vQQAseUsOM+biPDYzq6end+6LjcccElLpQaIZe6dg==", - "dev": true, "requires": { "eth-sig-util": "^1.4.2", "ethereumjs-util": "^5.1.1", @@ -8594,7 +8702,6 @@ "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", @@ -8777,9 +8884,9 @@ } }, "eth-tx-summary": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz", - "integrity": "sha512-mu8g5tDkQxlFah58ggFhTzolE4OnYTj6j8SVsnGsiWT7WxN722RwnEsk/bco2foy+PLSEF2Mnoiw+wCqKoY72A==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.3.tgz", + "integrity": "sha512-1gZpA5fKarJOVSb5OUlPnhDQuIazqAkI61zlVvf5LdG47nEgw+/qhyZnuj3CUdE/TLTKuRzPLeyXLjaB4qWTRQ==", "requires": { "async": "^2.1.2", "bn.js": "^4.11.8", @@ -8790,30 +8897,54 @@ "ethereumjs-block": "^1.4.1", "ethereumjs-tx": "^1.1.1", "ethereumjs-util": "^5.0.1", - "ethereumjs-vm": "^2.3.4", + "ethereumjs-vm": "2.3.4", "through2": "^2.0.3", "treeify": "^1.0.1", "web3-provider-engine": "^13.3.2" }, "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "eth-block-tracker": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", + "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-query": "^2.1.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.3", "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" + "json-rpc-engine": "^3.6.0", + "pify": "^2.3.0", + "tape": "^4.6.3" + }, + "dependencies": { + "async-eventemitter": { + "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "from": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "requires": { + "async": "^2.4.0" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + } } }, "ethereumjs-vm": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz", - "integrity": "sha512-AJ7x44+xqyE5+UO3Nns19WkTdZfyqFZ+sEjIEpvme7Ipbe3iBU1uwCcHEdiu/yY9bdhr3IfSa/NfIKNeXPaRVQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.4.tgz", + "integrity": "sha512-Y4SlzNDqxrCO58jhp98HdnZVdjOqB+HC0hoU+N/DEp1aU+hFkRX/nru5F7/HkQRPIlA6aJlQp/xIA6xZs1kspw==", "requires": { "async": "^2.1.2", "async-eventemitter": "^0.2.2", @@ -8844,6 +8975,11 @@ } } }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, "web3-provider-engine": { "version": "13.8.0", "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", @@ -11010,15 +11146,25 @@ "dev": true }, "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", + "dev": true, "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0", - "path-is-absolute": "^1.0.0", - "rimraf": "^2.2.8" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "dependencies": { + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "fs-mkdirp-stream": { @@ -11806,6 +11952,46 @@ "node-fetch": "2.1.2", "whatwg-fetch": "2.0.4" } + }, + "eth-json-rpc-middleware": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz", + "integrity": "sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q==", + "dev": true, + "requires": { + "async": "^2.5.0", + "eth-query": "^2.1.2", + "eth-tx-summary": "^3.1.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.1.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^3.6.0", + "json-rpc-error": "^2.0.0", + "json-stable-stringify": "^1.0.1", + "promise-to-callback": "^1.0.0", + "tape": "^4.6.3" + } + }, + "ethereum-common": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.2.0.tgz", + "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==", + "dev": true + }, + "ethereumjs-block": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz", + "integrity": "sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg==", + "dev": true, + "requires": { + "async": "^2.0.1", + "ethereum-common": "0.2.0", + "ethereumjs-tx": "^1.2.2", + "ethereumjs-util": "^5.0.0", + "merkle-patricia-tree": "^2.1.2" + } } } }, @@ -11923,6 +12109,19 @@ "yargs": "^4.7.1" }, "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", @@ -16589,13 +16788,14 @@ "dev": true }, "json-rpc-engine": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz", - "integrity": "sha512-xYuD9M1pcld5OKPzVAoEG5MKtnR8iKMyNzRpeS3/mCJ7dcAcS67vqfOmYLoaIQfVRU5uClThbjri3VFR0vEwYg==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.7.3.tgz", + "integrity": "sha512-+FO3UWu/wafh/+MZ6BXy0HZU+f5plwUn82FgxpC0scJkEh5snOjFrAAtqCITPDfvfLHRUFOG5pQDUx2pspfERQ==", "requires": { "async": "^2.0.1", "babel-preset-env": "^1.3.2", "babelify": "^7.3.0", + "clone": "^2.1.1", "json-rpc-error": "^2.0.0", "promise-to-callback": "^1.0.0" }, @@ -16631,11 +16831,47 @@ "readable-stream": "^2.3.3" }, "dependencies": { + "async-eventemitter": { + "version": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "from": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "requires": { + "async": "^2.4.0" + } + }, "bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, + "eth-block-tracker": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-2.3.1.tgz", + "integrity": "sha512-NamWuMBIl8kmkJFVj8WzGatySTzQPQag4Xr677yFxdVtIxACFbL/dQowk0MzEqIKk93U1TwY3MjVU6mOcwZnKA==", + "requires": { + "async-eventemitter": "github:ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c", + "eth-query": "^2.1.0", + "ethereumjs-tx": "^1.3.3", + "ethereumjs-util": "^5.1.3", + "ethjs-util": "^0.1.3", + "json-rpc-engine": "^3.6.0", + "pify": "^2.3.0", + "tape": "^4.6.3" + } + }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, "ethjs-format": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.2.tgz", @@ -16671,6 +16907,11 @@ "is-hex-prefixed": "1.0.0", "strip-hex-prefix": "1.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -16722,6 +16963,7 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -17517,6 +17759,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, "requires": { "graceful-fs": "^4.1.9" } @@ -20201,7 +20444,7 @@ "requires": { "async": "^1.3.0", "flat-arguments": "^1.0.0", - "lodash": "^4.17.5", + "lodash": "^3.10.0", "minimist": "^1.1.0" }, "dependencies": { @@ -20211,7 +20454,7 @@ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, "lodash": { - "version": "4.17.5", + "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" } @@ -24866,7 +25109,8 @@ "precond": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=" + "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw=", + "dev": true }, "prelude-ls": { "version": "1.1.2", @@ -28180,11 +28424,10 @@ } }, "solc": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.23.tgz", - "integrity": "sha512-AT7anLHY6uIRg2It6N0UlCHeZ7YeecIkUhnlirrCgCPCUevtnoN48BxvgigN/4jJTRljv5oFhAJtI6gvHzT5DQ==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", + "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", "requires": { - "fs-extra": "^0.30.0", "memorystream": "^0.3.1", "require-from-string": "^1.1.0", "semver": "^5.3.0", @@ -29473,7 +29716,6 @@ "connect-query": "^1.0.0", "destroy": "^1.0.4", "fast-url-parser": "^1.1.3", - "fs-extra": "^0.30.0", "glob": "^7.1.2", "glob-slasher": "^1.0.1", "home-dir": "^1.0.0", @@ -29630,6 +29872,11 @@ } } }, + "swappable-obj-proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/swappable-obj-proxy/-/swappable-obj-proxy-1.0.2.tgz", + "integrity": "sha512-IDrfIgZr09yK9j8XSoeHACf9IaM03izjIiNBq7lZrXQYr2eXwjcRXJUcUmkOkTs3QrXigAGbVgaq86hsRH9DAg==" + }, "swarm-js": { "version": "0.1.37", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.37.tgz", @@ -31973,107 +32220,6 @@ "web3-utils": "1.0.0-beta.34" } }, - "web3-provider-engine": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-14.0.5.tgz", - "integrity": "sha512-1W/ue7VOwOMnmKgMY3HCpbixi6qhfl4r1dK8W597AwJLbrQ+twJKwWlFAedDpJjCc9MwRCCB3pyexW4HJVSiBg==", - "requires": { - "async": "^2.5.0", - "backoff": "^2.5.0", - "clone": "^2.0.0", - "cross-fetch": "^2.1.0", - "eth-block-tracker": "^3.0.0", - "eth-json-rpc-infura": "^3.1.0", - "eth-sig-util": "^1.4.2", - "ethereumjs-block": "^1.2.2", - "ethereumjs-tx": "^1.2.0", - "ethereumjs-util": "^5.1.5", - "ethereumjs-vm": "^2.3.4", - "json-rpc-error": "^2.0.0", - "json-stable-stringify": "^1.0.1", - "promise-to-callback": "^1.0.0", - "readable-stream": "^2.2.9", - "request": "^2.67.0", - "semaphore": "^1.0.3", - "tape": "^4.4.0", - "ws": "^5.1.1", - "xhr": "^2.2.0", - "xtend": "^4.0.1" - }, - "dependencies": { - "eth-block-tracker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.0.tgz", - "integrity": "sha512-Lhhu/+1GOeekMRDRhUcM7VSJRmX279DByrwzEbmG0JL1tcT3xRo6GLNXnidyJ7ahHJm+0JFhw/RqtTeIxagQwA==", - "requires": { - "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" - } - }, - "eth-json-rpc-infura": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.1.0.tgz", - "integrity": "sha512-uMYkEP6fga8CyNo8TMoA/7cxi6bL3V8pTvjKQikOi9iYl6/AO5xlfgniyAMElSiq2mmXz3lYa/9VYDMzt/J5aA==", - "requires": { - "cross-fetch": "^2.1.0", - "eth-json-rpc-middleware": "^1.5.0", - "json-rpc-engine": "^3.4.0", - "json-rpc-error": "^2.0.0", - "tape": "^4.8.0" - } - }, - "ethereumjs-util": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz", - "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - }, - "ethereumjs-vm": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.5.tgz", - "integrity": "sha512-AJ7x44+xqyE5+UO3Nns19WkTdZfyqFZ+sEjIEpvme7Ipbe3iBU1uwCcHEdiu/yY9bdhr3IfSa/NfIKNeXPaRVQ==", - "requires": { - "async": "^2.1.2", - "async-eventemitter": "^0.2.2", - "ethereum-common": "0.2.0", - "ethereumjs-account": "^2.0.3", - "ethereumjs-block": "~1.7.0", - "ethereumjs-util": "^5.1.3", - "fake-merkle-patricia-tree": "^1.0.1", - "functional-red-black-tree": "^1.0.1", - "merkle-patricia-tree": "^2.1.2", - "rustbn.js": "~0.1.1", - "safe-buffer": "^5.1.1" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "ws": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.1.1.tgz", - "integrity": "sha512-bOusvpCb09TOBLbpMKszd45WKC2KPtxiyiHanv+H2DE3Az+1db5a/L7sVJZVDPUC1Br8f0SKRr1KjLpD1U/IAw==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, "web3-providers-http": { "version": "1.0.0-beta.34", "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.0.0-beta.34.tgz", From 3111ae3a698f6f7e15ae6f10483fdd4694c009ab Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Jul 2018 14:57:23 -0700 Subject: [PATCH 069/183] dep - automated package-lock fixes --- package-lock.json | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 957792a6b..4a387f266 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8658,12 +8658,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#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf", + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#4ea2fdfed09e8f99117d9362d17c6b01b64a2bcf", + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", @@ -8941,6 +8941,20 @@ } } }, + "ethereumjs-util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", + "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "ethjs-util": "^0.1.3", + "keccak": "^1.0.2", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1", + "secp256k1": "^3.0.1" + } + }, "ethereumjs-vm": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/ethereumjs-vm/-/ethereumjs-vm-2.3.4.tgz", @@ -16963,7 +16977,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -17759,7 +17772,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, "requires": { "graceful-fs": "^4.1.9" } @@ -28428,12 +28440,25 @@ "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", "requires": { + "fs-extra": "^0.30.0", "memorystream": "^0.3.1", "require-from-string": "^1.1.0", "semver": "^5.3.0", "yargs": "^4.7.1" }, "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", @@ -29716,6 +29741,7 @@ "connect-query": "^1.0.0", "destroy": "^1.0.4", "fast-url-parser": "^1.1.3", + "fs-extra": "^0.30.0", "glob": "^7.1.2", "glob-slasher": "^1.0.1", "home-dir": "^1.0.0", @@ -29741,6 +29767,18 @@ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", From 0ada37ead77ca4506b216b961896342e6af94eac Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Jul 2018 15:46:33 -0700 Subject: [PATCH 070/183] test - e2e-beta - update some api calls --- test/e2e/beta/metamask-beta-ui.spec.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index 50998fd5d..ad7eda0f5 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -12,8 +12,6 @@ const { findElement, findElements, checkBrowserForConsoleErrors, - loadExtension, - verboseReportOnFailure, openNewPage, } = require('./helpers') @@ -53,7 +51,7 @@ describe('MetaMask', function () { } } if (this.currentTest.state === 'failed') { - await verboseReportOnFailure(driver, this.currentTest) + await verboseReportOnFailure({ browser, driver, title: this.currentTest.title }) } }) @@ -70,7 +68,7 @@ describe('MetaMask', function () { try { networkSelector = await findElement(driver, By.css('#network_component')) } catch (e) { - await loadExtension(driver, extensionId) + await driver.get(extensionUri) } await delay(regularDelayMs) }) @@ -240,7 +238,7 @@ describe('MetaMask', function () { await word11.click() await delay(tinyDelayMs) } catch (e) { - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await retypeSeedPhrase(words) } } @@ -597,7 +595,7 @@ describe('MetaMask', function () { await driver.close() await driver.switchTo().window(extension) - await loadExtension(driver, extensionId) + await driver.get(extensionUri) await driver.switchTo().window(extension) await delay(regularDelayMs) From 9f11042d72c15b1725fb5f4b6484cc9d9583b34b Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Jul 2018 16:03:53 -0700 Subject: [PATCH 071/183] test - e2e - move timings --- test/e2e/metamask.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index d80fc9430..2d0da46f0 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -79,6 +79,7 @@ describe('Metamask popup page', function () { it('allows the button to be clicked when scrolled to the bottom of TOU', async () => { const button = await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-column.flex-center.flex-grow > button')) await button.click() + await delay(300) }) it('shows privacy notice', async () => { @@ -89,7 +90,6 @@ describe('Metamask popup page', function () { }) it('shows phishing notice', async () => { - await delay(300) const noticeHeader = await driver.findElement(By.css('.terms-header')).getText() assert.equal(noticeHeader, 'PHISHING WARNING', 'shows phishing warning') const element = await driver.findElement(By.css('.markdown')) From 86e95b283bd64debe9ca888abef716bc1eecce9c Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Mon, 2 Jul 2018 16:48:26 -0700 Subject: [PATCH 072/183] Fix notice screen incorrectly disabling Accept button after multiple notices --- old-ui/app/components/notice.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/old-ui/app/components/notice.js b/old-ui/app/components/notice.js index 09d461c7b..1ec254555 100644 --- a/old-ui/app/components/notice.js +++ b/old-ui/app/components/notice.js @@ -116,12 +116,25 @@ Notice.prototype.render = function () { ) } +Notice.prototype.setInitialDisclaimerState = function () { + if (document.getElementsByClassName('notice-box')[0].clientHeight < 310) { + this.setState({disclaimerDisabled: false}) + } +} + Notice.prototype.componentDidMount = function () { // eslint-disable-next-line react/no-find-dom-node var node = findDOMNode(this) linker.setupListener(node) - if (document.getElementsByClassName('notice-box')[0].clientHeight < 310) { - this.setState({disclaimerDisabled: false}) + this.setInitialDisclaimerState() +} + +Notice.prototype.componentDidUpdate = function (prevProps) { + const { notice: { id } = {} } = this.props + const { notice: { id: prevNoticeId } = {} } = prevProps + + if (id !== prevNoticeId) { + this.setInitialDisclaimerState() } } From b75abfac60c1fa1d023237e7e3609580cce1a2d3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 2 Jul 2018 23:54:18 -0700 Subject: [PATCH 073/183] test - e2e - fix missing import --- test/e2e/metamask.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js index 2d0da46f0..9a277b453 100644 --- a/test/e2e/metamask.spec.js +++ b/test/e2e/metamask.spec.js @@ -3,7 +3,7 @@ const mkdirp = require('mkdirp') const path = require('path') const assert = require('assert') const pify = require('pify') -const { By, Key } = require('selenium-webdriver') +const { By, Key, until } = require('selenium-webdriver') const { delay, createModifiedTestBuild, setupBrowserAndExtension, verboseReportOnFailure } = require('./func') describe('Metamask popup page', function () { From 2b2cd87e2d6e93dadb3ddd20ebf854ab6f2d2382 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Jul 2018 12:17:46 -0700 Subject: [PATCH 074/183] test - e2e - contract test - add logs --- test/e2e/beta/contract-test/contract.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/e2e/beta/contract-test/contract.js b/test/e2e/beta/contract-test/contract.js index 19c29e5c1..84e11381f 100644 --- a/test/e2e/beta/contract-test/contract.js +++ b/test/e2e/beta/contract-test/contract.js @@ -31,23 +31,25 @@ The `piggybankContract` is compiled from: var piggybankContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"withdrawAmount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"remainingBal","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]); deployButton.addEventListener('click', function (event) { - + var piggybank = piggybankContract.new( { - from: web3.eth.accounts[0], - data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', + from: web3.eth.accounts[0], + data: '0x608060405234801561001057600080fd5b5033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000808190555061023b806100686000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d1461005c5780638da5cb5b1461009d578063d0e30db0146100f4575b600080fd5b34801561006857600080fd5b5061008760048036038101908080359060200190929190505050610112565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100b26101d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100fc6101f6565b6040518082815260200191505060405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561017057600080fd5b8160008082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f193505050501580156101c5573d6000803e3d6000fd5b506000549050919050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60003460008082825401925050819055506000549050905600a165627a7a72305820f237db3ec816a52589d82512117bc85bc08d3537683ffeff9059108caf3e5d400029', gas: '4700000' }, function (e, contract){ console.log(e, contract); + console.log('deployed!', contract); if (typeof contract.address !== 'undefined') { console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); console.log(`contract`, contract); depositButton.addEventListener('click', function (event) { - contract.deposit({ from: web3.eth.accounts[0], value: '0x29a2241af62c0000' }, function (result) { - console.log(result) - }) + console.log('contract.deposit', { from: web3.eth.accounts[0], value: '0x29a2241af62c0000' }) + contract.deposit({ from: web3.eth.accounts[0], value: '0x29a2241af62c0000' }, function (result) { + console.log(result) + }) }) withdrawButton.addEventListener('click', function (event) { @@ -58,4 +60,4 @@ deployButton.addEventListener('click', function (event) { } }) -}) \ No newline at end of file +}) From c7236359328e6b64a5bbb8bf012073e0dbf6ac8a Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Jul 2018 13:48:49 -0700 Subject: [PATCH 075/183] test - run ganache rpc without vm errors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 835474505..6489dfe24 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js", - "ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'", + "ganache:start": "ganache-cli --noVMErrorsOnRPCResponse -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'", "sentry:publish": "node ./development/sentry-publish.js", "lint": "eslint .", "lint:fix": "eslint . --fix", From 21ae81dc43a213870bcb31e814029d450ce78389 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Jul 2018 13:49:08 -0700 Subject: [PATCH 076/183] deps - update lock --- package-lock.json | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16373dc19..80096daf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16962,7 +16962,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -17758,7 +17757,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", - "dev": true, "requires": { "graceful-fs": "^4.1.9" } @@ -28427,12 +28425,25 @@ "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.24.tgz", "integrity": "sha512-2xd7Cf1HeVwrIb6Bu1cwY2/TaLRodrppCq3l7rhLimFQgmxptXhTC3+/wesVLpB09F1A2kZgvbMOgH7wvhFnBQ==", "requires": { + "fs-extra": "^0.30.0", "memorystream": "^0.3.1", "require-from-string": "^1.1.0", "semver": "^5.3.0", "yargs": "^4.7.1" }, "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "yargs": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", @@ -29715,6 +29726,7 @@ "connect-query": "^1.0.0", "destroy": "^1.0.4", "fast-url-parser": "^1.1.3", + "fs-extra": "^0.30.0", "glob": "^7.1.2", "glob-slasher": "^1.0.1", "home-dir": "^1.0.0", @@ -29740,6 +29752,18 @@ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", From fa02a6c7c65f6866998171881fd657570fe3fe7b Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 3 Jul 2018 13:56:18 -0700 Subject: [PATCH 077/183] test - unit - remove tests for obsolete methods --- .../transactions/pending-tx-test.js | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/test/unit/app/controllers/transactions/pending-tx-test.js b/test/unit/app/controllers/transactions/pending-tx-test.js index 2a2db0560..ba15f1953 100644 --- a/test/unit/app/controllers/transactions/pending-tx-test.js +++ b/test/unit/app/controllers/transactions/pending-tx-test.js @@ -96,58 +96,6 @@ describe('PendingTransactionTracker', function () { }) }) - describe('#checkForTxInBlock', function () { - it('should return if no pending transactions', function () { - // throw a type error if it trys to do anything on the block - // thus failing the test - const block = Proxy.revocable({}, {}).revoke() - pendingTxTracker.checkForTxInBlock(block) - }) - it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { - const block = Proxy.revocable({}, {}).revoke() - pendingTxTracker.getPendingTransactions = () => [txMetaNoHash] - pendingTxTracker.once('tx:failed', (txId, err) => { - assert(txId, txMetaNoHash.id, 'should pass txId') - done() - }) - pendingTxTracker.checkForTxInBlock(block) - }) - it('should emit \'txConfirmed\' if the tx is in the block', function (done) { - const block = { transactions: [txMeta]} - pendingTxTracker.getPendingTransactions = () => [txMeta] - pendingTxTracker.once('tx:confirmed', (txId) => { - assert(txId, txMeta.id, 'should pass txId') - done() - }) - pendingTxTracker.once('tx:failed', (_, err) => { done(err) }) - pendingTxTracker.checkForTxInBlock(block) - }) - }) - describe('#queryPendingTxs', function () { - it('should call #_checkPendingTxs if their is no oldBlock', function (done) { - let oldBlock - const newBlock = { number: '0x01' } - pendingTxTracker._checkPendingTxs = done - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - }) - it('should call #_checkPendingTxs if oldBlock and the newBlock have a diff of greater then 1', function (done) { - const oldBlock = { number: '0x01' } - const newBlock = { number: '0x03' } - pendingTxTracker._checkPendingTxs = done - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - }) - it('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less', function (done) { - const oldBlock = { number: '0x1' } - const newBlock = { number: '0x2' } - pendingTxTracker._checkPendingTxs = () => { - const err = new Error('should not call #_checkPendingTxs if oldBlock and the newBlock have a diff of 1 or less') - done(err) - } - pendingTxTracker.queryPendingTxs({ oldBlock, newBlock }) - done() - }) - }) - describe('#_checkPendingTx', function () { it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { pendingTxTracker.once('tx:failed', (txId, err) => { From 2e50348241af3aa0319144110cc75d2731f65e28 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 23 Jul 2018 17:11:51 -0400 Subject: [PATCH 078/183] added instascan pkg --- package-lock.json | 83 +++++++++++++++++++++++++++++++++++++++++++---- package.json | 1 + 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 443e173a9..3e1b69db9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8390,12 +8390,13 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.0.1.tgz", "integrity": "sha512-lxHZOQspexk3DaGj4RBbWy4C/qNOWRnxpaJzNnYD3WEmC8shcJ4tHs7Xv878rzvILfJnSFSCCiKQhng1m80oBQ==", "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -8673,12 +8674,13 @@ "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#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -8720,12 +8722,14 @@ "integrity": "sha512-lxHZOQspexk3DaGj4RBbWy4C/qNOWRnxpaJzNnYD3WEmC8shcJ4tHs7Xv878rzvILfJnSFSCCiKQhng1m80oBQ==", "dev": true, "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { "ethereumjs-abi": { "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "dev": true, "requires": { "bn.js": "^4.10.0", "ethereumjs-util": "^5.0.0" @@ -8737,6 +8741,7 @@ "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", @@ -11788,6 +11793,17 @@ } } }, + "fsm-as-promised": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/fsm-as-promised/-/fsm-as-promised-0.13.2.tgz", + "integrity": "sha1-X04RCGgotwoZItx7T4HAgX1ugjg=", + "dev": true, + "requires": { + "es6-promise": "^4.0.2", + "lodash": "^4.16.2", + "stampit": "^3.0.1" + } + }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", @@ -15599,6 +15615,17 @@ } } }, + "instascan": { + "version": "github:brunobar79/instascan#141f7b2aa12c9e833de41ba3daf37a1c1b7c070e", + "from": "github:brunobar79/instascan#141f7b2aa12c9e833de41ba3daf37a1c1b7c070e", + "dev": true, + "requires": { + "babel-polyfill": "^6.9.1", + "fsm-as-promised": "^0.13.0", + "visibilityjs": "^1.2.3", + "webrtc-adapter": "^6.3.0" + } + }, "interpret": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", @@ -27154,6 +27181,15 @@ "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==" }, + "rtcpeerconnection-shim": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.13.tgz", + "integrity": "sha512-Xz4zQLZNs9lFBvqbaHGIjLWtyZ1V82ec5r+WNEo7NlIx3zF5M3ytn9mkkfYeZmpE032cNg3Vvf0rP8kNXUNd9w==", + "dev": true, + "requires": { + "sdp": "^2.6.0" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", @@ -27472,6 +27508,12 @@ } } }, + "sdp": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.7.4.tgz", + "integrity": "sha512-0+wTfgvUUEGcvvFoHIC0aiGbx6gzwAUm8FkKt5Oqqkjf9mEEDLgwnoDKX7MYTGXrNNwzikVbutJ+OVNAGmJBQw==", + "dev": true + }, "secp256k1": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.4.0.tgz", @@ -28521,6 +28563,12 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "stampit": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/stampit/-/stampit-3.2.1.tgz", + "integrity": "sha1-lTpBpJRYoLKG/7HjydbOcDblids=", + "dev": true + }, "state-toggle": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.0.tgz", @@ -30684,6 +30732,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, "requires": { "is-typedarray": "^1.0.0" } @@ -31624,6 +31673,12 @@ } } }, + "visibilityjs": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/visibilityjs/-/visibilityjs-1.2.8.tgz", + "integrity": "sha512-Y+aL3OUX88b+/VSmkmC2ApuLbf0grzbNLpCfIDSw3BzTU6PqcPsdgIOaw8b+eZoy+DdQqnVN3y/Evow9vQq9Ig==", + "dev": true + }, "vlq": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", @@ -31707,6 +31762,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#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", @@ -31715,7 +31771,7 @@ "dependencies": { "bignumber.js": { "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", - "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git" } } }, @@ -32214,7 +32270,8 @@ "dev": true, "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.34" + "web3-core-helpers": "1.0.0-beta.34", + "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" }, "dependencies": { "underscore": { @@ -32225,7 +32282,8 @@ }, "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", + "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "dev": true, "requires": { "debug": "^2.2.0", "nan": "^2.3.3", @@ -33216,6 +33274,16 @@ } } }, + "webrtc-adapter": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-6.3.0.tgz", + "integrity": "sha512-WRLIEzXLCTSifhR1tqiK+HXuySLQ+8vESHBeJ0Uq5N9Eewa2hL+54fKnMqtB5sCSG7/crfntdovpp4R4ttvd8w==", + "dev": true, + "requires": { + "rtcpeerconnection-shim": "^1.2.10", + "sdp": "^2.7.0" + } + }, "websocket": { "version": "1.0.26", "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.26.tgz", @@ -33581,7 +33649,8 @@ "yaeti": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "dev": true }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index 376f773e5..168ab0171 100644 --- a/package.json +++ b/package.json @@ -257,6 +257,7 @@ "gulp-watch": "^5.0.0", "gulp-zip": "^4.0.0", "http-server": "^0.11.1", + "instascan": "github:brunobar79/instascan#141f7b2aa12c9e833de41ba3daf37a1c1b7c070e", "image-size": "^0.6.2", "isomorphic-fetch": "^2.2.1", "jsdoc": "^3.5.5", From 0940ecd57b6efbf76171579ffe72dfd8a683f5be Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 23 Jul 2018 17:12:20 -0400 Subject: [PATCH 079/183] added camera snippet injection to inpage.js --- app/scripts/inpage.js | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 7dd7fda02..1fafe7813 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -5,6 +5,7 @@ const log = require('loglevel') const LocalMessageDuplexStream = require('post-message-stream') const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('./lib/inpage-provider.js') +const Instascan = require('instascan') restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') @@ -96,3 +97,41 @@ function restoreContextAfterImports () { console.warn('MetaMask - global.define could not be overwritten.') } } + +function initCameraScanner () { + // Append preview div + const preview = document.createElement('div') + preview.id = 'metamask-preview-wrapper' + preview.style = 'position:absolute; top: 20px; left: 20px; z-indez: 99999999999999; width: 300px; height: 300px; overflow: hidden' + const previewVideo = document.createElement('video') + previewVideo.id = 'metamask-preview-video' + previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%' + preview.appendChild(previewVideo) + document.body.appendChild(preview) + console.log('injected') + const scanner = new Instascan.Scanner({ + video: document.getElementById('metamask-preview-video'), + backgroundScan: false, + continuous: true, + }) + scanner.addListener('scan', function (content) { + alert(content) + scanner.stop().then(_ => { + document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper')) + }) + }) + Instascan.Camera.getCameras().then(function (cameras) { + if (cameras.length > 0) { + scanner.start(cameras[1]) + } else { + console.error('No cameras found.') + } + }).catch(function (e) { + console.error(e) + }) +} + +setTimeout(_ => { + console.log('injecting...') + initCameraScanner() +}, 3000) From 02091486094dcc818096ce13a22cdc140a2e8347 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 23 Jul 2018 19:45:13 -0400 Subject: [PATCH 080/183] fixes --- app/scripts/inpage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 1fafe7813..1a7bea7c0 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -102,10 +102,10 @@ function initCameraScanner () { // Append preview div const preview = document.createElement('div') preview.id = 'metamask-preview-wrapper' - preview.style = 'position:absolute; top: 20px; left: 20px; z-indez: 99999999999999; width: 300px; height: 300px; overflow: hidden' + preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' const previewVideo = document.createElement('video') previewVideo.id = 'metamask-preview-video' - previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%' + previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;' preview.appendChild(previewVideo) document.body.appendChild(preview) console.log('injected') @@ -122,7 +122,7 @@ function initCameraScanner () { }) Instascan.Camera.getCameras().then(function (cameras) { if (cameras.length > 0) { - scanner.start(cameras[1]) + scanner.start(cameras[0]) } else { console.error('No cameras found.') } From f7ad978474f42eb96f4f6c79376391504cf228c1 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 23 Jul 2018 21:27:51 -0400 Subject: [PATCH 081/183] camera working back and forth --- app/scripts/contentscript.js | 47 ++++++++++++++ app/scripts/inpage.js | 38 ----------- app/scripts/metamask-controller.js | 24 ++++++- app/scripts/platforms/extension.js | 65 +++---------------- ui/app/actions.js | 21 ++++++ .../send-content/send-content.component.js | 2 + ui/app/components/send/send.component.js | 12 +++- ui/app/components/send/send.container.js | 2 + 8 files changed, 116 insertions(+), 95 deletions(-) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 7c775fb04..87f7c63ef 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -6,6 +6,7 @@ const PongStream = require('ping-pong-stream/pong') const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') const PortStream = require('./lib/port-stream.js') +const Instascan = require('instascan') const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' @@ -199,3 +200,49 @@ function redirectToPhishingWarning () { console.log('MetaMask - redirecting to phishing warning') window.location.href = 'https://metamask.io/phishing.html' } + +function initQrCodeScanner () { + // Append preview div + const preview = document.createElement('div') + preview.id = 'metamask-preview-wrapper' + preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' + const previewVideo = document.createElement('video') + previewVideo.id = 'metamask-preview-video' + previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;' + preview.appendChild(previewVideo) + document.body.appendChild(preview) + console.log('injected') + const scanner = new Instascan.Scanner({ + video: document.getElementById('metamask-preview-video'), + backgroundScan: false, + continuous: true, + }) + scanner.addListener('scan', function (content) { + console.log('QR-SCANNER: got code (IN-PAGE)', content) + scanner.stop().then(_ => { + console.log('QR-SCANNER: stopped scanner and sending msg (IN-PAGE)', content) + extension.runtime.sendMessage({ + action: 'qr-code-scanner-data', + data: content, + }) + console.log('QR-SCANNER: message sent (IN-PAGE)', content) + document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper')) + }) + }) + Instascan.Camera.getCameras().then(function (cameras) { + if (cameras.length > 0) { + scanner.start(cameras[0]) + } else { + console.error('No cameras found.') + } + }).catch(function (e) { + console.error(e) + }) +} + +extension.runtime.onMessage.addListener(({ action }) => { + console.log('QR-SCANNER: message received (IN-PAGE)', action) + initQrCodeScanner() +}) +console.log('QR-SCANNER: now listening (IN-PAGE)') + diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 1a7bea7c0..20621b73f 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -5,7 +5,6 @@ const log = require('loglevel') const LocalMessageDuplexStream = require('post-message-stream') const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('./lib/inpage-provider.js') -const Instascan = require('instascan') restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') @@ -98,40 +97,3 @@ function restoreContextAfterImports () { } } -function initCameraScanner () { - // Append preview div - const preview = document.createElement('div') - preview.id = 'metamask-preview-wrapper' - preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' - const previewVideo = document.createElement('video') - previewVideo.id = 'metamask-preview-video' - previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;' - preview.appendChild(previewVideo) - document.body.appendChild(preview) - console.log('injected') - const scanner = new Instascan.Scanner({ - video: document.getElementById('metamask-preview-video'), - backgroundScan: false, - continuous: true, - }) - scanner.addListener('scan', function (content) { - alert(content) - scanner.stop().then(_ => { - document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper')) - }) - }) - Instascan.Camera.getCameras().then(function (cameras) { - if (cameras.length > 0) { - scanner.start(cameras[0]) - } else { - console.error('No cameras found.') - } - }).catch(function (e) { - console.error(e) - }) -} - -setTimeout(_ => { - console.log('injecting...') - initCameraScanner() -}, 3000) diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index bcc7075c2..62d707432 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -380,6 +380,9 @@ module.exports = class MetamaskController extends EventEmitter { // TREZOR unlockTrezorAccount: nodeify(this.unlockTrezorAccount, this), + // QR code scanner + scanQrCode: nodeify(this.scanQrCode, this), + // vault management submitPassword: nodeify(this.submitPassword, this), @@ -653,7 +656,26 @@ module.exports = class MetamaskController extends EventEmitter { const { identities } = this.preferencesController.store.getState() return { ...keyState, identities } - } + } + + scanQrCode () { + return new Promise((resolve, reject) => { + console.log('QR-SCANNER: intializing QR code scanner feature (MM controller)') + // Tell contentscript to inject the QR reader + this.platform.sendMessage('qr-code-scanner-init') + console.log('QR-SCANNER: message to initialize has been sent (MM controller)') + // Wait for the scanner to send something back + this.platform.addMessageListener(({ action, data }) => { + console.log('QR-SCANNER: message received (MM controller)', action, data) + if (action && action === 'qr-code-scanner-data') { + const normalizedAddress = data.replace('ethereum:', '') + console.log('QR-SCANNER: resolving promise!', normalizedAddress) + return Promise.resolve(normalizedAddress) + } + }) + console.log('QR-SCANNER: now listening (MM controller)') + }) + } // diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 901c26cab..182df23b1 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -1,5 +1,4 @@ const extension = require('extensionizer') -const explorerLink = require('etherscan-link').createExplorerLink class ExtensionPlatform { @@ -18,11 +17,8 @@ class ExtensionPlatform { return extension.runtime.getManifest().version } - openExtensionInBrowser (route = null) { - let extensionURL = extension.runtime.getURL('home.html') - if (route) { - extensionURL += `#${route}` - } + openExtensionInBrowser () { + const extensionURL = extension.runtime.getURL('home.html') this.openWindow({ url: extensionURL }) } @@ -36,57 +32,16 @@ class ExtensionPlatform { } } - showTransactionNotification (txMeta) { - - const status = txMeta.status - if (status === 'confirmed') { - this._showConfirmedTransaction(txMeta) - } else if (status === 'failed') { - this._showFailedTransaction(txMeta) - } - } - - _showConfirmedTransaction (txMeta) { - - this._subscribeToNotificationClicked() - - const url = explorerLink(txMeta.hash, parseInt(txMeta.metamaskNetworkId)) - const nonce = parseInt(txMeta.txParams.nonce, 16) - - const title = 'Confirmed transaction' - const message = `Transaction ${nonce} confirmed! View on EtherScan` - this._showNotification(title, message, url) - } - - _showFailedTransaction (txMeta) { - - const nonce = parseInt(txMeta.txParams.nonce, 16) - const title = 'Failed transaction' - const message = `Transaction ${nonce} failed! ${txMeta.err.message}` - this._showNotification(title, message) - } - - _showNotification (title, message, url) { - extension.notifications.create( - url, - { - 'type': 'basic', - 'title': title, - 'iconUrl': extension.extension.getURL('../../images/icon-64.png'), - 'message': message, - }) + addMessageListener (cb) { + extension.runtime.onMessage.addListener(cb) } - _subscribeToNotificationClicked () { - if (!extension.notifications.onClicked.hasListener(this._viewOnEtherScan)) { - extension.notifications.onClicked.addListener(this._viewOnEtherScan) - } - } - - _viewOnEtherScan (txId) { - if (txId.startsWith('http://')) { - global.metamaskController.platform.openWindow({ url: txId }) - } + sendMessage (message, query = {}) { + extension.tabs.query(query, tabs => { + const activeTab = tabs.filter(tab => tab.active)[0] + extension.tabs.sendMessage(activeTab.id, message) + console.log('QR-SCANNER: message sent to tab', message, activeTab) + }) } } diff --git a/ui/app/actions.js b/ui/app/actions.js index 6c947fc35..9aba6853d 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -302,6 +302,7 @@ var actions = { CLEAR_PENDING_TOKENS: 'CLEAR_PENDING_TOKENS', setPendingTokens, clearPendingTokens, + scanQrCode, } module.exports = actions @@ -2194,3 +2195,23 @@ function clearPendingTokens () { type: actions.CLEAR_PENDING_TOKENS, } } + +function scanQrCode () { + log.debug(`background.scanQrCode`) + return (dispatch, getState) => { + dispatch(actions.showLoadingIndication()) + return new Promise((resolve, reject) => { + background.scanQrCode((err, data) => { + log.debug(`background.scanQrCode resolved!`, err, data) + if (err) { + log.error(err) + dispatch(actions.displayWarning(err.message)) + return reject(err) + } + + dispatch(actions.hideLoadingIndication()) + return resolve(data) + }) + }) + } +} diff --git a/ui/app/components/send/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js index 7a0b1a18e..566ee1c7f 100644 --- a/ui/app/components/send/send-content/send-content.component.js +++ b/ui/app/components/send/send-content/send-content.component.js @@ -11,6 +11,7 @@ export default class SendContent extends Component { static propTypes = { updateGas: PropTypes.func, + scanQrCode: PropTypes.func, }; render () { @@ -19,6 +20,7 @@ export default class SendContent extends Component {
this.props.updateGas(updateData)} /> + this.props.updateGas(updateData)} /> diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js index 6f1b20c55..5e967251d 100644 --- a/ui/app/components/send/send.component.js +++ b/ui/app/components/send/send.component.js @@ -38,12 +38,19 @@ export default class SendTransactionScreen extends PersistentForm { updateAndSetGasTotal: PropTypes.func, updateSendErrors: PropTypes.func, updateSendTokenBalance: PropTypes.func, + scanQrCode: PropTypes.func, }; static contextTypes = { t: PropTypes.func, }; + scanQrCode = async () => { + const scannedAddress = await this.props.scanQrCode() + console.log('QR-SCANNER: Got address (UI)', scannedAddress) + this.updateGas({ to: scannedAddress }) + } + updateGas ({ to: updatedToAddress, amount: value } = {}) { const { amount, @@ -170,7 +177,10 @@ export default class SendTransactionScreen extends PersistentForm { return (
- this.updateGas(updateData)}/> + this.updateGas(updateData)} + scanQrCode={_ => this.scanQrCode()} + />
) diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js index 44ebd2792..c3240be67 100644 --- a/ui/app/components/send/send.container.js +++ b/ui/app/components/send/send.container.js @@ -26,6 +26,7 @@ import { updateSendTokenBalance, updateGasData, setGasTotal, + scanQrCode, } from '../../actions' import { resetSendState, @@ -89,5 +90,6 @@ function mapDispatchToProps (dispatch) { }, updateSendErrors: newError => dispatch(updateSendErrors(newError)), resetSendState: () => dispatch(resetSendState()), + scanQrCode: () => dispatch(scanQrCode()), } } From d5929e5c42e230fc0a52337f86b5850e68516563 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Mon, 23 Jul 2018 22:10:57 -0400 Subject: [PATCH 082/183] added qr code scanner icon in send transaction --- app/scripts/contentscript.js | 7 +------ app/scripts/metamask-controller.js | 9 ++------- app/scripts/platforms/extension.js | 3 +-- ui/app/components/ens-input.js | 1 + .../send/send-content/send-content.component.js | 6 ++++-- .../send-content/send-to-row/send-to-row.component.js | 1 + ui/app/components/send/send.component.js | 2 +- ui/app/components/send/send.container.js | 2 ++ .../components/send/to-autocomplete/to-autocomplete.js | 8 ++++++-- ui/app/css/itcss/components/send.scss | 10 ++++++++++ 10 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 87f7c63ef..83ed85a1a 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -205,7 +205,7 @@ function initQrCodeScanner () { // Append preview div const preview = document.createElement('div') preview.id = 'metamask-preview-wrapper' - preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' + preview.style = 'position:fixed; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' const previewVideo = document.createElement('video') previewVideo.id = 'metamask-preview-video' previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;' @@ -218,14 +218,11 @@ function initQrCodeScanner () { continuous: true, }) scanner.addListener('scan', function (content) { - console.log('QR-SCANNER: got code (IN-PAGE)', content) scanner.stop().then(_ => { - console.log('QR-SCANNER: stopped scanner and sending msg (IN-PAGE)', content) extension.runtime.sendMessage({ action: 'qr-code-scanner-data', data: content, }) - console.log('QR-SCANNER: message sent (IN-PAGE)', content) document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper')) }) }) @@ -241,8 +238,6 @@ function initQrCodeScanner () { } extension.runtime.onMessage.addListener(({ action }) => { - console.log('QR-SCANNER: message received (IN-PAGE)', action) initQrCodeScanner() }) -console.log('QR-SCANNER: now listening (IN-PAGE)') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 62d707432..f67d4edf8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -660,20 +660,15 @@ module.exports = class MetamaskController extends EventEmitter { scanQrCode () { return new Promise((resolve, reject) => { - console.log('QR-SCANNER: intializing QR code scanner feature (MM controller)') // Tell contentscript to inject the QR reader - this.platform.sendMessage('qr-code-scanner-init') - console.log('QR-SCANNER: message to initialize has been sent (MM controller)') + this.platform.sendMessageToActiveTab('qr-code-scanner-init') // Wait for the scanner to send something back this.platform.addMessageListener(({ action, data }) => { - console.log('QR-SCANNER: message received (MM controller)', action, data) if (action && action === 'qr-code-scanner-data') { const normalizedAddress = data.replace('ethereum:', '') - console.log('QR-SCANNER: resolving promise!', normalizedAddress) - return Promise.resolve(normalizedAddress) + resolve(normalizedAddress) } }) - console.log('QR-SCANNER: now listening (MM controller)') }) } diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 182df23b1..1cab0bedd 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -36,11 +36,10 @@ class ExtensionPlatform { extension.runtime.onMessage.addListener(cb) } - sendMessage (message, query = {}) { + sendMessageToActiveTab (message, query = {}) { extension.tabs.query(query, tabs => { const activeTab = tabs.filter(tab => tab.active)[0] extension.tabs.sendMessage(activeTab.id, message) - console.log('QR-SCANNER: message sent to tab', message, activeTab) }) } } diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index b9f99b3d1..cfdf663a5 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -54,6 +54,7 @@ EnsInput.prototype.render = function () { const opts = extend(props, { list: 'addresses', onChange: this.onChange.bind(this), + qrScanner: true, }) return h('div', { style: { width: '100%', position: 'relative' }, diff --git a/ui/app/components/send/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js index 566ee1c7f..60f97ab32 100644 --- a/ui/app/components/send/send-content/send-content.component.js +++ b/ui/app/components/send/send-content/send-content.component.js @@ -19,8 +19,10 @@ export default class SendContent extends Component {
- this.props.updateGas(updateData)} /> - + this.props.updateGas(updateData)} + scanQrCode={ _ => this.props.scanQrCode()} + /> this.props.updateGas(updateData)} /> diff --git a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js index 892ad5d67..321d1cfac 100644 --- a/ui/app/components/send/send-content/send-to-row/send-to-row.component.js +++ b/ui/app/components/send/send-content/send-to-row/send-to-row.component.js @@ -51,6 +51,7 @@ export default class SendToRow extends Component { showError={inError} > this.props.scanQrCode()} accounts={toAccounts} closeDropdown={() => closeToDropdown()} dropdownOpen={toDropdownOpen} diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js index 5e967251d..6c439cd21 100644 --- a/ui/app/components/send/send.component.js +++ b/ui/app/components/send/send.component.js @@ -47,7 +47,7 @@ export default class SendTransactionScreen extends PersistentForm { scanQrCode = async () => { const scannedAddress = await this.props.scanQrCode() - console.log('QR-SCANNER: Got address (UI)', scannedAddress) + this.props.updateSendTo(scannedAddress) this.updateGas({ to: scannedAddress }) } diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js index c3240be67..417941601 100644 --- a/ui/app/components/send/send.container.js +++ b/ui/app/components/send/send.container.js @@ -23,6 +23,7 @@ import { getTokenBalance, } from './send.selectors' import { + updateSendTo, updateSendTokenBalance, updateGasData, setGasTotal, @@ -91,5 +92,6 @@ function mapDispatchToProps (dispatch) { updateSendErrors: newError => dispatch(updateSendErrors(newError)), resetSendState: () => dispatch(resetSendState()), scanQrCode: () => dispatch(scanQrCode()), + updateSendTo: (to, nickname) => dispatch(updateSendTo(to, nickname)), } } diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js index 80cfa7a85..2b8923dd1 100644 --- a/ui/app/components/send/to-autocomplete/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js @@ -94,11 +94,12 @@ ToAutoComplete.prototype.render = function () { dropdownOpen, onChange, inError, + qrScanner, } = this.props return h('div.send-v2__to-autocomplete', {}, [ - h('input.send-v2__to-autocomplete__input', { + h(`input.send-v2__to-autocomplete__input${qrScanner?'.with-qr':''}`, { placeholder: this.context.t('recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, @@ -108,7 +109,10 @@ ToAutoComplete.prototype.render = function () { borderColor: inError ? 'red' : null, }, }), - + qrScanner && h(`i.fa.fa-qrcode.fa-lg.send-v2__to-autocomplete__qr-code`, { + style: { color: '#33333' }, + onClick: () => this.props.scanQrCode(), + }), !to && h(`i.fa.fa-caret-down.fa-lg.send-v2__to-autocomplete__down-caret`, { style: { color: '#dedede' }, onClick: () => this.handleInputEvent(), diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index e9c872ea7..e9f22a14e 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -626,6 +626,16 @@ top: 18px; right: 12px; } + + &__qr-code { + position: absolute; + top: 21px; + left: 13px; + } + + &__input.with-qr { + padding-left: 40px; + } } &__to-autocomplete, &__memo-text-area, &__hex-data { From 74fd6d1d1227d7a9e49623b73ee85985d79a1e46 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 24 Jul 2018 20:32:20 -0400 Subject: [PATCH 083/183] working without injection --- app/manifest.json | 3 +- app/scripts/contentscript.js | 41 ----- app/scripts/metamask-controller.js | 18 --- app/scripts/platforms/extension.js | 6 - ui/app/actions.js | 41 +++-- ui/app/app.js | 7 + ui/app/components/qr-scanner/index.js | 2 + .../qr-scanner/qr-scanner.component.js | 152 ++++++++++++++++++ ui/app/components/send/send.component.js | 20 ++- ui/app/components/send/send.container.js | 2 + ui/app/components/send/send.selectors.js | 5 + ui/app/reducers/app.js | 20 ++- ui/app/selectors.js | 1 + 13 files changed, 231 insertions(+), 87 deletions(-) create mode 100644 ui/app/components/qr-scanner/index.js create mode 100644 ui/app/components/qr-scanner/qr-scanner.component.js diff --git a/app/manifest.json b/app/manifest.json index 52256c5b7..6933652e6 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -76,5 +76,6 @@ "ids": [ "*" ] - } + }, + "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" } diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 83ed85a1a..72de16f31 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -6,7 +6,6 @@ const PongStream = require('ping-pong-stream/pong') const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') const PortStream = require('./lib/port-stream.js') -const Instascan = require('instascan') const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' @@ -201,43 +200,3 @@ function redirectToPhishingWarning () { window.location.href = 'https://metamask.io/phishing.html' } -function initQrCodeScanner () { - // Append preview div - const preview = document.createElement('div') - preview.id = 'metamask-preview-wrapper' - preview.style = 'position:fixed; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;' - const previewVideo = document.createElement('video') - previewVideo.id = 'metamask-preview-video' - previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;' - preview.appendChild(previewVideo) - document.body.appendChild(preview) - console.log('injected') - const scanner = new Instascan.Scanner({ - video: document.getElementById('metamask-preview-video'), - backgroundScan: false, - continuous: true, - }) - scanner.addListener('scan', function (content) { - scanner.stop().then(_ => { - extension.runtime.sendMessage({ - action: 'qr-code-scanner-data', - data: content, - }) - document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper')) - }) - }) - Instascan.Camera.getCameras().then(function (cameras) { - if (cameras.length > 0) { - scanner.start(cameras[0]) - } else { - console.error('No cameras found.') - } - }).catch(function (e) { - console.error(e) - }) -} - -extension.runtime.onMessage.addListener(({ action }) => { - initQrCodeScanner() -}) - diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f67d4edf8..c6be4b9d2 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -380,9 +380,6 @@ module.exports = class MetamaskController extends EventEmitter { // TREZOR unlockTrezorAccount: nodeify(this.unlockTrezorAccount, this), - // QR code scanner - scanQrCode: nodeify(this.scanQrCode, this), - // vault management submitPassword: nodeify(this.submitPassword, this), @@ -658,21 +655,6 @@ module.exports = class MetamaskController extends EventEmitter { return { ...keyState, identities } } - scanQrCode () { - return new Promise((resolve, reject) => { - // Tell contentscript to inject the QR reader - this.platform.sendMessageToActiveTab('qr-code-scanner-init') - // Wait for the scanner to send something back - this.platform.addMessageListener(({ action, data }) => { - if (action && action === 'qr-code-scanner-data') { - const normalizedAddress = data.replace('ethereum:', '') - resolve(normalizedAddress) - } - }) - }) - } - - // // Account Management // diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 1cab0bedd..452a51bd8 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -36,12 +36,6 @@ class ExtensionPlatform { extension.runtime.onMessage.addListener(cb) } - sendMessageToActiveTab (message, query = {}) { - extension.tabs.query(query, tabs => { - const activeTab = tabs.filter(tab => tab.active)[0] - extension.tabs.sendMessage(activeTab.id, message) - }) - } } module.exports = ExtensionPlatform diff --git a/ui/app/actions.js b/ui/app/actions.js index 9aba6853d..dd0e78b6a 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -31,6 +31,12 @@ var actions = { ALERT_CLOSE: 'UI_ALERT_CLOSE', showAlert: showAlert, hideAlert: hideAlert, + QR_SCANNER_OPEN: 'UI_QR_SCANNER_OPEN', + QR_SCANNER_CLOSE: 'UI_QR_SCANNER_CLOSE', + QR_CODE_DETECTED: 'UI_QR_CODE_DETECTED', + showQrScanner, + hideQrScanner, + qrCodeDetected, // network dropdown open NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN', NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE', @@ -1752,6 +1758,25 @@ function hideAlert () { } } +function showQrScanner () { + return { + type: actions.QR_SCANNER_OPEN, + } +} + +function qrCodeDetected (qrCodeData) { + return { + type: actions.QR_CODE_DETECTED, + value: qrCodeData, + } +} + +function hideQrScanner () { + return { + type: actions.QR_SCANNER_CLOSE, + } +} + function showLoadingIndication (message) { return { @@ -2197,21 +2222,7 @@ function clearPendingTokens () { } function scanQrCode () { - log.debug(`background.scanQrCode`) return (dispatch, getState) => { - dispatch(actions.showLoadingIndication()) - return new Promise((resolve, reject) => { - background.scanQrCode((err, data) => { - log.debug(`background.scanQrCode resolved!`, err, data) - if (err) { - log.error(err) - dispatch(actions.displayWarning(err.message)) - return reject(err) - } - - dispatch(actions.hideLoadingIndication()) - return resolve(data) - }) - }) + dispatch(actions.showQrScanner()) } } diff --git a/ui/app/app.js b/ui/app/app.js index dbb6146d1..9363d21d1 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -39,6 +39,8 @@ const Modal = require('./components/modals/index').Modal // Global Alert const Alert = require('./components/alert') +const QrScanner = require('./components/qr-scanner') + const AppHeader = require('./components/app-header') import UnlockPage from './components/pages/unlock-page' @@ -132,6 +134,8 @@ class App extends Component { // global alert h(Alert, {visible: this.props.alertOpen, msg: alertMessage}), + h(QrScanner, {visible: this.props.qrScannerOpen}), + h(AppHeader), // sidebar @@ -270,6 +274,7 @@ App.propTypes = { currentView: PropTypes.object, sidebarOpen: PropTypes.bool, alertOpen: PropTypes.bool, + qrScannerOpen: PropTypes.bool, hideSidebar: PropTypes.func, isMascara: PropTypes.bool, isOnboarding: PropTypes.bool, @@ -306,6 +311,7 @@ function mapStateToProps (state) { networkDropdownOpen, sidebarOpen, alertOpen, + qrScannerOpen, alertMessage, isLoading, loadingMessage, @@ -333,6 +339,7 @@ function mapStateToProps (state) { networkDropdownOpen, sidebarOpen, alertOpen, + qrScannerOpen, alertMessage, isLoading, loadingMessage, diff --git a/ui/app/components/qr-scanner/index.js b/ui/app/components/qr-scanner/index.js new file mode 100644 index 000000000..f459f6702 --- /dev/null +++ b/ui/app/components/qr-scanner/index.js @@ -0,0 +1,2 @@ +import QrScanner from './qr-scanner.component' +module.exports = QrScanner diff --git a/ui/app/components/qr-scanner/qr-scanner.component.js b/ui/app/components/qr-scanner/qr-scanner.component.js new file mode 100644 index 000000000..cc07e53a2 --- /dev/null +++ b/ui/app/components/qr-scanner/qr-scanner.component.js @@ -0,0 +1,152 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' +import { hideQrScanner, qrCodeDetected} from '../../actions' +import Instascan from 'instascan' + +class QrScanner extends Component { + static propTypes = { + visible: PropTypes.bool, + hideQrScanner: PropTypes.func, + qrCodeDetected: PropTypes.func, + } + constructor (props) { + super(props) + this.state = { + msg: 'Place the QR code in front of your camera so we can read it...', + } + this.scanning = false + } + + parseContent (content) { + let type = 'unknown' + let values = {} + + // Here we could add more cases + // To parse other codes (transactions for ex.) + + if (content.split('ethereum:').length > 1) { + type = 'address' + values = {'address': content.split('ethereum:')[1] } + } + return {type, values} + } + + componentDidUpdate () { + if (this.props.visible && this.camera && !this.scanning) { + const scanner = new Instascan.Scanner({ + video: this.camera, + backgroundScan: false, + continuous: true, + }) + scanner.addListener('scan', (content) => { + scanner.stop().then(_ => { + const result = this.parseContent(content) + if (result.type !== 'unknown') { + console.log('QR-SCANNER: CODE DETECTED', result) + this.props.qrCodeDetected(result) + this.props.hideQrScanner() + } else { + this.setState({msg: 'Error: We couldn\'t identify that QR code'}) + } + }) + }) + Instascan.Camera.getCameras().then((cameras) => { + if (cameras.length > 0) { + scanner.start(cameras[0]) + console.log('QR-SCANNER: started scanning with camera', cameras[0]) + } else { + console.log('QR-SCANNER: no cameras found') + } + }).catch(function (e) { + console.error(e) + }) + this.scanning = true + } + } + + render () { + const { visible } = this.props + + if (!visible) { + return null + } + + return ( +
+
+

+ Scan QR code +

+
+
+
+ {this.state.msg} +
+
+
this.props.hideQrScanner() } + /> +
+ ) + } +} + +function mapDispatchToProps (dispatch) { + return { + hideQrScanner: () => dispatch(hideQrScanner()), + qrCodeDetected: (data) => dispatch(qrCodeDetected(data)), + } +} +function mapStateToProps (state) { + return {} +} + +export default connect(mapStateToProps, mapDispatchToProps)(QrScanner) diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js index 6c439cd21..fb7eef329 100644 --- a/ui/app/components/send/send.component.js +++ b/ui/app/components/send/send.component.js @@ -39,16 +39,26 @@ export default class SendTransactionScreen extends PersistentForm { updateSendErrors: PropTypes.func, updateSendTokenBalance: PropTypes.func, scanQrCode: PropTypes.func, + qrCodeData: PropTypes.object, }; static contextTypes = { t: PropTypes.func, }; - scanQrCode = async () => { - const scannedAddress = await this.props.scanQrCode() - this.props.updateSendTo(scannedAddress) - this.updateGas({ to: scannedAddress }) + componentWillReceiveProps (nextProps) { + if (nextProps.qrCodeData) { + if (nextProps.qrCodeData.type === 'address') { + const scannedAddress = nextProps.qrCodeData.values.address.toLowerCase() + const currentAddress = this.props.to && this.props.to.toLowerCase() + if (currentAddress !== scannedAddress) { + this.props.updateSendTo(scannedAddress) + this.updateGas({ to: scannedAddress }) + + // Here we should clear props.qrCodeData + } + } + } } updateGas ({ to: updatedToAddress, amount: value } = {}) { @@ -179,7 +189,7 @@ export default class SendTransactionScreen extends PersistentForm { this.updateGas(updateData)} - scanQrCode={_ => this.scanQrCode()} + scanQrCode={_ => this.props.scanQrCode()} />
diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js index 417941601..67a441a9d 100644 --- a/ui/app/components/send/send.container.js +++ b/ui/app/components/send/send.container.js @@ -21,6 +21,7 @@ import { getSendFromObject, getSendTo, getTokenBalance, + getQrCodeData, } from './send.selectors' import { updateSendTo, @@ -62,6 +63,7 @@ function mapStateToProps (state) { tokenBalance: getTokenBalance(state), tokenContract: getSelectedTokenContract(state), tokenToFiatRate: getSelectedTokenToFiatRate(state), + qrCodeData: getQrCodeData(state), } } diff --git a/ui/app/components/send/send.selectors.js b/ui/app/components/send/send.selectors.js index cf07eafe1..4e81d1f9e 100644 --- a/ui/app/components/send/send.selectors.js +++ b/ui/app/components/send/send.selectors.js @@ -46,6 +46,7 @@ const selectors = { getTokenExchangeRate, getUnapprovedTxs, transactionsSelector, + getQrCodeData, } module.exports = selectors @@ -282,3 +283,7 @@ function transactionsSelector (state) { : txsToRender .sort((a, b) => b.time - a.time) } + +function getQrCodeData (state) { + return state.appState.qrCodeData +} \ No newline at end of file diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 50d8bcba7..9775638a7 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -50,7 +50,9 @@ function reduceApp (state, action) { }, sidebarOpen: false, alertOpen: false, + qrScannerOpen: false, alertMessage: null, + qrCodeData: null, networkDropdownOpen: false, currentView: seedWords ? seedConfView : defaultView, accountDetail: { @@ -90,7 +92,7 @@ function reduceApp (state, action) { sidebarOpen: false, }) - // sidebar methods + // alert methods case actions.ALERT_OPEN: return extend(appState, { alertOpen: true, @@ -102,6 +104,22 @@ function reduceApp (state, action) { alertOpen: false, alertMessage: null, }) + // qr scanner methods + case actions.QR_SCANNER_OPEN: + return extend(appState, { + qrScannerOpen: true, + }) + + case actions.QR_SCANNER_CLOSE: + return extend(appState, { + qrScannerOpen: false, + }) + + case actions.QR_CODE_DETECTED: + return extend(appState, { + qrCodeData: action.value, + }) + // modal methods: case actions.MODAL_OPEN: diff --git a/ui/app/selectors.js b/ui/app/selectors.js index d86462275..14d9dcd1d 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -194,3 +194,4 @@ function getTotalUnapprovedCount ({ metamask }) { return Object.keys(unapprovedTxs).length + unapprovedMsgCount + unapprovedPersonalMsgCount + unapprovedTypedMessagesCount } + From eeb902dbf0d77a487903c386c11fca5bd9114300 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 24 Jul 2018 21:13:17 -0400 Subject: [PATCH 084/183] decent UI --- .../qr-scanner/qr-scanner.component.js | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/ui/app/components/qr-scanner/qr-scanner.component.js b/ui/app/components/qr-scanner/qr-scanner.component.js index cc07e53a2..4cc296441 100644 --- a/ui/app/components/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/qr-scanner/qr-scanner.component.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types' import {connect} from 'react-redux' import { hideQrScanner, qrCodeDetected} from '../../actions' import Instascan from 'instascan' +import Spinner from '../spinner' class QrScanner extends Component { static propTypes = { @@ -13,50 +14,41 @@ class QrScanner extends Component { constructor (props) { super(props) this.state = { - msg: 'Place the QR code in front of your camera so we can read it...', + ready: false, + msg: 'Accesing your camera...', } this.scanning = false } - parseContent (content) { - let type = 'unknown' - let values = {} - - // Here we could add more cases - // To parse other codes (transactions for ex.) - - if (content.split('ethereum:').length > 1) { - type = 'address' - values = {'address': content.split('ethereum:')[1] } - } - return {type, values} - } - componentDidUpdate () { if (this.props.visible && this.camera && !this.scanning) { - const scanner = new Instascan.Scanner({ + this.scanner = new Instascan.Scanner({ video: this.camera, backgroundScan: false, continuous: true, }) - scanner.addListener('scan', (content) => { - scanner.stop().then(_ => { + this.scanner.addListener('scan', (content) => { + this.scanner.stop().then(_ => { const result = this.parseContent(content) if (result.type !== 'unknown') { console.log('QR-SCANNER: CODE DETECTED', result) this.props.qrCodeDetected(result) this.props.hideQrScanner() + this.setState({ ready: false }) } else { this.setState({msg: 'Error: We couldn\'t identify that QR code'}) } + this.scanning = false }) }) Instascan.Camera.getCameras().then((cameras) => { if (cameras.length > 0) { - scanner.start(cameras[0]) + this.scanner.start(cameras[0]) + this.setState({ ready: true }) + this.setState({ msg: 'Place the QR code in front of your camera so we can read it...'}) console.log('QR-SCANNER: started scanning with camera', cameras[0]) } else { - console.log('QR-SCANNER: no cameras found') + this.setState({ msg: 'No camera found :('}) } }).catch(function (e) { console.error(e) @@ -65,6 +57,29 @@ class QrScanner extends Component { } } + parseContent (content) { + let type = 'unknown' + let values = {} + + // Here we could add more cases + // To parse other codes (transactions for ex.) + + if (content.split('ethereum:').length > 1) { + type = 'address' + values = {'address': content.split('ethereum:')[1] } + } + return {type, values} + } + + + stopAndClose = () => { + this.scanner.stop().then(_ => { + this.scanning = false + this.props.hideQrScanner() + this.setState({ ready: false }) + }) + } + render () { const { visible } = this.props @@ -92,6 +107,8 @@ class QrScanner extends Component {

Scan QR code

@@ -101,17 +118,22 @@ class QrScanner extends Component { overflow: 'hidden', width: '100%', height: '275px', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', }}>
{this.state.msg} @@ -132,7 +154,7 @@ class QrScanner extends Component { animationName: 'anim_171532470906313', animationTimingFunction: 'ease-out', }} - onClick={_ => this.props.hideQrScanner() } + onClick={this.stopAndClose} />
) From 4759915856440028186df56d4646565dc5c4a5d6 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Tue, 24 Jul 2018 22:34:15 -0400 Subject: [PATCH 085/183] fix spinner and qr icon --- ui/app/components/qr-scanner/qr-scanner.component.js | 7 +++++-- ui/app/css/itcss/components/send.scss | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/app/components/qr-scanner/qr-scanner.component.js b/ui/app/components/qr-scanner/qr-scanner.component.js index 4cc296441..fd3361cf2 100644 --- a/ui/app/components/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/qr-scanner/qr-scanner.component.js @@ -44,8 +44,11 @@ class QrScanner extends Component { Instascan.Camera.getCameras().then((cameras) => { if (cameras.length > 0) { this.scanner.start(cameras[0]) - this.setState({ ready: true }) - this.setState({ msg: 'Place the QR code in front of your camera so we can read it...'}) + setTimeout(_ => { + this.setState({ + ready: true, + msg: 'Place the QR code in front of your camera so we can read it...'}) + }, 2000) console.log('QR-SCANNER: started scanning with camera', cameras[0]) } else { this.setState({ msg: 'No camera found :('}) diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index e9f22a14e..ad6199f02 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -631,6 +631,7 @@ position: absolute; top: 21px; left: 13px; + cursor: pointer; } &__input.with-qr { From 6cd4bc9f4ecb2c4a066da0aceb36d1a24bbe33e2 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Thu, 26 Jul 2018 20:24:39 -0400 Subject: [PATCH 086/183] working without permission issues --- app/manifest.json | 3 +- package-lock.json | 17 +++- package.json | 8 +- .../qr-scanner/qr-scanner.component.js | 80 ++++++++++--------- 4 files changed, 64 insertions(+), 44 deletions(-) diff --git a/app/manifest.json b/app/manifest.json index 6933652e6..52256c5b7 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -76,6 +76,5 @@ "ids": [ "*" ] - }, - "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'" + } } diff --git a/package-lock.json b/package-lock.json index 3e1b69db9..0fd733fa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1623,6 +1623,15 @@ "@types/react": "*" } }, + "@zxing/library": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.7.0.tgz", + "integrity": "sha512-VJ1cJaCWVF8MspnuyaZKGKlrSQLqQ5usgSap8uuCAvWGQ6W6OwN1NeGvnjhT+9hmnwkHK8XjaflvzaDBC7nKnw==", + "requires": { + "text-encoding": "^0.6.4", + "ts-custom-error": "^2.2.1" + } + }, "JSONStream": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", @@ -30207,8 +30216,7 @@ "text-encoding": { "version": "0.6.4", "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", - "dev": true + "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" }, "text-table": { "version": "0.2.0", @@ -30668,6 +30676,11 @@ "resolved": "https://registry.npmjs.org/try-require/-/try-require-1.2.1.tgz", "integrity": "sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I=" }, + "ts-custom-error": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-2.2.1.tgz", + "integrity": "sha512-lHKZtU+PXkVuap6nlFZybIAFLUO8B3jbCs1VynBL8AUSAHfeG6HpztcBTDRp5I+fN5820N9kGg+eTIvr+le2yg==" + }, "tslib": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", diff --git a/package.json b/package.json index 168ab0171..1ab582428 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ }, "dependencies": { "@material-ui/core": "^1.0.0", + "@zxing/library": "^0.7.0", "abi-decoder": "^1.0.9", "asmcrypto.js": "0.22.0", "async": "^2.5.0", @@ -94,6 +95,7 @@ "eslint-plugin-react": "^7.4.0", "eth-bin-to-ops": "^1.0.1", "eth-contract-metadata": "github:MetaMask/eth-contract-metadata#master", + "eth-ens-namehash": "^2.0.8", "eth-hd-keyring": "^2.0.0", "eth-json-rpc-filters": "^1.2.6", "eth-json-rpc-infura": "^3.0.0", @@ -142,6 +144,7 @@ "metamascara": "^2.0.0", "metamask-logo": "^2.1.4", "mkdirp": "^0.5.1", + "multihashes": "^0.4.12", "multiplex": "^6.7.0", "number-to-bn": "^1.7.0", "obj-multiplex": "^1.0.0", @@ -195,9 +198,7 @@ "web3": "^0.20.1", "web3-provider-engine": "^14.0.5", "web3-stream-provider": "^3.0.1", - "xtend": "^4.0.1", - "multihashes": "^0.4.12", - "eth-ens-namehash": "^2.0.8" + "xtend": "^4.0.1" }, "devDependencies": { "@sentry/cli": "^1.30.3", @@ -257,7 +258,6 @@ "gulp-watch": "^5.0.0", "gulp-zip": "^4.0.0", "http-server": "^0.11.1", - "instascan": "github:brunobar79/instascan#141f7b2aa12c9e833de41ba3daf37a1c1b7c070e", "image-size": "^0.6.2", "isomorphic-fetch": "^2.2.1", "jsdoc": "^3.5.5", diff --git a/ui/app/components/qr-scanner/qr-scanner.component.js b/ui/app/components/qr-scanner/qr-scanner.component.js index fd3361cf2..e0b2c40d6 100644 --- a/ui/app/components/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/qr-scanner/qr-scanner.component.js @@ -2,8 +2,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import {connect} from 'react-redux' import { hideQrScanner, qrCodeDetected} from '../../actions' -import Instascan from 'instascan' import Spinner from '../spinner' +import { BrowserQRCodeReader } from '@zxing/library' class QrScanner extends Component { static propTypes = { @@ -18,18 +18,36 @@ class QrScanner extends Component { msg: 'Accesing your camera...', } this.scanning = false + this.codeReader = null } componentDidUpdate () { if (this.props.visible && this.camera && !this.scanning) { - this.scanner = new Instascan.Scanner({ - video: this.camera, - backgroundScan: false, - continuous: true, - }) - this.scanner.addListener('scan', (content) => { - this.scanner.stop().then(_ => { - const result = this.parseContent(content) + this.scanning = true + this.initCamera() + } + } + + initCamera () { + console.log('QR-SCANNER: initCamera ') + this.codeReader = new BrowserQRCodeReader() + this.codeReader.getVideoInputDevices() + .then(videoInputDevices => { + console.log('QR-SCANNER: getVideoInputDevices ', videoInputDevices) + setTimeout(_ => { + this.setState({ + ready: true, + msg: 'Place the QR code in front of your camera so we can read it...'}) + console.log('QR-SCANNER: this.state.ready = true') + }, 2000) + + console.log('QR-SCANNER: started scanning...') + this.codeReader.decodeFromInputVideoDevice(videoInputDevices[0].deviceId, 'video') + .then(content => { + console.log('QR-SCANNER: content found!', content) + this.codeReader.reset() + console.log('QR-SCANNER: stopped scanning...') + const result = this.parseContent(content.text) if (result.type !== 'unknown') { console.log('QR-SCANNER: CODE DETECTED', result) this.props.qrCodeDetected(result) @@ -37,27 +55,15 @@ class QrScanner extends Component { this.setState({ ready: false }) } else { this.setState({msg: 'Error: We couldn\'t identify that QR code'}) + console.log('QR-SCANNER: Unknown code') } - this.scanning = false }) + .catch(err => { + console.log('QR-SCANNER: decodeFromInputVideoDevice threw an exception: ', err) + }) + }).catch(err => { + console.log('QR-SCANNER: getVideoInputDevices threw an exception: ', err) }) - Instascan.Camera.getCameras().then((cameras) => { - if (cameras.length > 0) { - this.scanner.start(cameras[0]) - setTimeout(_ => { - this.setState({ - ready: true, - msg: 'Place the QR code in front of your camera so we can read it...'}) - }, 2000) - console.log('QR-SCANNER: started scanning with camera', cameras[0]) - } else { - this.setState({ msg: 'No camera found :('}) - } - }).catch(function (e) { - console.error(e) - }) - this.scanning = true - } } parseContent (content) { @@ -76,11 +82,11 @@ class QrScanner extends Component { stopAndClose = () => { - this.scanner.stop().then(_ => { - this.scanning = false - this.props.hideQrScanner() - this.setState({ ready: false }) - }) + console.log('QR-SCANNER: stopping scanner...') + this.codeReader.reset() + this.scanning = false + this.props.hideQrScanner() + this.setState({ ready: false }) } render () { @@ -126,11 +132,13 @@ class QrScanner extends Component { justifyContent: 'center', }}>