diff options
Diffstat (limited to 'app/scripts/metamask-controller.js')
-rw-r--r-- | app/scripts/metamask-controller.js | 729 |
1 files changed, 515 insertions, 214 deletions
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index d53094e43..29b13dc62 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1,303 +1,595 @@ +const EventEmitter = require('events') const extend = require('xtend') -const EthStore = require('eth-store') +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 IdentityStore = require('./lib/idStore') -const messageManager = require('./lib/message-manager') -const HostStore = require('./lib/remote-store.js').HostStore -const Web3 = require('web3') +const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex +const KeyringController = require('./keyring-controller') +const PreferencesController = require('./lib/controllers/preferences') +const CurrencyController = require('./lib/controllers/currency') +const NoticeController = require('./notice-controller') +const ShapeShiftController = require('./lib/controllers/shapeshift') +const MessageManager = require('./lib/message-manager') +const TxManager = require('./transaction-manager') const ConfigManager = require('./lib/config-manager') const extension = require('./lib/extension') +const autoFaucet = require('./lib/auto-faucet') +const nodeify = require('./lib/nodeify') +const IdStoreMigrator = require('./lib/idStore-migrator') +const accountImporter = require('./account-import-strategies') -module.exports = class MetamaskController { +const version = require('../manifest.json').version + +module.exports = class MetamaskController extends EventEmitter { constructor (opts) { + super() this.opts = opts - this.configManager = new ConfigManager(opts) - this.idStore = new IdentityStore({ - configManager: this.configManager, + let initState = opts.initState || {} + + // observable state store + this.store = new ObservableStore(initState) + + // network store + this.networkStore = new ObservableStore({ network: 'loading' }) + + // config manager + this.configManager = new ConfigManager({ + store: this.store, + }) + + // preferences controller + this.preferencesController = new PreferencesController({ + initState: initState.PreferencesController, + }) + + // currency controller + this.currencyController = new CurrencyController({ + initState: initState.CurrencyController, + }) + this.currencyController.updateConversionRate() + this.currencyController.scheduleConversionInterval() + + // 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) + this.ethStore = new EthStore({ + provider: this.provider, + blockTracker: this.provider, + }) + + // key mgmt + this.keyringController = new KeyringController({ + initState: initState.KeyringController, + ethStore: this.ethStore, + getNetwork: this.getNetworkState.bind(this), + }) + this.keyringController.on('newAccount', (address) => { + this.preferencesController.setSelectedAddress(address) + autoFaucet(address) + }) + + // tx mgmt + this.txManager = new TxManager({ + initState: initState.TransactionManager, + networkStore: this.networkStore, + preferencesStore: this.preferencesController.store, + txHistoryLimit: 40, + getNetwork: this.getNetworkState.bind(this), + signTransaction: this.keyringController.signTransaction.bind(this.keyringController), + provider: this.provider, + blockTracker: this.provider, + }) + + // notices + this.noticeController = new NoticeController({ + initState: initState.NoticeController, }) - this.provider = this.initializeProvider(opts) - this.ethStore = new EthStore(this.provider) - this.idStore.setStore(this.ethStore) - this.messageManager = messageManager + this.noticeController.updateNoticesList() + // to be uncommented when retrieving notices from a remote server. + // this.noticeController.startPolling() + + this.shapeshiftController = new ShapeShiftController({ + initState: initState.ShapeShiftController, + }) + + this.lookupNetwork() + this.messageManager = new MessageManager() this.publicConfigStore = this.initPublicConfigStore() - this.configManager.setCurrentFiat('USD') - this.configManager.updateConversionRate() - this.scheduleConversionInterval() + + // TEMPORARY UNTIL FULL DEPRECATION: + this.idStoreMigrator = new IdStoreMigrator({ + configManager: this.configManager, + }) + + // manual disk state subscriptions + this.txManager.store.subscribe((state) => { + this.store.updateState({ TransactionManager: state }) + }) + this.keyringController.store.subscribe((state) => { + this.store.updateState({ KeyringController: state }) + }) + this.preferencesController.store.subscribe((state) => { + this.store.updateState({ PreferencesController: state }) + }) + this.currencyController.store.subscribe((state) => { + this.store.updateState({ CurrencyController: state }) + }) + this.noticeController.store.subscribe((state) => { + this.store.updateState({ NoticeController: state }) + }) + this.shapeshiftController.store.subscribe((state) => { + this.store.updateState({ ShapeShiftController: state }) + }) + + // manual mem state subscriptions + this.networkStore.subscribe(this.sendUpdate.bind(this)) + this.ethStore.subscribe(this.sendUpdate.bind(this)) + this.txManager.memStore.subscribe(this.sendUpdate.bind(this)) + this.messageManager.memStore.subscribe(this.sendUpdate.bind(this)) + this.keyringController.memStore.subscribe(this.sendUpdate.bind(this)) + this.preferencesController.store.subscribe(this.sendUpdate.bind(this)) + this.currencyController.store.subscribe(this.sendUpdate.bind(this)) + this.noticeController.memStore.subscribe(this.sendUpdate.bind(this)) + this.shapeshiftController.store.subscribe(this.sendUpdate.bind(this)) } + // + // Constructor helpers + // + + initializeProvider () { + let provider = MetaMaskProvider({ + static: { + eth_syncing: false, + web3_clientVersion: `MetaMask/v${version}`, + }, + rpcUrl: this.configManager.getCurrentRpcAddress(), + // account mgmt + getAccounts: (cb) => { + let selectedAddress = this.preferencesController.getSelectedAddress() + let result = selectedAddress ? [selectedAddress] : [] + cb(null, result) + }, + // tx signing + processTransaction: (txParams, cb) => this.newUnapprovedTransaction(txParams, cb), + // msg signing + processMessage: this.newUnsignedMessage.bind(this), + }) + return provider + } + + initPublicConfigStore () { + // get init state + const publicConfigStore = new ObservableStore() + + // sync publicConfigStore with transform + pipe( + this.store, + storeTransform(selectPublicState.bind(this)), + publicConfigStore + ) + + function selectPublicState(state) { + const result = { selectedAddress: undefined } + try { + result.selectedAddress = state.PreferencesController.selectedAddress + result.networkVersion = this.getNetworkState() + } catch (_) {} + return result + } + + return publicConfigStore + } + + // + // State Management + // + getState () { + + const wallet = this.configManager.getWallet() + const vault = this.keyringController.store.getState().vault + const isInitialized = (!!wallet || !!vault) return extend( + { + isInitialized, + }, + this.networkStore.getState(), this.ethStore.getState(), - this.idStore.getState(), - this.configManager.getConfig() + this.txManager.memStore.getState(), + this.messageManager.memStore.getState(), + this.keyringController.memStore.getState(), + this.preferencesController.store.getState(), + this.currencyController.store.getState(), + this.noticeController.memStore.getState(), + // config manager + this.configManager.getConfig(), + this.shapeshiftController.store.getState(), + { + lostAccounts: this.configManager.getLostAccounts(), + seedWords: this.configManager.getSeedWords(), + } ) } + // + // Remote Features + // + getApi () { - const idStore = this.idStore + const keyringController = this.keyringController + const preferencesController = this.preferencesController + const txManager = this.txManager + const messageManager = this.messageManager + const noticeController = this.noticeController return { - getState: (cb) => { cb(null, this.getState()) }, - setRpcTarget: this.setRpcTarget.bind(this), - setProviderType: this.setProviderType.bind(this), - useEtherscanProvider: this.useEtherscanProvider.bind(this), - agreeToDisclaimer: this.agreeToDisclaimer.bind(this), - setCurrentFiat: this.setCurrentFiat.bind(this), - agreeToEthWarning: this.agreeToEthWarning.bind(this), - - // forward directly to idStore - createNewVault: idStore.createNewVault.bind(idStore), - recoverFromSeed: idStore.recoverFromSeed.bind(idStore), - submitPassword: idStore.submitPassword.bind(idStore), - setSelectedAddress: idStore.setSelectedAddress.bind(idStore), - approveTransaction: idStore.approveTransaction.bind(idStore), - cancelTransaction: idStore.cancelTransaction.bind(idStore), - signMessage: idStore.signMessage.bind(idStore), - cancelMessage: idStore.cancelMessage.bind(idStore), - setLocked: idStore.setLocked.bind(idStore), - clearSeedWordCache: idStore.clearSeedWordCache.bind(idStore), - exportAccount: idStore.exportAccount.bind(idStore), - revealAccount: idStore.revealAccount.bind(idStore), - saveAccountLabel: idStore.saveAccountLabel.bind(idStore), - tryPassword: idStore.tryPassword.bind(idStore), - recoverSeed: idStore.recoverSeed.bind(idStore), + // etc + getState: (cb) => cb(null, this.getState()), + setRpcTarget: this.setRpcTarget.bind(this), + setProviderType: this.setProviderType.bind(this), + useEtherscanProvider: this.useEtherscanProvider.bind(this), + setCurrentCurrency: this.setCurrentCurrency.bind(this), + setGasMultiplier: this.setGasMultiplier.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), + + // vault management + submitPassword: this.submitPassword.bind(this), + + // PreferencesController + setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController), + + // 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), + + // messageManager + signMessage: this.signMessage.bind(this), + cancelMessage: messageManager.rejectMsg.bind(messageManager), + + // notices + checkNotices: noticeController.updateNoticesList.bind(noticeController), + markNoticeRead: noticeController.markNoticeRead.bind(noticeController), } } - setupProviderConnection (stream, originDomain) { - stream.on('data', this.onRpcRequest.bind(this, stream, originDomain)) + setupUntrustedCommunication (connectionStream, originDomain) { + // setup multiplexing + var mx = setupMultiplex(connectionStream) + // connect features + this.setupProviderConnection(mx.createStream('provider'), originDomain) + this.setupPublicConfig(mx.createStream('publicConfig')) } - onRpcRequest (stream, originDomain, request) { - var payloads = Array.isArray(request) ? request : [request] - payloads.forEach(function (payload) { - // Append origin to rpc payload - payload.origin = originDomain - // Append origin to signature request - if (payload.method === 'eth_sendTransaction') { - payload.params[0].origin = originDomain - } else if (payload.method === 'eth_sign') { - payload.params.push({ origin: originDomain }) - } - }) + setupTrustedCommunication (connectionStream, originDomain) { + // setup multiplexing + var mx = setupMultiplex(connectionStream) + // connect features + this.setupControllerConnection(mx.createStream('controller')) + this.setupProviderConnection(mx.createStream('provider'), originDomain) + } - // handle rpc request - this.provider.sendAsync(request, function onPayloadHandled (err, response) { - logger(err, request, response) - if (response) { - try { - stream.write(response) - } catch (err) { - logger(err) - } - } + setupControllerConnection (outStream) { + const api = this.getApi() + const dnode = Dnode(api) + outStream.pipe(dnode).pipe(outStream) + dnode.on('remote', (remote) => { + // push updates to popup + const sendUpdate = remote.sendUpdate.bind(remote) + this.on('update', sendUpdate) }) + } + setupProviderConnection (outStream, originDomain) { + streamIntoProvider(outStream, this.provider, logger) function logger (err, request, response) { if (err) return console.error(err) - if (!request.isMetamaskInternal) { - if (global.METAMASK_DEBUG) { - console.log(`RPC (${originDomain}):`, request, '->', response) - } - if (response.error) { - console.error('Error in RPC response:\n', response.error) - } + if (response.error) { + console.error('Error in RPC response:\n', response.error) + } + if (request.isMetamaskInternal) return + if (global.METAMASK_DEBUG) { + console.log(`RPC (${originDomain}):`, request, '->', response) } } } - sendUpdate () { - if (this.remote) { - this.remote.sendUpdate(this.getState()) - } + setupPublicConfig (outStream) { + pipe( + this.publicConfigStore, + outStream + ) } - initializeProvider (opts) { - const idStore = this.idStore + sendUpdate () { + this.emit('update', this.getState()) + } - var providerOpts = { - rpcUrl: this.configManager.getCurrentRpcAddress(), - // account mgmt - getAccounts: (cb) => { - var selectedAddress = idStore.getSelectedAddress() - var result = selectedAddress ? [selectedAddress] : [] - cb(null, result) - }, - // tx signing - approveTransaction: this.newUnsignedTransaction.bind(this), - signTransaction: idStore.signTransaction.bind(idStore), - // msg signing - approveMessage: this.newUnsignedMessage.bind(this), - signMessage: idStore.signMessage.bind(idStore), - } + // + // Vault Management + // - var provider = MetaMaskProvider(providerOpts) - var web3 = new Web3(provider) - idStore.web3 = web3 - idStore.getNetwork() + submitPassword (password, cb) { + this.migrateOldVaultIfAny(password) + .then(this.keyringController.submitPassword.bind(this.keyringController, password)) + .then((newState) => { cb(null, newState) }) + .catch((reason) => { cb(reason) }) + } - provider.on('block', this.processBlock.bind(this)) - provider.on('error', idStore.getNetwork.bind(idStore)) + // + // Opinionated Keyring Management + // - return provider + addNewAccount (cb) { + const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) + promiseToCallback(this.keyringController.addNewAccount(primaryKeyring))(cb) } - initPublicConfigStore () { - // get init state - var initPublicState = extend( - idStoreToPublic(this.idStore.getState()), - configToPublic(this.configManager.getConfig()) - ) + // Adds the current vault's seed words to the UI's state tree. + // + // Used when creating a first vault, to allow confirmation. + // Also used when revealing the seed words in the confirmation view. + placeSeedWords (cb) { + const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + if (!primaryKeyring) return cb(new Error('MetamaskController - No HD Key Tree found')) + primaryKeyring.serialize() + .then((serialized) => { + const seedWords = serialized.mnemonic + this.configManager.setSeedWords(seedWords) + cb() + }) + } - var publicConfigStore = new HostStore(initPublicState) + // ClearSeedWordCache + // + // Removes the primary account's seed words from the UI's state tree, + // ensuring they are only ever available in the background process. + clearSeedWordCache (cb) { + this.configManager.setSeedWords(null) + cb(null, this.preferencesController.getSelectedAddress()) + } - // subscribe to changes - this.configManager.subscribe(function (state) { - storeSetFromObj(publicConfigStore, configToPublic(state)) - }) - this.idStore.on('update', function (state) { - storeSetFromObj(publicConfigStore, idStoreToPublic(state)) + importAccountWithStrategy (strategy, args, cb) { + accountImporter.importAccount(strategy, args) + .then((privateKey) => { + return this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) }) + .then(keyring => keyring.getAccounts()) + .then((accounts) => this.preferencesController.setSelectedAddress(accounts[0])) + .then(() => { cb(null, this.keyringController.fullUpdate()) }) + .catch((reason) => { cb(reason) }) + } - // idStore substate - function idStoreToPublic (state) { - return { - selectedAddress: state.selectedAddress, - } - } - // config substate - function configToPublic (state) { - return { - provider: state.provider, - selectedAddress: state.selectedAccount, - } - } - // dump obj into store - function storeSetFromObj (store, obj) { - Object.keys(obj).forEach(function (key) { - store.set(key, obj[key]) + + // + // Identity Management + // + + newUnapprovedTransaction (txParams, cb) { + const self = this + self.txManager.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`, (status) => { + switch (status) { + case 'submitted': + return cb(null, txMeta.hash) + case 'rejected': + return cb(new Error('MetaMask Tx Signature: User denied transaction signature.')) + default: + return cb(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(txMeta.txParams)}`)) + } }) - } + }) + } - return publicConfigStore + newUnsignedMessage (msgParams, cb) { + let msgId = this.messageManager.addUnapprovedMessage(msgParams) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + this.messageManager.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return cb(null, data.rawSig) + case 'rejected': + return cb(new Error('MetaMask Message Signature: User denied transaction signature.')) + default: + return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) } - newUnsignedTransaction (txParams, onTxDoneCb) { - const idStore = this.idStore - var state = idStore.getState() + signMessage (msgParams, cb) { + const msgId = msgParams.metamaskId + promiseToCallback( + // sets the status op the message to 'approved' + // and removes the metamaskId for signing + this.messageManager.approveMessage(msgParams) + .then((cleanMsgParams) => { + // signs the message + return this.keyringController.signMessage(cleanMsgParams) + }) + .then((rawSig) => { + // tells the listener that the message has been signed + // and can be returned to the dapp + this.messageManager.setMsgStatusSigned(msgId, rawSig) + }) + )(cb) + } - // It's locked - if (!state.isUnlocked) { - this.opts.unlockAccountMessage() - idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, noop) - // It's unlocked - } else { - idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, (err, txData) => { - if (err) return onTxDoneCb(err) - this.opts.showUnconfirmedTx(txParams, txData, onTxDoneCb) - }) - } + markAccountsFound (cb) { + this.configManager.setLostAccounts([]) + this.sendUpdate() + cb(null, this.getState()) } - newUnsignedMessage (msgParams, cb) { - var state = this.idStore.getState() - if (!state.isUnlocked) { - this.idStore.addUnconfirmedMessage(msgParams, cb) - this.opts.unlockAccountMessage() - } else { - this.addUnconfirmedMessage(msgParams, cb) + // Migrate Old Vault If Any + // @string password + // + // returns Promise() + // + // Temporary step used when logging in. + // Checks if old style (pre-3.0.0) Metamask Vault exists. + // If so, persists that vault in the new vault format + // with the provided password, so the other unlock steps + // may be completed without interruption. + migrateOldVaultIfAny (password) { + + if (!this.checkIfShouldMigrate()) { + return Promise.resolve(password) } + + const keyringController = this.keyringController + + return this.idStoreMigrator.migratedVaultForPassword(password) + .then(this.restoreOldVaultAccounts.bind(this)) + .then(this.restoreOldLostAccounts.bind(this)) + .then(keyringController.persistAllKeyrings.bind(keyringController, password)) + .then(() => password) } - addUnconfirmedMessage (msgParams, cb) { - const idStore = this.idStore - const msgId = idStore.addUnconfirmedMessage(msgParams, cb) - this.opts.showUnconfirmedMessage(msgParams, msgId) + checkIfShouldMigrate() { + return !!this.configManager.getWallet() && !this.configManager.getVault() } - setupPublicConfig (stream) { - var storeStream = this.publicConfigStore.createStream() - stream.pipe(storeStream).pipe(stream) + restoreOldVaultAccounts(migratorOutput) { + const { serialized } = migratorOutput + return this.keyringController.restoreKeyring(serialized) + .then(() => migratorOutput) } - // Log blocks - processBlock (block) { - if (global.METAMASK_DEBUG) { - console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) + restoreOldLostAccounts(migratorOutput) { + const { lostAccounts } = migratorOutput + if (lostAccounts) { + this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address)) + return this.importLostAccounts(migratorOutput) } - this.verifyNetwork() + return Promise.resolve(migratorOutput) } - verifyNetwork () { - // Check network when restoring connectivity: - if (this.idStore._currentState.network === 'loading') { - this.idStore.getNetwork() - } + // IMPORT LOST ACCOUNTS + // @Object with key lostAccounts: @Array accounts <{ address, privateKey }> + // Uses the array's private keys to create a new Simple Key Pair keychain + // and add it to the keyring controller. + importLostAccounts ({ lostAccounts }) { + const privKeys = lostAccounts.map(acct => acct.privateKey) + return this.keyringController.restoreKeyring({ + type: 'Simple Key Pair', + data: privKeys, + }) } + // // config // - agreeToDisclaimer (cb) { - try { - this.configManager.setConfirmed(true) - cb() - } catch (e) { - cb(e) + // Log blocks + logBlock (block) { + if (global.METAMASK_DEBUG) { + console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) } + this.verifyNetwork() } - setCurrentFiat (fiat, cb) { + setCurrentCurrency (currencyCode, cb) { try { - this.configManager.setCurrentFiat(fiat) - this.configManager.updateConversionRate() - this.scheduleConversionInterval() + this.currencyController.setCurrentCurrency(currencyCode) + this.currencyController.updateConversionRate() const data = { - conversionRate: this.configManager.getConversionRate(), - currentFiat: this.configManager.getCurrentFiat(), - conversionDate: this.configManager.getConversionDate(), + conversionRate: this.currencyController.getConversionRate(), + currentFiat: this.currencyController.getCurrentCurrency(), + conversionDate: this.currencyController.getConversionDate(), } - cb(data) - } catch (e) { - cb(null, e) + cb(null, data) + } catch (err) { + cb(err) } } - scheduleConversionInterval () { - if (this.conversionInterval) { - clearInterval(this.conversionInterval) + buyEth (address, amount) { + if (!amount) amount = '5' + + const network = this.getNetworkState() + let url + + switch (network) { + case '1': + url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH` + break + + case '3': + url = 'https://faucet.metamask.io/' + break } - this.conversionInterval = setInterval(() => { - this.configManager.updateConversionRate() - }, 300000) + + if (url) extension.tabs.create({ url }) } - agreeToEthWarning (cb) { + createShapeShiftTx (depositAddress, depositType) { + this.shapeshiftController.createShapeShiftTx(depositAddress, depositType) + } + + setGasMultiplier (gasMultiplier, cb) { try { - this.configManager.setShouldntShowWarning() + this.txManager.setGasMultiplier(gasMultiplier) cb() - } catch (e) { - cb(e) + } catch (err) { + cb(err) } } - // called from popup + // + // network + // + + verifyNetwork () { + // Check network when restoring connectivity: + if (this.isNetworkLoading()) this.lookupNetwork() + } + setRpcTarget (rpcTarget) { this.configManager.setRpcTarget(rpcTarget) extension.runtime.reload() - this.idStore.getNetwork() + this.lookupNetwork() } setProviderType (type) { this.configManager.setProviderType(type) extension.runtime.reload() - this.idStore.getNetwork() + this.lookupNetwork() } useEtherscanProvider () { @@ -305,24 +597,33 @@ module.exports = class MetamaskController { extension.runtime.reload() } - buyEth (address, amount) { - if (!amount) amount = '5' + getNetworkState () { + return this.networkStore.getState().network + } - var network = this.idStore._currentState.network - var url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH` + setNetworkState (network) { + return this.networkStore.updateState({ network }) + } + + isNetworkLoading () { + return this.getNetworkState() === 'loading' + } - if (network === '2') { - url = 'https://testfaucet.metamask.io/' + lookupNetwork (err) { + if (err) { + this.setNetworkState('loading') } - extension.tabs.create({ - url, + 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) }) } - createShapeShiftTx (depositAddress, depositType) { - this.configManager.createShapeShiftTx(depositAddress, depositType) - } } - -function noop () {} |