2021-02-04 19:15:23 +01:00
|
|
|
import { ObservableStore } from '@metamask/obs-store';
|
|
|
|
import { normalize as normalizeAddress } from 'eth-sig-util';
|
2023-01-12 20:05:48 +01:00
|
|
|
import { IPFS_DEFAULT_GATEWAY_URL } from '../../../shared/constants/network';
|
2021-02-12 16:25:58 +01:00
|
|
|
import { isPrefixedFormattedHexString } from '../../../shared/modules/network.utils';
|
2023-01-20 16:14:40 +01:00
|
|
|
import { LedgerTransportTypes } from '../../../shared/constants/hardware-wallets';
|
2023-02-01 00:49:00 +01:00
|
|
|
import { ThemeType } from '../../../shared/constants/preferences';
|
2021-02-26 16:40:25 +01:00
|
|
|
import { NETWORK_EVENTS } from './network';
|
2017-01-30 21:42:24 +01:00
|
|
|
|
2020-05-06 00:19:38 +02:00
|
|
|
export default class PreferencesController {
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
|
|
|
*
|
2022-07-27 15:28:05 +02:00
|
|
|
* @typedef {object} PreferencesController
|
|
|
|
* @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
|
2020-11-10 18:30:41 +01:00
|
|
|
* @property {Array} store.frequentRpcList A list of custom rpcs to provide the user
|
2018-04-16 19:08:04 +02:00
|
|
|
* @property {boolean} store.useBlockie The users preference for blockie identicons within the UI
|
2019-09-27 06:30:36 +02:00
|
|
|
* @property {boolean} store.useNonceField The users preference for nonce field within the UI
|
2022-07-27 15:28:05 +02:00
|
|
|
* @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.
|
2022-07-27 15:28:05 +02:00
|
|
|
* @property {object} store.knownMethodData Contains all data methods known by the user
|
2018-04-16 19:08:04 +02:00
|
|
|
* @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
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
constructor(opts = {}) {
|
2020-08-19 18:27:05 +02:00
|
|
|
const initState = {
|
2018-10-26 10:26:43 +02:00
|
|
|
frequentRpcListDetail: [],
|
2017-11-27 16:11:48 +01:00
|
|
|
useBlockie: false,
|
2019-09-27 06:30:36 +02:00
|
|
|
useNonceField: false,
|
2020-02-27 07:29:41 +01:00
|
|
|
usePhishDetect: true,
|
2021-05-05 15:58:29 +02:00
|
|
|
dismissSeedBackUpReminder: false,
|
2022-12-01 22:16:04 +01:00
|
|
|
useMultiAccountBalanceChecker: true,
|
2021-09-09 22:56:27 +02:00
|
|
|
|
|
|
|
// set to true means the dynamic list from the API is being used
|
|
|
|
// set to false will be using the static list from contract-metadata
|
2022-08-10 03:26:25 +02:00
|
|
|
useTokenDetection: false,
|
2022-11-15 19:49:42 +01:00
|
|
|
useNftDetection: false,
|
2023-01-17 16:23:04 +01:00
|
|
|
useCurrencyRateCheck: true,
|
2021-12-01 05:12:27 +01:00
|
|
|
openSeaEnabled: false,
|
2021-11-11 20:18:50 +01:00
|
|
|
advancedGasFee: null,
|
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.
|
2019-03-26 16:07:53 +01:00
|
|
|
featureFlags: {
|
2019-08-21 20:42:14 +02:00
|
|
|
showIncomingTransactions: true,
|
2019-03-26 16:07:53 +01:00
|
|
|
},
|
2019-01-22 19:22:56 +01:00
|
|
|
knownMethodData: {},
|
2018-03-22 16:09:16 +01:00
|
|
|
currentLocale: opts.initLangCode,
|
2018-04-19 05:33:51 +02:00
|
|
|
identities: {},
|
2018-06-04 23:05:56 +02:00
|
|
|
lostIdentities: {},
|
2018-09-11 02:01:15 +02:00
|
|
|
forgottenPassword: false,
|
2018-10-17 01:03:29 +02:00
|
|
|
preferences: {
|
2020-05-13 16:53:00 +02:00
|
|
|
autoLockTimeLimit: undefined,
|
|
|
|
showFiatInTestnets: false,
|
2021-10-28 21:31:05 +02:00
|
|
|
showTestNetworks: false,
|
2018-10-26 10:26:43 +02:00
|
|
|
useNativeCurrencyAsPrimaryCurrency: true,
|
2021-03-09 20:35:55 +01:00
|
|
|
hideZeroBalanceTokens: false,
|
2018-10-17 01:03:29 +02:00
|
|
|
},
|
2019-12-12 20:28:07 +01:00
|
|
|
// ENS decentralized website resolution
|
2021-12-14 00:41:10 +01:00
|
|
|
ipfsGateway: IPFS_DEFAULT_GATEWAY_URL,
|
2021-04-15 19:41:40 +02:00
|
|
|
infuraBlocked: null,
|
2021-10-21 21:17:03 +02:00
|
|
|
ledgerTransportType: window.navigator.hid
|
2023-01-20 16:14:40 +01:00
|
|
|
? LedgerTransportTypes.webhid
|
|
|
|
: LedgerTransportTypes.u2f,
|
2022-11-17 15:13:02 +01:00
|
|
|
transactionSecurityCheckEnabled: false,
|
2023-02-01 00:49:00 +01:00
|
|
|
theme: ThemeType.os,
|
2020-11-03 00:41:28 +01:00
|
|
|
...opts.initState,
|
2021-02-04 19:15:23 +01:00
|
|
|
};
|
2018-06-04 23:21:46 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
this.network = opts.network;
|
|
|
|
this.store = new ObservableStore(initState);
|
|
|
|
this.store.setMaxListeners(12);
|
|
|
|
this.openPopup = opts.openPopup;
|
2022-08-10 03:26:25 +02:00
|
|
|
this.tokenListController = opts.tokenListController;
|
2021-06-22 19:39:44 +02:00
|
|
|
|
2021-04-15 19:41:40 +02:00
|
|
|
this._subscribeToInfuraAvailability();
|
2019-02-25 20:10:13 +01:00
|
|
|
|
|
|
|
global.setPreference = (key, value) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
return this.setFeatureFlag(key, value);
|
|
|
|
};
|
2017-01-30 21:42:24 +01:00
|
|
|
}
|
2019-07-31 22:17:11 +02:00
|
|
|
// PUBLIC METHODS
|
2017-01-30 21:42:24 +01:00
|
|
|
|
2018-09-11 02:01:15 +02:00
|
|
|
/**
|
|
|
|
* Sets the {@code forgottenPassword} state property
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {boolean} forgottenPassword - whether or not the user has forgotten their password
|
2018-09-11 02:01:15 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setPasswordForgotten(forgottenPassword) {
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ forgottenPassword });
|
2018-09-11 02:01:15 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
|
|
|
* Setter for the `useBlockie` property
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {boolean} val - Whether or not the user prefers blockie indicators
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setUseBlockie(val) {
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ useBlockie: val });
|
2017-11-24 02:33:44 +01:00
|
|
|
}
|
|
|
|
|
2019-09-27 06:30:36 +02:00
|
|
|
/**
|
|
|
|
* Setter for the `useNonceField` property
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {boolean} val - Whether or not the user prefers to set nonce
|
2019-09-27 06:30:36 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setUseNonceField(val) {
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ useNonceField: val });
|
2019-09-27 06:30:36 +02:00
|
|
|
}
|
|
|
|
|
2020-02-27 07:29:41 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `usePhishDetect` property
|
|
|
|
*
|
|
|
|
* @param {boolean} val - Whether or not the user prefers phishing domain protection
|
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setUsePhishDetect(val) {
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ usePhishDetect: val });
|
2020-02-27 07:29:41 +01:00
|
|
|
}
|
|
|
|
|
2022-12-01 22:16:04 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `useMultiAccountBalanceChecker` property
|
|
|
|
*
|
2022-12-19 18:46:36 +01:00
|
|
|
* @param {boolean} val - Whether or not the user prefers to turn off/on all security settings
|
2022-12-01 22:16:04 +01:00
|
|
|
*/
|
|
|
|
setUseMultiAccountBalanceChecker(val) {
|
|
|
|
this.store.updateState({ useMultiAccountBalanceChecker: val });
|
|
|
|
}
|
|
|
|
|
2021-07-16 01:08:16 +02:00
|
|
|
/**
|
2021-09-09 22:56:27 +02:00
|
|
|
* Setter for the `useTokenDetection` property
|
2021-07-16 01:08:16 +02:00
|
|
|
*
|
|
|
|
* @param {boolean} val - Whether or not the user prefers to use the static token list or dynamic token list from the API
|
|
|
|
*/
|
2021-09-09 22:56:27 +02:00
|
|
|
setUseTokenDetection(val) {
|
|
|
|
this.store.updateState({ useTokenDetection: val });
|
2022-08-10 03:26:25 +02:00
|
|
|
this.tokenListController.updatePreventPollingOnNetworkRestart(!val);
|
|
|
|
if (val) {
|
|
|
|
this.tokenListController.start();
|
|
|
|
} else {
|
|
|
|
this.tokenListController.clearingTokenListData();
|
|
|
|
this.tokenListController.stop();
|
|
|
|
}
|
2021-07-16 01:08:16 +02:00
|
|
|
}
|
|
|
|
|
2021-11-26 19:54:57 +01:00
|
|
|
/**
|
2022-11-15 19:49:42 +01:00
|
|
|
* Setter for the `useNftDetection` property
|
2021-11-26 19:54:57 +01:00
|
|
|
*
|
2022-11-15 19:49:42 +01:00
|
|
|
* @param {boolean} useNftDetection - Whether or not the user prefers to autodetect collectibles.
|
2021-11-26 19:54:57 +01:00
|
|
|
*/
|
2022-11-15 19:49:42 +01:00
|
|
|
setUseNftDetection(useNftDetection) {
|
|
|
|
this.store.updateState({ useNftDetection });
|
2021-11-26 19:54:57 +01:00
|
|
|
}
|
|
|
|
|
2023-01-17 16:23:04 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `useCurrencyRateCheck` property
|
|
|
|
*
|
|
|
|
* @param {boolean} val - Whether or not the user prefers to use currency rate check for ETH and tokens.
|
|
|
|
*/
|
|
|
|
setUseCurrencyRateCheck(val) {
|
|
|
|
this.store.updateState({ useCurrencyRateCheck: val });
|
|
|
|
}
|
|
|
|
|
2021-12-01 05:12:27 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `openSeaEnabled` property
|
|
|
|
*
|
2022-02-10 21:02:06 +01:00
|
|
|
* @param {boolean} openSeaEnabled - Whether or not the user prefers to use the OpenSea API for collectibles data.
|
2021-12-01 05:12:27 +01:00
|
|
|
*/
|
2022-02-10 21:02:06 +01:00
|
|
|
setOpenSeaEnabled(openSeaEnabled) {
|
|
|
|
this.store.updateState({
|
|
|
|
openSeaEnabled,
|
|
|
|
});
|
2021-12-01 05:12:27 +01:00
|
|
|
}
|
|
|
|
|
2021-11-11 20:18:50 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `advancedGasFee` property
|
|
|
|
*
|
|
|
|
* @param {object} val - holds the maxBaseFee and PriorityFee that the user set as default advanced settings.
|
|
|
|
*/
|
|
|
|
setAdvancedGasFee(val) {
|
|
|
|
this.store.updateState({ advancedGasFee: val });
|
|
|
|
}
|
|
|
|
|
2022-03-07 19:53:19 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `theme` property
|
|
|
|
*
|
|
|
|
* @param {string} val - 'default' or 'dark' value based on the mode selected by user.
|
|
|
|
*/
|
|
|
|
setTheme(val) {
|
|
|
|
this.store.updateState({ theme: val });
|
|
|
|
}
|
|
|
|
|
2022-11-17 15:13:02 +01:00
|
|
|
/**
|
|
|
|
* Setter for the `transactionSecurityCheckEnabled` property
|
|
|
|
*
|
|
|
|
* @param transactionSecurityCheckEnabled
|
|
|
|
*/
|
|
|
|
setTransactionSecurityCheckEnabled(transactionSecurityCheckEnabled) {
|
|
|
|
this.store.updateState({
|
|
|
|
transactionSecurityCheckEnabled,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-01-22 19:22:56 +01:00
|
|
|
/**
|
|
|
|
* Add new methodData to state, to avoid requesting this information again through Infura
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} fourBytePrefix - Four-byte method signature
|
|
|
|
* @param {string} methodData - Corresponding data method
|
2019-01-22 19:22:56 +01:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
addKnownMethodData(fourBytePrefix, methodData) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const { knownMethodData } = this.store.getState();
|
|
|
|
knownMethodData[fourBytePrefix] = methodData;
|
|
|
|
this.store.updateState({ knownMethodData });
|
2019-01-22 19:22:56 +01:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
|
|
|
* Setter for the `currentLocale` property
|
2018-04-16 19:08:04 +02:00
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} key - he preferred language locale key
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setCurrentLocale(key) {
|
|
|
|
const textDirection = ['ar', 'dv', 'fa', 'he', 'ku'].includes(key)
|
|
|
|
? 'rtl'
|
2021-02-04 19:15:23 +01:00
|
|
|
: 'auto';
|
2019-09-03 19:47:54 +02:00
|
|
|
this.store.updateState({
|
|
|
|
currentLocale: key,
|
2020-08-19 18:27:05 +02:00
|
|
|
textDirection,
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
|
|
|
return textDirection;
|
2018-03-16 01:29:45 +01:00
|
|
|
}
|
|
|
|
|
2018-06-03 20:27:25 +02:00
|
|
|
/**
|
|
|
|
* Updates identities to only include specified addresses. Removes identities
|
|
|
|
* not included in addresses array
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string[]} addresses - An array of hex addresses
|
2018-06-03 20:27:25 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setAddresses(addresses) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const oldIdentities = this.store.getState().identities;
|
2018-07-27 22:05:12 +02:00
|
|
|
|
2018-04-19 05:33:51 +02:00
|
|
|
const identities = addresses.reduce((ids, address, index) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
const oldId = oldIdentities[address] || {};
|
|
|
|
ids[address] = { name: `Account ${index + 1}`, address, ...oldId };
|
|
|
|
return ids;
|
|
|
|
}, {});
|
2021-09-10 19:37:19 +02:00
|
|
|
|
|
|
|
this.store.updateState({ identities });
|
2018-04-19 05:33:51 +02:00
|
|
|
}
|
|
|
|
|
2018-07-11 06:20:40 +02:00
|
|
|
/**
|
|
|
|
* Removes an address from state
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} address - A hex address
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {string} the address that was removed
|
2018-07-11 06:20:40 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
removeAddress(address) {
|
2021-09-10 19:37:19 +02:00
|
|
|
const { identities } = this.store.getState();
|
2020-12-08 21:38:00 +01:00
|
|
|
|
2018-07-11 06:20:40 +02:00
|
|
|
if (!identities[address]) {
|
2021-02-04 19:15:23 +01:00
|
|
|
throw new Error(`${address} can't be deleted cause it was not found`);
|
2018-07-11 06:20:40 +02:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
delete identities[address];
|
2021-09-10 19:37:19 +02:00
|
|
|
this.store.updateState({ identities });
|
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()) {
|
2022-09-27 17:52:01 +02:00
|
|
|
const [selected] = Object.keys(identities);
|
2021-02-04 19:15:23 +01:00
|
|
|
this.setSelectedAddress(selected);
|
2018-07-11 06:20:40 +02:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
return address;
|
2018-07-11 06:20:40 +02:00
|
|
|
}
|
|
|
|
|
2018-06-03 20:27:25 +02:00
|
|
|
/**
|
|
|
|
* Adds addresses to the identities object without removing identities
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string[]} addresses - An array of hex addresses
|
2018-06-03 20:27:25 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
addAddresses(addresses) {
|
2021-09-10 19:37:19 +02:00
|
|
|
const { identities } = this.store.getState();
|
2018-06-03 20:27:25 +02:00
|
|
|
addresses.forEach((address) => {
|
|
|
|
// skip if already exists
|
2019-11-20 01:03:20 +01:00
|
|
|
if (identities[address]) {
|
2021-02-04 19:15:23 +01:00
|
|
|
return;
|
2019-11-20 01:03:20 +01:00
|
|
|
}
|
2018-06-03 20:27:25 +02:00
|
|
|
// add missing identity
|
2021-02-04 19:15:23 +01:00
|
|
|
const identityCount = Object.keys(identities).length;
|
2018-07-27 00:04:34 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
identities[address] = { name: `Account ${identityCount + 1}`, address };
|
|
|
|
});
|
2021-09-10 19:37:19 +02:00
|
|
|
this.store.updateState({ identities });
|
2018-06-03 20:27:25 +02:00
|
|
|
}
|
|
|
|
|
2020-03-20 20:37:27 +01:00
|
|
|
/**
|
2018-06-04 22:43:26 +02:00
|
|
|
* Synchronizes identity entries with known accounts.
|
|
|
|
* Removes any unknown identities, and returns the resulting selected address.
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {Array<string>} addresses - known to the vault.
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {Promise<string>} selectedAddress the selected address.
|
2018-06-04 22:43:26 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
syncAddresses(addresses) {
|
2020-03-20 20:37:27 +01:00
|
|
|
if (!Array.isArray(addresses) || addresses.length === 0) {
|
2021-06-29 00:38:20 +02:00
|
|
|
throw new Error('Expected non-empty array of addresses. Error #11201');
|
2020-03-20 20:37:27 +01:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const { identities, lostIdentities } = this.store.getState();
|
2018-06-04 23:24:45 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
const newlyLost = {};
|
2018-06-04 22:43:26 +02:00
|
|
|
Object.keys(identities).forEach((identity) => {
|
|
|
|
if (!addresses.includes(identity)) {
|
2021-02-04 19:15:23 +01:00
|
|
|
newlyLost[identity] = identities[identity];
|
|
|
|
delete identities[identity];
|
2018-06-04 22:43:26 +02:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2018-06-04 22:43:26 +02:00
|
|
|
|
2018-06-04 23:21:46 +02:00
|
|
|
// Identities are no longer present.
|
2018-06-04 23:24:45 +02:00
|
|
|
if (Object.keys(newlyLost).length > 0) {
|
2018-06-05 20:51:27 +02:00
|
|
|
// store lost accounts
|
2020-07-21 23:10:45 +02:00
|
|
|
Object.keys(newlyLost).forEach((key) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
lostIdentities[key] = newlyLost[key];
|
|
|
|
});
|
2018-06-04 23:21:46 +02:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ identities, lostIdentities });
|
|
|
|
this.addAddresses(addresses);
|
2018-06-04 22:43:26 +02:00
|
|
|
|
2018-06-05 00:18:12 +02:00
|
|
|
// If the selected account is no longer valid,
|
|
|
|
// select an arbitrary other account:
|
2021-02-04 19:15:23 +01:00
|
|
|
let selected = this.getSelectedAddress();
|
2018-06-04 22:43:26 +02:00
|
|
|
if (!addresses.includes(selected)) {
|
2022-09-27 17:52:01 +02:00
|
|
|
[selected] = addresses;
|
2021-02-04 19:15:23 +01:00
|
|
|
this.setSelectedAddress(selected);
|
2018-06-04 22:43:26 +02:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
return selected;
|
2018-06-04 22:43:26 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
|
|
|
* Setter for the `selectedAddress` property
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} _address - A new hex address for an account
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
setSelectedAddress(_address) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const address = normalizeAddress(_address);
|
2020-04-16 20:20:01 +02:00
|
|
|
|
2021-09-10 19:37:19 +02:00
|
|
|
const { identities } = this.store.getState();
|
2021-02-04 19:15:23 +01:00
|
|
|
const selectedIdentity = identities[address];
|
2020-04-16 20:20:01 +02:00
|
|
|
if (!selectedIdentity) {
|
2021-02-04 19:15:23 +01:00
|
|
|
throw new Error(`Identity for '${address} not found`);
|
2020-04-16 20:20:01 +02:00
|
|
|
}
|
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
selectedIdentity.lastSelected = Date.now();
|
|
|
|
this.store.updateState({ identities, selectedAddress: address });
|
2017-01-30 21:42:24 +01:00
|
|
|
}
|
|
|
|
|
2018-04-16 19:08:04 +02:00
|
|
|
/**
|
|
|
|
* Getter for the `selectedAddress` property
|
|
|
|
*
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {string} The hex address for the currently selected account
|
2018-04-16 19:08:04 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
getSelectedAddress() {
|
2021-02-04 19:15:23 +01:00
|
|
|
return this.store.getState().selectedAddress;
|
2017-01-30 21:42:24 +01:00
|
|
|
}
|
|
|
|
|
2018-04-19 05:33:51 +02:00
|
|
|
/**
|
|
|
|
* Sets a custom label for an account
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} account - the account to set a label for
|
|
|
|
* @param {string} label - the custom label for the account
|
|
|
|
* @returns {Promise<string>}
|
2018-04-19 05:33:51 +02:00
|
|
|
*/
|
2023-01-20 21:20:18 +01:00
|
|
|
async setAccountLabel(account, label) {
|
2019-11-20 01:03:20 +01:00
|
|
|
if (!account) {
|
2020-11-03 00:41:28 +01:00
|
|
|
throw new Error(
|
|
|
|
`setAccountLabel requires a valid address, got ${String(account)}`,
|
2021-02-04 19:15:23 +01:00
|
|
|
);
|
2019-11-20 01:03:20 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
const address = normalizeAddress(account);
|
|
|
|
const { identities } = this.store.getState();
|
|
|
|
identities[address] = identities[address] || {};
|
|
|
|
identities[address].name = label;
|
|
|
|
this.store.updateState({ identities });
|
2023-01-20 21:20:18 +01:00
|
|
|
return label;
|
2018-04-19 05:33:51 +02:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
2018-10-19 22:20:54 +02:00
|
|
|
* Adds custom RPC url to state.
|
2018-04-18 20:41:39 +02:00
|
|
|
*
|
2020-10-06 19:57:02 +02:00
|
|
|
* @param {string} rpcUrl - The RPC url to add to frequentRpcList.
|
|
|
|
* @param {string} chainId - The chainId of the selected network.
|
|
|
|
* @param {string} [ticker] - Ticker symbol of the selected network.
|
|
|
|
* @param {string} [nickname] - Nickname of the selected network.
|
2022-07-27 15:28:05 +02:00
|
|
|
* @param {object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2023-01-12 20:05:48 +01:00
|
|
|
upsertToFrequentRpcList(
|
2020-11-03 00:41:28 +01:00
|
|
|
rpcUrl,
|
|
|
|
chainId,
|
|
|
|
ticker = 'ETH',
|
|
|
|
nickname = '',
|
|
|
|
rpcPrefs = {},
|
|
|
|
) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const rpcList = this.getFrequentRpcListDetail();
|
2020-10-12 21:05:40 +02:00
|
|
|
|
2019-11-20 01:03:20 +01:00
|
|
|
const index = rpcList.findIndex((element) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
return element.rpcUrl === rpcUrl;
|
|
|
|
});
|
2019-07-31 22:17:11 +02:00
|
|
|
if (index !== -1) {
|
2023-01-12 20:05:48 +01:00
|
|
|
rpcList.splice(index, 1, { rpcUrl, chainId, ticker, nickname, rpcPrefs });
|
|
|
|
return;
|
2019-07-31 22:17:11 +02:00
|
|
|
}
|
2020-10-06 19:57:02 +02:00
|
|
|
|
|
|
|
if (!isPrefixedFormattedHexString(chainId)) {
|
2021-02-04 19:15:23 +01:00
|
|
|
throw new Error(`Invalid chainId: "${chainId}"`);
|
2018-10-19 22:20:54 +02:00
|
|
|
}
|
2020-10-06 19:57:02 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
rpcList.push({ rpcUrl, chainId, ticker, nickname, rpcPrefs });
|
|
|
|
this.store.updateState({ frequentRpcListDetail: rpcList });
|
2019-07-31 22:17:11 +02:00
|
|
|
}
|
2018-10-19 22:20:54 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes custom RPC url from state.
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} url - The RPC url to remove from frequentRpcList.
|
2022-01-07 16:57:33 +01:00
|
|
|
* @returns {Promise<Array>} Promise resolving to updated frequentRpcList.
|
2018-10-19 22:20:54 +02:00
|
|
|
*/
|
2023-01-20 21:20:18 +01:00
|
|
|
async removeFromFrequentRpcList(url) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const rpcList = this.getFrequentRpcListDetail();
|
2019-11-20 01:03:20 +01:00
|
|
|
const index = rpcList.findIndex((element) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
return element.rpcUrl === url;
|
|
|
|
});
|
2018-10-19 22:20:54 +02:00
|
|
|
if (index !== -1) {
|
2021-02-04 19:15:23 +01:00
|
|
|
rpcList.splice(index, 1);
|
2017-02-23 00:12:56 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ frequentRpcListDetail: rpcList });
|
2023-01-20 21:20:18 +01:00
|
|
|
return rpcList;
|
2017-02-21 21:32:13 +01:00
|
|
|
}
|
|
|
|
|
2018-04-18 20:41:39 +02:00
|
|
|
/**
|
2018-10-26 10:26:43 +02:00
|
|
|
* Getter for the `frequentRpcListDetail` property.
|
2018-04-18 20:41:39 +02:00
|
|
|
*
|
2022-01-07 16:57:33 +01:00
|
|
|
* @returns {Array<Array>} An array of rpc urls.
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
getFrequentRpcListDetail() {
|
2021-02-04 19:15:23 +01:00
|
|
|
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.
|
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} feature - A key that corresponds to a UI feature.
|
|
|
|
* @param {boolean} activated - Indicates whether or not the UI feature should be displayed
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {Promise<object>} Promises a new object; the updated featureFlags object.
|
2018-04-18 20:41:39 +02:00
|
|
|
*/
|
2023-01-20 21:20:18 +01:00
|
|
|
async setFeatureFlag(feature, activated) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const currentFeatureFlags = this.store.getState().featureFlags;
|
2017-11-14 17:04:55 +01:00
|
|
|
const updatedFeatureFlags = {
|
|
|
|
...currentFeatureFlags,
|
|
|
|
[feature]: activated,
|
2021-02-04 19:15:23 +01:00
|
|
|
};
|
2017-11-14 17:04:55 +01:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ featureFlags: updatedFeatureFlags });
|
2017-11-16 20:28:59 +01:00
|
|
|
|
2023-01-20 21:20:18 +01:00
|
|
|
return updatedFeatureFlags;
|
2017-11-14 17:04:55 +01:00
|
|
|
}
|
|
|
|
|
2018-10-17 01:03:29 +02:00
|
|
|
/**
|
|
|
|
* Updates the `preferences` property, which is an object. These are user-controlled features
|
|
|
|
* found in the settings page.
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} preference - The preference to enable or disable.
|
|
|
|
* @param {boolean} value - Indicates whether or not the preference should be enabled or disabled.
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {Promise<object>} Promises a new object; the updated preferences object.
|
2018-10-17 01:03:29 +02:00
|
|
|
*/
|
2023-01-20 21:20:18 +01:00
|
|
|
async setPreference(preference, value) {
|
2021-02-04 19:15:23 +01:00
|
|
|
const currentPreferences = this.getPreferences();
|
2018-10-17 01:03:29 +02:00
|
|
|
const updatedPreferences = {
|
|
|
|
...currentPreferences,
|
|
|
|
[preference]: value,
|
2021-02-04 19:15:23 +01:00
|
|
|
};
|
2018-10-17 01:03:29 +02:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ preferences: updatedPreferences });
|
2023-01-20 21:20:18 +01:00
|
|
|
return updatedPreferences;
|
2018-10-17 01:03:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A getter for the `preferences` property
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2022-07-27 15:28:05 +02:00
|
|
|
* @returns {object} A key-boolean map of user-selected preferences.
|
2018-10-17 01:03:29 +02:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
getPreferences() {
|
2021-02-04 19:15:23 +01:00
|
|
|
return this.store.getState().preferences;
|
2018-10-17 01:03:29 +02:00
|
|
|
}
|
|
|
|
|
2019-12-12 20:28:07 +01:00
|
|
|
/**
|
|
|
|
* A getter for the `ipfsGateway` property
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {string} The current IPFS gateway domain
|
2019-12-12 20:28:07 +01:00
|
|
|
*/
|
2020-11-03 00:41:28 +01:00
|
|
|
getIpfsGateway() {
|
2021-02-04 19:15:23 +01:00
|
|
|
return this.store.getState().ipfsGateway;
|
2019-12-12 20:28:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A setter for the `ipfsGateway` property
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
2020-01-13 19:36:36 +01:00
|
|
|
* @param {string} domain - The new IPFS gateway domain
|
2020-11-10 18:30:41 +01:00
|
|
|
* @returns {Promise<string>} A promise of the update IPFS gateway domain
|
2019-12-12 20:28:07 +01:00
|
|
|
*/
|
2023-01-20 21:20:18 +01:00
|
|
|
async setIpfsGateway(domain) {
|
2021-02-04 19:15:23 +01:00
|
|
|
this.store.updateState({ ipfsGateway: domain });
|
2023-01-20 21:20:18 +01:00
|
|
|
return domain;
|
2019-12-12 20:28:07 +01:00
|
|
|
}
|
|
|
|
|
2021-04-26 20:05:48 +02:00
|
|
|
/**
|
2022-01-07 16:57:33 +01:00
|
|
|
* A setter for the `ledgerTransportType` property.
|
|
|
|
*
|
2021-10-21 21:17:03 +02:00
|
|
|
* @param {string} ledgerTransportType - Either 'ledgerLive', 'webhid' or 'u2f'
|
|
|
|
* @returns {string} The transport type that was set.
|
2021-04-26 20:05:48 +02:00
|
|
|
*/
|
2021-10-21 21:17:03 +02:00
|
|
|
setLedgerTransportPreference(ledgerTransportType) {
|
|
|
|
this.store.updateState({ ledgerTransportType });
|
|
|
|
return ledgerTransportType;
|
2021-04-26 20:05:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-01-07 16:57:33 +01:00
|
|
|
* A getter for the `ledgerTransportType` property.
|
|
|
|
*
|
|
|
|
* @returns {string} The current preferred Ledger transport type.
|
2021-04-26 20:05:48 +02:00
|
|
|
*/
|
2021-10-21 21:17:03 +02:00
|
|
|
getLedgerTransportPreference() {
|
|
|
|
return this.store.getState().ledgerTransportType;
|
2021-04-26 20:05:48 +02:00
|
|
|
}
|
|
|
|
|
2021-05-05 15:58:29 +02:00
|
|
|
/**
|
|
|
|
* A setter for the user preference to dismiss the seed phrase backup reminder
|
2022-01-07 16:57:33 +01:00
|
|
|
*
|
|
|
|
* @param {bool} dismissSeedBackUpReminder - User preference for dismissing the back up reminder.
|
2021-05-05 15:58:29 +02:00
|
|
|
*/
|
|
|
|
async setDismissSeedBackUpReminder(dismissSeedBackUpReminder) {
|
|
|
|
await this.store.updateState({
|
|
|
|
dismissSeedBackUpReminder,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-01-30 21:42:24 +01:00
|
|
|
//
|
|
|
|
// PRIVATE METHODS
|
|
|
|
//
|
2018-08-07 00:28:47 +02:00
|
|
|
|
2021-04-15 19:41:40 +02:00
|
|
|
_subscribeToInfuraAvailability() {
|
|
|
|
this.network.on(NETWORK_EVENTS.INFURA_IS_BLOCKED, () => {
|
|
|
|
this._setInfuraBlocked(true);
|
|
|
|
});
|
|
|
|
this.network.on(NETWORK_EVENTS.INFURA_IS_UNBLOCKED, () => {
|
|
|
|
this._setInfuraBlocked(false);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* A setter for the `infuraBlocked` property
|
|
|
|
*
|
2022-01-07 16:57:33 +01:00
|
|
|
* @param {boolean} isBlocked - Bool indicating whether Infura is blocked
|
2021-04-15 19:41:40 +02:00
|
|
|
*/
|
|
|
|
_setInfuraBlocked(isBlocked) {
|
|
|
|
const { infuraBlocked } = this.store.getState();
|
|
|
|
|
|
|
|
if (infuraBlocked === isBlocked) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.store.updateState({ infuraBlocked: isBlocked });
|
|
|
|
}
|
2017-01-30 21:42:24 +01:00
|
|
|
}
|