mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'master' into Version-3.7.1
This commit is contained in:
commit
6be1aa82c0
10
CHANGELOG.md
10
CHANGELOG.md
@ -2,6 +2,16 @@
|
||||
|
||||
## Current Master
|
||||
|
||||
- Now when switching networks the extension does not restart
|
||||
|
||||
## 3.7.0 2017-5-23
|
||||
|
||||
- Add Transaction Number (nonce) to transaction list.
|
||||
- Label the pending tx icon with a tooltip.
|
||||
- Fix bug where website filters would pile up and not deallocate when leaving a site.
|
||||
- Continually resubmit pending txs for a period of time to ensure successful broadcast.
|
||||
- ENS names will no longer resolve to their owner if no resolver is set. Resolvers must be explicitly set and configured.
|
||||
|
||||
## 3.6.5 2017-5-17
|
||||
|
||||
- Fix bug where edited gas parameters would not take effect.
|
||||
|
128
app/scripts/controllers/network.js
Normal file
128
app/scripts/controllers/network.js
Normal file
@ -0,0 +1,128 @@
|
||||
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 = 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)
|
||||
}
|
||||
}
|
@ -4,11 +4,14 @@ const extend = require('xtend')
|
||||
const Semaphore = require('semaphore')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const EthQuery = require('eth-query')
|
||||
const TxProviderUtil = require('../lib/tx-utils')
|
||||
const createId = require('../lib/random-id')
|
||||
const denodeify = require('denodeify')
|
||||
|
||||
module.exports = class TransactionManager extends EventEmitter {
|
||||
const RETRY_LIMIT = 200
|
||||
const RESUBMIT_INTERVAL = 10000 // Ten seconds
|
||||
|
||||
module.exports = class TransactionController extends EventEmitter {
|
||||
constructor (opts) {
|
||||
super()
|
||||
this.store = new ObservableStore(extend({
|
||||
@ -20,8 +23,8 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
this.txHistoryLimit = opts.txHistoryLimit
|
||||
this.provider = opts.provider
|
||||
this.blockTracker = opts.blockTracker
|
||||
this.query = new EthQuery(this.provider)
|
||||
this.txProviderUtils = new TxProviderUtil(this.provider)
|
||||
this.query = opts.ethQuery
|
||||
this.txProviderUtils = new TxProviderUtil(this.query)
|
||||
this.blockTracker.on('block', this.checkForTxInBlock.bind(this))
|
||||
this.signEthTx = opts.signTransaction
|
||||
this.nonceLock = Semaphore(1)
|
||||
@ -31,6 +34,8 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
this.store.subscribe(() => this._updateMemstore())
|
||||
this.networkStore.subscribe(() => this._updateMemstore())
|
||||
this.preferencesStore.subscribe(() => this._updateMemstore())
|
||||
|
||||
this.continuallyResubmitPendingTxs()
|
||||
}
|
||||
|
||||
getState () {
|
||||
@ -38,7 +43,7 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
}
|
||||
|
||||
getNetwork () {
|
||||
return this.networkStore.getState().network
|
||||
return this.networkStore.getState()
|
||||
}
|
||||
|
||||
getSelectedAddress () {
|
||||
@ -230,7 +235,11 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
publishTransaction (txId, rawTx, cb) {
|
||||
publishTransaction (txId, rawTx, cb = warn) {
|
||||
const txMeta = this.getTx(txId)
|
||||
txMeta.rawTx = rawTx
|
||||
this.updateTx(txMeta)
|
||||
|
||||
this.txProviderUtils.publishTransaction(rawTx, (err, txHash) => {
|
||||
if (err) return cb(err)
|
||||
this.setTxHash(txId, txHash)
|
||||
@ -353,7 +362,7 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
message: 'There was a problem loading this transaction.',
|
||||
}
|
||||
this.updateTx(txMeta)
|
||||
return console.error(err)
|
||||
return log.error(err)
|
||||
}
|
||||
if (txParams.blockNumber) {
|
||||
this.setTxStatusConfirmed(txId)
|
||||
@ -379,6 +388,7 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
this.emit(`${txMeta.id}:${status}`, txId)
|
||||
if (status === 'submitted' || status === 'rejected') {
|
||||
this.emit(`${txMeta.id}:finished`, txMeta)
|
||||
|
||||
}
|
||||
this.updateTx(txMeta)
|
||||
this.emit('updateBadge')
|
||||
@ -398,7 +408,47 @@ module.exports = class TransactionManager extends EventEmitter {
|
||||
})
|
||||
this.memStore.updateState({ unapprovedTxs, selectedAddressTxList })
|
||||
}
|
||||
|
||||
continuallyResubmitPendingTxs () {
|
||||
const pending = this.getTxsByMetaData('status', 'submitted')
|
||||
const resubmit = denodeify(this.resubmitTx.bind(this))
|
||||
Promise.all(pending.map(txMeta => resubmit(txMeta)))
|
||||
.catch((reason) => {
|
||||
log.info('Problem resubmitting tx', reason)
|
||||
})
|
||||
.then(() => {
|
||||
global.setTimeout(() => {
|
||||
this.continuallyResubmitPendingTxs()
|
||||
}, RESUBMIT_INTERVAL)
|
||||
})
|
||||
}
|
||||
|
||||
resubmitTx (txMeta, cb) {
|
||||
// Increment a try counter.
|
||||
if (!('retryCount' in txMeta)) {
|
||||
txMeta.retryCount = 0
|
||||
}
|
||||
|
||||
// Only auto-submit already-signed txs:
|
||||
if (!('rawTx' in txMeta)) {
|
||||
return cb()
|
||||
}
|
||||
|
||||
if (txMeta.retryCount > RETRY_LIMIT) {
|
||||
txMeta.err = {
|
||||
isWarning: true,
|
||||
message: 'Gave up submitting tx.',
|
||||
}
|
||||
this.updateTx(txMeta)
|
||||
return log.error(txMeta.err.message)
|
||||
}
|
||||
|
||||
txMeta.retryCount++
|
||||
const rawTx = txMeta.rawTx
|
||||
this.txProviderUtils.publishTransaction(rawTx, cb)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const warn = () => console.warn('warn was used no cb provided')
|
||||
const warn = () => log.warn('warn was used no cb provided')
|
||||
|
@ -3,7 +3,8 @@
|
||||
//
|
||||
|
||||
module.exports = {
|
||||
config: {
|
||||
config: {},
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: 'rinkeby',
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
const MetamaskConfig = require('../config.js')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const normalize = require('eth-sig-util').normalize
|
||||
const MetamaskConfig = require('../config.js')
|
||||
|
||||
|
||||
const MAINNET_RPC = MetamaskConfig.network.mainnet
|
||||
const ROPSTEN_RPC = MetamaskConfig.network.ropsten
|
||||
@ -33,36 +34,6 @@ ConfigManager.prototype.getConfig = function () {
|
||||
return data.config
|
||||
}
|
||||
|
||||
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: 'rpc',
|
||||
rpcTarget: rpcUrl,
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.setProviderType = function (type) {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: type,
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.useEtherscanProvider = function () {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: 'etherscan',
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.getProvider = function () {
|
||||
var config = this.getConfig()
|
||||
return config.provider
|
||||
}
|
||||
|
||||
ConfigManager.prototype.setData = function (data) {
|
||||
this.store.putState(data)
|
||||
}
|
||||
@ -136,6 +107,35 @@ ConfigManager.prototype.getSeedWords = function () {
|
||||
var data = this.getData()
|
||||
return data.seedWords
|
||||
}
|
||||
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: 'rpc',
|
||||
rpcTarget: rpcUrl,
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.setProviderType = function (type) {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: type,
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.useEtherscanProvider = function () {
|
||||
var config = this.getConfig()
|
||||
config.provider = {
|
||||
type: 'etherscan',
|
||||
}
|
||||
this.setConfig(config)
|
||||
}
|
||||
|
||||
ConfigManager.prototype.getProvider = function () {
|
||||
var config = this.getConfig()
|
||||
return config.provider
|
||||
}
|
||||
|
||||
ConfigManager.prototype.getCurrentRpcAddress = function () {
|
||||
var provider = this.getProvider()
|
||||
|
@ -1,5 +1,7 @@
|
||||
const pipe = require('pump')
|
||||
const StreamProvider = require('web3-stream-provider')
|
||||
const ProviderEngine = require('web3-provider-engine')
|
||||
const FilterSubprovider = require('web3-provider-engine/subproviders/filters')
|
||||
const StreamSubprovider = require('web3-provider-engine/subproviders/stream')
|
||||
const LocalStorageStore = require('obs-store')
|
||||
const ObjectMultiplex = require('./obj-multiplex')
|
||||
const createRandomId = require('./random-id')
|
||||
@ -27,14 +29,24 @@ function MetamaskInpageProvider (connectionStream) {
|
||||
)
|
||||
|
||||
// connect to async provider
|
||||
const asyncProvider = self.asyncProvider = new StreamProvider()
|
||||
const engine = new ProviderEngine()
|
||||
|
||||
const filterSubprovider = new FilterSubprovider()
|
||||
engine.addProvider(filterSubprovider)
|
||||
|
||||
const streamSubprovider = new StreamSubprovider()
|
||||
engine.addProvider(streamSubprovider)
|
||||
|
||||
pipe(
|
||||
asyncProvider,
|
||||
streamSubprovider,
|
||||
multiStream.createStream('provider'),
|
||||
asyncProvider,
|
||||
streamSubprovider,
|
||||
(err) => logStreamDisconnectWarning('MetaMask RpcProvider', err)
|
||||
)
|
||||
|
||||
// start polling
|
||||
engine.start()
|
||||
|
||||
self.idMap = {}
|
||||
// handle sendAsync requests via asyncProvider
|
||||
self.sendAsync = function (payload, cb) {
|
||||
@ -46,7 +58,7 @@ function MetamaskInpageProvider (connectionStream) {
|
||||
return message
|
||||
})
|
||||
// forward to asyncProvider
|
||||
asyncProvider.sendAsync(request, function (err, res) {
|
||||
engine.sendAsync(request, function (err, res) {
|
||||
if (err) return cb(err)
|
||||
// transform messages to original ids
|
||||
eachJsonMessage(res, (message) => {
|
||||
|
@ -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) {
|
||||
|
@ -7,9 +7,9 @@ const ObservableStore = require('obs-store')
|
||||
const EthStore = require('./lib/eth-store')
|
||||
const EthQuery = require('eth-query')
|
||||
const streamIntoProvider = require('web3-stream-provider/handler')
|
||||
const MetaMaskProvider = require('web3-provider-engine/zero.js')
|
||||
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
|
||||
const KeyringController = require('./keyring-controller')
|
||||
const NetworkController = require('./controllers/network')
|
||||
const PreferencesController = require('./controllers/preferences')
|
||||
const CurrencyController = require('./controllers/currency')
|
||||
const NoticeController = require('./notice-controller')
|
||||
@ -40,8 +40,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.store = new ObservableStore(initState)
|
||||
|
||||
// network store
|
||||
this.networkStore = new ObservableStore({ network: 'loading' })
|
||||
|
||||
this.networkController = new NetworkController(initState.NetworkController)
|
||||
// config manager
|
||||
this.configManager = new ConfigManager({
|
||||
store: this.store,
|
||||
@ -61,8 +61,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
// rpc provider
|
||||
this.provider = this.initializeProvider()
|
||||
this.provider.on('block', this.logBlock.bind(this))
|
||||
this.provider.on('error', this.verifyNetwork.bind(this))
|
||||
|
||||
// eth data query tools
|
||||
this.ethQuery = new EthQuery(this.provider)
|
||||
@ -75,7 +73,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.keyringController = new KeyringController({
|
||||
initState: initState.KeyringController,
|
||||
ethStore: this.ethStore,
|
||||
getNetwork: this.getNetworkState.bind(this),
|
||||
getNetwork: this.networkController.getNetworkState.bind(this.networkController),
|
||||
})
|
||||
this.keyringController.on('newAccount', (address) => {
|
||||
this.preferencesController.setSelectedAddress(address)
|
||||
@ -92,13 +90,14 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
// tx mgmt
|
||||
this.txController = new TransactionController({
|
||||
initState: initState.TransactionController || initState.TransactionManager,
|
||||
networkStore: this.networkStore,
|
||||
networkStore: this.networkController.networkStore,
|
||||
preferencesStore: this.preferencesController.store,
|
||||
txHistoryLimit: 40,
|
||||
getNetwork: this.getNetworkState.bind(this),
|
||||
getNetwork: this.networkController.getNetworkState.bind(this),
|
||||
signTransaction: this.keyringController.signTransaction.bind(this.keyringController),
|
||||
provider: this.provider,
|
||||
blockTracker: this.provider,
|
||||
ethQuery: this.ethQuery,
|
||||
})
|
||||
|
||||
// notices
|
||||
@ -113,7 +112,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
initState: initState.ShapeShiftController,
|
||||
})
|
||||
|
||||
this.lookupNetwork()
|
||||
this.networkController.lookupNetwork()
|
||||
this.messageManager = new MessageManager()
|
||||
this.personalMessageManager = new PersonalMessageManager()
|
||||
this.publicConfigStore = this.initPublicConfigStore()
|
||||
@ -140,9 +139,12 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.shapeshiftController.store.subscribe((state) => {
|
||||
this.store.updateState({ ShapeShiftController: state })
|
||||
})
|
||||
this.networkController.store.subscribe((state) => {
|
||||
this.store.updateState({ NetworkController: state })
|
||||
})
|
||||
|
||||
// manual mem state subscriptions
|
||||
this.networkStore.subscribe(this.sendUpdate.bind(this))
|
||||
this.networkController.store.subscribe(this.sendUpdate.bind(this))
|
||||
this.ethStore.subscribe(this.sendUpdate.bind(this))
|
||||
this.txController.memStore.subscribe(this.sendUpdate.bind(this))
|
||||
this.messageManager.memStore.subscribe(this.sendUpdate.bind(this))
|
||||
@ -160,12 +162,12 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
//
|
||||
|
||||
initializeProvider () {
|
||||
const provider = MetaMaskProvider({
|
||||
return this.networkController.initializeProvider({
|
||||
static: {
|
||||
eth_syncing: false,
|
||||
web3_clientVersion: `MetaMask/v${version}`,
|
||||
},
|
||||
rpcUrl: this.configManager.getCurrentRpcAddress(),
|
||||
rpcUrl: this.networkController.getCurrentRpcAddress(),
|
||||
// account mgmt
|
||||
getAccounts: (cb) => {
|
||||
const isUnlocked = this.keyringController.memStore.getState().isUnlocked
|
||||
@ -185,7 +187,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
// new style msg signing
|
||||
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
|
||||
})
|
||||
return provider
|
||||
}
|
||||
|
||||
initPublicConfigStore () {
|
||||
@ -221,7 +222,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
{
|
||||
isInitialized,
|
||||
},
|
||||
this.networkStore.getState(),
|
||||
this.networkController.store.getState(),
|
||||
this.ethStore.getState(),
|
||||
this.txController.memStore.getState(),
|
||||
this.messageManager.memStore.getState(),
|
||||
@ -255,8 +256,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
return {
|
||||
// etc
|
||||
getState: (cb) => cb(null, this.getState()),
|
||||
setProviderType: this.setProviderType.bind(this),
|
||||
useEtherscanProvider: this.useEtherscanProvider.bind(this),
|
||||
setProviderType: this.networkController.setProviderType.bind(this.networkController),
|
||||
setCurrentCurrency: this.setCurrentCurrency.bind(this),
|
||||
markAccountsFound: this.markAccountsFound.bind(this),
|
||||
// coinbase
|
||||
@ -590,10 +590,6 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
//
|
||||
|
||||
// Log blocks
|
||||
logBlock (block) {
|
||||
log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
|
||||
this.verifyNetwork()
|
||||
}
|
||||
|
||||
setCurrentCurrency (currencyCode, cb) {
|
||||
try {
|
||||
@ -612,7 +608,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
buyEth (address, amount) {
|
||||
if (!amount) amount = '5'
|
||||
const network = this.getNetworkState()
|
||||
const network = this.networkController.getNetworkState()
|
||||
const url = getBuyEthUrl({ network, address, amount })
|
||||
if (url) this.platform.openWindow({ url })
|
||||
}
|
||||
@ -620,69 +616,21 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
createShapeShiftTx (depositAddress, depositType) {
|
||||
this.shapeshiftController.createShapeShiftTx(depositAddress, depositType)
|
||||
}
|
||||
|
||||
//
|
||||
// network
|
||||
//
|
||||
|
||||
verifyNetwork () {
|
||||
// Check network when restoring connectivity:
|
||||
if (this.isNetworkLoading()) this.lookupNetwork()
|
||||
}
|
||||
// network
|
||||
|
||||
setDefaultRpc () {
|
||||
this.configManager.setRpcTarget('http://localhost:8545')
|
||||
this.platform.reload()
|
||||
this.lookupNetwork()
|
||||
this.networkController.setRpcTarget('http://localhost:8545')
|
||||
return Promise.resolve('http://localhost:8545')
|
||||
}
|
||||
|
||||
setCustomRpc (rpcTarget, rpcList) {
|
||||
this.configManager.setRpcTarget(rpcTarget)
|
||||
this.networkController.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 })
|
||||
}
|
||||
|
||||
isNetworkLoading () {
|
||||
return this.getNetworkState() === 'loading'
|
||||
}
|
||||
|
||||
lookupNetwork (err) {
|
||||
if (err) {
|
||||
this.setNetworkState('loading')
|
||||
}
|
||||
|
||||
this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
|
||||
if (err) {
|
||||
this.setNetworkState('loading')
|
||||
return
|
||||
}
|
||||
log.info('web3.getNetwork returned ' + network)
|
||||
this.setNetworkState(network)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
34
app/scripts/migrations/014.js
Normal file
34
app/scripts/migrations/014.js
Normal file
@ -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
|
||||
}
|
@ -24,4 +24,5 @@ module.exports = [
|
||||
require('./011'),
|
||||
require('./012'),
|
||||
require('./013'),
|
||||
require('./014'),
|
||||
]
|
||||
|
@ -69,7 +69,7 @@
|
||||
"ethereumjs-tx": "^1.3.0",
|
||||
"ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
"ethjs-ens": "^1.0.2",
|
||||
"ethjs-ens": "^2.0.0",
|
||||
"express": "^4.14.0",
|
||||
"extension-link-enabler": "^1.0.0",
|
||||
"extensionizer": "^1.0.0",
|
||||
@ -87,6 +87,7 @@
|
||||
"mississippi": "^1.2.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"multiplex": "^6.7.0",
|
||||
"number-to-bn": "^1.7.0",
|
||||
"obs-store": "^2.3.1",
|
||||
"once": "^1.3.3",
|
||||
"ping-pong-stream": "^1.0.0",
|
||||
@ -121,7 +122,7 @@
|
||||
"valid-url": "^1.0.9",
|
||||
"vreme": "^3.0.2",
|
||||
"web3": "0.18.2",
|
||||
"web3-provider-engine": "^12.0.6",
|
||||
"web3-provider-engine": "^12.1.0",
|
||||
"web3-stream-provider": "^2.0.6",
|
||||
"xtend": "^4.0.1"
|
||||
},
|
||||
|
74
test/unit/network-contoller-test.js
Normal file
74
test/unit/network-contoller-test.js
Normal file
@ -0,0 +1,74 @@
|
||||
const EventEmitter = require('events')
|
||||
const assert = require('assert')
|
||||
const NetworkController = require('../../app/scripts/controllers/network')
|
||||
|
||||
describe('# Network Controller', function () {
|
||||
let networkController
|
||||
|
||||
beforeEach(function () {
|
||||
networkController = new NetworkController({
|
||||
provider: {
|
||||
type: 'rinkeby',
|
||||
},
|
||||
})
|
||||
// stub out provider
|
||||
networkController._provider = new EventEmitter()
|
||||
networkController.providerInit = {
|
||||
getAccounts: () => {},
|
||||
}
|
||||
|
||||
networkController.ethQuery = new Proxy({}, {
|
||||
get: (obj, name) => {
|
||||
return () => {}
|
||||
},
|
||||
})
|
||||
})
|
||||
describe('network', function () {
|
||||
describe('#provider', function() {
|
||||
it('provider should be updatable without reassignment', function () {
|
||||
networkController.initializeProvider(networkController.providerInit)
|
||||
const provider = networkController.provider
|
||||
networkController._provider = {test: true}
|
||||
assert.ok(provider.test)
|
||||
})
|
||||
})
|
||||
describe('#getNetworkState', function () {
|
||||
it('should return loading when new', function () {
|
||||
let networkState = networkController.getNetworkState()
|
||||
assert.equal(networkState, 'loading', 'network is loading')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#setNetworkState', function () {
|
||||
it('should update the network', function () {
|
||||
networkController.setNetworkState(1)
|
||||
let networkState = networkController.getNetworkState()
|
||||
assert.equal(networkState, 1, 'network is 1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('#getRpcAddressForType', function () {
|
||||
it('should return the right rpc address', function () {
|
||||
let rpcTarget = networkController.getRpcAddressForType('mainnet')
|
||||
assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress')
|
||||
})
|
||||
})
|
||||
describe('#setProviderType', function () {
|
||||
it('should update provider.type', function () {
|
||||
networkController.setProviderType('mainnet')
|
||||
const type = networkController.getProviderConfig().type
|
||||
assert.equal(type, 'mainnet', 'provider type is updated')
|
||||
})
|
||||
it('should set the network to loading', function () {
|
||||
networkController.setProviderType('mainnet')
|
||||
const loading = networkController.isNetworkLoading()
|
||||
assert.ok(loading, 'network is loading')
|
||||
})
|
||||
it('should set the right rpcTarget', function () {
|
||||
networkController.setProviderType('mainnet')
|
||||
const rpcTarget = networkController.getProviderConfig().rpcTarget
|
||||
assert.equal(rpcTarget, 'https://mainnet.infura.io/metamask', 'returns the right rpcAddress')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -2,6 +2,7 @@ const assert = require('assert')
|
||||
const EventEmitter = require('events')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const EthTx = require('ethereumjs-tx')
|
||||
const EthQuery = require('eth-query')
|
||||
const ObservableStore = require('obs-store')
|
||||
const clone = require('clone')
|
||||
const sinon = require('sinon')
|
||||
@ -16,9 +17,10 @@ describe('Transaction Controller', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
txController = new TransactionController({
|
||||
networkStore: new ObservableStore({ network: currentNetworkId }),
|
||||
networkStore: new ObservableStore(currentNetworkId),
|
||||
txHistoryLimit: 10,
|
||||
blockTracker: new EventEmitter(),
|
||||
ethQuery: new EthQuery(new EventEmitter()),
|
||||
signTransaction: (ethTx) => new Promise((resolve) => {
|
||||
ethTx.sign(privKey)
|
||||
resolve()
|
||||
|
@ -9,7 +9,11 @@ describe('txUtils', function () {
|
||||
let txUtils
|
||||
|
||||
before(function () {
|
||||
txUtils = new TxUtils()
|
||||
txUtils = new TxUtils(new Proxy({}, {
|
||||
get: (obj, name) => {
|
||||
return () => {}
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
describe('chain Id', function () {
|
||||
|
@ -1,6 +1,7 @@
|
||||
const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const Tooltip = require('./tooltip')
|
||||
|
||||
const Identicon = require('./identicon')
|
||||
|
||||
@ -32,11 +33,16 @@ TransactionIcon.prototype.render = function () {
|
||||
})
|
||||
|
||||
case 'submitted':
|
||||
return h('i.fa.fa-ellipsis-h', {
|
||||
return h(Tooltip, {
|
||||
title: 'Pending',
|
||||
position: 'bottom',
|
||||
}, [
|
||||
h('i.fa.fa-ellipsis-h', {
|
||||
style: {
|
||||
fontSize: '27px',
|
||||
},
|
||||
})
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
if (isMsg) {
|
||||
|
@ -8,6 +8,7 @@ const explorerLink = require('../../lib/explorer-link')
|
||||
const CopyButton = require('./copyButton')
|
||||
const vreme = new (require('vreme'))
|
||||
const Tooltip = require('./tooltip')
|
||||
const numberToBN = require('number-to-bn')
|
||||
|
||||
const TransactionIcon = require('./transaction-list-item-icon')
|
||||
const ShiftListItem = require('./shift-list-item')
|
||||
@ -39,6 +40,8 @@ TransactionListItem.prototype.render = function () {
|
||||
txParams = transaction.msgParams
|
||||
}
|
||||
|
||||
const nonce = txParams.nonce ? numberToBN(txParams.nonce).toString(10) : ''
|
||||
|
||||
const isClickable = ('hash' in transaction && isLinkable) || isPending
|
||||
return (
|
||||
h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
|
||||
@ -69,6 +72,22 @@ TransactionListItem.prototype.render = function () {
|
||||
]),
|
||||
]),
|
||||
|
||||
h(Tooltip, {
|
||||
title: 'Transaction Number',
|
||||
position: 'bottom',
|
||||
}, [
|
||||
h('span', {
|
||||
style: {
|
||||
display: 'flex',
|
||||
cursor: 'normal',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '10px',
|
||||
},
|
||||
}, nonce),
|
||||
]),
|
||||
|
||||
h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [
|
||||
domainField(txParams),
|
||||
h('div', date),
|
||||
|
Loading…
Reference in New Issue
Block a user