aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/controllers/network
diff options
context:
space:
mode:
authorAlexander Tseung <alextsg@gmail.com>2018-04-13 05:17:36 +0800
committerAlexander Tseung <alextsg@gmail.com>2018-04-24 01:18:05 +0800
commit9e41f58af2f236389f11bd1d401da73c0d709b2d (patch)
treecf3cb4dbc49e4ac9fa4a5d8c4d08c32e9a6e8052 /app/scripts/controllers/network
parent74c419f9b65841c2966d1fe3b7414bf11e09e0d8 (diff)
downloadtangerine-wallet-browser-9e41f58af2f236389f11bd1d401da73c0d709b2d.tar.gz
tangerine-wallet-browser-9e41f58af2f236389f11bd1d401da73c0d709b2d.tar.zst
tangerine-wallet-browser-9e41f58af2f236389f11bd1d401da73c0d709b2d.zip
Clean up network config
Diffstat (limited to 'app/scripts/controllers/network')
-rw-r--r--app/scripts/controllers/network/enums.js56
-rw-r--r--app/scripts/controllers/network/index.js2
-rw-r--r--app/scripts/controllers/network/network.js218
-rw-r--r--app/scripts/controllers/network/util.js65
4 files changed, 341 insertions, 0 deletions
diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js
new file mode 100644
index 000000000..4f29e301b
--- /dev/null
+++ b/app/scripts/controllers/network/enums.js
@@ -0,0 +1,56 @@
+const ROPSTEN = 'ropsten'
+const RINKEBY = 'rinkeby'
+const KOVAN = 'kovan'
+const MAINNET = 'mainnet'
+const LOCALHOST = 'localhost'
+
+const ROPSTEN_CODE = 3
+const RINKEYBY_CODE = 4
+const KOVAN_CODE = 42
+
+const ROPSTEN_DISPLAY_NAME = 'Ropsten'
+const RINKEBY_DISPLAY_NAME = 'Rinkeby'
+const KOVAN_DISPLAY_NAME = 'Kovan'
+const MAINNET_DISPLAY_NAME = 'Main Ethereum Network'
+
+const MAINNET_RPC_URL = 'https://mainnet.infura.io/metamask'
+const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask'
+const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
+const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask'
+const LOCALHOST_RPC_URL = 'http://localhost:8545'
+
+const MAINNET_RPC_URL_BETA = 'https://mainnet.infura.io/metamask2'
+const ROPSTEN_RPC_URL_BETA = 'https://ropsten.infura.io/metamask2'
+const KOVAN_RPC_URL_BETA = 'https://kovan.infura.io/metamask2'
+const RINKEBY_RPC_URL_BETA = 'https://rinkeby.infura.io/metamask2'
+
+const DEFAULT_NETWORK = 'rinkeby'
+const OLD_UI_NETWORK_TYPE = 'network'
+const BETA_UI_NETWORK_TYPE = 'networkBeta'
+
+module.exports = {
+ ROPSTEN,
+ RINKEBY,
+ KOVAN,
+ MAINNET,
+ LOCALHOST,
+ ROPSTEN_CODE,
+ RINKEYBY_CODE,
+ KOVAN_CODE,
+ ROPSTEN_DISPLAY_NAME,
+ RINKEBY_DISPLAY_NAME,
+ KOVAN_DISPLAY_NAME,
+ MAINNET_DISPLAY_NAME,
+ MAINNET_RPC_URL,
+ ROPSTEN_RPC_URL,
+ KOVAN_RPC_URL,
+ RINKEBY_RPC_URL,
+ LOCALHOST_RPC_URL,
+ MAINNET_RPC_URL_BETA,
+ ROPSTEN_RPC_URL_BETA,
+ KOVAN_RPC_URL_BETA,
+ RINKEBY_RPC_URL_BETA,
+ DEFAULT_NETWORK,
+ OLD_UI_NETWORK_TYPE,
+ BETA_UI_NETWORK_TYPE,
+}
diff --git a/app/scripts/controllers/network/index.js b/app/scripts/controllers/network/index.js
new file mode 100644
index 000000000..fb095bf33
--- /dev/null
+++ b/app/scripts/controllers/network/index.js
@@ -0,0 +1,2 @@
+const NetworkController = require('./network')
+module.exports = NetworkController
diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js
new file mode 100644
index 000000000..6fd983bb2
--- /dev/null
+++ b/app/scripts/controllers/network/network.js
@@ -0,0 +1,218 @@
+const assert = require('assert')
+const EventEmitter = require('events')
+const createMetamaskProvider = require('web3-provider-engine/zero.js')
+const SubproviderFromProvider = require('web3-provider-engine/subproviders/web3.js')
+const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider')
+const ObservableStore = require('obs-store')
+const ComposedStore = require('obs-store/lib/composed')
+const extend = require('xtend')
+const EthQuery = require('eth-query')
+const createEventEmitterProxy = require('../../lib/events-proxy.js')
+const log = require('loglevel')
+const {
+ ROPSTEN,
+ RINKEBY,
+ KOVAN,
+ MAINNET,
+ OLD_UI_NETWORK_TYPE,
+ DEFAULT_NETWORK,
+} = require('./enums')
+const { getNetworkEndpoints } = require('./util')
+const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET]
+
+module.exports = class NetworkController extends EventEmitter {
+
+ constructor (config) {
+ super()
+
+ this._networkEndpointVersion = OLD_UI_NETWORK_TYPE
+ this._networkEndpoints = getNetworkEndpoints(OLD_UI_NETWORK_TYPE)
+ this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
+
+ config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
+ this.networkStore = new ObservableStore('loading')
+ this.providerStore = new ObservableStore(config.provider)
+ this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
+ this._proxy = createEventEmitterProxy()
+
+ this.on('networkDidChange', this.lookupNetwork)
+ }
+
+ async setNetworkEndpoints (version) {
+ if (version === this._networkEndpointVersion) {
+ return
+ }
+
+ this._networkEndpointVersion = version
+ this._networkEndpoints = getNetworkEndpoints(version)
+ this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
+ const { type } = this.getProviderConfig()
+
+ return this.setProviderType(type, true)
+ }
+
+ initializeProvider (_providerParams) {
+ this._baseProviderParams = _providerParams
+ const { type, rpcTarget } = this.providerStore.getState()
+ // map rpcTarget to rpcUrl
+ const opts = {
+ type,
+ rpcUrl: rpcTarget,
+ }
+ this._configureProvider(opts)
+ this._proxy.on('block', this._logBlock.bind(this))
+ this._proxy.on('error', this.verifyNetwork.bind(this))
+ this.ethQuery = new EthQuery(this._proxy)
+ this.lookupNetwork()
+ return this._proxy
+ }
+
+ 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 () {
+ // Prevent firing when provider is not defined.
+ if (!this.ethQuery || !this.ethQuery.sendAsync) {
+ return log.warn('NetworkController - lookupNetwork aborted due to missing ethQuery')
+ }
+ 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,
+ })
+ this._switchNetwork({ rpcUrl })
+ }
+
+ getCurrentRpcAddress () {
+ const provider = this.getProviderConfig()
+ if (!provider) return null
+ return this.getRpcAddressForType(provider.type)
+ }
+
+ async setProviderType (type, forceUpdate = false) {
+ assert(type !== 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`)
+ // skip if type already matches
+ if (type === this.getProviderConfig().type && !forceUpdate) {
+ return
+ }
+
+ const rpcTarget = this.getRpcAddressForType(type)
+ assert(rpcTarget, `NetworkController - unknown rpc address for type "${type}"`)
+ this.providerStore.updateState({ type, rpcTarget })
+ this._switchNetwork({ type })
+ }
+
+ getProviderConfig () {
+ return this.providerStore.getState()
+ }
+
+ getRpcAddressForType (type, provider = this.getProviderConfig()) {
+ if (this._networkEndpoints[type]) {
+ return this._networkEndpoints[type]
+ }
+
+ return provider && provider.rpcTarget ? provider.rpcTarget : this._defaultRpc
+ }
+
+ //
+ // Private
+ //
+
+ _switchNetwork (opts) {
+ this.setNetworkState('loading')
+ this._configureProvider(opts)
+ this.emit('networkDidChange')
+ }
+
+ _configureProvider (opts) {
+ // type-based rpc endpoints
+ const { type } = opts
+ if (type) {
+ // type-based infura rpc endpoints
+ const isInfura = INFURA_PROVIDER_TYPES.includes(type)
+ opts.rpcUrl = this.getRpcAddressForType(type)
+ if (isInfura) {
+ this._configureInfuraProvider(opts)
+ // other type-based rpc endpoints
+ } else {
+ this._configureStandardProvider(opts)
+ }
+ // url-based rpc endpoints
+ } else {
+ this._configureStandardProvider(opts)
+ }
+ }
+
+ _configureInfuraProvider (opts) {
+ log.info('_configureInfuraProvider', opts)
+ const infuraProvider = createInfuraProvider({
+ network: opts.type,
+ })
+ const infuraSubprovider = new SubproviderFromProvider(infuraProvider)
+ const providerParams = extend(this._baseProviderParams, {
+ rpcUrl: opts.rpcUrl,
+ engineParams: {
+ pollingInterval: 8000,
+ blockTrackerProvider: infuraProvider,
+ },
+ dataSubprovider: infuraSubprovider,
+ })
+ const provider = createMetamaskProvider(providerParams)
+ this._setProvider(provider)
+ }
+
+ _configureStandardProvider ({ rpcUrl }) {
+ const providerParams = extend(this._baseProviderParams, {
+ rpcUrl,
+ engineParams: {
+ pollingInterval: 8000,
+ },
+ })
+ const provider = createMetamaskProvider(providerParams)
+ this._setProvider(provider)
+ }
+
+ _setProvider (provider) {
+ // collect old block tracker events
+ const oldProvider = this._provider
+ let blockTrackerHandlers
+ if (oldProvider) {
+ // capture old block handlers
+ blockTrackerHandlers = oldProvider._blockTracker.proxyEventHandlers
+ // tear down
+ oldProvider.removeAllListeners()
+ oldProvider.stop()
+ }
+ // override block tracler
+ provider._blockTracker = createEventEmitterProxy(provider._blockTracker, blockTrackerHandlers)
+ // set as new provider
+ this._provider = provider
+ this._proxy.setTarget(provider)
+ }
+
+ _logBlock (block) {
+ log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`)
+ this.verifyNetwork()
+ }
+}
diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js
new file mode 100644
index 000000000..4f38ccda4
--- /dev/null
+++ b/app/scripts/controllers/network/util.js
@@ -0,0 +1,65 @@
+const {
+ ROPSTEN,
+ RINKEBY,
+ KOVAN,
+ MAINNET,
+ LOCALHOST,
+ ROPSTEN_CODE,
+ RINKEYBY_CODE,
+ KOVAN_CODE,
+ ROPSTEN_DISPLAY_NAME,
+ RINKEBY_DISPLAY_NAME,
+ KOVAN_DISPLAY_NAME,
+ MAINNET_DISPLAY_NAME,
+ MAINNET_RPC_URL,
+ ROPSTEN_RPC_URL,
+ KOVAN_RPC_URL,
+ RINKEBY_RPC_URL,
+ LOCALHOST_RPC_URL,
+ MAINNET_RPC_URL_BETA,
+ ROPSTEN_RPC_URL_BETA,
+ KOVAN_RPC_URL_BETA,
+ RINKEBY_RPC_URL_BETA,
+ OLD_UI_NETWORK_TYPE,
+ BETA_UI_NETWORK_TYPE,
+} = require('./enums')
+
+const networkToNameMap = {
+ [ROPSTEN]: ROPSTEN_DISPLAY_NAME,
+ [RINKEBY]: RINKEBY_DISPLAY_NAME,
+ [KOVAN]: KOVAN_DISPLAY_NAME,
+ [MAINNET]: MAINNET_DISPLAY_NAME,
+ [ROPSTEN_CODE]: ROPSTEN_DISPLAY_NAME,
+ [RINKEYBY_CODE]: RINKEBY_DISPLAY_NAME,
+ [KOVAN_CODE]: KOVAN_DISPLAY_NAME,
+}
+
+const networkEndpointsMap = {
+ [OLD_UI_NETWORK_TYPE]: {
+ [LOCALHOST]: LOCALHOST_RPC_URL,
+ [MAINNET]: MAINNET_RPC_URL,
+ [ROPSTEN]: ROPSTEN_RPC_URL,
+ [KOVAN]: KOVAN_RPC_URL,
+ [RINKEBY]: RINKEBY_RPC_URL,
+ },
+ [BETA_UI_NETWORK_TYPE]: {
+ [LOCALHOST]: LOCALHOST_RPC_URL,
+ [MAINNET]: MAINNET_RPC_URL_BETA,
+ [ROPSTEN]: ROPSTEN_RPC_URL_BETA,
+ [KOVAN]: KOVAN_RPC_URL_BETA,
+ [RINKEBY]: RINKEBY_RPC_URL_BETA,
+ },
+}
+
+const getNetworkDisplayName = key => networkToNameMap[key]
+
+const getNetworkEndpoints = (networkType = OLD_UI_NETWORK_TYPE) => {
+ return {
+ ...networkEndpointsMap[networkType],
+ }
+}
+
+module.exports = {
+ getNetworkDisplayName,
+ getNetworkEndpoints,
+}