aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorHackyMiner <hackyminer@gmail.com>2018-10-26 16:26:43 +0800
committerWhymarrh Whitby <whymarrh.whitby@gmail.com>2018-10-26 16:26:43 +0800
commit54a8ade2669cb5f8f046509873bc2a9c25425847 (patch)
treeaaf40ae8168848b89365647bb863d0c967932ef8 /app
parenteaca9a0e8a6a8e65a4dd099c8f860a9616b7360e (diff)
downloadtangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar.gz
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar.bz2
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar.lz
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar.xz
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.tar.zst
tangerine-wallet-browser-54a8ade2669cb5f8f046509873bc2a9c25425847.zip
Add support for RPC endpoints with custom chain IDs (#5134)
Diffstat (limited to 'app')
-rw-r--r--app/_locales/en/messages.json22
-rw-r--r--app/scripts/controllers/currency.js52
-rw-r--r--app/scripts/controllers/network/network.js60
-rw-r--r--app/scripts/controllers/preferences.js31
-rw-r--r--app/scripts/metamask-controller.js18
5 files changed, 148 insertions, 35 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index ca141da5a..5423c76dc 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -692,9 +692,27 @@
"newRecipient": {
"message": "New Recipient"
},
- "newRPC": {
+ "newNetwork": {
+ "message": "New Network"
+ },
+ "rpcURL": {
"message": "New RPC URL"
},
+ "showAdvancedOptions": {
+ "message": "Show Advanced Options"
+ },
+ "hideAdvancedOptions": {
+ "message": "Hide Advanced Options"
+ },
+ "optionalChainId": {
+ "message": "ChainID (optional)"
+ },
+ "optionalSymbol": {
+ "message": "Symbol (optional)"
+ },
+ "optionalNickname": {
+ "message": "Nickname (optional)"
+ },
"next": {
"message": "Next"
},
@@ -803,7 +821,7 @@
"message": "Primary Currency"
},
"primaryCurrencySettingDescription": {
- "message": "Select ETH to prioritize displaying values in ETH. Select Fiat to prioritize displaying values in your selected currency."
+ "message": "Select native to prioritize displaying values in the native currency of the chain (e.g. ETH). Select Fiat to prioritize displaying values in your selected fiat currency."
},
"privacyMsg": {
"message": "Privacy Policy"
diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js
index d5bc5fe2b..1e866d2c9 100644
--- a/app/scripts/controllers/currency.js
+++ b/app/scripts/controllers/currency.js
@@ -21,6 +21,7 @@ class CurrencyController {
* since midnight of January 1, 1970
* @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method.
* Used to clear an existing interval on subsequent calls of that method.
+ * @property {string} nativeCurrency The ticker/symbol of the native chain currency
*
*/
constructor (opts = {}) {
@@ -28,6 +29,7 @@ class CurrencyController {
currentCurrency: 'usd',
conversionRate: 0,
conversionDate: 'N/A',
+ nativeCurrency: 'ETH',
}, opts.initState)
this.store = new ObservableStore(initState)
}
@@ -37,6 +39,29 @@ class CurrencyController {
//
/**
+ * A getter for the nativeCurrency property
+ *
+ * @returns {string} A 2-4 character shorthand that describes the specific currency
+ *
+ */
+ getNativeCurrency () {
+ return this.store.getState().nativeCurrency
+ }
+
+ /**
+ * A setter for the nativeCurrency property
+ *
+ * @param {string} nativeCurrency The new currency to set as the nativeCurrency in the store
+ *
+ */
+ setNativeCurrency (nativeCurrency) {
+ this.store.updateState({
+ nativeCurrency,
+ ticker: nativeCurrency,
+ })
+ }
+
+ /**
* A getter for the currentCurrency property
*
* @returns {string} A 2-4 character shorthand that describes a specific currency, currently selected by the user
@@ -104,15 +129,32 @@ class CurrencyController {
*
*/
async updateConversionRate () {
- let currentCurrency
+ let currentCurrency, nativeCurrency
try {
currentCurrency = this.getCurrentCurrency()
- const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`)
+ nativeCurrency = this.getNativeCurrency()
+ let apiUrl
+ if (nativeCurrency === 'ETH') {
+ apiUrl = `https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`
+ } else {
+ apiUrl = `https://min-api.cryptocompare.com/data/price?fsym=${nativeCurrency.toUpperCase()}&tsyms=${currentCurrency.toUpperCase()}`
+ }
+ const response = await fetch(apiUrl)
const parsedResponse = await response.json()
- this.setConversionRate(Number(parsedResponse.bid))
- this.setConversionDate(Number(parsedResponse.timestamp))
+ if (nativeCurrency === 'ETH') {
+ this.setConversionRate(Number(parsedResponse.bid))
+ this.setConversionDate(Number(parsedResponse.timestamp))
+ } else {
+ if (parsedResponse[currentCurrency.toUpperCase()]) {
+ this.setConversionRate(Number(parsedResponse[currentCurrency.toUpperCase()]))
+ this.setConversionDate(parseInt((new Date()).getTime() / 1000))
+ } else {
+ this.setConversionRate(0)
+ this.setConversionDate('N/A')
+ }
+ }
} catch (err) {
- log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err)
+ log.warn(`MetaMask - Failed to query currency conversion:`, nativeCurrency, currentCurrency, err)
this.setConversionRate(0)
this.setConversionDate('N/A')
}
diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js
index c1667d9a6..b459b8013 100644
--- a/app/scripts/controllers/network/network.js
+++ b/app/scripts/controllers/network/network.js
@@ -11,6 +11,8 @@ const createInfuraClient = require('./createInfuraClient')
const createJsonRpcClient = require('./createJsonRpcClient')
const createLocalhostClient = require('./createLocalhostClient')
const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy')
+const extend = require('extend')
+const networks = { networkList: {} }
const {
ROPSTEN,
@@ -29,6 +31,10 @@ const defaultProviderConfig = {
type: testMode ? RINKEBY : MAINNET,
}
+const defaultNetworkConfig = {
+ ticker: 'ETH',
+}
+
module.exports = class NetworkController extends EventEmitter {
constructor (opts = {}) {
@@ -39,7 +45,8 @@ module.exports = class NetworkController extends EventEmitter {
// create stores
this.providerStore = new ObservableStore(providerConfig)
this.networkStore = new ObservableStore('loading')
- this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
+ 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
@@ -51,8 +58,8 @@ module.exports = class NetworkController extends EventEmitter {
initializeProvider (providerParams) {
this._baseProviderParams = providerParams
- const { type, rpcTarget } = this.providerStore.getState()
- this._configureProvider({ type, rpcTarget })
+ const { type, rpcTarget, chainId, ticker, nickname } = this.providerStore.getState()
+ this._configureProvider({ type, rpcTarget, chainId, ticker, nickname })
this.lookupNetwork()
}
@@ -72,7 +79,20 @@ module.exports = class NetworkController extends EventEmitter {
return this.networkStore.getState()
}
- setNetworkState (network) {
+ 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
return this.networkStore.putState(network)
}
@@ -85,18 +105,22 @@ module.exports = class NetworkController extends EventEmitter {
if (!this._provider) {
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
}
+ var { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider)
ethQuery.sendAsync({ method: 'net_version' }, (err, network) => {
if (err) return this.setNetworkState('loading')
log.info('web3.getNetwork returned ' + network)
- this.setNetworkState(network)
+ this.setNetworkState(network, type)
})
}
- setRpcTarget (rpcTarget) {
+ setRpcTarget (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
const providerConfig = {
type: 'rpc',
rpcTarget,
+ chainId,
+ ticker,
+ nickname,
}
this.providerConfig = providerConfig
}
@@ -132,7 +156,7 @@ module.exports = class NetworkController extends EventEmitter {
}
_configureProvider (opts) {
- const { type, rpcTarget } = opts
+ const { type, rpcTarget, chainId, ticker, nickname } = opts
// infura type-based endpoints
const isInfura = INFURA_PROVIDER_TYPES.includes(type)
if (isInfura) {
@@ -142,7 +166,7 @@ module.exports = class NetworkController extends EventEmitter {
this._configureLocalhostProvider()
// url-based rpc endpoints
} else if (type === 'rpc') {
- this._configureStandardProvider({ rpcUrl: rpcTarget })
+ this._configureStandardProvider({ rpcUrl: rpcTarget, chainId, ticker, nickname })
} else {
throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
}
@@ -152,6 +176,11 @@ module.exports = class NetworkController extends EventEmitter {
log.info('NetworkController - configureInfuraProvider', type)
const networkClient = createInfuraClient({ network: type })
this._setNetworkClient(networkClient)
+ // setup networkConfig
+ var settings = {
+ ticker: 'ETH',
+ }
+ this.networkConfig.putState(settings)
}
_configureLocalhostProvider () {
@@ -160,9 +189,22 @@ module.exports = class NetworkController extends EventEmitter {
this._setNetworkClient(networkClient)
}
- _configureStandardProvider ({ rpcUrl }) {
+ _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
+ var settings = {
+ network: chainId,
+ }
+ settings = extend(settings, networks.networkList['rpc'])
+ this.networkConfig.putState(settings)
this._setNetworkClient(networkClient)
}
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index 20b13398c..120801f06 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -25,7 +25,7 @@ class PreferencesController {
*/
constructor (opts = {}) {
const initState = extend({
- frequentRpcList: [],
+ frequentRpcListDetail: [],
currentAccountTab: 'history',
accountTokens: {},
assetImages: {},
@@ -39,7 +39,7 @@ class PreferencesController {
seedWords: null,
forgottenPassword: false,
preferences: {
- useETHAsPrimaryCurrency: true,
+ useNativeCurrencyAsPrimaryCurrency: true,
},
}, opts.initState)
@@ -392,19 +392,22 @@ class PreferencesController {
* Adds custom RPC url to state.
*
* @param {string} url The RPC url to add to frequentRpcList.
+ * @param {number} chainId Optional chainId of the selected network.
+ * @param {string} ticker Optional ticker symbol of the selected network.
+ * @param {string} nickname Optional nickname of the selected network.
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
*
*/
- addToFrequentRpcList (url) {
- const rpcList = this.getFrequentRpcList()
- const index = rpcList.findIndex((element) => { return element === url })
+ addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '') {
+ const rpcList = this.getFrequentRpcListDetail()
+ const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
if (url !== 'http://localhost:8545') {
- rpcList.push(url)
+ rpcList.push({ rpcUrl: url, chainId, ticker, nickname })
}
- this.store.updateState({ frequentRpcList: rpcList })
+ this.store.updateState({ frequentRpcListiDetail: rpcList })
return Promise.resolve(rpcList)
}
@@ -416,23 +419,23 @@ class PreferencesController {
*
*/
removeFromFrequentRpcList (url) {
- const rpcList = this.getFrequentRpcList()
- const index = rpcList.findIndex((element) => { return element === url })
+ const rpcList = this.getFrequentRpcListDetail()
+ const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
- this.store.updateState({ frequentRpcList: rpcList })
+ this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
}
/**
- * Getter for the `frequentRpcList` property.
+ * Getter for the `frequentRpcListDetail` property.
*
- * @returns {array<string>} An array of one or two rpc urls.
+ * @returns {array<array>} An array of rpc urls.
*
*/
- getFrequentRpcList () {
- return this.store.getState().frequentRpcList
+ getFrequentRpcListDetail () {
+ return this.store.getState().frequentRpcListDetail
}
/**
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 7913662d4..3778dbdb6 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -138,12 +138,12 @@ module.exports = class MetamaskController extends EventEmitter {
this.accountTracker.stop()
}
})
-
+
// ensure accountTracker updates balances after network change
this.networkController.on('networkDidChange', () => {
this.accountTracker._updateAccounts()
})
-
+
// key mgmt
const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring]
this.keyringController = new KeyringController({
@@ -197,6 +197,8 @@ module.exports = class MetamaskController extends EventEmitter {
})
this.networkController.on('networkDidChange', () => {
this.balancesController.updateAllBalances()
+ var currentCurrency = this.currencyController.getCurrentCurrency()
+ this.setCurrentCurrency(currentCurrency, function() {})
})
this.balancesController.updateAllBalances()
@@ -1412,10 +1414,13 @@ module.exports = class MetamaskController extends EventEmitter {
* @param {Function} cb - A callback function returning currency info.
*/
setCurrentCurrency (currencyCode, cb) {
+ const { ticker } = this.networkController.getNetworkConfig()
try {
+ this.currencyController.setNativeCurrency(ticker)
this.currencyController.setCurrentCurrency(currencyCode)
this.currencyController.updateConversionRate()
const data = {
+ nativeCurrency: ticker || 'ETH',
conversionRate: this.currencyController.getConversionRate(),
currentCurrency: this.currencyController.getCurrentCurrency(),
conversionDate: this.currencyController.getConversionDate(),
@@ -1454,11 +1459,14 @@ module.exports = class MetamaskController extends EventEmitter {
/**
* A method for selecting a custom URL for an ethereum RPC provider.
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
+ * @param {number} chainId - The chainId of the selected network.
+ * @param {string} ticker - The ticker symbol of the selected network.
+ * @param {string} nickname - Optional nickname of the selected network.
* @returns {Promise<String>} - The RPC Target URL confirmed.
*/
- async setCustomRpc (rpcTarget) {
- this.networkController.setRpcTarget(rpcTarget)
- await this.preferencesController.addToFrequentRpcList(rpcTarget)
+ async setCustomRpc (rpcTarget, chainId, ticker = 'ETH', nickname = '') {
+ this.networkController.setRpcTarget(rpcTarget, chainId, ticker, nickname)
+ await this.preferencesController.addToFrequentRpcList(rpcTarget, chainId, ticker, nickname)
return rpcTarget
}