1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-23 11:46:13 +02:00
metamask-extension/app/scripts/controllers/network/network.js

253 lines
7.8 KiB
JavaScript
Raw Normal View History

import assert from 'assert'
import EventEmitter from 'events'
import ObservableStore from 'obs-store'
import ComposedStore from 'obs-store/lib/composed'
import EthQuery from 'eth-query'
import JsonRpcEngine from 'json-rpc-engine'
import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'
import log from 'loglevel'
import createMetamaskMiddleware from './createMetamaskMiddleware'
import createInfuraClient from './createInfuraClient'
import createJsonRpcClient from './createJsonRpcClient'
import createLocalhostClient from './createLocalhostClient'
import { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy'
import extend from 'extend'
const networks = { networkList: {} }
import { ROPSTEN, RINKEBY, KOVAN, MAINNET, LOCALHOST, GOERLI } from './enums'
2019-04-17 19:34:49 +02:00
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET, GOERLI]
const env = process.env.METAMASK_ENV
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
let defaultProviderConfigType
if (process.env.IN_TEST === 'true') {
defaultProviderConfigType = LOCALHOST
} else if (METAMASK_DEBUG || env === 'test') {
defaultProviderConfigType = RINKEBY
} else {
defaultProviderConfigType = MAINNET
}
const defaultProviderConfig = {
type: defaultProviderConfigType,
}
const defaultNetworkConfig = {
ticker: 'ETH',
}
export default class NetworkController extends EventEmitter {
constructor (opts = {}) {
super()
// parse options
const providerConfig = opts.provider || defaultProviderConfig
// create stores
this.providerStore = new ObservableStore(providerConfig)
2017-09-27 23:10:58 +02:00
this.networkStore = new ObservableStore('loading')
this.networkConfig = new ObservableStore(defaultNetworkConfig)
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
2017-05-23 08:12:28 +02:00
this.on('networkDidChange', this.lookupNetwork)
// provider and block tracker
this._provider = null
this._blockTracker = null
// provider and block tracker proxies - because the network changes
this._providerProxy = null
this._blockTrackerProxy = null
2017-05-23 07:56:10 +02:00
}
initializeProvider (providerParams) {
this._baseProviderParams = providerParams
const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
this.lookupNetwork()
}
// return the proxies so the references will always be good
2018-05-17 06:08:19 +02:00
getProviderAndBlockTracker () {
const provider = this._providerProxy
const blockTracker = this._blockTrackerProxy
return { provider, blockTracker }
}
2017-05-23 07:56:10 +02:00
verifyNetwork () {
2017-09-30 01:09:38 +02:00
// Check network when restoring connectivity:
if (this.isNetworkLoading()) {
this.lookupNetwork()
}
}
getNetworkState () {
2017-05-23 08:12:28 +02:00
return this.networkStore.getState()
}
getNetworkConfig () {
return this.networkConfig.getState()
}
setNetworkState (network, type) {
if (network === 'loading') {
return this.networkStore.putState(network)
}
// type must be defined
if (!type) {
return
}
network = networks.networkList[type] && networks.networkList[type].chainId ? networks.networkList[type].chainId : network
2017-05-23 08:12:28 +02:00
return this.networkStore.putState(network)
}
isNetworkLoading () {
return this.getNetworkState() === 'loading'
}
2017-05-23 08:12:28 +02:00
lookupNetwork () {
// Prevent firing when provider is not defined.
if (!this._provider) {
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
}
const { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider)
const initialNetwork = this.getNetworkState()
2018-11-03 20:28:59 +01:00
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
const currentNetwork = this.getNetworkState()
if (initialNetwork === currentNetwork) {
if (err) {
return this.setNetworkState('loading')
}
log.info('web3.getNetwork returned ' + network)
this.setNetworkState(network, type)
}
})
}
New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form.
2019-05-09 19:27:14 +02:00
setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
const providerConfig = {
2017-05-23 08:12:28 +02:00
type: 'rpc',
rpcTarget,
chainId,
ticker,
nickname,
New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form.
2019-05-09 19:27:14 +02:00
rpcPrefs,
}
this.providerConfig = providerConfig
}
async setProviderType (type, rpcTarget = '', ticker = 'ETH', nickname = '') {
assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`)
assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`)
const providerConfig = { type, rpcTarget, ticker, nickname }
this.providerConfig = providerConfig
}
resetConnection () {
this.providerConfig = this.getProviderConfig()
}
set providerConfig (providerConfig) {
this.providerStore.updateState(providerConfig)
this._switchNetwork(providerConfig)
}
2017-05-23 08:12:28 +02:00
getProviderConfig () {
return this.providerStore.getState()
}
2017-09-30 01:09:38 +02:00
//
// Private
//
_switchNetwork (opts) {
2017-09-30 01:09:38 +02:00
this.setNetworkState('loading')
this._configureProvider(opts)
this.emit('networkDidChange', opts.type)
2017-09-30 01:09:38 +02:00
}
_configureProvider (opts) {
const { type, rpcTarget, chainId, ticker, nickname } = opts
// infura type-based endpoints
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
if (isInfura) {
this._configureInfuraProvider(opts)
// other type-based rpc endpoints
} else if (type === LOCALHOST) {
this._configureLocalhostProvider()
// url-based rpc endpoints
2018-05-17 06:08:19 +02:00
} else if (type === 'rpc') {
this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
}
}
_configureInfuraProvider ({ type }) {
log.info('NetworkController - configureInfuraProvider', type)
const networkClient = createInfuraClient({
network: type,
onRequest: (req) => this.emit('rpc-req', { network: type, req }),
})
this._setNetworkClient(networkClient)
// setup networkConfig
const settings = {
ticker: 'ETH',
}
this.networkConfig.putState(settings)
}
_configureLocalhostProvider () {
log.info('NetworkController - configureLocalhostProvider')
const networkClient = createLocalhostClient()
this._setNetworkClient(networkClient)
}
_configureStandardProvider ({ rpcUrl, chainId, ticker, nickname }) {
log.info('NetworkController - configureStandardProvider', rpcUrl)
const networkClient = createJsonRpcClient({ rpcUrl })
// hack to add a 'rpc' network with chainId
networks.networkList['rpc'] = {
chainId: chainId,
rpcUrl,
ticker: ticker || 'ETH',
nickname,
}
// setup networkConfig
let settings = {
network: chainId,
}
settings = extend(settings, networks.networkList['rpc'])
this.networkConfig.putState(settings)
this._setNetworkClient(networkClient)
}
_setNetworkClient ({ networkMiddleware, blockTracker }) {
const metamaskMiddleware = createMetamaskMiddleware(this._baseProviderParams)
const engine = new JsonRpcEngine()
engine.push(metamaskMiddleware)
engine.push(networkMiddleware)
const provider = providerFromEngine(engine)
this._setProviderAndBlockTracker({ provider, blockTracker })
}
_setProviderAndBlockTracker ({ provider, blockTracker }) {
// update or intialize proxies
if (this._providerProxy) {
this._providerProxy.setTarget(provider)
} else {
this._providerProxy = createSwappableProxy(provider)
}
if (this._blockTrackerProxy) {
this._blockTrackerProxy.setTarget(blockTracker)
} else {
this._blockTrackerProxy = createEventEmitterProxy(blockTracker, { eventFilter: 'skipInternal' })
}
// set new provider and blockTracker
this._provider = provider
this._blockTracker = blockTracker
}
}