aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Serrano <kevin.serrano@consensys.net>2017-05-25 00:55:32 +0800
committerKevin Serrano <kevin.serrano@consensys.net>2017-05-25 00:55:32 +0800
commit45285a5a2f0776787bd1e7ecd9b49c5d5456cd06 (patch)
treeb7cc0da01f95478a943fe074870277fcc76d5b88
parent60281f72506c6b1775e75e8426a09d91893ab6ac (diff)
parentd06a812004a5acc0a26fcdd5c29254b17fca25a0 (diff)
downloadtangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar.gz
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar.bz2
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar.lz
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar.xz
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.tar.zst
tangerine-wallet-browser-45285a5a2f0776787bd1e7ecd9b49c5d5456cd06.zip
Merge branch 'master' into i1412-decimalizethegas
-rw-r--r--CHANGELOG.md5
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/controllers/network.js129
-rw-r--r--app/scripts/controllers/transactions.js66
-rw-r--r--app/scripts/first-time-state.js3
-rw-r--r--app/scripts/lib/config-manager.js62
-rw-r--r--app/scripts/lib/tx-utils.js8
-rw-r--r--app/scripts/metamask-controller.js98
-rw-r--r--app/scripts/migrations/014.js34
-rw-r--r--app/scripts/migrations/index.js1
-rw-r--r--development/announcer.js2
-rw-r--r--test/unit/network-contoller-test.js77
-rw-r--r--test/unit/tx-controller-test.js4
-rw-r--r--test/unit/tx-utils-test.js6
14 files changed, 373 insertions, 124 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d11d7ef6..215aee936 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,9 +2,14 @@
## Current Master
+- Now when switching networks the extension does not restart
+
+## 3.7.0 2017-5-23
+
- Add Transaction Number (nonce) to transaction list.
- Label the pending tx icon with a tooltip.
- Fix bug where website filters would pile up and not deallocate when leaving a site.
+- Continually resubmit pending txs for a period of time to ensure successful broadcast.
- ENS names will no longer resolve to their owner if no resolver is set. Resolvers must be explicitly set and configured.
## 3.6.5 2017-5-17
diff --git a/app/manifest.json b/app/manifest.json
index 31e4598c7..c3e2b7511 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "3.6.5",
+ "version": "3.7.1",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",
diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js
new file mode 100644
index 000000000..c07f13b8d
--- /dev/null
+++ b/app/scripts/controllers/network.js
@@ -0,0 +1,129 @@
+const EventEmitter = require('events')
+const MetaMaskProvider = require('web3-provider-engine/zero.js')
+const ObservableStore = require('obs-store')
+const ComposedStore = require('obs-store/lib/composed')
+const extend = require('xtend')
+const EthQuery = require('eth-query')
+const RPC_ADDRESS_LIST = require('../config.js').network
+const DEFAULT_RPC = RPC_ADDRESS_LIST['rinkeby']
+
+module.exports = class NetworkController extends EventEmitter {
+ constructor (config) {
+ super()
+ this.networkStore = new ObservableStore('loading')
+ config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
+ this.providerStore = new ObservableStore(config.provider)
+ this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
+ this._providerListeners = {}
+
+ this.on('networkDidChange', this.lookupNetwork)
+ this.providerStore.subscribe((state) => this.switchNetwork({rpcUrl: state.rpcTarget}))
+ }
+
+ get provider () {
+ return this._proxy
+ }
+
+ set provider (provider) {
+ this._provider = provider
+ }
+
+ initializeProvider (opts) {
+ this.providerInit = opts
+ this._provider = MetaMaskProvider(opts)
+ this._proxy = new Proxy(this._provider, {
+ get: (obj, name) => {
+ if (name === 'on') return this._on.bind(this)
+ return this._provider[name]
+ },
+ set: (obj, name, value) => {
+ this._provider[name] = value
+ },
+ })
+ this.provider.on('block', this._logBlock.bind(this))
+ this.provider.on('error', this.verifyNetwork.bind(this))
+ this.ethQuery = new EthQuery(this.provider)
+ this.lookupNetwork()
+ return this.provider
+ }
+
+ switchNetwork (providerInit) {
+ this.setNetworkState('loading')
+ const newInit = extend(this.providerInit, providerInit)
+ this.providerInit = newInit
+
+ this._provider.removeAllListeners()
+ this._provider.stop()
+ this.provider = MetaMaskProvider(newInit)
+ // apply the listners created by other controllers
+ Object.keys(this._providerListeners).forEach((key) => {
+ this._providerListeners[key].forEach((handler) => this._provider.addListener(key, handler))
+ })
+ this.emit('networkDidChange')
+ }
+
+
+ verifyNetwork () {
+ // Check network when restoring connectivity:
+ if (this.isNetworkLoading()) this.lookupNetwork()
+ }
+
+ getNetworkState () {
+ return this.networkStore.getState()
+ }
+
+ setNetworkState (network) {
+ return this.networkStore.putState(network)
+ }
+
+ isNetworkLoading () {
+ return this.getNetworkState() === 'loading'
+ }
+
+ lookupNetwork () {
+ this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
+ if (err) return this.setNetworkState('loading')
+ log.info('web3.getNetwork returned ' + network)
+ this.setNetworkState(network)
+ })
+ }
+
+ setRpcTarget (rpcUrl) {
+ this.providerStore.updateState({
+ type: 'rpc',
+ rpcTarget: rpcUrl,
+ })
+ }
+
+ getCurrentRpcAddress () {
+ const provider = this.getProviderConfig()
+ if (!provider) return null
+ return this.getRpcAddressForType(provider.type)
+ }
+
+ setProviderType (type) {
+ if (type === this.getProviderConfig().type) return
+ const rpcTarget = this.getRpcAddressForType(type)
+ this.providerStore.updateState({type, rpcTarget})
+ }
+
+ getProviderConfig () {
+ return this.providerStore.getState()
+ }
+
+ getRpcAddressForType (type, provider = this.getProviderConfig()) {
+ if (RPC_ADDRESS_LIST[type]) return RPC_ADDRESS_LIST[type]
+ return provider && provider.rpcTarget ? provider.rpcTarget : DEFAULT_RPC
+ }
+
+ _logBlock (block) {
+ log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
+ this.verifyNetwork()
+ }
+
+ _on (event, handler) {
+ if (!this._providerListeners[event]) this._providerListeners[event] = []
+ this._providerListeners[event].push(handler)
+ this._provider.on(event, handler)
+ }
+}
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 21dd25b30..faccf1ab1 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -4,11 +4,14 @@ const extend = require('xtend')
const Semaphore = require('semaphore')
const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util')
-const EthQuery = require('eth-query')
const TxProviderUtil = require('../lib/tx-utils')
const createId = require('../lib/random-id')
+const denodeify = require('denodeify')
-module.exports = class TransactionManager extends EventEmitter {
+const RETRY_LIMIT = 200
+const RESUBMIT_INTERVAL = 10000 // Ten seconds
+
+module.exports = class TransactionController extends EventEmitter {
constructor (opts) {
super()
this.store = new ObservableStore(extend({
@@ -20,8 +23,8 @@ module.exports = class TransactionManager extends EventEmitter {
this.txHistoryLimit = opts.txHistoryLimit
this.provider = opts.provider
this.blockTracker = opts.blockTracker
- this.query = new EthQuery(this.provider)
- this.txProviderUtils = new TxProviderUtil(this.provider)
+ this.query = opts.ethQuery
+ this.txProviderUtils = new TxProviderUtil(this.query)
this.blockTracker.on('block', this.checkForTxInBlock.bind(this))
this.signEthTx = opts.signTransaction
this.nonceLock = Semaphore(1)
@@ -31,6 +34,8 @@ module.exports = class TransactionManager extends EventEmitter {
this.store.subscribe(() => this._updateMemstore())
this.networkStore.subscribe(() => this._updateMemstore())
this.preferencesStore.subscribe(() => this._updateMemstore())
+
+ this.continuallyResubmitPendingTxs()
}
getState () {
@@ -38,7 +43,7 @@ module.exports = class TransactionManager extends EventEmitter {
}
getNetwork () {
- return this.networkStore.getState().network
+ return this.networkStore.getState()
}
getSelectedAddress () {
@@ -230,7 +235,11 @@ module.exports = class TransactionManager extends EventEmitter {
})
}
- publishTransaction (txId, rawTx, cb) {
+ publishTransaction (txId, rawTx, cb = warn) {
+ const txMeta = this.getTx(txId)
+ txMeta.rawTx = rawTx
+ this.updateTx(txMeta)
+
this.txProviderUtils.publishTransaction(rawTx, (err, txHash) => {
if (err) return cb(err)
this.setTxHash(txId, txHash)
@@ -353,7 +362,7 @@ module.exports = class TransactionManager extends EventEmitter {
message: 'There was a problem loading this transaction.',
}
this.updateTx(txMeta)
- return console.error(err)
+ return log.error(err)
}
if (txParams.blockNumber) {
this.setTxStatusConfirmed(txId)
@@ -379,6 +388,7 @@ module.exports = class TransactionManager extends EventEmitter {
this.emit(`${txMeta.id}:${status}`, txId)
if (status === 'submitted' || status === 'rejected') {
this.emit(`${txMeta.id}:finished`, txMeta)
+
}
this.updateTx(txMeta)
this.emit('updateBadge')
@@ -398,7 +408,47 @@ module.exports = class TransactionManager extends EventEmitter {
})
this.memStore.updateState({ unapprovedTxs, selectedAddressTxList })
}
+
+ continuallyResubmitPendingTxs () {
+ const pending = this.getTxsByMetaData('status', 'submitted')
+ const resubmit = denodeify(this.resubmitTx.bind(this))
+ Promise.all(pending.map(txMeta => resubmit(txMeta)))
+ .catch((reason) => {
+ log.info('Problem resubmitting tx', reason)
+ })
+ .then(() => {
+ global.setTimeout(() => {
+ this.continuallyResubmitPendingTxs()
+ }, RESUBMIT_INTERVAL)
+ })
+ }
+
+ resubmitTx (txMeta, cb) {
+ // Increment a try counter.
+ if (!('retryCount' in txMeta)) {
+ txMeta.retryCount = 0
+ }
+
+ // Only auto-submit already-signed txs:
+ if (!('rawTx' in txMeta)) {
+ return cb()
+ }
+
+ if (txMeta.retryCount > RETRY_LIMIT) {
+ txMeta.err = {
+ isWarning: true,
+ message: 'Gave up submitting tx.',
+ }
+ this.updateTx(txMeta)
+ return log.error(txMeta.err.message)
+ }
+
+ txMeta.retryCount++
+ const rawTx = txMeta.rawTx
+ this.txProviderUtils.publishTransaction(rawTx, cb)
+ }
+
}
-const warn = () => console.warn('warn was used no cb provided')
+const warn = () => log.warn('warn was used no cb provided')
diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js
index 29ec1d8d3..dc7788311 100644
--- a/app/scripts/first-time-state.js
+++ b/app/scripts/first-time-state.js
@@ -3,7 +3,8 @@
//
module.exports = {
- config: {
+ config: {},
+ NetworkController: {
provider: {
type: 'rinkeby',
},
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index d77cd2126..9c0dffe9c 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -1,6 +1,7 @@
-const MetamaskConfig = require('../config.js')
const ethUtil = require('ethereumjs-util')
const normalize = require('eth-sig-util').normalize
+const MetamaskConfig = require('../config.js')
+
const MAINNET_RPC = MetamaskConfig.network.mainnet
const ROPSTEN_RPC = MetamaskConfig.network.ropsten
@@ -33,36 +34,6 @@ ConfigManager.prototype.getConfig = function () {
return data.config
}
-ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
- var config = this.getConfig()
- config.provider = {
- type: 'rpc',
- rpcTarget: rpcUrl,
- }
- this.setConfig(config)
-}
-
-ConfigManager.prototype.setProviderType = function (type) {
- var config = this.getConfig()
- config.provider = {
- type: type,
- }
- this.setConfig(config)
-}
-
-ConfigManager.prototype.useEtherscanProvider = function () {
- var config = this.getConfig()
- config.provider = {
- type: 'etherscan',
- }
- this.setConfig(config)
-}
-
-ConfigManager.prototype.getProvider = function () {
- var config = this.getConfig()
- return config.provider
-}
-
ConfigManager.prototype.setData = function (data) {
this.store.putState(data)
}
@@ -136,6 +107,35 @@ ConfigManager.prototype.getSeedWords = function () {
var data = this.getData()
return data.seedWords
}
+ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
+ var config = this.getConfig()
+ config.provider = {
+ type: 'rpc',
+ rpcTarget: rpcUrl,
+ }
+ this.setConfig(config)
+}
+
+ConfigManager.prototype.setProviderType = function (type) {
+ var config = this.getConfig()
+ config.provider = {
+ type: type,
+ }
+ this.setConfig(config)
+}
+
+ConfigManager.prototype.useEtherscanProvider = function () {
+ var config = this.getConfig()
+ config.provider = {
+ type: 'etherscan',
+ }
+ this.setConfig(config)
+}
+
+ConfigManager.prototype.getProvider = function () {
+ var config = this.getConfig()
+ return config.provider
+}
ConfigManager.prototype.getCurrentRpcAddress = function () {
var provider = this.getProvider()
diff --git a/app/scripts/lib/tx-utils.js b/app/scripts/lib/tx-utils.js
index 084ca3721..76b311653 100644
--- a/app/scripts/lib/tx-utils.js
+++ b/app/scripts/lib/tx-utils.js
@@ -1,5 +1,4 @@
const async = require('async')
-const EthQuery = require('eth-query')
const ethUtil = require('ethereumjs-util')
const Transaction = require('ethereumjs-tx')
const normalize = require('eth-sig-util').normalize
@@ -7,15 +6,14 @@ const BN = ethUtil.BN
/*
tx-utils are utility methods for Transaction manager
-its passed a provider and that is passed to ethquery
+its passed ethquery
and used to do things like calculate gas of a tx.
*/
module.exports = class txProviderUtils {
- constructor (provider) {
- this.provider = provider
- this.query = new EthQuery(provider)
+ constructor (ethQuery) {
+ this.query = ethQuery
}
analyzeGasUsage (txMeta, cb) {
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index f18da9033..a7eb3d056 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -7,9 +7,9 @@ const ObservableStore = require('obs-store')
const EthStore = require('./lib/eth-store')
const EthQuery = require('eth-query')
const streamIntoProvider = require('web3-stream-provider/handler')
-const MetaMaskProvider = require('web3-provider-engine/zero.js')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
const KeyringController = require('./keyring-controller')
+const NetworkController = require('./controllers/network')
const PreferencesController = require('./controllers/preferences')
const CurrencyController = require('./controllers/currency')
const NoticeController = require('./notice-controller')
@@ -40,8 +40,8 @@ module.exports = class MetamaskController extends EventEmitter {
this.store = new ObservableStore(initState)
// network store
- this.networkStore = new ObservableStore({ network: 'loading' })
+ this.networkController = new NetworkController(initState.NetworkController)
// config manager
this.configManager = new ConfigManager({
store: this.store,
@@ -61,8 +61,6 @@ module.exports = class MetamaskController extends EventEmitter {
// rpc provider
this.provider = this.initializeProvider()
- this.provider.on('block', this.logBlock.bind(this))
- this.provider.on('error', this.verifyNetwork.bind(this))
// eth data query tools
this.ethQuery = new EthQuery(this.provider)
@@ -75,7 +73,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.keyringController = new KeyringController({
initState: initState.KeyringController,
ethStore: this.ethStore,
- getNetwork: this.getNetworkState.bind(this),
+ getNetwork: this.networkController.getNetworkState.bind(this.networkController),
})
this.keyringController.on('newAccount', (address) => {
this.preferencesController.setSelectedAddress(address)
@@ -92,13 +90,14 @@ module.exports = class MetamaskController extends EventEmitter {
// tx mgmt
this.txController = new TransactionController({
initState: initState.TransactionController || initState.TransactionManager,
- networkStore: this.networkStore,
+ networkStore: this.networkController.networkStore,
preferencesStore: this.preferencesController.store,
txHistoryLimit: 40,
- getNetwork: this.getNetworkState.bind(this),
+ getNetwork: this.networkController.getNetworkState.bind(this),
signTransaction: this.keyringController.signTransaction.bind(this.keyringController),
provider: this.provider,
blockTracker: this.provider,
+ ethQuery: this.ethQuery,
})
// notices
@@ -113,7 +112,7 @@ module.exports = class MetamaskController extends EventEmitter {
initState: initState.ShapeShiftController,
})
- this.lookupNetwork()
+ this.networkController.lookupNetwork()
this.messageManager = new MessageManager()
this.personalMessageManager = new PersonalMessageManager()
this.publicConfigStore = this.initPublicConfigStore()
@@ -140,9 +139,12 @@ module.exports = class MetamaskController extends EventEmitter {
this.shapeshiftController.store.subscribe((state) => {
this.store.updateState({ ShapeShiftController: state })
})
+ this.networkController.store.subscribe((state) => {
+ this.store.updateState({ NetworkController: state })
+ })
// manual mem state subscriptions
- this.networkStore.subscribe(this.sendUpdate.bind(this))
+ this.networkController.store.subscribe(this.sendUpdate.bind(this))
this.ethStore.subscribe(this.sendUpdate.bind(this))
this.txController.memStore.subscribe(this.sendUpdate.bind(this))
this.messageManager.memStore.subscribe(this.sendUpdate.bind(this))
@@ -160,12 +162,12 @@ module.exports = class MetamaskController extends EventEmitter {
//
initializeProvider () {
- const provider = MetaMaskProvider({
+ return this.networkController.initializeProvider({
static: {
eth_syncing: false,
web3_clientVersion: `MetaMask/v${version}`,
},
- rpcUrl: this.configManager.getCurrentRpcAddress(),
+ rpcUrl: this.networkController.getCurrentRpcAddress(),
// account mgmt
getAccounts: (cb) => {
const isUnlocked = this.keyringController.memStore.getState().isUnlocked
@@ -185,7 +187,6 @@ module.exports = class MetamaskController extends EventEmitter {
// new style msg signing
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
})
- return provider
}
initPublicConfigStore () {
@@ -221,7 +222,7 @@ module.exports = class MetamaskController extends EventEmitter {
{
isInitialized,
},
- this.networkStore.getState(),
+ this.networkController.store.getState(),
this.ethStore.getState(),
this.txController.memStore.getState(),
this.messageManager.memStore.getState(),
@@ -255,8 +256,7 @@ module.exports = class MetamaskController extends EventEmitter {
return {
// etc
getState: (cb) => cb(null, this.getState()),
- setProviderType: this.setProviderType.bind(this),
- useEtherscanProvider: this.useEtherscanProvider.bind(this),
+ setProviderType: this.networkController.setProviderType.bind(this.networkController),
setCurrentCurrency: this.setCurrentCurrency.bind(this),
markAccountsFound: this.markAccountsFound.bind(this),
// coinbase
@@ -590,10 +590,6 @@ module.exports = class MetamaskController extends EventEmitter {
//
// Log blocks
- logBlock (block) {
- log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
- this.verifyNetwork()
- }
setCurrentCurrency (currencyCode, cb) {
try {
@@ -612,7 +608,7 @@ module.exports = class MetamaskController extends EventEmitter {
buyEth (address, amount) {
if (!amount) amount = '5'
- const network = this.getNetworkState()
+ const network = this.networkController.getNetworkState()
const url = getBuyEthUrl({ network, address, amount })
if (url) this.platform.openWindow({ url })
}
@@ -620,69 +616,21 @@ module.exports = class MetamaskController extends EventEmitter {
createShapeShiftTx (depositAddress, depositType) {
this.shapeshiftController.createShapeShiftTx(depositAddress, depositType)
}
-
- //
- // network
- //
-
- verifyNetwork () {
- // Check network when restoring connectivity:
- if (this.isNetworkLoading()) this.lookupNetwork()
- }
+// network
setDefaultRpc () {
- this.configManager.setRpcTarget('http://localhost:8545')
- this.platform.reload()
- this.lookupNetwork()
+ this.networkController.setRpcTarget('http://localhost:8545')
return Promise.resolve('http://localhost:8545')
}
setCustomRpc (rpcTarget, rpcList) {
- this.configManager.setRpcTarget(rpcTarget)
- return this.preferencesController.updateFrequentRpcList(rpcTarget)
- .then(() => {
- this.platform.reload()
- this.lookupNetwork()
- return Promise.resolve(rpcTarget)
- })
- }
+ this.networkController.setRpcTarget(rpcTarget)
- setProviderType (type) {
- this.configManager.setProviderType(type)
- this.platform.reload()
- this.lookupNetwork()
- }
-
- useEtherscanProvider () {
- this.configManager.useEtherscanProvider()
- this.platform.reload()
- }
-
- getNetworkState () {
- return this.networkStore.getState().network
- }
-
- setNetworkState (network) {
- return this.networkStore.updateState({ network })
- }
-
- isNetworkLoading () {
- return this.getNetworkState() === 'loading'
- }
-
- lookupNetwork (err) {
- if (err) {
- this.setNetworkState('loading')
- }
-
- this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
- if (err) {
- this.setNetworkState('loading')
- return
- }
- log.info('web3.getNetwork returned ' + network)
- this.setNetworkState(network)
+ return this.preferencesController.updateFrequentRpcList(rpcTarget)
+ .then(() => {
+ return Promise.resolve(rpcTarget)
})
}
+
}
diff --git a/app/scripts/migrations/014.js b/app/scripts/migrations/014.js
new file mode 100644
index 000000000..0fe92125b
--- /dev/null
+++ b/app/scripts/migrations/014.js
@@ -0,0 +1,34 @@
+const version = 14
+
+/*
+
+This migration removes provider from config and moves it too NetworkController.
+
+*/
+
+const clone = require('clone')
+
+module.exports = {
+ version,
+
+ migrate: function (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ try {
+ const state = versionedData.data
+ const newState = transformState(state)
+ versionedData.data = newState
+ } catch (err) {
+ console.warn(`MetaMask Migration #${version}` + err.stack)
+ }
+ return Promise.resolve(versionedData)
+ },
+}
+
+function transformState (state) {
+ const newState = state
+ newState.NetworkController = {}
+ newState.NetworkController.provider = newState.config.provider
+ delete newState.config.provider
+ return newState
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 3a95cf88e..fb1ad7863 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -24,4 +24,5 @@ module.exports = [
require('./011'),
require('./012'),
require('./013'),
+ require('./014'),
]
diff --git a/development/announcer.js b/development/announcer.js
index 110d41fd4..43ae60acb 100644
--- a/development/announcer.js
+++ b/development/announcer.js
@@ -7,6 +7,6 @@ var changelog = fs.readFileSync(path.join(__dirname, '..', 'CHANGELOG.md')).toSt
var log = changelog.split(version)[1].split('##')[0].trim()
-let msg = `*MetaMask ${version}* now published to the Chrome Store! It should auto-update over the next hour!\n${log}`
+let msg = `*MetaMask ${version}* now published to the Chrome Store! It should auto-update soon!\n${log}`
console.log(msg)
diff --git a/test/unit/network-contoller-test.js b/test/unit/network-contoller-test.js
new file mode 100644
index 000000000..76452b303
--- /dev/null
+++ b/test/unit/network-contoller-test.js
@@ -0,0 +1,77 @@
+const assert = require('assert')
+const NetworkController = require('../../app/scripts/controllers/network')
+
+describe('# Network Controller', function () {
+ let networkController
+
+ beforeEach(function () {
+ networkController = new NetworkController({
+ provider: {
+ type: 'rinkeby',
+ },
+ })
+ // stub out provider
+ networkController._provider = new Proxy({}, {
+ get: (obj, name) => {
+ return () => {}
+ },
+ })
+ networkController.providerInit = {
+ getAccounts: () => {},
+ }
+
+ networkController.ethQuery = new Proxy({}, {
+ get: (obj, name) => {
+ return () => {}
+ },
+ })
+ })
+ describe('network', function () {
+ describe('#provider', function() {
+ it('provider should be updatable without reassignment', function () {
+ networkController.initializeProvider(networkController.providerInit)
+ const provider = networkController.provider
+ networkController._provider = {test: true}
+ assert.ok(provider.test)
+ })
+ })
+ describe('#getNetworkState', function () {
+ it('should return loading when new', function () {
+ let networkState = networkController.getNetworkState()
+ assert.equal(networkState, 'loading', 'network is loading')
+ })
+ })
+
+ describe('#setNetworkState', function () {
+ it('should update the network', function () {
+ networkController.setNetworkState(1)
+ let networkState = networkController.getNetworkState()
+ assert.equal(networkState, 1, 'network is 1')
+ })
+ })
+
+ describe('#getRpcAddressForType', function () {
+ it('should return the right rpc address', function () {
+ let rpcTarget = networkController.getRpcAddressForType('mainnet')
+ assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress')
+ })
+ })
+ describe('#setProviderType', function () {
+ it('should update provider.type', function () {
+ networkController.setProviderType('mainnet')
+ const type = networkController.getProviderConfig().type
+ assert.equal(type, 'mainnet', 'provider type is updated')
+ })
+ it('should set the network to loading', function () {
+ networkController.setProviderType('mainnet')
+ const loading = networkController.isNetworkLoading()
+ assert.ok(loading, 'network is loading')
+ })
+ it('should set the right rpcTarget', function () {
+ networkController.setProviderType('mainnet')
+ const rpcTarget = networkController.getProviderConfig().rpcTarget
+ assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress')
+ })
+ })
+ })
+})
diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js
index d4e8d79f0..711e1ea79 100644
--- a/test/unit/tx-controller-test.js
+++ b/test/unit/tx-controller-test.js
@@ -2,6 +2,7 @@ const assert = require('assert')
const EventEmitter = require('events')
const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx')
+const EthQuery = require('eth-query')
const ObservableStore = require('obs-store')
const clone = require('clone')
const sinon = require('sinon')
@@ -16,9 +17,10 @@ describe('Transaction Controller', function () {
beforeEach(function () {
txController = new TransactionController({
- networkStore: new ObservableStore({ network: currentNetworkId }),
+ networkStore: new ObservableStore(currentNetworkId),
txHistoryLimit: 10,
blockTracker: new EventEmitter(),
+ ethQuery: new EthQuery(new EventEmitter()),
signTransaction: (ethTx) => new Promise((resolve) => {
ethTx.sign(privKey)
resolve()
diff --git a/test/unit/tx-utils-test.js b/test/unit/tx-utils-test.js
index 57d4638a0..7ace1f587 100644
--- a/test/unit/tx-utils-test.js
+++ b/test/unit/tx-utils-test.js
@@ -9,7 +9,11 @@ describe('txUtils', function () {
let txUtils
before(function () {
- txUtils = new TxUtils()
+ txUtils = new TxUtils(new Proxy({}, {
+ get: (obj, name) => {
+ return () => {}
+ },
+ }))
})
describe('chain Id', function () {