A Metamask fork with Infura removed and default networks editable
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
ciphermask/app/scripts/controllers/network/network.js

271 lines
8.0 KiB

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 { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy'
import createMetamaskMiddleware from './createMetamaskMiddleware'
import createInfuraClient from './createInfuraClient'
import createJsonRpcClient from './createJsonRpcClient'
import createLocalhostClient from './createLocalhostClient'
import {
RINKEBY,
MAINNET,
LOCALHOST,
INFURA_PROVIDER_TYPES,
} from './enums'
const networks = { networkList: {} }
const env = process.env.METAMASK_ENV
const { METAMASK_DEBUG } = process.env
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)
this.networkStore = new ObservableStore('loading')
this.networkConfig = new ObservableStore(defaultNetworkConfig)
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore, settings: this.networkConfig })
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
}
/**
* Sets the Infura project ID
*
* @param {string} projectId - The Infura project ID
* @throws {Error} if the project ID is not a valid string
* @return {void}
*/
setInfuraProjectId (projectId) {
if (!projectId || typeof projectId !== 'string') {
throw new Error('Invalid Infura project ID')
}
this._infuraProjectId = projectId
}
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
getProviderAndBlockTracker () {
const provider = this._providerProxy
const blockTracker = this._blockTrackerProxy
return { provider, blockTracker }
}
verifyNetwork () {
// Check network when restoring connectivity:
if (this.isNetworkLoading()) {
this.lookupNetwork()
}
}
getNetworkState () {
return this.networkStore.getState()
}
getNetworkConfig () {
return this.networkConfig.getState()
}
setNetworkState (network, type) {
if (network === 'loading') {
this.networkStore.putState(network)
return
}
// type must be defined
if (!type) {
return
}
this.networkStore.putState(networks.networkList[type]?.chainId || network)
}
isNetworkLoading () {
return this.getNetworkState() === 'loading'
}
lookupNetwork () {
// Prevent firing when provider is not defined.
if (!this._provider) {
log.warn('NetworkController - lookupNetwork aborted due to missing provider')
return
}
const { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider)
const initialNetwork = this.getNetworkState()
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
const currentNetwork = this.getNetworkState()
if (initialNetwork === currentNetwork) {
if (err) {
this.setNetworkState('loading')
return
}
log.info(`web3.getNetwork returned ${network}`)
this.setNetworkState(network, type)
}
})
}
setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
const providerConfig = {
type: 'rpc',
rpcTarget,
chainId,
ticker,
nickname,
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)
}
getProviderConfig () {
return this.providerStore.getState()
}
//
// Private
//
_switchNetwork (opts) {
this.setNetworkState('loading')
this._configureProvider(opts)
this.emit('networkDidChange', opts.type)
}
_configureProvider (opts) {
const { type, rpcTarget, chainId, ticker, nickname } = opts
// infura type-based endpoints
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
if (isInfura) {
this._configureInfuraProvider(type, this._infuraProjectId)
// other type-based rpc endpoints
} else if (type === LOCALHOST) {
this._configureLocalhostProvider()
// url-based rpc endpoints
} else if (type === 'rpc') {
this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
}
}
_configureInfuraProvider (type, projectId) {
log.info('NetworkController - configureInfuraProvider', type)
const networkClient = createInfuraClient({
network: type,
projectId,
})
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,
rpcUrl,
ticker: ticker || 'ETH',
nickname,
}
// setup networkConfig
let settings = {
network: chainId,
}
settings = Object.assign(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
}
}