1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 19:26:13 +02:00
metamask-extension/app/scripts/controllers/preferences.js

705 lines
23 KiB
JavaScript
Raw Normal View History

const ObservableStore = require('obs-store')
const normalizeAddress = require('eth-sig-util').normalize
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
const { isValidAddress, sha3, bufferToHex } = require('ethereumjs-util')
const extend = require('xtend')
class PreferencesController {
2018-04-18 20:41:39 +02:00
/**
*
* @typedef {Object} PreferencesController
2018-04-23 18:41:02 +02:00
* @param {object} opts Overrides the defaults for the initial state of this.store
* @property {object} store The stored object containing a users preferences, stored in local storage
* @property {array} store.frequentRpcList A list of custom rpcs to provide the user
* @property {string} store.currentAccountTab Indicates the selected tab in the ui
* @property {array} store.tokens The tokens the user wants display in their token lists
2018-07-27 22:05:12 +02:00
* @property {object} store.accountTokens The tokens stored per account and then per network type
2018-08-21 17:59:42 +02:00
* @property {object} store.assetImages Contains assets objects related to assets added
* @property {boolean} store.useBlockie The users preference for blockie identicons within the UI
* @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the
2019-02-25 20:10:13 +01:00
* user wishes to see that feature.
*
* Feature flags can be set by the global function `setPreference(feature, enabled)`, and so should not expose any sensitive behavior.
* @property {object} store.knownMethodData Contains all data methods known by the user
* @property {string} store.currentLocale The preferred language locale key
* @property {string} store.selectedAddress A hex string that matches the currently selected address in the app
*
2018-04-18 20:41:39 +02:00
*/
constructor (opts = {}) {
const initState = extend({
frequentRpcListDetail: [],
currentAccountTab: 'history',
2018-07-27 22:05:12 +02:00
accountTokens: {},
2018-08-21 17:59:42 +02:00
assetImages: {},
tokens: [],
2018-06-19 00:33:50 +02:00
suggestedTokens: {},
useBlockie: false,
2019-02-25 20:10:13 +01:00
// WARNING: Do not use feature flags for security-sensitive things.
// Feature flag toggling is available in the global namespace
// for convenient testing of pre-release features, and should never
// perform sensitive operations.
featureFlags: {
privacyMode: true,
},
knownMethodData: {},
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
participateInMetaMetrics: null,
firstTimeFlowType: null,
currentLocale: opts.initLangCode,
identities: {},
lostIdentities: {},
forgottenPassword: false,
preferences: {
useNativeCurrencyAsPrimaryCurrency: true,
},
completedOnboarding: false,
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
metaMetricsId: null,
metaMetricsSendCount: 0,
}, opts.initState)
2018-06-04 23:21:46 +02:00
this.diagnostics = opts.diagnostics
this.network = opts.network
this.store = new ObservableStore(initState)
2018-09-27 20:19:09 +02:00
this.openPopup = opts.openPopup
2018-07-27 22:05:12 +02:00
this._subscribeProviderType()
2019-02-25 20:10:13 +01:00
global.setPreference = (key, value) => {
return this.setFeatureFlag(key, value)
}
}
// PUBLIC METHODS
/**
* Sets the {@code forgottenPassword} state property
* @param {boolean} forgottenPassword whether or not the user has forgotten their password
*/
setPasswordForgotten (forgottenPassword) {
this.store.updateState({ forgottenPassword })
}
2018-04-18 20:41:39 +02:00
/**
* Setter for the `useBlockie` property
*
* @param {boolean} val Whether or not the user prefers blockie indicators
*
*/
setUseBlockie (val) {
this.store.updateState({ useBlockie: val })
2017-11-24 02:33:44 +01:00
}
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
/**
* Setter for the `participateInMetaMetrics` property
*
* @param {boolean} bool Whether or not the user wants to participate in MetaMetrics
* @returns {string|null} the string of the new metametrics id, or null if not set
*
*/
setParticipateInMetaMetrics (bool) {
this.store.updateState({ participateInMetaMetrics: bool })
let metaMetricsId = null
if (bool && !this.store.getState().metaMetricsId) {
metaMetricsId = bufferToHex(sha3(String(Date.now()) + String(Math.round(Math.random() * Number.MAX_SAFE_INTEGER))))
this.store.updateState({ metaMetricsId })
} else if (bool === false) {
this.store.updateState({ metaMetricsId })
}
return metaMetricsId
}
getMetaMetricsId () {
return this.store.getState().metaMetricsId
}
getParticipateInMetaMetrics () {
return this.store.getState().participateInMetaMetrics
}
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
setMetaMetricsSendCount (val) {
this.store.updateState({ metaMetricsSendCount: val })
}
getMetaMetricsSendCount () {
return this.store.getState().metaMetricsSendCount
}
/**
* Setter for the `firstTimeFlowType` property
*
* @param {String} type Indicates the type of first time flow - create or import - the user wishes to follow
*
*/
setFirstTimeFlowType (type) {
this.store.updateState({ firstTimeFlowType: type })
}
Metametrics (#6171) * Add metametrics provider and util. * Add backend api and state for participating in metametrics. * Add frontend action for participating in metametrics. * Add metametrics opt-in screen. * Add metametrics events to first time flow. * Add metametrics events for route changes * Add metametrics events for send and confirm screens * Add metametrics events to dropdowns, transactions, log in and out, settings, sig requests and main screen * Ensures each log in is measured as a new visit by metametrics. * Ensure metametrics is called with an empty string for dimensions params if specified * Adds opt in metametrics modal after unlock for existing users * Adds settings page toggle for opting in and out of MetaMetrics * Switch metametrics dimensions to page level scope * Lint, test and translation fixes for metametrics. * Update design for metametrics opt-in screen * Complete responsive styling of metametrics-opt-in modal * Use new chart image on metrics opt in screens * Incorporate the metametrics opt-in screen into the new onboarding flow * Update e2e tests to accomodate metametrics changes * Mock out metametrics network requests in integration tests * Fix tx-list integration test to support metametrics provider. * Send number of tokens and accounts data with every metametrics event. * Update metametrics event descriptor schema and add new events. * Fix import tos bug and send gas button bug due to metametrics changes. * Various small fixes on the metametrics branch. * Add origin custom variable type to metametrics.util * Fix names of onboarding complete actions (metametrics). * Fix names of Metrics Options actions (metametrics). * Clean up code related to metametrics. * Fix bad merge conflict resolution and improve promise handling in sendMetaMetrics event and confrim tx base * Don't send a second metrics event if user has gone back during first time flow. * Collect metametrics on going back from onboarding create/import. * Add missing custom variable constants for metametrics * Fix metametrics provider * Make height of opt-in modal responsive. * Adjust text content for opt-in modal. * Update metametrics event names and clean up code in opt-in-modal * Put phishing warning step next to last in onboarding flow * Link terms of service on create and import screens of first time flow * Add subtext to options on the onboarding select action screen. * Fix styling of bullet points on end of onboarding screen. * Combine phishing warning and congratulations screens. * Fix placement of users if unlocking after an incomplete onboarding import flow. * Fix capitalization in opt-in screen * Fix last onboarding screen translations * Add link to 'Learn More' on the last screen of onboarding * Code clean up: metametrics branch * Update e2e tests for phishing warning step removal * e2e tests passing on metametrics branch * Different tracking urls for metametrics on development and prod
2019-03-05 16:45:01 +01:00
2018-06-19 00:05:41 +02:00
getSuggestedTokens () {
return this.store.getState().suggestedTokens
}
2018-08-21 17:59:42 +02:00
getAssetImages () {
return this.store.getState().assetImages
}
2018-08-21 17:59:42 +02:00
addSuggestedERC20Asset (tokenOpts) {
this._validateERC20AssetParams(tokenOpts)
2018-06-19 00:33:50 +02:00
const suggested = this.getSuggestedTokens()
2018-08-23 20:54:40 +02:00
const { rawAddress, symbol, decimals, image } = tokenOpts
2018-08-07 00:28:47 +02:00
const address = normalizeAddress(rawAddress)
2018-08-23 20:54:40 +02:00
const newEntry = { address, symbol, decimals, image }
2018-08-07 00:28:47 +02:00
suggested[address] = newEntry
2018-06-19 00:33:50 +02:00
this.store.updateState({ suggestedTokens: suggested })
}
/**
* Add new methodData to state, to avoid requesting this information again through Infura
*
* @param {string} fourBytePrefix Four-byte method signature
* @param {string} methodData Corresponding data method
*/
addKnownMethodData (fourBytePrefix, methodData) {
const knownMethodData = this.store.getState().knownMethodData
knownMethodData[fourBytePrefix] = methodData
this.store.updateState({ knownMethodData })
}
2018-06-19 00:05:41 +02:00
/**
* RPC engine middleware for requesting new asset added
2018-06-19 00:05:41 +02:00
*
* @param req
* @param res
* @param {Function} - next
* @param {Function} - end
*/
async requestWatchAsset (req, res, next, end) {
2018-10-19 18:57:11 +02:00
if (req.method === 'metamask_watchAsset' || req.method === 'wallet_watchAsset') {
const { type, options } = req.params
switch (type) {
case 'ERC20':
2018-08-21 18:12:45 +02:00
const result = await this._handleWatchAssetERC20(options)
if (result instanceof Error) {
end(result)
} else {
res.result = result
end()
}
break
default:
end(new Error(`Asset of type ${type} not supported`))
2018-06-19 00:33:50 +02:00
}
2018-06-19 00:05:41 +02:00
} else {
next()
2018-06-19 00:05:41 +02:00
}
}
2018-04-18 20:41:39 +02:00
/**
* Getter for the `useBlockie` property
*
* @returns {boolean} this.store.useBlockie
*
*/
2017-11-24 02:33:44 +01:00
getUseBlockie () {
return this.store.getState().useBlockie
}
2018-04-18 20:41:39 +02:00
/**
* Setter for the `currentLocale` property
*
* @param {string} key he preferred language locale key
2018-04-18 20:41:39 +02:00
*
*/
2018-03-16 01:29:45 +01:00
setCurrentLocale (key) {
this.store.updateState({ currentLocale: key })
}
/**
* Updates identities to only include specified addresses. Removes identities
* not included in addresses array
*
2018-06-03 20:30:11 +02:00
* @param {string[]} addresses An array of hex addresses
*
*/
setAddresses (addresses) {
const oldIdentities = this.store.getState().identities
const oldAccountTokens = this.store.getState().accountTokens
2018-07-27 22:05:12 +02:00
const identities = addresses.reduce((ids, address, index) => {
const oldId = oldIdentities[address] || {}
ids[address] = {name: `Account ${index + 1}`, address, ...oldId}
return ids
}, {})
2018-07-31 01:09:17 +02:00
const accountTokens = addresses.reduce((tokens, address) => {
const oldTokens = oldAccountTokens[address] || {}
tokens[address] = oldTokens
return tokens
}, {})
2018-07-27 22:05:12 +02:00
this.store.updateState({ identities, accountTokens })
}
2018-07-11 06:20:40 +02:00
/**
* Removes an address from state
*
* @param {string} address A hex address
* @returns {string} the address that was removed
*/
removeAddress (address) {
const identities = this.store.getState().identities
2018-07-27 22:05:12 +02:00
const accountTokens = this.store.getState().accountTokens
2018-07-11 06:20:40 +02:00
if (!identities[address]) {
throw new Error(`${address} can't be deleted cause it was not found`)
}
delete identities[address]
2018-07-27 22:05:12 +02:00
delete accountTokens[address]
this.store.updateState({ identities, accountTokens })
2018-07-11 06:20:40 +02:00
// If the selected account is no longer valid,
// select an arbitrary other account:
if (address === this.getSelectedAddress()) {
const selected = Object.keys(identities)[0]
this.setSelectedAddress(selected)
}
return address
}
/**
* Adds addresses to the identities object without removing identities
*
2018-06-03 20:30:11 +02:00
* @param {string[]} addresses An array of hex addresses
*
*/
addAddresses (addresses) {
const identities = this.store.getState().identities
2018-07-27 22:05:12 +02:00
const accountTokens = this.store.getState().accountTokens
addresses.forEach((address) => {
// skip if already exists
if (identities[address]) return
// add missing identity
const identityCount = Object.keys(identities).length
accountTokens[address] = {}
identities[address] = { name: `Account ${identityCount + 1}`, address }
})
2018-07-27 22:05:12 +02:00
this.store.updateState({ identities, accountTokens })
}
/*
* Synchronizes identity entries with known accounts.
* Removes any unknown identities, and returns the resulting selected address.
*
* @param {Array<string>} addresses known to the vault.
* @returns {Promise<string>} selectedAddress the selected address.
*/
syncAddresses (addresses) {
2018-07-03 00:49:33 +02:00
const { identities, lostIdentities } = this.store.getState()
2018-07-03 00:49:33 +02:00
const newlyLost = {}
Object.keys(identities).forEach((identity) => {
if (!addresses.includes(identity)) {
newlyLost[identity] = identities[identity]
2018-06-05 00:34:38 +02:00
delete identities[identity]
}
})
2018-06-04 23:21:46 +02:00
// Identities are no longer present.
if (Object.keys(newlyLost).length > 0) {
2018-06-04 23:21:46 +02:00
// Notify our servers:
if (this.diagnostics) this.diagnostics.reportOrphans(newlyLost)
// store lost accounts
2018-07-03 00:49:33 +02:00
for (const key in newlyLost) {
lostIdentities[key] = newlyLost[key]
}
2018-06-04 23:21:46 +02:00
}
this.store.updateState({ identities, lostIdentities })
this.addAddresses(addresses)
2018-06-05 00:18:12 +02:00
// If the selected account is no longer valid,
// select an arbitrary other account:
let selected = this.getSelectedAddress()
if (!addresses.includes(selected)) {
selected = addresses[0]
this.setSelectedAddress(selected)
}
return selected
}
2018-08-04 01:24:12 +02:00
removeSuggestedTokens () {
return new Promise((resolve) => {
2018-08-04 01:24:12 +02:00
this.store.updateState({ suggestedTokens: {} })
resolve({})
2018-08-04 01:24:12 +02:00
})
}
2018-04-18 20:41:39 +02:00
/**
* Setter for the `selectedAddress` property
*
* @param {string} _address A new hex address for an account
2018-07-31 21:59:19 +02:00
* @returns {Promise<void>} Promise resolves with tokens
2018-04-18 20:41:39 +02:00
*
*/
2017-02-21 21:32:13 +01:00
setSelectedAddress (_address) {
2018-07-27 01:28:12 +02:00
const address = normalizeAddress(_address)
2018-07-31 21:59:19 +02:00
this._updateTokens(address)
this.store.updateState({ selectedAddress: address })
const tokens = this.store.getState().tokens
2018-07-27 01:28:12 +02:00
return Promise.resolve(tokens)
}
/**
* Getter for the `selectedAddress` property
*
* @returns {string} The hex address for the currently selected account
*
*/
getSelectedAddress () {
return this.store.getState().selectedAddress
}
/**
* Contains data about tokens users add to their account.
* @typedef {Object} AddedToken
* @property {string} address - The hex address for the token contract. Will be all lower cased and hex-prefixed.
* @property {string} symbol - The symbol of the token, usually 3 or 4 capitalized letters
* {@link https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#symbol}
* @property {boolean} decimals - The number of decimals the token uses.
* {@link https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#decimals}
*/
/**
* Adds a new token to the token array, or updates the token if passed an address that already exists.
* Modifies the existing tokens array from the store. All objects in the tokens array array AddedToken objects.
* @see AddedToken {@link AddedToken}
*
* @param {string} rawAddress Hex address of the token contract. May or may not be a checksum address.
* @param {string} symbol The symbol of the token
* @param {number} decimals The number of decimals the token uses.
* @returns {Promise<array>} Promises the new array of AddedToken objects.
*
*/
2018-08-23 20:54:40 +02:00
async addToken (rawAddress, symbol, decimals, image) {
const address = normalizeAddress(rawAddress)
const newEntry = { address, symbol, decimals }
const tokens = this.store.getState().tokens
2018-08-21 17:59:42 +02:00
const assetImages = this.getAssetImages()
const previousEntry = tokens.find((token) => {
return token.address === address
})
const previousIndex = tokens.indexOf(previousEntry)
if (previousEntry) {
tokens[previousIndex] = newEntry
} else {
tokens.push(newEntry)
}
2018-08-23 20:54:40 +02:00
assetImages[address] = image
2018-08-21 17:59:42 +02:00
this._updateAccountTokens(tokens, assetImages)
return Promise.resolve(tokens)
}
2018-04-18 20:41:39 +02:00
/**
* Removes a specified token from the tokens array.
*
* @param {string} rawAddress Hex address of the token contract to remove.
2018-04-18 20:47:06 +02:00
* @returns {Promise<array>} The new array of AddedToken objects
2018-04-18 20:41:39 +02:00
*
*/
removeToken (rawAddress) {
const tokens = this.store.getState().tokens
2018-08-21 17:59:42 +02:00
const assetImages = this.getAssetImages()
const updatedTokens = tokens.filter(token => token.address !== rawAddress)
2018-08-21 17:59:42 +02:00
delete assetImages[rawAddress]
this._updateAccountTokens(updatedTokens, assetImages)
return Promise.resolve(updatedTokens)
}
2018-04-18 20:41:39 +02:00
/**
* A getter for the `tokens` property
*
* @returns {array} The current array of AddedToken objects
*
*/
getTokens () {
return this.store.getState().tokens
}
/**
* Sets a custom label for an account
* @param {string} account the account to set a label for
* @param {string} label the custom label for the account
* @return {Promise<string>}
*/
setAccountLabel (account, label) {
if (!account) throw new Error('setAccountLabel requires a valid address, got ' + String(account))
const address = normalizeAddress(account)
const {identities} = this.store.getState()
identities[address] = identities[address] || {}
identities[address].name = label
this.store.updateState({ identities })
return Promise.resolve(label)
}
2018-04-18 20:41:39 +02:00
/**
* Setter for the `currentAccountTab` property
2018-04-18 20:41:39 +02:00
*
* @param {string} currentAccountTab Specifies the new tab to be marked as current
* @returns {Promise<void>} Promise resolves with undefined
*
*/
setCurrentAccountTab (currentAccountTab) {
return new Promise((resolve) => {
this.store.updateState({ currentAccountTab })
resolve()
})
}
/**
* updates custom RPC details
*
* @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.
*
*/
updateRpc (newRpcDetails) {
const rpcList = this.getFrequentRpcListDetail()
const index = rpcList.findIndex((element) => { return element.rpcUrl === newRpcDetails.rpcUrl })
if (index > -1) {
const rpcDetail = rpcList[index]
const updatedRpc = extend(rpcDetail, newRpcDetails)
rpcList[index] = updatedRpc
this.store.updateState({ frequentRpcListDetail: rpcList })
} else {
New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form.
2019-05-09 19:27:14 +02:00
const { rpcUrl, chainId, ticker, nickname, rpcPrefs = {} } = newRpcDetails
return this.addToFrequentRpcList(rpcUrl, chainId, ticker, nickname, rpcPrefs)
}
return Promise.resolve(rpcList)
}
2018-04-18 20:41:39 +02:00
/**
* Adds custom RPC url to state.
2018-04-18 20:41:39 +02:00
*
* @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.
2018-04-18 20:41:39 +02:00
*
*/
addToFrequentRpcList (url, chainId, ticker = 'ETH', nickname = '', rpcPrefs = {}) {
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') {
let checkedChainId
if (!!chainId && !Number.isNaN(parseInt(chainId))) {
checkedChainId = chainId
New settings custom rpc form (#6490) * Add networks tab to settings, with header. * Adds network list to settings network tab. * Adds form to settings networks tab and connects it to network list. * Network tab: form adding and editing working * Settings network form properly handles input errors * Add translations for settings network form * Clean up styles of settings network tab. * Add popup-view styles and behaviour to settings network tab. * Fix save button on settings network form * Adds 'Add Network' button and addMode to settings networks tab * Lint fix for settings networks tab addition * Fix navigation in settings networks tab. * Editing an rpcurl in networks tab does not create new network, just changes rpc of old * Fix layout of settings tabs other than network * Networks dropdown 'Custom Rpc' item links to networks tab in settings. * Update settings sidebar networks subheader. * Make networks tab buttons width consistent with input widths in extension view. * Fix settings screen subheader height in popup view * Fix height of add networks button in popup view * Add optional label to chainId and symbol form labels in networks setting tab * Style fixes for networks tab headers * Add ability to customize block explorer used by custom rpc * Stylistic improvements+fixes to custom rpc form. * Hide cancel button. * Highlight and show network form of provider by default. * Standardize network subheader name to 'Networks' * Update e2e tests for new settings network form * Update unit tests for new rpcPrefs prop * Extract blockexplorer url construction into method. * Fix broken styles on non-network tabs in popup mode * Fix block explorer url links for cases when provider in state has not been updated. * Fix vertical spacing of network form * Don't allow click of save button on network form if nothing has changed * Ensure add network button is shown in popup view * Lint fix for networks tab * Fix block explorer url preference setting. * Fix e2e tests for custom blockexplorer in account details modal changes. * Update integration test states to include frequentRpcList property * Fix some capitalizations in en/messages.json * Remove some console.logs added during custom rpc form work * Fix external account link text and url for modal and dropdown. * Documentation, url validation, proptype required additions and lint fixes on network tab and form.
2019-05-09 19:27:14 +02:00
}
rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs })
}
this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
}
/**
* Removes custom RPC url from state.
*
* @param {string} url The RPC url to remove from frequentRpcList.
* @returns {Promise<array>} Promise resolving to updated frequentRpcList.
*
*/
removeFromFrequentRpcList (url) {
const rpcList = this.getFrequentRpcListDetail()
const index = rpcList.findIndex((element) => { return element.rpcUrl === url })
if (index !== -1) {
rpcList.splice(index, 1)
}
this.store.updateState({ frequentRpcListDetail: rpcList })
return Promise.resolve(rpcList)
2017-02-21 21:32:13 +01:00
}
2018-04-18 20:41:39 +02:00
/**
* Getter for the `frequentRpcListDetail` property.
2018-04-18 20:41:39 +02:00
*
* @returns {array<array>} An array of rpc urls.
2018-04-18 20:41:39 +02:00
*
*/
getFrequentRpcListDetail () {
return this.store.getState().frequentRpcListDetail
2017-02-21 21:32:13 +01:00
}
2017-11-14 17:04:55 +01:00
2018-04-18 20:41:39 +02:00
/**
* Updates the `featureFlags` property, which is an object. One property within that object will be set to a boolean.
*
* @param {string} feature A key that corresponds to a UI feature.
* @param {boolean} activated Indicates whether or not the UI feature should be displayed
2018-04-18 20:41:39 +02:00
* @returns {Promise<object>} Promises a new object; the updated featureFlags object.
*
*/
2017-11-14 17:04:55 +01:00
setFeatureFlag (feature, activated) {
const currentFeatureFlags = this.store.getState().featureFlags
const updatedFeatureFlags = {
...currentFeatureFlags,
[feature]: activated,
}
this.store.updateState({ featureFlags: updatedFeatureFlags })
2017-11-16 20:28:59 +01:00
2017-11-14 17:04:55 +01:00
return Promise.resolve(updatedFeatureFlags)
}
2018-04-18 20:41:39 +02:00
/**
* A getter for the `featureFlags` property
*
* @returns {object} A key-boolean map, where keys refer to features and booleans to whether the
* user wishes to see that feature
2018-04-18 20:41:39 +02:00
*
*/
2017-11-14 17:04:55 +01:00
getFeatureFlags () {
return this.store.getState().featureFlags
}
/**
* Updates the `preferences` property, which is an object. These are user-controlled features
* found in the settings page.
* @param {string} preference The preference to enable or disable.
* @param {boolean} value Indicates whether or not the preference should be enabled or disabled.
* @returns {Promise<object>} Promises a new object; the updated preferences object.
*/
setPreference (preference, value) {
const currentPreferences = this.getPreferences()
const updatedPreferences = {
...currentPreferences,
[preference]: value,
}
this.store.updateState({ preferences: updatedPreferences })
return Promise.resolve(updatedPreferences)
}
/**
* A getter for the `preferences` property
* @returns {object} A key-boolean map of user-selected preferences.
*/
getPreferences () {
return this.store.getState().preferences
}
/**
* Sets the completedOnboarding state to true, indicating that the user has completed the
* onboarding process.
*/
completeOnboarding () {
this.store.updateState({ completedOnboarding: true })
return Promise.resolve(true)
}
//
// PRIVATE METHODS
//
2018-08-07 00:28:47 +02:00
/**
* Subscription to network provider type.
*
*
*/
_subscribeProviderType () {
2018-07-31 21:59:19 +02:00
this.network.providerStore.subscribe(() => {
const { tokens } = this._getTokenRelatedStates()
this.store.updateState({ tokens })
})
}
/**
* Updates `accountTokens` and `tokens` of current account and network according to it.
*
2018-07-31 19:07:28 +02:00
* @param {array} tokens Array of tokens to be updated.
*
*/
2018-08-21 17:59:42 +02:00
_updateAccountTokens (tokens, assetImages) {
2018-07-31 21:59:19 +02:00
const { accountTokens, providerType, selectedAddress } = this._getTokenRelatedStates()
accountTokens[selectedAddress][providerType] = tokens
2018-08-21 17:59:42 +02:00
this.store.updateState({ accountTokens, tokens, assetImages })
2018-07-27 22:05:12 +02:00
}
2018-07-27 22:05:12 +02:00
/**
* Updates `tokens` of current account and network.
2018-07-27 22:05:12 +02:00
*
2018-07-31 21:59:19 +02:00
* @param {string} selectedAddress Account address to be updated with.
2018-07-27 22:05:12 +02:00
*
*/
_updateTokens (selectedAddress) {
2018-07-31 21:59:19 +02:00
const { tokens } = this._getTokenRelatedStates(selectedAddress)
this.store.updateState({ tokens })
}
/**
* A getter for `tokens` and `accountTokens` related states.
*
* @param {string} selectedAddress A new hex address for an account
2018-07-31 22:18:06 +02:00
* @returns {Object.<array, object, string, string>} States to interact with tokens in `accountTokens`
2018-07-31 21:59:19 +02:00
*
*/
_getTokenRelatedStates (selectedAddress) {
const accountTokens = this.store.getState().accountTokens
2018-07-31 21:59:19 +02:00
if (!selectedAddress) selectedAddress = this.store.getState().selectedAddress
const providerType = this.network.providerStore.getState().type
if (!(selectedAddress in accountTokens)) accountTokens[selectedAddress] = {}
if (!(providerType in accountTokens[selectedAddress])) accountTokens[selectedAddress][providerType] = []
const tokens = accountTokens[selectedAddress][providerType]
2018-07-31 21:59:19 +02:00
return { tokens, accountTokens, providerType, selectedAddress }
2018-08-07 00:28:47 +02:00
}
/**
* Handle the suggestion of an ERC20 asset through `watchAsset`
* *
2018-08-21 17:59:42 +02:00
* @param {Promise} promise Promise according to addition of ERC20 token
*
*/
async _handleWatchAssetERC20 (options) {
2018-08-23 20:54:40 +02:00
const { address, symbol, decimals, image } = options
const rawAddress = address
2018-08-21 18:12:45 +02:00
try {
this._validateERC20AssetParams({ rawAddress, symbol, decimals })
} catch (err) {
return err
}
2018-08-23 20:54:40 +02:00
const tokenOpts = { rawAddress, decimals, symbol, image }
2018-08-21 17:59:42 +02:00
this.addSuggestedERC20Asset(tokenOpts)
2018-09-27 20:19:09 +02:00
return this.openPopup().then(() => {
const tokenAddresses = this.getTokens().filter(token => token.address === normalizeAddress(rawAddress))
return tokenAddresses.length > 0
})
}
2018-08-21 17:59:42 +02:00
/**
* 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
*
*/
_validateERC20AssetParams (opts) {
const { rawAddress, symbol, decimals } = opts
if (!rawAddress || !symbol || typeof decimals === 'undefined') throw new Error(`Cannot suggest token without address, symbol, and decimals`)
if (!(symbol.length < 7)) throw new Error(`Invalid symbol ${symbol} more than six characters`)
2018-08-21 17:59:42 +02:00
const numDecimals = parseInt(decimals, 10)
if (isNaN(numDecimals) || numDecimals > 36 || numDecimals < 0) {
throw new Error(`Invalid decimals ${decimals} must be at least 0, and not over 36`)
}
if (!isValidAddress(rawAddress)) throw new Error(`Invalid address ${rawAddress}`)
}
}
module.exports = PreferencesController