diff options
Diffstat (limited to 'app/scripts')
-rw-r--r-- | app/scripts/background.js | 2 | ||||
-rw-r--r-- | app/scripts/controllers/preferences.js | 68 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 3 |
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 |