aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/controllers/balance.js6
-rw-r--r--app/scripts/controllers/network/createInfuraClient.js37
-rw-r--r--app/scripts/controllers/network/createJsonRpcClient.js37
-rw-r--r--app/scripts/controllers/network/createLocalhostClient.js33
-rw-r--r--app/scripts/controllers/network/createMetamaskMiddleware.js43
-rw-r--r--app/scripts/controllers/network/network.js121
-rw-r--r--app/scripts/controllers/recent-blocks.js44
-rw-r--r--app/scripts/controllers/transactions/index.js1
-rw-r--r--app/scripts/controllers/transactions/nonce-tracker.js18
-rw-r--r--app/scripts/lib/events-proxy.js42
-rw-r--r--app/scripts/metamask-controller.js7
-rw-r--r--docs/developing-on-deps.md3
-rw-r--r--docs/porting_to_new_environment.md2
-rw-r--r--package.json9
-rw-r--r--test/unit/app/controllers/network-contoller-test.js9
-rw-r--r--test/unit/app/controllers/transactions/nonce-tracker-test.js8
16 files changed, 257 insertions, 163 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<array>} Promises an array of transaction objects.
diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js
new file mode 100644
index 000000000..adbf4c001
--- /dev/null
+++ b/app/scripts/controllers/network/createInfuraClient.js
@@ -0,0 +1,37 @@
+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-cache')
+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 }) {
+ 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..d712ed135
--- /dev/null
+++ b/app/scripts/controllers/network/createJsonRpcClient.js
@@ -0,0 +1,37 @@
+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')
+const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache')
+const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware')
+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..990dc6a95
--- /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 providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware')
+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..8b17829b7
--- /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/createScaffoldMiddleware')
+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..9e622981b 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 JsonRpcEngine = require('json-rpc-engine')
+const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine')
const log = require('loglevel')
+const createMetamaskMiddleware = require('./createMetamaskMiddleware')
+const createInfuraClient = require('./createInfuraClient')
+const createJsonRpcClient = require('./createJsonRpcClient')
+const createLocalhostClient = require('./createLocalhostClient')
+const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
+
const {
ROPSTEN,
RINKEBY,
@@ -16,7 +19,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
@@ -38,21 +40,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 +82,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,9 +132,9 @@ 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'){
+ } else if (type === 'rpc') {
this._configureStandardProvider({ rpcUrl: rpcTarget })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
@@ -133,47 +142,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/recent-blocks.js b/app/scripts/controllers/recent-blocks.js
index 1377c1ba9..9a215d0e5 100644
--- a/app/scripts/controllers/recent-blocks.js
+++ b/app/scripts/controllers/recent-blocks.js
@@ -1,8 +1,9 @@
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')
+const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration))
class RecentBlocksController {
@@ -34,7 +35,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 +56,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,21 +122,20 @@ class RecentBlocksController {
* @returns {Promise<void>} Promises undefined
*/
async backfill() {
- this.blockTracker.once('block', async (block) => {
- let blockNum = block.number
+ this.blockTracker.once('latest', async (blockNumberHex) => {
let recentBlocks
+ let 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)
- blockNum = newBlock.number
+ blockNumber = Number.parseInt(newBlock.number, 16)
}
state = this.store.getState()
@@ -140,24 +143,12 @@ 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<void>} Promises undefined
- *
- */
- async wait () {
- return new Promise((resolve) => {
- setTimeout(resolve, 100)
- })
- }
-
- /**
* Uses EthQuery to get a block that has a given block number.
*
* @param {number} number The number of the block to get
@@ -165,13 +156,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)
}
}
diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js
index 541f1db73..128f5b86f 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/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<Function>} */ (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
-}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 1b1d26886..14eb749e7 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({
@@ -1038,7 +1039,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/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 3b1e46052..983c81f3e 100644
--- a/docs/porting_to_new_environment.md
+++ b/docs/porting_to_new_environment.md
@@ -89,8 +89,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!
diff --git a/package.json b/package.json
index b5d8b545f..5df405b27 100644
--- a/package.json
+++ b/package.json
@@ -92,10 +92,12 @@
"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",
+ "eth-json-rpc-filters": "^1.2.8",
"eth-json-rpc-infura": "^3.0.0",
+ "eth-json-rpc-middleware": "^2.1.0",
"eth-keyring-controller": "^3.1.1",
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",
@@ -130,7 +132,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.1",
"json-rpc-middleware-stream": "^1.0.1",
"lodash.debounce": "^4.0.8",
"lodash.memoize": "^4.1.2",
@@ -185,11 +187,11 @@
"shallow-copy": "0.0.1",
"sw-controller": "^1.0.3",
"sw-stream": "^2.0.2",
+ "swappable-obj-proxy": "^1.0.2",
"textarea-caret": "^3.0.1",
"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"
},
@@ -226,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",
diff --git a/test/unit/app/controllers/network-contoller-test.js b/test/unit/app/controllers/network-contoller-test.js
index 789850ef3..701eb5718 100644
--- a/test/unit/app/controllers/network-contoller-test.js
+++ b/test/unit/app/controllers/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 () {
diff --git a/test/unit/app/controllers/transactions/nonce-tracker-test.js b/test/unit/app/controllers/transactions/nonce-tracker-test.js
index fc852458c..78d637706 100644
--- a/test/unit/app/controllers/transactions/nonce-tracker-test.js
+++ b/test/unit/app/controllers/transactions/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,
})
}
-