aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'app/scripts')
-rw-r--r--app/scripts/background.js2
-rw-r--r--app/scripts/controllers/preferences.js68
-rw-r--r--app/scripts/metamask-controller.js3
3 files changed, 73 insertions, 0 deletions
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 7eb7b1255..c0b00730d 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -253,6 +253,7 @@ function setupController (initState, initLangCode) {
showUnconfirmedMessage: triggerUi,
unlockAccountMessage: triggerUi,
showUnapprovedTx: triggerUi,
+ showAddTokenUi: triggerUi,
// initial state
initState,
// initial locale code
@@ -446,3 +447,4 @@ extension.runtime.onInstalled.addListener(function (details) {
extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
}
})
+
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index 707fd7de9..a42bb77b3 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -1,5 +1,6 @@
const ObservableStore = require('obs-store')
const normalizeAddress = require('eth-sig-util').normalize
+const isValidAddress = require('ethereumjs-util').isValidAddress
const extend = require('xtend')
@@ -27,6 +28,7 @@ class PreferencesController {
currentAccountTab: 'history',
accountTokens: {},
tokens: [],
+ suggestedTokens: {},
useBlockie: false,
featureFlags: {},
currentLocale: opts.initLangCode,
@@ -37,6 +39,7 @@ class PreferencesController {
this.diagnostics = opts.diagnostics
this.network = opts.network
this.store = new ObservableStore(initState)
+ this.showAddTokenUi = opts.showAddTokenUi
this._subscribeProviderType()
}
// PUBLIC METHODS
@@ -51,6 +54,47 @@ class PreferencesController {
this.store.updateState({ useBlockie: val })
}
+ getSuggestedTokens () {
+ return this.store.getState().suggestedTokens
+ }
+
+ addSuggestedToken (tokenOpts) {
+ this._validateSuggestedTokenParams(tokenOpts)
+ const suggested = this.getSuggestedTokens()
+ const { rawAddress, symbol, decimals } = tokenOpts
+ const address = normalizeAddress(rawAddress)
+ const newEntry = { address, symbol, decimals }
+ suggested[address] = newEntry
+ this.store.updateState({ suggestedTokens: suggested })
+ }
+
+ /**
+ * RPC engine middleware for requesting new token added
+ *
+ * @param req
+ * @param res
+ * @param {Function} - next
+ * @param {Function} - end
+ */
+ requestAddToken (req, res, next, end) {
+ if (req.method === 'eth_watchToken') {
+ const [ rawAddress, symbol, decimals ] = req.params
+ this._validateSuggestedTokenParams({ rawAddress, symbol, decimals })
+ const tokenOpts = {
+ rawAddress,
+ decimals,
+ symbol,
+ }
+
+ this.addSuggestedToken(tokenOpts)
+ this.showAddTokenUi()
+ res.result = rawAddress
+ return end()
+ } else {
+ return next()
+ }
+ }
+
/**
* Getter for the `useBlockie` property
*
@@ -186,6 +230,13 @@ class PreferencesController {
return selected
}
+ removeSuggestedTokens () {
+ return new Promise((resolve, reject) => {
+ this.store.updateState({ suggestedTokens: {} })
+ resolve()
+ })
+ }
+
/**
* Setter for the `selectedAddress` property
*
@@ -387,6 +438,23 @@ class PreferencesController {
//
// PRIVATE METHODS
//
+
+ /**
+ * Validates that the passed options for suggested token have all required properties.
+ *
+ * @param {Object} opts The options object to validate
+ * @throws {string} Throw a custom error indicating that address, symbol and/or decimals
+ * doesn't fulfill requirements
+ *
+ */
+ _validateSuggestedTokenParams (opts) {
+ const { rawAddress, symbol, decimals } = opts
+ if (!rawAddress || !symbol || !decimals) throw new Error(`Cannot suggest token without address, symbol, and decimals`)
+ if (!(symbol.length < 5)) throw new Error(`Invalid symbol ${symbol} more than four characters`)
+ const numDecimals = parseInt(decimals, 10)
+ if (isNaN(numDecimals) || numDecimals > 18 || numDecimals < 0) throw new Error(`Invalid decimals ${decimals}`)
+ if (!isValidAddress(rawAddress)) throw new Error(`Invalid address ${rawAddress}`)
+
/**
* Subscription to network provider type.
*
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index db323e3fe..1464b16a6 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -87,6 +87,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.preferencesController = new PreferencesController({
initState: initState.PreferencesController,
initLangCode: opts.initLangCode,
+ showAddTokenUi: opts.showAddTokenUi,
network: this.networkController,
})
@@ -392,6 +393,7 @@ module.exports = class MetamaskController extends EventEmitter {
setSelectedAddress: nodeify(preferencesController.setSelectedAddress, preferencesController),
addToken: nodeify(preferencesController.addToken, preferencesController),
removeToken: nodeify(preferencesController.removeToken, preferencesController),
+ removeSuggestedTokens: nodeify(preferencesController.removeSuggestedTokens, preferencesController),
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController),
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
@@ -1243,6 +1245,7 @@ module.exports = class MetamaskController extends EventEmitter {
engine.push(createOriginMiddleware({ origin }))
engine.push(createLoggerMiddleware({ origin }))
engine.push(filterMiddleware)
+ engine.push(this.preferencesController.requestAddToken.bind(this.preferencesController))
engine.push(createProviderMiddleware({ provider: this.provider }))
// setup connection