aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts
diff options
context:
space:
mode:
authorDan Finlay <dan@danfinlay.com>2017-06-13 08:06:39 +0800
committerDan Finlay <dan@danfinlay.com>2017-06-13 08:17:16 +0800
commita741cc4fc4fb68e3f460c70ea848bdf3d2d2c894 (patch)
tree58652d4789e71a47a763096e746bd25904d91bfe /app/scripts
parentd05d9a5f57b9311d6f29539233f9065330e8bda4 (diff)
parentbbe0c73dca45542b519036bec2bae5feb1e55485 (diff)
downloadtangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar.gz
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar.bz2
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar.lz
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar.xz
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.tar.zst
tangerine-wallet-browser-a741cc4fc4fb68e3f460c70ea848bdf3d2d2c894.zip
Merge branch 'master' into AddTokenList
Diffstat (limited to 'app/scripts')
-rw-r--r--app/scripts/account-import-strategies/index.js2
-rw-r--r--app/scripts/background.js50
-rw-r--r--app/scripts/config.js9
-rw-r--r--app/scripts/contentscript.js3
-rw-r--r--app/scripts/controllers/address-book.js8
-rw-r--r--app/scripts/controllers/currency.js10
-rw-r--r--app/scripts/controllers/network.js129
-rw-r--r--app/scripts/controllers/preferences.js8
-rw-r--r--app/scripts/controllers/transactions.js (renamed from app/scripts/transaction-manager.js)98
-rw-r--r--app/scripts/first-time-state.js12
-rw-r--r--app/scripts/inpage.js21
-rw-r--r--app/scripts/keyring-controller.js4
-rw-r--r--app/scripts/lib/auto-reload.js47
-rw-r--r--app/scripts/lib/buy-eth-url.js8
-rw-r--r--app/scripts/lib/config-manager.js78
-rw-r--r--app/scripts/lib/eth-store.js4
-rw-r--r--app/scripts/lib/inpage-provider.js5
-rw-r--r--app/scripts/lib/message-manager.js4
-rw-r--r--app/scripts/lib/migrator/index.js43
-rw-r--r--app/scripts/lib/notification-manager.js5
-rw-r--r--app/scripts/lib/personal-message-manager.js4
-rw-r--r--app/scripts/lib/tx-utils.js30
-rw-r--r--app/scripts/metamask-controller.js233
-rw-r--r--app/scripts/migrations/002.js2
-rw-r--r--app/scripts/migrations/003.js2
-rw-r--r--app/scripts/migrations/004.js2
-rw-r--r--app/scripts/migrations/005.js2
-rw-r--r--app/scripts/migrations/006.js2
-rw-r--r--app/scripts/migrations/007.js2
-rw-r--r--app/scripts/migrations/008.js2
-rw-r--r--app/scripts/migrations/009.js2
-rw-r--r--app/scripts/migrations/010.js2
-rw-r--r--app/scripts/migrations/011.js2
-rw-r--r--app/scripts/migrations/012.js2
-rw-r--r--app/scripts/migrations/013.js34
-rw-r--r--app/scripts/migrations/014.js34
-rw-r--r--app/scripts/migrations/_multi-keyring.js11
-rw-r--r--app/scripts/migrations/index.js2
-rw-r--r--app/scripts/popup-core.js6
-rw-r--r--app/scripts/popup.js2
40 files changed, 550 insertions, 376 deletions
diff --git a/app/scripts/account-import-strategies/index.js b/app/scripts/account-import-strategies/index.js
index d5124eb7f..96e2b5912 100644
--- a/app/scripts/account-import-strategies/index.js
+++ b/app/scripts/account-import-strategies/index.js
@@ -4,7 +4,7 @@ const ethUtil = require('ethereumjs-util')
const accountImporter = {
- importAccount(strategy, args) {
+ importAccount (strategy, args) {
try {
const importer = this.strategies[strategy]
const privateKeyHex = importer.apply(null, args)
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 7211f1e0c..1dbfb1b98 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -1,6 +1,5 @@
const urlUtil = require('url')
const endOfStream = require('end-of-stream')
-const asyncQ = require('async-q')
const pipe = require('pump')
const LocalStorageStore = require('obs-store/lib/localStorage')
const storeTransform = require('obs-store/lib/transform')
@@ -30,38 +29,32 @@ let popupIsOpen = false
const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY })
// initialization flow
-asyncQ.waterfall([
- () => loadStateFromPersistence(),
- (initState) => setupController(initState),
-])
-.then(() => console.log('MetaMask initialization complete.'))
-.catch((err) => { console.error(err) })
+initialize().catch(console.error)
+
+async function initialize () {
+ const initState = await loadStateFromPersistence()
+ await setupController(initState)
+ console.log('MetaMask initialization complete.')
+}
//
// State and Persistence
//
-function loadStateFromPersistence() {
+async function loadStateFromPersistence () {
// migrations
- let migrator = new Migrator({ migrations })
- let initialState = migrator.generateInitialState(firstTimeState)
- return asyncQ.waterfall([
- // read from disk
- () => Promise.resolve(diskStore.getState() || initialState),
- // migrate data
- (versionedData) => migrator.migrateData(versionedData),
- // write to disk
- (versionedData) => {
- diskStore.putState(versionedData)
- return Promise.resolve(versionedData)
- },
- // resolve to just data
- (versionedData) => Promise.resolve(versionedData.data),
- ])
+ const migrator = new Migrator({ migrations })
+ // read from disk
+ let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState)
+ // migrate data
+ versionedData = await migrator.migrateData(versionedData)
+ // write to disk
+ diskStore.putState(versionedData)
+ // return just the data
+ return versionedData.data
}
function setupController (initState) {
-
//
// MetaMask Controller
//
@@ -85,8 +78,8 @@ function setupController (initState) {
diskStore
)
- function versionifyData(state) {
- let versionedData = diskStore.getState()
+ function versionifyData (state) {
+ const versionedData = diskStore.getState()
versionedData.data = state
return versionedData
}
@@ -121,13 +114,13 @@ function setupController (initState) {
//
updateBadge()
- controller.txManager.on('updateBadge', updateBadge)
+ controller.txController.on('updateBadge', updateBadge)
controller.messageManager.on('updateBadge', updateBadge)
// plugin badge text
function updateBadge () {
var label = ''
- var unapprovedTxCount = controller.txManager.unapprovedTxCount
+ var unapprovedTxCount = controller.txController.unapprovedTxCount
var unapprovedMsgCount = controller.messageManager.unapprovedMsgCount
var count = unapprovedTxCount + unapprovedMsgCount
if (count) {
@@ -138,7 +131,6 @@ function setupController (initState) {
}
return Promise.resolve()
-
}
//
diff --git a/app/scripts/config.js b/app/scripts/config.js
index ec421744d..8e28db80e 100644
--- a/app/scripts/config.js
+++ b/app/scripts/config.js
@@ -1,16 +1,15 @@
const MAINET_RPC_URL = 'https://mainnet.infura.io/metamask'
-const TESTNET_RPC_URL = 'https://ropsten.infura.io/metamask'
+const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask'
const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
-const DEFAULT_RPC_URL = TESTNET_RPC_URL
+const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask'
global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
module.exports = {
network: {
- default: DEFAULT_RPC_URL,
mainnet: MAINET_RPC_URL,
- testnet: TESTNET_RPC_URL,
- morden: TESTNET_RPC_URL,
+ ropsten: ROPSTEN_RPC_URL,
kovan: KOVAN_RPC_URL,
+ rinkeby: RINKEBY_RPC_URL,
},
}
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 4d7e682d3..291b922e8 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -61,7 +61,6 @@ function setupStreams () {
// ignore unused channels (handled by background)
mx.ignoreStream('provider')
mx.ignoreStream('publicConfig')
- mx.ignoreStream('reload')
}
function shouldInjectWeb3 () {
@@ -77,7 +76,7 @@ function doctypeCheck () {
}
}
-function suffixCheck() {
+function suffixCheck () {
var prohibitedTypes = ['xml', 'pdf']
var currentUrl = window.location.href
var currentRegex
diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js
index c66eb2bd4..6fb4ee114 100644
--- a/app/scripts/controllers/address-book.js
+++ b/app/scripts/controllers/address-book.js
@@ -39,11 +39,11 @@ class AddressBookController {
// pushed object is an object of two fields. Current behavior does not set an
// upper limit to the number of addresses.
_addToAddressBook (address, name) {
- let addressBook = this._getAddressBook()
- let identities = this._getIdentities()
+ const addressBook = this._getAddressBook()
+ const identities = this._getIdentities()
- let addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name })
- let identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() })
+ const addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name })
+ const identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() })
// trigger this condition if we own this address--no need to overwrite.
if (identitiesIndex !== -1) {
return Promise.resolve(addressBook)
diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js
index c4904f8ac..1f20dc005 100644
--- a/app/scripts/controllers/currency.js
+++ b/app/scripts/controllers/currency.js
@@ -45,15 +45,17 @@ class CurrencyController {
updateConversionRate () {
const currentCurrency = this.getCurrentCurrency()
- return fetch(`https://www.cryptonator.com/api/ticker/eth-${currentCurrency}`)
+ return fetch(`https://api.cryptonator.com/api/ticker/eth-${currentCurrency}`)
.then(response => response.json())
.then((parsedResponse) => {
this.setConversionRate(Number(parsedResponse.ticker.price))
this.setConversionDate(Number(parsedResponse.timestamp))
}).catch((err) => {
- console.warn('MetaMask - Failed to query currency conversion.')
- this.setConversionRate(0)
- this.setConversionDate('N/A')
+ if (err) {
+ console.warn('MetaMask - Failed to query currency conversion.')
+ this.setConversionRate(0)
+ this.setConversionDate('N/A')
+ }
})
}
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/preferences.js b/app/scripts/controllers/preferences.js
index c7f675a41..7212c7c43 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -36,8 +36,8 @@ class PreferencesController {
}
addToFrequentRpcList (_url) {
- let rpcList = this.getFrequentRpcList()
- let index = rpcList.findIndex((element) => { return element === _url })
+ const rpcList = this.getFrequentRpcList()
+ const index = rpcList.findIndex((element) => { return element === _url })
if (index !== -1) {
rpcList.splice(index, 1)
}
@@ -53,13 +53,9 @@ class PreferencesController {
getFrequentRpcList () {
return this.store.getState().frequentRpcList
}
-
//
// PRIVATE METHODS
//
-
-
-
}
module.exports = PreferencesController
diff --git a/app/scripts/transaction-manager.js b/app/scripts/controllers/transactions.js
index 22d807748..8be73fad8 100644
--- a/app/scripts/transaction-manager.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 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,17 +23,19 @@ 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)
// memstore is computed from a few different stores
this._updateMemstore()
- this.store.subscribe(() => this._updateMemstore() )
- this.networkStore.subscribe(() => this._updateMemstore() )
- this.preferencesStore.subscribe(() => this._updateMemstore() )
+ 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 () {
@@ -47,8 +52,8 @@ module.exports = class TransactionManager extends EventEmitter {
// Returns the tx list
getTxList () {
- let network = this.getNetwork()
- let fullTxList = this.getFullTxList()
+ const network = this.getNetwork()
+ const fullTxList = this.getFullTxList()
return fullTxList.filter(txMeta => txMeta.metamaskNetworkId === network)
}
@@ -64,10 +69,10 @@ module.exports = class TransactionManager extends EventEmitter {
// Adds a tx to the txlist
addTx (txMeta) {
- let txCount = this.getTxCount()
- let network = this.getNetwork()
- let fullTxList = this.getFullTxList()
- let txHistoryLimit = this.txHistoryLimit
+ const txCount = this.getTxCount()
+ const network = this.getNetwork()
+ const fullTxList = this.getFullTxList()
+ const txHistoryLimit = this.txHistoryLimit
// checks if the length of the tx history is
// longer then desired persistence limit
@@ -197,7 +202,7 @@ module.exports = class TransactionManager extends EventEmitter {
}
fillInTxParams (txId, cb) {
- let txMeta = this.getTx(txId)
+ const txMeta = this.getTx(txId)
this.txProviderUtils.fillInTxParams(txMeta.txParams, (err) => {
if (err) return cb(err)
this.updateTx(txMeta)
@@ -205,7 +210,7 @@ module.exports = class TransactionManager extends EventEmitter {
})
}
- getChainId() {
+ getChainId () {
const networkState = this.networkStore.getState()
const getChainId = parseInt(networkState.network)
if (Number.isNaN(getChainId)) {
@@ -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)
@@ -242,7 +251,7 @@ module.exports = class TransactionManager extends EventEmitter {
// receives a txHash records the tx as signed
setTxHash (txId, txHash) {
// Add the tx hash to the persisted meta-tx object
- let txMeta = this.getTx(txId)
+ const txMeta = this.getTx(txId)
txMeta.hash = txHash
this.updateTx(txMeta)
}
@@ -315,7 +324,7 @@ module.exports = class TransactionManager extends EventEmitter {
}
setTxStatusFailed (txId, reason) {
- let txMeta = this.getTx(txId)
+ const txMeta = this.getTx(txId)
txMeta.err = reason
this.updateTx(txMeta)
this._setTxStatus(txId, 'failed')
@@ -338,7 +347,7 @@ module.exports = class TransactionManager extends EventEmitter {
var txHash = txMeta.hash
var txId = txMeta.id
if (!txHash) {
- let errReason = {
+ const errReason = {
errCode: 'No hash was provided',
message: 'We had an error while submitting this transaction, please try again.',
}
@@ -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)
@@ -380,6 +389,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')
@@ -399,7 +409,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 3196981ba..5e8577100 100644
--- a/app/scripts/first-time-state.js
+++ b/app/scripts/first-time-state.js
@@ -1,11 +1,15 @@
+// test and development environment variables
+const env = process.env.METAMASK_ENV
+const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
+
//
// The default state of MetaMask
//
-
module.exports = {
- config: {
+ config: {},
+ NetworkController: {
provider: {
- type: 'testnet',
+ type: (METAMASK_DEBUG || env === 'test') ? 'rinkeby' : 'mainnet',
},
},
-} \ No newline at end of file
+}
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js
index 419f78cd6..ec764535e 100644
--- a/app/scripts/inpage.js
+++ b/app/scripts/inpage.js
@@ -31,26 +31,11 @@ web3.setProvider = function () {
console.log('MetaMask - overrode web3.setProvider')
}
console.log('MetaMask - injected web3')
-// export global web3, with usage-detection reload fn
-var triggerReload = setupDappAutoReload(web3)
-
-// listen for reset requests from metamask
-var reloadStream = inpageProvider.multiStream.createStream('reload')
-reloadStream.once('data', triggerReload)
-
-// setup ping timeout autoreload
-// LocalMessageDuplexStream does not self-close, so reload if pingStream fails
-// var pingChannel = inpageProvider.multiStream.createStream('pingpong')
-// var pingStream = new PingStream({ objectMode: true })
-// wait for first successful reponse
-
-// disable pingStream until https://github.com/MetaMask/metamask-plugin/issues/746 is resolved more gracefully
-// metamaskStream.once('data', function(){
-// pingStream.pipe(pingChannel).pipe(pingStream)
-// })
-// endOfStream(pingStream, triggerReload)
+// export global web3, with usage-detection
+setupDappAutoReload(web3, inpageProvider.publicConfigStore)
// set web3 defaultAccount
+
inpageProvider.publicConfigStore.subscribe(function (state) {
web3.eth.defaultAccount = state.selectedAddress
})
diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js
index 16df6efa6..5b3c80e40 100644
--- a/app/scripts/keyring-controller.js
+++ b/app/scripts/keyring-controller.js
@@ -187,7 +187,7 @@ class KeyringController extends EventEmitter {
.then((accounts) => {
switch (type) {
case 'Simple Key Pair':
- let isNotIncluded = !accounts.find((key) => key === newAccount[0] || key === ethUtil.stripHexPrefix(newAccount[0]))
+ const isNotIncluded = !accounts.find((key) => key === newAccount[0] || key === ethUtil.stripHexPrefix(newAccount[0]))
return (isNotIncluded) ? Promise.resolve(newAccount) : Promise.reject(new Error('The account you\'re are trying to import is a duplicate'))
default:
return Promise.resolve(newAccount)
@@ -582,7 +582,7 @@ class KeyringController extends EventEmitter {
})
}
- _updateMemStoreKeyrings() {
+ _updateMemStoreKeyrings () {
Promise.all(this.keyrings.map(this.displayForKeyring))
.then((keyrings) => {
this.memStore.updateState({ keyrings })
diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js
index 1302df35f..534047330 100644
--- a/app/scripts/lib/auto-reload.js
+++ b/app/scripts/lib/auto-reload.js
@@ -1,30 +1,33 @@
-const once = require('once')
-const ensnare = require('ensnare')
-
module.exports = setupDappAutoReload
-function setupDappAutoReload (web3) {
+function setupDappAutoReload (web3, observable) {
// export web3 as a global, checking for usage
- var pageIsUsingWeb3 = false
- var resetWasRequested = false
- global.web3 = ensnare(web3, once(function () {
- // if web3 usage happened after a reset request, trigger reset late
- if (resetWasRequested) return triggerReset()
- // mark web3 as used
- pageIsUsingWeb3 = true
- // reset web3 reference
- global.web3 = web3
- }))
+ global.web3 = new Proxy(web3, {
+ get: (_web3, name) => {
+ // get the time of use
+ if (name !== '_used') _web3._used = Date.now()
+ return _web3[name]
+ },
+ set: (_web3, name, value) => {
+ _web3[name] = value
+ },
+ })
+ var networkVersion
- return handleResetRequest
+ observable.subscribe(function (state) {
+ // get the initial network
+ const curentNetVersion = state.networkVersion
+ if (!networkVersion) networkVersion = curentNetVersion
- function handleResetRequest () {
- resetWasRequested = true
- // ignore if web3 was not used
- if (!pageIsUsingWeb3) return
- // reload after short timeout
- setTimeout(triggerReset, 500)
- }
+ if (curentNetVersion !== networkVersion && web3._used) {
+ const timeSinceUse = Date.now() - web3._used
+ // if web3 was recently used then delay the reloading of the page
+ timeSinceUse > 500 ? triggerReset() : setTimeout(triggerReset, 500)
+ // prevent reentry into if statement if state updates again before
+ // reload
+ networkVersion = curentNetVersion
+ }
+ })
}
// reload the page
diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js
index 91a1ec322..b9dde3c28 100644
--- a/app/scripts/lib/buy-eth-url.js
+++ b/app/scripts/lib/buy-eth-url.js
@@ -1,6 +1,6 @@
module.exports = getBuyEthUrl
-function getBuyEthUrl({ network, amount, address }){
+function getBuyEthUrl ({ network, amount, address }) {
let url
switch (network) {
case '1':
@@ -11,9 +11,13 @@ function getBuyEthUrl({ network, amount, address }){
url = 'https://faucet.metamask.io/'
break
+ case '4':
+ url = 'https://www.rinkeby.io/'
+ break
+
case '42':
url = 'https://github.com/kovan-testnet/faucet'
break
}
return url
-} \ No newline at end of file
+}
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index e31cb45ed..9c0dffe9c 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -1,11 +1,12 @@
-const MetamaskConfig = require('../config.js')
const ethUtil = require('ethereumjs-util')
const normalize = require('eth-sig-util').normalize
+const MetamaskConfig = require('../config.js')
+
-const TESTNET_RPC = MetamaskConfig.network.testnet
const MAINNET_RPC = MetamaskConfig.network.mainnet
-const MORDEN_RPC = MetamaskConfig.network.morden
+const ROPSTEN_RPC = MetamaskConfig.network.ropsten
const KOVAN_RPC = MetamaskConfig.network.kovan
+const RINKEBY_RPC = MetamaskConfig.network.rinkeby
/* The config-manager is a convenience object
* wrapping a pojo-migrator.
@@ -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()
@@ -145,17 +145,17 @@ ConfigManager.prototype.getCurrentRpcAddress = function () {
case 'mainnet':
return MAINNET_RPC
- case 'testnet':
- return TESTNET_RPC
-
- case 'morden':
- return MORDEN_RPC
+ case 'ropsten':
+ return ROPSTEN_RPC
case 'kovan':
return KOVAN_RPC
+ case 'rinkeby':
+ return RINKEBY_RPC
+
default:
- return provider && provider.rpcTarget ? provider.rpcTarget : TESTNET_RPC
+ return provider && provider.rpcTarget ? provider.rpcTarget : RINKEBY_RPC
}
}
diff --git a/app/scripts/lib/eth-store.js b/app/scripts/lib/eth-store.js
index 243253df2..ebba98f5c 100644
--- a/app/scripts/lib/eth-store.js
+++ b/app/scripts/lib/eth-store.js
@@ -10,7 +10,7 @@
const async = require('async')
const EthQuery = require('eth-query')
const ObservableStore = require('obs-store')
-function noop() {}
+function noop () {}
class EthereumStore extends ObservableStore {
@@ -21,6 +21,7 @@ class EthereumStore extends ObservableStore {
transactions: {},
currentBlockNumber: '0',
currentBlockHash: '',
+ currentBlockGasLimit: '',
})
this._provider = opts.provider
this._query = new EthQuery(this._provider)
@@ -73,6 +74,7 @@ class EthereumStore extends ObservableStore {
this._currentBlockNumber = blockNumber
this.updateState({ currentBlockNumber: parseInt(blockNumber) })
this.updateState({ currentBlockHash: `0x${block.hash.toString('hex')}`})
+ this.updateState({ currentBlockGasLimit: `0x${block.gasLimit.toString('hex')}` })
async.parallel([
this._updateAccounts.bind(this),
this._updateTransactions.bind(this, blockNumber),
diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js
index 92936de2f..8b8623974 100644
--- a/app/scripts/lib/inpage-provider.js
+++ b/app/scripts/lib/inpage-provider.js
@@ -34,6 +34,7 @@ function MetamaskInpageProvider (connectionStream) {
asyncProvider,
(err) => logStreamDisconnectWarning('MetaMask RpcProvider', err)
)
+ // start and stop polling to unblock first block lock
self.idMap = {}
// handle sendAsync requests via asyncProvider
@@ -85,7 +86,7 @@ MetamaskInpageProvider.prototype.send = function (payload) {
break
case 'net_version':
- let networkVersion = self.publicConfigStore.getState().networkVersion
+ const networkVersion = self.publicConfigStore.getState().networkVersion
result = networkVersion
break
@@ -125,7 +126,7 @@ function eachJsonMessage (payload, transformFn) {
}
}
-function logStreamDisconnectWarning(remoteLabel, err){
+function logStreamDisconnectWarning (remoteLabel, err) {
let warningMsg = `MetamaskInpageProvider - lost connection to ${remoteLabel}`
if (err) warningMsg += '\n' + err.stack
console.warn(warningMsg)
diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js
index 711d5f159..f52e048e0 100644
--- a/app/scripts/lib/message-manager.js
+++ b/app/scripts/lib/message-manager.js
@@ -4,7 +4,7 @@ const ethUtil = require('ethereumjs-util')
const createId = require('./random-id')
-module.exports = class MessageManager extends EventEmitter{
+module.exports = class MessageManager extends EventEmitter {
constructor (opts) {
super()
this.memStore = new ObservableStore({
@@ -108,7 +108,7 @@ module.exports = class MessageManager extends EventEmitter{
}
-function normalizeMsgData(data) {
+function normalizeMsgData (data) {
if (data.slice(0, 2) === '0x') {
// data is already hex
return data
diff --git a/app/scripts/lib/migrator/index.js b/app/scripts/lib/migrator/index.js
index 312345263..4fd2cae92 100644
--- a/app/scripts/lib/migrator/index.js
+++ b/app/scripts/lib/migrator/index.js
@@ -1,42 +1,35 @@
-const asyncQ = require('async-q')
-
class Migrator {
constructor (opts = {}) {
- let migrations = opts.migrations || []
+ const migrations = opts.migrations || []
+ // sort migrations by version
this.migrations = migrations.sort((a, b) => a.version - b.version)
- let lastMigration = this.migrations.slice(-1)[0]
+ // grab migration with highest version
+ const lastMigration = this.migrations.slice(-1)[0]
// use specified defaultVersion or highest migration version
this.defaultVersion = opts.defaultVersion || (lastMigration && lastMigration.version) || 0
}
// run all pending migrations on meta in place
- migrateData (versionedData = this.generateInitialState()) {
- let remaining = this.migrations.filter(migrationIsPending)
-
- return (
- asyncQ.eachSeries(remaining, (migration) => this.runMigration(versionedData, migration))
- .then(() => versionedData)
- )
-
- // migration is "pending" if hit has a higher
+ async migrateData (versionedData = this.generateInitialState()) {
+ const pendingMigrations = this.migrations.filter(migrationIsPending)
+
+ for (const index in pendingMigrations) {
+ const migration = pendingMigrations[index]
+ versionedData = await migration.migrate(versionedData)
+ if (!versionedData.data) throw new Error('Migrator - migration returned empty data')
+ if (versionedData.version !== undefined && versionedData.meta.version !== migration.version) throw new Error('Migrator - Migration did not update version number correctly')
+ }
+
+ return versionedData
+
+ // migration is "pending" if it has a higher
// version number than currentVersion
- function migrationIsPending(migration) {
+ function migrationIsPending (migration) {
return migration.version > versionedData.meta.version
}
}
- runMigration(versionedData, migration) {
- return (
- migration.migrate(versionedData)
- .then((versionedData) => {
- if (!versionedData.data) return Promise.reject(new Error('Migrator - Migration returned empty data'))
- if (migration.version !== undefined && versionedData.meta.version !== migration.version) return Promise.reject(new Error('Migrator - Migration did not update version number correctly'))
- return Promise.resolve(versionedData)
- })
- )
- }
-
generateInitialState (initState) {
return {
meta: {
diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js
index 55e5b8dd2..7846ef7f0 100644
--- a/app/scripts/lib/notification-manager.js
+++ b/app/scripts/lib/notification-manager.js
@@ -24,9 +24,6 @@ class NotificationManager {
width,
height,
})
- .catch((reason) => {
- log.error('failed to create poupup', reason)
- })
}
})
}
@@ -71,4 +68,4 @@ class NotificationManager {
}
-module.exports = NotificationManager \ No newline at end of file
+module.exports = NotificationManager
diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js
index bbc978446..6602f5aa8 100644
--- a/app/scripts/lib/personal-message-manager.js
+++ b/app/scripts/lib/personal-message-manager.js
@@ -5,7 +5,7 @@ const createId = require('./random-id')
const hexRe = /^[0-9A-Fa-f]+$/g
-module.exports = class PersonalMessageManager extends EventEmitter{
+module.exports = class PersonalMessageManager extends EventEmitter {
constructor (opts) {
super()
this.memStore = new ObservableStore({
@@ -108,7 +108,7 @@ module.exports = class PersonalMessageManager extends EventEmitter{
this.emit('updateBadge')
}
- normalizeMsgData(data) {
+ normalizeMsgData (data) {
try {
const stripped = ethUtil.stripHexPrefix(data)
if (stripped.match(hexRe)) {
diff --git a/app/scripts/lib/tx-utils.js b/app/scripts/lib/tx-utils.js
index e8e23f8b5..149d93102 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) {
@@ -35,7 +33,9 @@ module.exports = class txProviderUtils {
txMeta.gasLimitSpecified = Boolean(txParams.gas)
// if not, fallback to block gasLimit
if (!txMeta.gasLimitSpecified) {
- txParams.gas = blockGasLimitHex
+ const blockGasLimitBN = hexToBn(blockGasLimitHex)
+ const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
+ txParams.gas = bnToHex(saferGasLimitBN)
}
// run tx, see if it will OOG
this.query.estimateGas(txParams, cb)
@@ -75,14 +75,14 @@ module.exports = class txProviderUtils {
}
fillInTxParams (txParams, cb) {
- let fromAddress = txParams.from
- let reqs = {}
+ const fromAddress = txParams.from
+ const reqs = {}
if (isUndef(txParams.gas)) reqs.gas = (cb) => this.query.estimateGas(txParams, cb)
if (isUndef(txParams.gasPrice)) reqs.gasPrice = (cb) => this.query.gasPrice(cb)
if (isUndef(txParams.nonce)) reqs.nonce = (cb) => this.query.getTransactionCount(fromAddress, 'pending', cb)
- async.parallel(reqs, function(err, result) {
+ async.parallel(reqs, function (err, result) {
if (err) return cb(err)
// write results to txParams obj
Object.assign(txParams, result)
@@ -123,14 +123,20 @@ module.exports = class txProviderUtils {
// util
-function isUndef(value) {
+function isUndef (value) {
return value === undefined
}
-function bnToHex(inputBn) {
+function bnToHex (inputBn) {
return ethUtil.addHexPrefix(inputBn.toString(16))
}
-function hexToBn(inputHex) {
+function hexToBn (inputHex) {
return new BN(ethUtil.stripHexPrefix(inputHex), 16)
}
+
+function BnMultiplyByFraction (targetBN, numerator, denominator) {
+ const numBN = new BN(numerator)
+ const denomBN = new BN(denominator)
+ return targetBN.mul(numBN).div(denomBN)
+}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 2b8fc9cb8..a7eb3d056 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -4,13 +4,12 @@ const promiseToCallback = require('promise-to-callback')
const pipe = require('pump')
const Dnode = require('dnode')
const ObservableStore = require('obs-store')
-const storeTransform = require('obs-store/lib/transform')
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')
@@ -18,7 +17,7 @@ const ShapeShiftController = require('./controllers/shapeshift')
const AddressBookController = require('./controllers/address-book')
const MessageManager = require('./lib/message-manager')
const PersonalMessageManager = require('./lib/personal-message-manager')
-const TxManager = require('./transaction-manager')
+const TransactionController = require('./controllers/transactions')
const ConfigManager = require('./lib/config-manager')
const autoFaucet = require('./lib/auto-faucet')
const nodeify = require('./lib/nodeify')
@@ -32,7 +31,7 @@ module.exports = class MetamaskController extends EventEmitter {
constructor (opts) {
super()
this.opts = opts
- let initState = opts.initState || {}
+ const initState = opts.initState || {}
// platform-specific api
this.platform = opts.platform
@@ -41,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,
@@ -62,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)
@@ -76,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)
@@ -91,15 +88,16 @@ module.exports = class MetamaskController extends EventEmitter {
}, this.keyringController)
// tx mgmt
- this.txManager = new TxManager({
- initState: initState.TransactionManager,
- networkStore: this.networkStore,
+ this.txController = new TransactionController({
+ initState: initState.TransactionController || initState.TransactionManager,
+ 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
@@ -114,14 +112,14 @@ 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()
// manual disk state subscriptions
- this.txManager.store.subscribe((state) => {
- this.store.updateState({ TransactionManager: state })
+ this.txController.store.subscribe((state) => {
+ this.store.updateState({ TransactionController: state })
})
this.keyringController.store.subscribe((state) => {
this.store.updateState({ KeyringController: state })
@@ -141,11 +139,14 @@ 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.txManager.memStore.subscribe(this.sendUpdate.bind(this))
+ this.txController.memStore.subscribe(this.sendUpdate.bind(this))
this.messageManager.memStore.subscribe(this.sendUpdate.bind(this))
this.personalMessageManager.memStore.subscribe(this.sendUpdate.bind(this))
this.keyringController.memStore.subscribe(this.sendUpdate.bind(this))
@@ -161,17 +162,21 @@ module.exports = class MetamaskController extends EventEmitter {
//
initializeProvider () {
-
- let 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) => {
- let selectedAddress = this.preferencesController.getSelectedAddress()
- let result = selectedAddress ? [selectedAddress] : []
+ 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)
+ }
cb(null, result)
},
// tx signing
@@ -182,26 +187,23 @@ module.exports = class MetamaskController extends EventEmitter {
// new style msg signing
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
})
- return provider
}
initPublicConfigStore () {
// get init state
const publicConfigStore = new ObservableStore()
- // sync publicConfigStore with transform
- pipe(
- this.store,
- storeTransform(selectPublicState.bind(this)),
- publicConfigStore
- )
+ // memStore -> transform -> publicConfigStore
+ this.on('update', (memState) => {
+ const publicState = selectPublicState(memState)
+ publicConfigStore.putState(publicState)
+ })
- function selectPublicState(state) {
- const result = { selectedAddress: undefined }
- try {
- result.selectedAddress = state.PreferencesController.selectedAddress
- result.networkVersion = this.getNetworkState()
- } catch (_) {}
+ function selectPublicState (memState) {
+ const result = {
+ selectedAddress: memState.isUnlocked ? memState.selectedAddress : undefined,
+ networkVersion: memState.network,
+ }
return result
}
@@ -220,9 +222,9 @@ module.exports = class MetamaskController extends EventEmitter {
{
isInitialized,
},
- this.networkStore.getState(),
+ this.networkController.store.getState(),
this.ethStore.getState(),
- this.txManager.memStore.getState(),
+ this.txController.memStore.getState(),
this.messageManager.memStore.getState(),
this.personalMessageManager.memStore.getState(),
this.keyringController.memStore.getState(),
@@ -247,62 +249,61 @@ module.exports = class MetamaskController extends EventEmitter {
getApi () {
const keyringController = this.keyringController
const preferencesController = this.preferencesController
- const txManager = this.txManager
+ const txController = this.txController
const noticeController = this.noticeController
const addressBookController = this.addressBookController
return {
// etc
- getState: (cb) => cb(null, this.getState()),
- setProviderType: this.setProviderType.bind(this),
- useEtherscanProvider: this.useEtherscanProvider.bind(this),
- setCurrentCurrency: this.setCurrentCurrency.bind(this),
- markAccountsFound: this.markAccountsFound.bind(this),
+ getState: (cb) => cb(null, this.getState()),
+ setProviderType: this.networkController.setProviderType.bind(this.networkController),
+ setCurrentCurrency: this.setCurrentCurrency.bind(this),
+ markAccountsFound: this.markAccountsFound.bind(this),
// coinbase
buyEth: this.buyEth.bind(this),
// shapeshift
createShapeShiftTx: this.createShapeShiftTx.bind(this),
// primary HD keyring management
- addNewAccount: this.addNewAccount.bind(this),
- placeSeedWords: this.placeSeedWords.bind(this),
- clearSeedWordCache: this.clearSeedWordCache.bind(this),
- importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
+ addNewAccount: this.addNewAccount.bind(this),
+ placeSeedWords: this.placeSeedWords.bind(this),
+ clearSeedWordCache: this.clearSeedWordCache.bind(this),
+ importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
// vault management
submitPassword: this.submitPassword.bind(this),
// PreferencesController
- setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController),
- setDefaultRpc: nodeify(this.setDefaultRpc).bind(this),
- setCustomRpc: nodeify(this.setCustomRpc).bind(this),
+ setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController),
+ setDefaultRpc: nodeify(this.setDefaultRpc).bind(this),
+ setCustomRpc: nodeify(this.setCustomRpc).bind(this),
// AddressController
- setAddressBook: nodeify(addressBookController.setAddressBook).bind(addressBookController),
+ setAddressBook: nodeify(addressBookController.setAddressBook).bind(addressBookController),
// KeyringController
- setLocked: nodeify(keyringController.setLocked).bind(keyringController),
+ setLocked: nodeify(keyringController.setLocked).bind(keyringController),
createNewVaultAndKeychain: nodeify(keyringController.createNewVaultAndKeychain).bind(keyringController),
- createNewVaultAndRestore: nodeify(keyringController.createNewVaultAndRestore).bind(keyringController),
- addNewKeyring: nodeify(keyringController.addNewKeyring).bind(keyringController),
- saveAccountLabel: nodeify(keyringController.saveAccountLabel).bind(keyringController),
- exportAccount: nodeify(keyringController.exportAccount).bind(keyringController),
-
- // txManager
- approveTransaction: txManager.approveTransaction.bind(txManager),
- cancelTransaction: txManager.cancelTransaction.bind(txManager),
+ createNewVaultAndRestore: nodeify(keyringController.createNewVaultAndRestore).bind(keyringController),
+ addNewKeyring: nodeify(keyringController.addNewKeyring).bind(keyringController),
+ saveAccountLabel: nodeify(keyringController.saveAccountLabel).bind(keyringController),
+ exportAccount: nodeify(keyringController.exportAccount).bind(keyringController),
+
+ // txController
+ approveTransaction: txController.approveTransaction.bind(txController),
+ cancelTransaction: txController.cancelTransaction.bind(txController),
updateAndApproveTransaction: this.updateAndApproveTx.bind(this),
// messageManager
- signMessage: nodeify(this.signMessage).bind(this),
- cancelMessage: this.cancelMessage.bind(this),
+ signMessage: nodeify(this.signMessage).bind(this),
+ cancelMessage: this.cancelMessage.bind(this),
// personalMessageManager
- signPersonalMessage: nodeify(this.signPersonalMessage).bind(this),
- cancelPersonalMessage: this.cancelPersonalMessage.bind(this),
+ signPersonalMessage: nodeify(this.signPersonalMessage).bind(this),
+ cancelPersonalMessage: this.cancelPersonalMessage.bind(this),
// notices
- checkNotices: noticeController.updateNoticesList.bind(noticeController),
+ checkNotices: noticeController.updateNoticesList.bind(noticeController),
markNoticeRead: noticeController.markNoticeRead.bind(noticeController),
}
}
@@ -342,9 +343,7 @@ module.exports = class MetamaskController extends EventEmitter {
console.error('Error in RPC response:\n', response.error)
}
if (request.isMetamaskInternal) return
- if (global.METAMASK_DEBUG) {
- console.log(`RPC (${originDomain}):`, request, '->', response)
- }
+ log.info(`RPC (${originDomain}):`, request, '->', response)
}
}
@@ -422,12 +421,12 @@ module.exports = class MetamaskController extends EventEmitter {
newUnapprovedTransaction (txParams, cb) {
log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`)
const self = this
- self.txManager.addUnapprovedTransaction(txParams, (err, txMeta) => {
+ self.txController.addUnapprovedTransaction(txParams, (err, txMeta) => {
if (err) return cb(err)
self.sendUpdate()
self.opts.showUnapprovedTx(txMeta)
// listen for tx completion (success, fail)
- self.txManager.once(`${txMeta.id}:finished`, (completedTx) => {
+ self.txController.once(`${txMeta.id}:finished`, (completedTx) => {
switch (completedTx.status) {
case 'submitted':
return cb(null, completedTx.hash)
@@ -441,7 +440,7 @@ module.exports = class MetamaskController extends EventEmitter {
}
newUnsignedMessage (msgParams, cb) {
- let msgId = this.messageManager.addUnapprovedMessage(msgParams)
+ const msgId = this.messageManager.addUnapprovedMessage(msgParams)
this.sendUpdate()
this.opts.showUnconfirmedMessage()
this.messageManager.once(`${msgId}:finished`, (data) => {
@@ -461,7 +460,7 @@ module.exports = class MetamaskController extends EventEmitter {
return cb(new Error('MetaMask Message Signature: from field is required.'))
}
- let msgId = this.personalMessageManager.addUnapprovedMessage(msgParams)
+ const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams)
this.sendUpdate()
this.opts.showUnconfirmedMessage()
this.personalMessageManager.once(`${msgId}:finished`, (data) => {
@@ -476,11 +475,11 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
- updateAndApproveTx(txMeta, cb) {
+ updateAndApproveTx (txMeta, cb) {
log.debug(`MetaMaskController - updateAndApproveTx: ${JSON.stringify(txMeta)}`)
- const txManager = this.txManager
- txManager.updateTx(txMeta)
- txManager.approveTransaction(txMeta.id, cb)
+ const txController = this.txController
+ txController.updateTx(txMeta)
+ txController.approveTransaction(txMeta.id, cb)
}
signMessage (msgParams, cb) {
@@ -502,7 +501,7 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
- cancelMessage(msgId, cb) {
+ cancelMessage (msgId, cb) {
const messageManager = this.messageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
@@ -512,7 +511,7 @@ module.exports = class MetamaskController extends EventEmitter {
// Prefixed Style Message Signing Methods:
approvePersonalMessage (msgParams, cb) {
- let msgId = this.personalMessageManager.addUnapprovedMessage(msgParams)
+ const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams)
this.sendUpdate()
this.opts.showUnconfirmedMessage()
this.personalMessageManager.once(`${msgId}:finished`, (data) => {
@@ -545,7 +544,7 @@ module.exports = class MetamaskController extends EventEmitter {
})
}
- cancelPersonalMessage(msgId, cb) {
+ cancelPersonalMessage (msgId, cb) {
const messageManager = this.personalMessageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
@@ -559,13 +558,13 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.getState())
}
- restoreOldVaultAccounts(migratorOutput) {
+ restoreOldVaultAccounts (migratorOutput) {
const { serialized } = migratorOutput
return this.keyringController.restoreKeyring(serialized)
.then(() => migratorOutput)
}
- restoreOldLostAccounts(migratorOutput) {
+ restoreOldLostAccounts (migratorOutput) {
const { lostAccounts } = migratorOutput
if (lostAccounts) {
this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address))
@@ -591,12 +590,6 @@ module.exports = class MetamaskController extends EventEmitter {
//
// Log blocks
- logBlock (block) {
- if (global.METAMASK_DEBUG) {
- console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
- }
- this.verifyNetwork()
- }
setCurrentCurrency (currencyCode, cb) {
try {
@@ -615,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 })
}
@@ -623,71 +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)
- })
- }
-
- 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 })
- }
+ this.networkController.setRpcTarget(rpcTarget)
- 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
- }
- if (global.METAMASK_DEBUG) {
- console.log('web3.getNetwork returned ' + network)
- }
- this.setNetworkState(network)
+ return this.preferencesController.updateFrequentRpcList(rpcTarget)
+ .then(() => {
+ return Promise.resolve(rpcTarget)
})
}
+
}
diff --git a/app/scripts/migrations/002.js b/app/scripts/migrations/002.js
index 36a870342..b1d88f2ef 100644
--- a/app/scripts/migrations/002.js
+++ b/app/scripts/migrations/002.js
@@ -7,7 +7,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
if (versionedData.data.config.provider.type === 'etherscan') {
diff --git a/app/scripts/migrations/003.js b/app/scripts/migrations/003.js
index 1893576ad..140f81d40 100644
--- a/app/scripts/migrations/003.js
+++ b/app/scripts/migrations/003.js
@@ -8,7 +8,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
if (versionedData.data.config.provider.rpcTarget === oldTestRpc) {
diff --git a/app/scripts/migrations/004.js b/app/scripts/migrations/004.js
index 405d932f8..cd558300c 100644
--- a/app/scripts/migrations/004.js
+++ b/app/scripts/migrations/004.js
@@ -6,7 +6,7 @@ module.exports = {
version,
migrate: function (versionedData) {
- let safeVersionedData = clone(versionedData)
+ const safeVersionedData = clone(versionedData)
safeVersionedData.meta.version = version
try {
if (safeVersionedData.data.config.provider.type !== 'rpc') return Promise.resolve(safeVersionedData)
diff --git a/app/scripts/migrations/005.js b/app/scripts/migrations/005.js
index e4b84f460..f7b68dfe4 100644
--- a/app/scripts/migrations/005.js
+++ b/app/scripts/migrations/005.js
@@ -14,7 +14,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/006.js b/app/scripts/migrations/006.js
index 94d1b6ecd..51ea6e3e7 100644
--- a/app/scripts/migrations/006.js
+++ b/app/scripts/migrations/006.js
@@ -13,7 +13,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/007.js b/app/scripts/migrations/007.js
index 236e35224..d9887b9c8 100644
--- a/app/scripts/migrations/007.js
+++ b/app/scripts/migrations/007.js
@@ -13,7 +13,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/008.js b/app/scripts/migrations/008.js
index cd5e95d22..da7cb2e60 100644
--- a/app/scripts/migrations/008.js
+++ b/app/scripts/migrations/008.js
@@ -13,7 +13,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/009.js b/app/scripts/migrations/009.js
index 4612fefdc..f47db55ac 100644
--- a/app/scripts/migrations/009.js
+++ b/app/scripts/migrations/009.js
@@ -13,7 +13,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/010.js b/app/scripts/migrations/010.js
index c0cc56ae4..e4b9ac07e 100644
--- a/app/scripts/migrations/010.js
+++ b/app/scripts/migrations/010.js
@@ -13,7 +13,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/011.js b/app/scripts/migrations/011.js
index 0d5d6d307..782ec809d 100644
--- a/app/scripts/migrations/011.js
+++ b/app/scripts/migrations/011.js
@@ -12,7 +12,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/012.js b/app/scripts/migrations/012.js
index 8361b3793..f69ccbb02 100644
--- a/app/scripts/migrations/012.js
+++ b/app/scripts/migrations/012.js
@@ -12,7 +12,7 @@ module.exports = {
version,
migrate: function (originalVersionedData) {
- let versionedData = clone(originalVersionedData)
+ const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
diff --git a/app/scripts/migrations/013.js b/app/scripts/migrations/013.js
new file mode 100644
index 000000000..8f11e510e
--- /dev/null
+++ b/app/scripts/migrations/013.js
@@ -0,0 +1,34 @@
+const version = 13
+
+/*
+
+This migration modifies the network config from ambiguous 'testnet' to explicit 'ropsten'
+
+*/
+
+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
+ if (newState.config.provider.type === 'testnet') {
+ newState.config.provider.type = 'ropsten'
+ }
+ return newState
+}
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/_multi-keyring.js b/app/scripts/migrations/_multi-keyring.js
index 04c966d4d..253aa3d9d 100644
--- a/app/scripts/migrations/_multi-keyring.js
+++ b/app/scripts/migrations/_multi-keyring.js
@@ -15,15 +15,15 @@ const KeyringController = require('../../app/scripts/lib/keyring-controller')
const password = 'obviously not correct'
module.exports = {
- version,
+ version,
migrate: function (versionedData) {
versionedData.meta.version = version
- let store = new ObservableStore(versionedData.data)
- let configManager = new ConfigManager({ store })
- let idStoreMigrator = new IdentityStoreMigrator({ configManager })
- let keyringController = new KeyringController({
+ const store = new ObservableStore(versionedData.data)
+ const configManager = new ConfigManager({ store })
+ const idStoreMigrator = new IdentityStoreMigrator({ configManager })
+ const keyringController = new KeyringController({
configManager: configManager,
})
@@ -46,6 +46,5 @@ module.exports = {
return Promise.resolve(versionedData)
})
})
-
},
}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 019b4d13d..fb1ad7863 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -23,4 +23,6 @@ module.exports = [
require('./010'),
require('./011'),
require('./012'),
+ require('./013'),
+ require('./014'),
]
diff --git a/app/scripts/popup-core.js b/app/scripts/popup-core.js
index 1e5d70e8b..f1eb394d7 100644
--- a/app/scripts/popup-core.js
+++ b/app/scripts/popup-core.js
@@ -1,7 +1,7 @@
const EventEmitter = require('events').EventEmitter
const async = require('async')
const Dnode = require('dnode')
-const Web3 = require('web3')
+const EthQuery = require('eth-query')
const launchMetamaskUi = require('../../ui')
const StreamProvider = require('web3-stream-provider')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
@@ -16,7 +16,6 @@ function initializePopup ({ container, connectionStream }, cb) {
(cb) => connectToAccountManager(connectionStream, cb),
(accountManager, cb) => launchMetamaskUi({ container, accountManager }, cb),
], cb)
-
}
function connectToAccountManager (connectionStream, cb) {
@@ -33,7 +32,8 @@ function setupWeb3Connection (connectionStream) {
providerStream.pipe(connectionStream).pipe(providerStream)
connectionStream.on('error', console.error.bind(console))
providerStream.on('error', console.error.bind(console))
- global.web3 = new Web3(providerStream)
+ global.ethereumProvider = providerStream
+ global.ethQuery = new EthQuery(providerStream)
}
function setupControllerConnection (connectionStream, cb) {
diff --git a/app/scripts/popup.js b/app/scripts/popup.js
index 0fbde54b3..5f17f0651 100644
--- a/app/scripts/popup.js
+++ b/app/scripts/popup.js
@@ -41,7 +41,7 @@ function closePopupIfOpen (windowType) {
}
}
-function displayCriticalError(err) {
+function displayCriticalError (err) {
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
container.style.height = '80px'
log.error(err.stack)