@metamask/assets-controllers 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.0.1]
10
+ ### Fixed
11
+ - Fix race condition where some token detections can get mistakenly added to the wrong account ([#956](https://github.com/MetaMask/controllers/pull/956))
12
+
9
13
  ## [1.0.0]
10
14
  ### Added
11
15
  - Initial release
@@ -18,5 +22,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
22
  ### Changed
19
23
  - Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/controllers/pull/845))
20
24
 
21
- [Unreleased]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@1.0.0...HEAD
25
+ [Unreleased]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@1.0.1...HEAD
26
+ [1.0.1]: https://github.com/MetaMask/controllers/compare/@metamask/assets-controllers@1.0.0...@metamask/assets-controllers@1.0.1
22
27
  [1.0.0]: https://github.com/MetaMask/controllers/releases/tag/@metamask/assets-controllers@1.0.0
@@ -128,7 +128,7 @@ class TokenDetectionController extends base_controller_1.BaseController {
128
128
  return;
129
129
  }
130
130
  const { tokens } = this.getTokensState();
131
- const { selectedAddress } = this.config;
131
+ const { selectedAddress, chainId } = this.config;
132
132
  const tokensAddresses = tokens.map(
133
133
  /* istanbul ignore next*/ (token) => token.address.toLowerCase());
134
134
  const { tokenList } = this.getTokenListState();
@@ -173,7 +173,10 @@ class TokenDetectionController extends base_controller_1.BaseController {
173
173
  }
174
174
  }
175
175
  if (tokensToAdd.length) {
176
- yield this.addDetectedTokens(tokensToAdd);
176
+ yield this.addDetectedTokens(tokensToAdd, {
177
+ selectedAddress,
178
+ chainId,
179
+ });
177
180
  }
178
181
  }));
179
182
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TokenDetectionController.js","sourceRoot":"","sources":["../src/TokenDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport { isTokenDetectionSupportedForNetwork } from './assetsUtil';\nimport type { TokensController, TokensState } from './TokensController';\nimport type { AssetsContractController } from './AssetsContractController';\nimport { Token } from './TokenRatesController';\nimport { TokenListState } from './TokenListController';\n\nconst DEFAULT_INTERVAL = 180000;\n\n/**\n * @type TokenDetectionConfig\n *\n * TokenDetection configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property selectedAddress - Vault selected address\n * @property chainId - The chain ID of the current network\n * @property isDetectionEnabledFromPreferences - Boolean to track if detection is enabled from PreferencesController\n * @property isDetectionEnabledForNetwork - Boolean to track if detected is enabled for current network\n */\nexport interface TokenDetectionConfig extends BaseConfig {\n interval: number;\n selectedAddress: string;\n chainId: string;\n isDetectionEnabledFromPreferences: boolean;\n isDetectionEnabledForNetwork: boolean;\n}\n\n/**\n * Controller that passively polls on a set interval for Tokens auto detection\n */\nexport class TokenDetectionController extends BaseController<\n TokenDetectionConfig,\n BaseState\n> {\n private intervalId?: ReturnType<typeof setTimeout>;\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenDetectionController';\n\n private getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n\n private addDetectedTokens: TokensController['addDetectedTokens'];\n\n private getTokensState: () => TokensState;\n\n private getTokenListState: () => TokenListState;\n\n /**\n * Creates a TokenDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.\n * @param options.addDetectedTokens - Add a list of detected tokens.\n * @param options.getTokenListState - Gets the current state of the TokenList controller.\n * @param options.getTokensState - Gets the current state of the Tokens controller.\n * @param options.getNetworkState - Gets the state of the network controller.\n * @param options.getPreferencesState - Gets the state of the preferences controller.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getBalancesInSingleCall,\n addDetectedTokens,\n getTokenListState,\n getTokensState,\n getNetworkState,\n getPreferencesState,\n }: {\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n addDetectedTokens: TokensController['addDetectedTokens'];\n getTokenListState: () => TokenListState;\n getTokensState: () => TokensState;\n getNetworkState: () => NetworkState;\n getPreferencesState: () => PreferencesState;\n },\n config?: Partial<TokenDetectionConfig>,\n state?: Partial<BaseState>,\n ) {\n const {\n provider: { chainId: defaultChainId },\n } = getNetworkState();\n const { useTokenDetection: defaultUseTokenDetection } =\n getPreferencesState();\n\n super(config, state);\n this.defaultConfig = {\n interval: DEFAULT_INTERVAL,\n selectedAddress: '',\n disabled: true,\n chainId: defaultChainId,\n isDetectionEnabledFromPreferences: defaultUseTokenDetection,\n isDetectionEnabledForNetwork:\n isTokenDetectionSupportedForNetwork(defaultChainId),\n ...config,\n };\n\n this.initialize();\n this.getTokensState = getTokensState;\n this.getTokenListState = getTokenListState;\n this.addDetectedTokens = addDetectedTokens;\n this.getBalancesInSingleCall = getBalancesInSingleCall;\n\n onTokenListStateChange(({ tokenList }) => {\n const hasTokens = Object.keys(tokenList).length;\n\n if (hasTokens) {\n this.detectTokens();\n }\n });\n\n onPreferencesStateChange(({ selectedAddress, useTokenDetection }) => {\n const {\n selectedAddress: currentSelectedAddress,\n isDetectionEnabledFromPreferences,\n } = this.config;\n const isSelectedAddressChanged =\n selectedAddress !== currentSelectedAddress;\n const isDetectionChangedFromPreferences =\n isDetectionEnabledFromPreferences !== useTokenDetection;\n\n this.configure({\n isDetectionEnabledFromPreferences: useTokenDetection,\n selectedAddress,\n });\n\n if (\n useTokenDetection &&\n (isSelectedAddressChanged || isDetectionChangedFromPreferences)\n ) {\n this.detectTokens();\n }\n });\n\n onNetworkStateChange(({ provider: { chainId } }) => {\n const { chainId: currentChainId } = this.config;\n const isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(chainId);\n const isChainIdChanged = currentChainId !== chainId;\n\n this.configure({\n chainId,\n isDetectionEnabledForNetwork,\n });\n\n if (isDetectionEnabledForNetwork && isChainIdChanged) {\n this.detectTokens();\n }\n });\n }\n\n /**\n * Start polling for detected tokens.\n */\n async start() {\n this.configure({ disabled: false });\n await this.startPolling();\n }\n\n /**\n * Stop polling for detected tokens.\n */\n stop() {\n this.configure({ disabled: true });\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - An interval on which to poll.\n */\n private async startPolling(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.stopPolling();\n await this.detectTokens();\n this.intervalId = setInterval(async () => {\n await this.detectTokens();\n }, this.config.interval);\n }\n\n /**\n * Triggers asset ERC20 token auto detection for each contract address in contract metadata on mainnet.\n */\n async detectTokens() {\n const {\n disabled,\n isDetectionEnabledForNetwork,\n isDetectionEnabledFromPreferences,\n } = this.config;\n if (\n disabled ||\n !isDetectionEnabledForNetwork ||\n !isDetectionEnabledFromPreferences\n ) {\n return;\n }\n const { tokens } = this.getTokensState();\n const { selectedAddress } = this.config;\n\n const tokensAddresses = tokens.map(\n /* istanbul ignore next*/ (token) => token.address.toLowerCase(),\n );\n const { tokenList } = this.getTokenListState();\n const tokensToDetect: string[] = [];\n for (const address in tokenList) {\n if (!tokensAddresses.includes(address)) {\n tokensToDetect.push(address);\n }\n }\n const sliceOfTokensToDetect = [];\n sliceOfTokensToDetect[0] = tokensToDetect.slice(0, 1000);\n sliceOfTokensToDetect[1] = tokensToDetect.slice(\n 1000,\n tokensToDetect.length - 1,\n );\n\n /* istanbul ignore else */\n if (!selectedAddress) {\n return;\n }\n\n for (const tokensSlice of sliceOfTokensToDetect) {\n if (tokensSlice.length === 0) {\n break;\n }\n\n await safelyExecute(async () => {\n const balances = await this.getBalancesInSingleCall(\n selectedAddress,\n tokensSlice,\n );\n const tokensToAdd: Token[] = [];\n for (const tokenAddress in balances) {\n let ignored;\n /* istanbul ignore else */\n const { ignoredTokens } = this.getTokensState();\n if (ignoredTokens.length) {\n ignored = ignoredTokens.find(\n (ignoredTokenAddress) =>\n ignoredTokenAddress === toChecksumHexAddress(tokenAddress),\n );\n }\n const caseInsensitiveTokenKey =\n Object.keys(tokenList).find(\n (i) => i.toLowerCase() === tokenAddress.toLowerCase(),\n ) || '';\n\n if (ignored === undefined) {\n const { decimals, symbol, aggregators, iconUrl } =\n tokenList[caseInsensitiveTokenKey];\n tokensToAdd.push({\n address: tokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n });\n }\n }\n\n if (tokensToAdd.length) {\n await this.addDetectedTokens(tokensToAdd);\n }\n });\n }\n }\n}\n\nexport default TokenDetectionController;\n"]}
1
+ {"version":3,"file":"TokenDetectionController.js","sourceRoot":"","sources":["../src/TokenDetectionController.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport type { NetworkState } from '@metamask/network-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport {\n safelyExecute,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport { isTokenDetectionSupportedForNetwork } from './assetsUtil';\nimport type { TokensController, TokensState } from './TokensController';\nimport type { AssetsContractController } from './AssetsContractController';\nimport { Token } from './TokenRatesController';\nimport { TokenListState } from './TokenListController';\n\nconst DEFAULT_INTERVAL = 180000;\n\n/**\n * @type TokenDetectionConfig\n *\n * TokenDetection configuration\n * @property interval - Polling interval used to fetch new token rates\n * @property selectedAddress - Vault selected address\n * @property chainId - The chain ID of the current network\n * @property isDetectionEnabledFromPreferences - Boolean to track if detection is enabled from PreferencesController\n * @property isDetectionEnabledForNetwork - Boolean to track if detected is enabled for current network\n */\nexport interface TokenDetectionConfig extends BaseConfig {\n interval: number;\n selectedAddress: string;\n chainId: string;\n isDetectionEnabledFromPreferences: boolean;\n isDetectionEnabledForNetwork: boolean;\n}\n\n/**\n * Controller that passively polls on a set interval for Tokens auto detection\n */\nexport class TokenDetectionController extends BaseController<\n TokenDetectionConfig,\n BaseState\n> {\n private intervalId?: ReturnType<typeof setTimeout>;\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokenDetectionController';\n\n private getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n\n private addDetectedTokens: TokensController['addDetectedTokens'];\n\n private getTokensState: () => TokensState;\n\n private getTokenListState: () => TokenListState;\n\n /**\n * Creates a TokenDetectionController instance.\n *\n * @param options - The controller options.\n * @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.onTokenListStateChange - Allows subscribing to token list controller state changes.\n * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.\n * @param options.addDetectedTokens - Add a list of detected tokens.\n * @param options.getTokenListState - Gets the current state of the TokenList controller.\n * @param options.getTokensState - Gets the current state of the Tokens controller.\n * @param options.getNetworkState - Gets the state of the network controller.\n * @param options.getPreferencesState - Gets the state of the preferences controller.\n * @param config - Initial options used to configure this controller.\n * @param state - Initial state to set on this controller.\n */\n constructor(\n {\n onPreferencesStateChange,\n onNetworkStateChange,\n onTokenListStateChange,\n getBalancesInSingleCall,\n addDetectedTokens,\n getTokenListState,\n getTokensState,\n getNetworkState,\n getPreferencesState,\n }: {\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n onTokenListStateChange: (\n listener: (tokenListState: TokenListState) => void,\n ) => void;\n getBalancesInSingleCall: AssetsContractController['getBalancesInSingleCall'];\n addDetectedTokens: TokensController['addDetectedTokens'];\n getTokenListState: () => TokenListState;\n getTokensState: () => TokensState;\n getNetworkState: () => NetworkState;\n getPreferencesState: () => PreferencesState;\n },\n config?: Partial<TokenDetectionConfig>,\n state?: Partial<BaseState>,\n ) {\n const {\n provider: { chainId: defaultChainId },\n } = getNetworkState();\n const { useTokenDetection: defaultUseTokenDetection } =\n getPreferencesState();\n\n super(config, state);\n this.defaultConfig = {\n interval: DEFAULT_INTERVAL,\n selectedAddress: '',\n disabled: true,\n chainId: defaultChainId,\n isDetectionEnabledFromPreferences: defaultUseTokenDetection,\n isDetectionEnabledForNetwork:\n isTokenDetectionSupportedForNetwork(defaultChainId),\n ...config,\n };\n\n this.initialize();\n this.getTokensState = getTokensState;\n this.getTokenListState = getTokenListState;\n this.addDetectedTokens = addDetectedTokens;\n this.getBalancesInSingleCall = getBalancesInSingleCall;\n\n onTokenListStateChange(({ tokenList }) => {\n const hasTokens = Object.keys(tokenList).length;\n\n if (hasTokens) {\n this.detectTokens();\n }\n });\n\n onPreferencesStateChange(({ selectedAddress, useTokenDetection }) => {\n const {\n selectedAddress: currentSelectedAddress,\n isDetectionEnabledFromPreferences,\n } = this.config;\n const isSelectedAddressChanged =\n selectedAddress !== currentSelectedAddress;\n const isDetectionChangedFromPreferences =\n isDetectionEnabledFromPreferences !== useTokenDetection;\n\n this.configure({\n isDetectionEnabledFromPreferences: useTokenDetection,\n selectedAddress,\n });\n\n if (\n useTokenDetection &&\n (isSelectedAddressChanged || isDetectionChangedFromPreferences)\n ) {\n this.detectTokens();\n }\n });\n\n onNetworkStateChange(({ provider: { chainId } }) => {\n const { chainId: currentChainId } = this.config;\n const isDetectionEnabledForNetwork =\n isTokenDetectionSupportedForNetwork(chainId);\n const isChainIdChanged = currentChainId !== chainId;\n\n this.configure({\n chainId,\n isDetectionEnabledForNetwork,\n });\n\n if (isDetectionEnabledForNetwork && isChainIdChanged) {\n this.detectTokens();\n }\n });\n }\n\n /**\n * Start polling for detected tokens.\n */\n async start() {\n this.configure({ disabled: false });\n await this.startPolling();\n }\n\n /**\n * Stop polling for detected tokens.\n */\n stop() {\n this.configure({ disabled: true });\n this.stopPolling();\n }\n\n private stopPolling() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n }\n }\n\n /**\n * Starts a new polling interval.\n *\n * @param interval - An interval on which to poll.\n */\n private async startPolling(interval?: number): Promise<void> {\n interval && this.configure({ interval }, false, false);\n this.stopPolling();\n await this.detectTokens();\n this.intervalId = setInterval(async () => {\n await this.detectTokens();\n }, this.config.interval);\n }\n\n /**\n * Triggers asset ERC20 token auto detection for each contract address in contract metadata on mainnet.\n */\n async detectTokens() {\n const {\n disabled,\n isDetectionEnabledForNetwork,\n isDetectionEnabledFromPreferences,\n } = this.config;\n if (\n disabled ||\n !isDetectionEnabledForNetwork ||\n !isDetectionEnabledFromPreferences\n ) {\n return;\n }\n const { tokens } = this.getTokensState();\n const { selectedAddress, chainId } = this.config;\n\n const tokensAddresses = tokens.map(\n /* istanbul ignore next*/ (token) => token.address.toLowerCase(),\n );\n const { tokenList } = this.getTokenListState();\n const tokensToDetect: string[] = [];\n for (const address in tokenList) {\n if (!tokensAddresses.includes(address)) {\n tokensToDetect.push(address);\n }\n }\n const sliceOfTokensToDetect = [];\n sliceOfTokensToDetect[0] = tokensToDetect.slice(0, 1000);\n sliceOfTokensToDetect[1] = tokensToDetect.slice(\n 1000,\n tokensToDetect.length - 1,\n );\n\n /* istanbul ignore else */\n if (!selectedAddress) {\n return;\n }\n\n for (const tokensSlice of sliceOfTokensToDetect) {\n if (tokensSlice.length === 0) {\n break;\n }\n\n await safelyExecute(async () => {\n const balances = await this.getBalancesInSingleCall(\n selectedAddress,\n tokensSlice,\n );\n const tokensToAdd: Token[] = [];\n for (const tokenAddress in balances) {\n let ignored;\n /* istanbul ignore else */\n const { ignoredTokens } = this.getTokensState();\n if (ignoredTokens.length) {\n ignored = ignoredTokens.find(\n (ignoredTokenAddress) =>\n ignoredTokenAddress === toChecksumHexAddress(tokenAddress),\n );\n }\n const caseInsensitiveTokenKey =\n Object.keys(tokenList).find(\n (i) => i.toLowerCase() === tokenAddress.toLowerCase(),\n ) || '';\n\n if (ignored === undefined) {\n const { decimals, symbol, aggregators, iconUrl } =\n tokenList[caseInsensitiveTokenKey];\n tokensToAdd.push({\n address: tokenAddress,\n decimals,\n symbol,\n aggregators,\n image: iconUrl,\n isERC721: false,\n });\n }\n }\n\n if (tokensToAdd.length) {\n await this.addDetectedTokens(tokensToAdd, {\n selectedAddress,\n chainId,\n });\n }\n });\n }\n }\n}\n\nexport default TokenDetectionController;\n"]}
@@ -155,8 +155,14 @@ export declare class TokensController extends BaseController<TokensConfig, Token
155
155
  * Adds a batch of detected tokens to the stored token list.
156
156
  *
157
157
  * @param incomingDetectedTokens - Array of detected tokens to be added or updated.
158
+ * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.
159
+ * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.
160
+ * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.
158
161
  */
159
- addDetectedTokens(incomingDetectedTokens: Token[]): Promise<void>;
162
+ addDetectedTokens(incomingDetectedTokens: Token[], detectionDetails?: {
163
+ selectedAddress: string;
164
+ chainId: string;
165
+ }): Promise<void>;
160
166
  /**
161
167
  * Adds isERC721 field to token object. This is called when a user attempts to add tokens that
162
168
  * were previously added which do not yet had isERC721 field.
@@ -207,12 +213,16 @@ export declare class TokensController extends BaseController<TokensConfig, Token
207
213
  * @param params.newTokens - The new tokens to set for the current network and selected account.
208
214
  * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.
209
215
  * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.
216
+ * @param params.detectionAddress - The address on which the detected tokens to add were detected.
217
+ * @param params.detectionChainId - The chainId on which the detected tokens to add were detected.
210
218
  * @returns The updated `allTokens` and `allIgnoredTokens` state.
211
219
  */
212
220
  _getNewAllTokensState(params: {
213
221
  newTokens?: Token[];
214
222
  newIgnoredTokens?: string[];
215
223
  newDetectedTokens?: Token[];
224
+ detectionAddress?: string;
225
+ detectionChainId?: string;
216
226
  }): {
217
227
  newAllTokens: {
218
228
  [key: string]: {
@@ -269,13 +269,17 @@ class TokensController extends base_controller_1.BaseController {
269
269
  * Adds a batch of detected tokens to the stored token list.
270
270
  *
271
271
  * @param incomingDetectedTokens - Array of detected tokens to be added or updated.
272
+ * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.
273
+ * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.
274
+ * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.
272
275
  */
273
- addDetectedTokens(incomingDetectedTokens) {
276
+ addDetectedTokens(incomingDetectedTokens, detectionDetails) {
277
+ var _a;
274
278
  return __awaiter(this, void 0, void 0, function* () {
275
279
  const releaseLock = yield this.mutex.acquire();
276
280
  const { tokens, detectedTokens, ignoredTokens } = this.state;
277
281
  const newTokens = [...tokens];
278
- const newDetectedTokens = [...detectedTokens];
282
+ let newDetectedTokens = [...detectedTokens];
279
283
  try {
280
284
  incomingDetectedTokens.forEach((tokenToAdd) => {
281
285
  const { address, symbol, decimals, image, aggregators, isERC721 } = tokenToAdd;
@@ -309,10 +313,19 @@ class TokensController extends base_controller_1.BaseController {
309
313
  }
310
314
  }
311
315
  });
316
+ const { selectedAddress: detectionAddress, chainId: detectionChainId } = detectionDetails || {};
312
317
  const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState({
313
318
  newTokens,
314
319
  newDetectedTokens,
320
+ detectionAddress,
321
+ detectionChainId,
315
322
  });
323
+ const { chainId, selectedAddress } = this.config;
324
+ // if the newly added detectedTokens were detected on (and therefore added to) a different chainId/selectedAddress than the currently configured combo
325
+ // the newDetectedTokens (which should contain the detectedTokens on the current chainId/address combo) needs to be repointed to the current chainId/address pair
326
+ // if the detectedTokens were detected on the current chainId/address then this won't change anything.
327
+ newDetectedTokens =
328
+ ((_a = newAllDetectedTokens === null || newAllDetectedTokens === void 0 ? void 0 : newAllDetectedTokens[chainId]) === null || _a === void 0 ? void 0 : _a[selectedAddress]) || [];
316
329
  this.update({
317
330
  tokens: newTokens,
318
331
  allTokens: newAllTokens,
@@ -492,29 +505,33 @@ class TokensController extends base_controller_1.BaseController {
492
505
  * @param params.newTokens - The new tokens to set for the current network and selected account.
493
506
  * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.
494
507
  * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.
508
+ * @param params.detectionAddress - The address on which the detected tokens to add were detected.
509
+ * @param params.detectionChainId - The chainId on which the detected tokens to add were detected.
495
510
  * @returns The updated `allTokens` and `allIgnoredTokens` state.
496
511
  */
497
512
  _getNewAllTokensState(params) {
498
- const { newTokens, newIgnoredTokens, newDetectedTokens } = params;
513
+ const { newTokens, newIgnoredTokens, newDetectedTokens, detectionAddress, detectionChainId, } = params;
499
514
  const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;
500
515
  const { chainId, selectedAddress } = this.config;
516
+ const userAddressToAddTokens = detectionAddress !== null && detectionAddress !== void 0 ? detectionAddress : selectedAddress;
517
+ const chainIdToAddTokens = detectionChainId !== null && detectionChainId !== void 0 ? detectionChainId : chainId;
501
518
  let newAllTokens = allTokens;
502
- if (newTokens) {
503
- const networkTokens = allTokens[chainId];
504
- const newNetworkTokens = Object.assign(Object.assign({}, networkTokens), { [selectedAddress]: newTokens });
505
- newAllTokens = Object.assign(Object.assign({}, allTokens), { [chainId]: newNetworkTokens });
519
+ if (newTokens === null || newTokens === void 0 ? void 0 : newTokens.length) {
520
+ const networkTokens = allTokens[chainIdToAddTokens];
521
+ const newNetworkTokens = Object.assign(Object.assign({}, networkTokens), { [userAddressToAddTokens]: newTokens });
522
+ newAllTokens = Object.assign(Object.assign({}, allTokens), { [chainIdToAddTokens]: newNetworkTokens });
506
523
  }
507
524
  let newAllIgnoredTokens = allIgnoredTokens;
508
- if (newIgnoredTokens) {
509
- const networkIgnoredTokens = allIgnoredTokens[chainId];
510
- const newIgnoredNetworkTokens = Object.assign(Object.assign({}, networkIgnoredTokens), { [selectedAddress]: newIgnoredTokens });
511
- newAllIgnoredTokens = Object.assign(Object.assign({}, allIgnoredTokens), { [chainId]: newIgnoredNetworkTokens });
525
+ if (newIgnoredTokens === null || newIgnoredTokens === void 0 ? void 0 : newIgnoredTokens.length) {
526
+ const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];
527
+ const newIgnoredNetworkTokens = Object.assign(Object.assign({}, networkIgnoredTokens), { [userAddressToAddTokens]: newIgnoredTokens });
528
+ newAllIgnoredTokens = Object.assign(Object.assign({}, allIgnoredTokens), { [chainIdToAddTokens]: newIgnoredNetworkTokens });
512
529
  }
513
530
  let newAllDetectedTokens = allDetectedTokens;
514
- if (newDetectedTokens) {
515
- const networkDetectedTokens = allDetectedTokens[chainId];
516
- const newDetectedNetworkTokens = Object.assign(Object.assign({}, networkDetectedTokens), { [selectedAddress]: newDetectedTokens });
517
- newAllDetectedTokens = Object.assign(Object.assign({}, allDetectedTokens), { [chainId]: newDetectedNetworkTokens });
531
+ if (newDetectedTokens === null || newDetectedTokens === void 0 ? void 0 : newDetectedTokens.length) {
532
+ const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];
533
+ const newDetectedNetworkTokens = Object.assign(Object.assign({}, networkDetectedTokens), { [userAddressToAddTokens]: newDetectedTokens });
534
+ newAllDetectedTokens = Object.assign(Object.assign({}, allDetectedTokens), { [chainIdToAddTokens]: newDetectedNetworkTokens });
518
535
  }
519
536
  return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };
520
537
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from 'events';\nimport contractsMap from '@metamask/contract-metadata';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport { v1 as random } from 'uuid';\nimport { Mutex } from 'async-mutex';\nimport { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { AbortController as WhatwgAbortController } from 'abort-controller';\nimport {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { NetworkState } from '@metamask/network-controller';\nimport {\n NetworkType,\n toChecksumHexAddress,\n MAINNET,\n ERC721_INTERFACE_ID,\n} from '@metamask/controller-utils';\nimport type { Token } from './TokenRatesController';\nimport { TokenListToken } from './TokenListController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property networkType - Network ID as per net_version\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n networkType: NetworkType;\n selectedAddress: string;\n chainId: string;\n provider: any;\n}\n\n/**\n * @type AssetSuggestionResult\n * @property result - Promise resolving to a new suggested asset address\n * @property suggestedAssetMeta - Meta information about this new suggested asset\n */\ninterface AssetSuggestionResult {\n result: Promise<string>;\n suggestedAssetMeta: SuggestedAssetMeta;\n}\n\nenum SuggestedAssetStatus {\n accepted = 'accepted',\n failed = 'failed',\n pending = 'pending',\n rejected = 'rejected',\n}\n\nexport type SuggestedAssetMetaBase = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n};\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property error - Synthesized error information for failed asset suggestions\n * @property id - Generated UUID associated with this suggested asset\n * @property status - String status of this this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n */\nexport type SuggestedAssetMeta =\n | (SuggestedAssetMetaBase & {\n status: SuggestedAssetStatus.failed;\n error: Error;\n })\n | (SuggestedAssetMetaBase & {\n status:\n | SuggestedAssetStatus.accepted\n | SuggestedAssetStatus.rejected\n | SuggestedAssetStatus.pending;\n });\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n * @property suggestedAssets - List of pending suggested assets to be added or canceled\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [key: string]: { [key: string]: Token[] } };\n allIgnoredTokens: { [key: string]: { [key: string]: string[] } };\n allDetectedTokens: { [key: string]: { [key: string]: Token[] } };\n suggestedAssets: SuggestedAssetMeta[];\n}\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private mutex = new Mutex();\n\n private ethersProvider: any;\n\n private abortController: WhatwgAbortController;\n\n private failSuggestedAsset(\n suggestedAssetMeta: SuggestedAssetMeta,\n error: unknown,\n ) {\n const failedSuggestedAssetMeta = {\n ...suggestedAssetMeta,\n status: SuggestedAssetStatus.failed,\n error,\n };\n this.hub.emit(\n `${suggestedAssetMeta.id}:finished`,\n failedSuggestedAssetMeta,\n );\n }\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n */\n constructor({\n onPreferencesStateChange,\n onNetworkStateChange,\n config,\n state,\n }: {\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n networkType: MAINNET,\n selectedAddress: '',\n chainId: '',\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n suggestedAssets: [],\n ...state,\n };\n\n this.initialize();\n this.abortController = new WhatwgAbortController();\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ provider }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = provider;\n this.abortController.abort();\n this.abortController = new WhatwgAbortController();\n this.configure({ chainId });\n this.ethersProvider = this._instantiateNewEthersProvider();\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n }\n\n _instantiateNewEthersProvider(): any {\n return new Web3Provider(this.config?.provider);\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param address - Hex address of the token contract.\n * @param symbol - Symbol of the token.\n * @param decimals - Number of decimals the token uses.\n * @param image - Image of the token.\n * @returns Current token list.\n */\n async addToken(\n address: string,\n symbol: string,\n decimals: number,\n image?: string,\n ): Promise<Token[]> {\n const currentChainId = this.config.chainId;\n const releaseLock = await this.mutex.acquire();\n try {\n address = toChecksumHexAddress(address);\n const { tokens, ignoredTokens, detectedTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n const [isERC721, tokenMetadata] = await Promise.all([\n this._detectIsERC721(address),\n this.fetchTokenMetadata(address),\n ]);\n if (currentChainId !== this.config.chainId) {\n throw new Error(\n 'TokensController Error: Switched networks while adding token',\n );\n }\n const newEntry: Token = {\n address,\n symbol,\n decimals,\n image:\n image ||\n formatIconUrlWithProxy({\n chainId: this.config.chainId,\n tokenAddress: address,\n }),\n isERC721,\n aggregators: formatAggregatorNames(tokenMetadata?.aggregators || []),\n };\n const previousEntry = newTokens.find(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousEntry) {\n const previousIndex = newTokens.indexOf(previousEntry);\n newTokens[previousIndex] = newEntry;\n } else {\n newTokens.push(newEntry);\n }\n\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => tokenAddress.toLowerCase() !== address.toLowerCase(),\n );\n const newDetectedTokens = detectedTokens.filter(\n (token) => token.address.toLowerCase() !== address.toLowerCase(),\n );\n const { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens } =\n this._getNewAllTokensState({\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n });\n\n this.update({\n tokens: newTokens,\n ignoredTokens: newIgnoredTokens,\n detectedTokens: newDetectedTokens,\n allTokens: newAllTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n return newTokens;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Add a batch of tokens.\n *\n * @param tokensToImport - Array of tokens to import.\n */\n async addTokens(tokensToImport: Token[]) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const importedTokensMap: { [key: string]: true } = {};\n // Used later to dedupe imported tokens\n const newTokensMap = tokens.reduce((output, current) => {\n output[current.address] = current;\n return output;\n }, {} as { [address: string]: Token });\n\n try {\n tokensToImport.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators } = tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const formattedToken: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n aggregators,\n };\n newTokensMap[address] = formattedToken;\n importedTokensMap[address.toLowerCase()] = true;\n return formattedToken;\n });\n const newTokens = Object.values(newTokensMap);\n\n const newDetectedTokens = detectedTokens.filter(\n (token) => !importedTokensMap[token.address.toLowerCase()],\n );\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()],\n );\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n */\n async addDetectedTokens(incomingDetectedTokens: Token[]) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n const newDetectedTokens: Token[] = [...detectedTokens];\n\n try {\n incomingDetectedTokens.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators, isERC721 } =\n tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const newEntry: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n isERC721,\n aggregators,\n };\n const previousImportedEntry = newTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedEntry) {\n // Update existing data of imported token\n const previousImportedIndex = newTokens.indexOf(\n previousImportedEntry,\n );\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex = ignoredTokens.indexOf(address);\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedEntry = newDetectedTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedEntry) {\n const previousDetectedIndex = newDetectedTokens.indexOf(\n previousDetectedEntry,\n );\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n },\n );\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(tokenAddress: string) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n this.ethersProvider,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n ethersProvider: any,\n ): Contract {\n const tokenContract = new Contract(tokenAddress, abi, ethersProvider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to state. Parameters will be validated according to\n * asset type being watched. A `<suggestedAssetMeta.id>:pending` hub event will be emitted once added.\n *\n * @param asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param type - The asset type.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset(asset: Token, type: string): Promise<AssetSuggestionResult> {\n const suggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n status: SuggestedAssetStatus.pending as SuggestedAssetStatus.pending,\n time: Date.now(),\n type,\n };\n try {\n switch (type) {\n case 'ERC20':\n validateTokenToWatch(asset);\n break;\n default:\n throw new Error(`Asset of type ${type} not supported`);\n }\n } catch (error) {\n this.failSuggestedAsset(suggestedAssetMeta, error);\n return Promise.reject(error);\n }\n\n const result: Promise<string> = new Promise((resolve, reject) => {\n this.hub.once(\n `${suggestedAssetMeta.id}:finished`,\n (meta: SuggestedAssetMeta) => {\n switch (meta.status) {\n case SuggestedAssetStatus.accepted:\n return resolve(meta.asset.address);\n case SuggestedAssetStatus.rejected:\n return reject(new Error('User rejected to watch the asset.'));\n case SuggestedAssetStatus.failed:\n return reject(new Error(meta.error.message));\n /* istanbul ignore next */\n default:\n return reject(new Error(`Unknown status: ${meta.status}`));\n }\n },\n );\n });\n\n const { suggestedAssets } = this.state;\n suggestedAssets.push(suggestedAssetMeta);\n this.update({ suggestedAssets: [...suggestedAssets] });\n this.hub.emit('pendingSuggestedAsset', suggestedAssetMeta);\n return { result, suggestedAssetMeta };\n }\n\n /**\n * Accepts to watch an asset and updates it's status and deletes the suggestedAsset from state,\n * adding the asset to corresponding asset state. In this case ERC20 tokens.\n * A `<suggestedAssetMeta.id>:finished` hub event is fired after accepted or failure.\n *\n * @param suggestedAssetID - The ID of the suggestedAsset to accept.\n */\n async acceptWatchAsset(suggestedAssetID: string): Promise<void> {\n const { suggestedAssets } = this.state;\n const index = suggestedAssets.findIndex(\n ({ id }) => suggestedAssetID === id,\n );\n const suggestedAssetMeta = suggestedAssets[index];\n try {\n switch (suggestedAssetMeta.type) {\n case 'ERC20':\n const { address, symbol, decimals, image } = suggestedAssetMeta.asset;\n await this.addToken(address, symbol, decimals, image);\n suggestedAssetMeta.status = SuggestedAssetStatus.accepted;\n this.hub.emit(\n `${suggestedAssetMeta.id}:finished`,\n suggestedAssetMeta,\n );\n break;\n default:\n throw new Error(\n `Asset of type ${suggestedAssetMeta.type} not supported`,\n );\n }\n } catch (error) {\n this.failSuggestedAsset(suggestedAssetMeta, error);\n }\n const newSuggestedAssets = suggestedAssets.filter(\n ({ id }) => id !== suggestedAssetID,\n );\n this.update({ suggestedAssets: [...newSuggestedAssets] });\n }\n\n /**\n * Rejects a watchAsset request based on its ID by setting its status to \"rejected\"\n * and emitting a `<suggestedAssetMeta.id>:finished` hub event.\n *\n * @param suggestedAssetID - The ID of the suggestedAsset to accept.\n */\n rejectWatchAsset(suggestedAssetID: string) {\n const { suggestedAssets } = this.state;\n const index = suggestedAssets.findIndex(\n ({ id }) => suggestedAssetID === id,\n );\n const suggestedAssetMeta = suggestedAssets[index];\n if (!suggestedAssetMeta) {\n return;\n }\n suggestedAssetMeta.status = SuggestedAssetStatus.rejected;\n this.hub.emit(`${suggestedAssetMeta.id}:finished`, suggestedAssetMeta);\n const newSuggestedAssets = suggestedAssets.filter(\n ({ id }) => id !== suggestedAssetID,\n );\n this.update({ suggestedAssets: [...newSuggestedAssets] });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n }) {\n const { newTokens, newIgnoredTokens, newDetectedTokens } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n let newAllTokens = allTokens;\n if (newTokens) {\n const networkTokens = allTokens[chainId];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [selectedAddress]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainId]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (newIgnoredTokens) {\n const networkIgnoredTokens = allIgnoredTokens[chainId];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [selectedAddress]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainId]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (newDetectedTokens) {\n const networkDetectedTokens = allDetectedTokens[chainId];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [selectedAddress]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainId]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n}\n\nexport default TokensController;\n"]}
1
+ {"version":3,"file":"TokensController.js","sourceRoot":"","sources":["../src/TokensController.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from 'events';\nimport contractsMap from '@metamask/contract-metadata';\nimport { abiERC721 } from '@metamask/metamask-eth-abis';\nimport { v1 as random } from 'uuid';\nimport { Mutex } from 'async-mutex';\nimport { Contract } from '@ethersproject/contracts';\nimport { Web3Provider } from '@ethersproject/providers';\nimport { AbortController as WhatwgAbortController } from 'abort-controller';\nimport {\n BaseController,\n BaseConfig,\n BaseState,\n} from '@metamask/base-controller';\nimport type { PreferencesState } from '@metamask/preferences-controller';\nimport type { NetworkState } from '@metamask/network-controller';\nimport {\n NetworkType,\n toChecksumHexAddress,\n MAINNET,\n ERC721_INTERFACE_ID,\n} from '@metamask/controller-utils';\nimport type { Token } from './TokenRatesController';\nimport { TokenListToken } from './TokenListController';\nimport {\n formatAggregatorNames,\n formatIconUrlWithProxy,\n validateTokenToWatch,\n} from './assetsUtil';\nimport {\n fetchTokenMetadata,\n TOKEN_METADATA_NO_SUPPORT_ERROR,\n} from './token-service';\n\n/**\n * @type TokensConfig\n *\n * Tokens controller configuration\n * @property networkType - Network ID as per net_version\n * @property selectedAddress - Vault selected address\n */\nexport interface TokensConfig extends BaseConfig {\n networkType: NetworkType;\n selectedAddress: string;\n chainId: string;\n provider: any;\n}\n\n/**\n * @type AssetSuggestionResult\n * @property result - Promise resolving to a new suggested asset address\n * @property suggestedAssetMeta - Meta information about this new suggested asset\n */\ninterface AssetSuggestionResult {\n result: Promise<string>;\n suggestedAssetMeta: SuggestedAssetMeta;\n}\n\nenum SuggestedAssetStatus {\n accepted = 'accepted',\n failed = 'failed',\n pending = 'pending',\n rejected = 'rejected',\n}\n\nexport type SuggestedAssetMetaBase = {\n id: string;\n time: number;\n type: string;\n asset: Token;\n};\n\n/**\n * @type SuggestedAssetMeta\n *\n * Suggested asset by EIP747 meta data\n * @property error - Synthesized error information for failed asset suggestions\n * @property id - Generated UUID associated with this suggested asset\n * @property status - String status of this this suggested asset\n * @property time - Timestamp associated with this this suggested asset\n * @property type - Type type this suggested asset\n * @property asset - Asset suggested object\n */\nexport type SuggestedAssetMeta =\n | (SuggestedAssetMetaBase & {\n status: SuggestedAssetStatus.failed;\n error: Error;\n })\n | (SuggestedAssetMetaBase & {\n status:\n | SuggestedAssetStatus.accepted\n | SuggestedAssetStatus.rejected\n | SuggestedAssetStatus.pending;\n });\n\n/**\n * @type TokensState\n *\n * Assets controller state\n * @property tokens - List of tokens associated with the active network and address pair\n * @property ignoredTokens - List of ignoredTokens associated with the active network and address pair\n * @property detectedTokens - List of detected tokens associated with the active network and address pair\n * @property allTokens - Object containing tokens by network and account\n * @property allIgnoredTokens - Object containing hidden/ignored tokens by network and account\n * @property allDetectedTokens - Object containing tokens detected with non-zero balances\n * @property suggestedAssets - List of pending suggested assets to be added or canceled\n */\nexport interface TokensState extends BaseState {\n tokens: Token[];\n ignoredTokens: string[];\n detectedTokens: Token[];\n allTokens: { [key: string]: { [key: string]: Token[] } };\n allIgnoredTokens: { [key: string]: { [key: string]: string[] } };\n allDetectedTokens: { [key: string]: { [key: string]: Token[] } };\n suggestedAssets: SuggestedAssetMeta[];\n}\n\n/**\n * Controller that stores assets and exposes convenience methods\n */\nexport class TokensController extends BaseController<\n TokensConfig,\n TokensState\n> {\n private mutex = new Mutex();\n\n private ethersProvider: any;\n\n private abortController: WhatwgAbortController;\n\n private failSuggestedAsset(\n suggestedAssetMeta: SuggestedAssetMeta,\n error: unknown,\n ) {\n const failedSuggestedAssetMeta = {\n ...suggestedAssetMeta,\n status: SuggestedAssetStatus.failed,\n error,\n };\n this.hub.emit(\n `${suggestedAssetMeta.id}:finished`,\n failedSuggestedAssetMeta,\n );\n }\n\n /**\n * Fetch metadata for a token.\n *\n * @param tokenAddress - The address of the token.\n * @returns The token metadata.\n */\n private async fetchTokenMetadata(\n tokenAddress: string,\n ): Promise<TokenListToken | undefined> {\n try {\n const token = await fetchTokenMetadata<TokenListToken>(\n this.config.chainId,\n tokenAddress,\n this.abortController.signal,\n );\n return token;\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes(TOKEN_METADATA_NO_SUPPORT_ERROR)\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * EventEmitter instance used to listen to specific EIP747 events\n */\n hub = new EventEmitter();\n\n /**\n * Name of this controller used during composition\n */\n override name = 'TokensController';\n\n /**\n * Creates a TokensController instance.\n *\n * @param options - The controller options.\n * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes.\n * @param options.onNetworkStateChange - Allows subscribing to network controller state changes.\n * @param options.config - Initial options used to configure this controller.\n * @param options.state - Initial state to set on this controller.\n */\n constructor({\n onPreferencesStateChange,\n onNetworkStateChange,\n config,\n state,\n }: {\n onPreferencesStateChange: (\n listener: (preferencesState: PreferencesState) => void,\n ) => void;\n onNetworkStateChange: (\n listener: (networkState: NetworkState) => void,\n ) => void;\n config?: Partial<TokensConfig>;\n state?: Partial<TokensState>;\n }) {\n super(config, state);\n\n this.defaultConfig = {\n networkType: MAINNET,\n selectedAddress: '',\n chainId: '',\n provider: undefined,\n ...config,\n };\n\n this.defaultState = {\n tokens: [],\n ignoredTokens: [],\n detectedTokens: [],\n allTokens: {},\n allIgnoredTokens: {},\n allDetectedTokens: {},\n suggestedAssets: [],\n ...state,\n };\n\n this.initialize();\n this.abortController = new WhatwgAbortController();\n\n onPreferencesStateChange(({ selectedAddress }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId } = this.config;\n this.configure({ selectedAddress });\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n\n onNetworkStateChange(({ provider }) => {\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { selectedAddress } = this.config;\n const { chainId } = provider;\n this.abortController.abort();\n this.abortController = new WhatwgAbortController();\n this.configure({ chainId });\n this.ethersProvider = this._instantiateNewEthersProvider();\n this.update({\n tokens: allTokens[chainId]?.[selectedAddress] || [],\n ignoredTokens: allIgnoredTokens[chainId]?.[selectedAddress] || [],\n detectedTokens: allDetectedTokens[chainId]?.[selectedAddress] || [],\n });\n });\n }\n\n _instantiateNewEthersProvider(): any {\n return new Web3Provider(this.config?.provider);\n }\n\n /**\n * Adds a token to the stored token list.\n *\n * @param address - Hex address of the token contract.\n * @param symbol - Symbol of the token.\n * @param decimals - Number of decimals the token uses.\n * @param image - Image of the token.\n * @returns Current token list.\n */\n async addToken(\n address: string,\n symbol: string,\n decimals: number,\n image?: string,\n ): Promise<Token[]> {\n const currentChainId = this.config.chainId;\n const releaseLock = await this.mutex.acquire();\n try {\n address = toChecksumHexAddress(address);\n const { tokens, ignoredTokens, detectedTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n const [isERC721, tokenMetadata] = await Promise.all([\n this._detectIsERC721(address),\n this.fetchTokenMetadata(address),\n ]);\n if (currentChainId !== this.config.chainId) {\n throw new Error(\n 'TokensController Error: Switched networks while adding token',\n );\n }\n const newEntry: Token = {\n address,\n symbol,\n decimals,\n image:\n image ||\n formatIconUrlWithProxy({\n chainId: this.config.chainId,\n tokenAddress: address,\n }),\n isERC721,\n aggregators: formatAggregatorNames(tokenMetadata?.aggregators || []),\n };\n const previousEntry = newTokens.find(\n (token) => token.address.toLowerCase() === address.toLowerCase(),\n );\n if (previousEntry) {\n const previousIndex = newTokens.indexOf(previousEntry);\n newTokens[previousIndex] = newEntry;\n } else {\n newTokens.push(newEntry);\n }\n\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => tokenAddress.toLowerCase() !== address.toLowerCase(),\n );\n const newDetectedTokens = detectedTokens.filter(\n (token) => token.address.toLowerCase() !== address.toLowerCase(),\n );\n\n const { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens } =\n this._getNewAllTokensState({\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n });\n\n this.update({\n tokens: newTokens,\n ignoredTokens: newIgnoredTokens,\n detectedTokens: newDetectedTokens,\n allTokens: newAllTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n return newTokens;\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Add a batch of tokens.\n *\n * @param tokensToImport - Array of tokens to import.\n */\n async addTokens(tokensToImport: Token[]) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const importedTokensMap: { [key: string]: true } = {};\n // Used later to dedupe imported tokens\n const newTokensMap = tokens.reduce((output, current) => {\n output[current.address] = current;\n return output;\n }, {} as { [address: string]: Token });\n\n try {\n tokensToImport.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators } = tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const formattedToken: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n aggregators,\n };\n newTokensMap[address] = formattedToken;\n importedTokensMap[address.toLowerCase()] = true;\n return formattedToken;\n });\n const newTokens = Object.values(newTokensMap);\n\n const newDetectedTokens = detectedTokens.filter(\n (token) => !importedTokensMap[token.address.toLowerCase()],\n );\n const newIgnoredTokens = ignoredTokens.filter(\n (tokenAddress) => !newTokensMap[tokenAddress.toLowerCase()],\n );\n\n const { newAllTokens, newAllDetectedTokens, newAllIgnoredTokens } =\n this._getNewAllTokensState({\n newTokens,\n newDetectedTokens,\n newIgnoredTokens,\n });\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n ignoredTokens: newIgnoredTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Ignore a batch of tokens.\n *\n * @param tokenAddressesToIgnore - Array of token addresses to ignore.\n */\n ignoreTokens(tokenAddressesToIgnore: string[]) {\n const { ignoredTokens, detectedTokens, tokens } = this.state;\n const ignoredTokensMap: { [key: string]: true } = {};\n let newIgnoredTokens: string[] = [...ignoredTokens];\n\n const checksummedTokenAddresses = tokenAddressesToIgnore.map((address) => {\n const checksumAddress = toChecksumHexAddress(address);\n ignoredTokensMap[address.toLowerCase()] = true;\n return checksumAddress;\n });\n newIgnoredTokens = [...ignoredTokens, ...checksummedTokenAddresses];\n const newDetectedTokens = detectedTokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n const newTokens = tokens.filter(\n (token) => !ignoredTokensMap[token.address.toLowerCase()],\n );\n\n const { newAllIgnoredTokens, newAllDetectedTokens, newAllTokens } =\n this._getNewAllTokensState({\n newIgnoredTokens,\n newDetectedTokens,\n newTokens,\n });\n\n this.update({\n ignoredTokens: newIgnoredTokens,\n tokens: newTokens,\n detectedTokens: newDetectedTokens,\n allIgnoredTokens: newAllIgnoredTokens,\n allDetectedTokens: newAllDetectedTokens,\n allTokens: newAllTokens,\n });\n }\n\n /**\n * Adds a batch of detected tokens to the stored token list.\n *\n * @param incomingDetectedTokens - Array of detected tokens to be added or updated.\n * @param detectionDetails - An object containing the chain ID and address of the currently selected network on which the incomingDetectedTokens were detected.\n * @param detectionDetails.selectedAddress - the account address on which the incomingDetectedTokens were detected.\n * @param detectionDetails.chainId - the chainId on which the incomingDetectedTokens were detected.\n */\n async addDetectedTokens(\n incomingDetectedTokens: Token[],\n detectionDetails?: { selectedAddress: string; chainId: string },\n ) {\n const releaseLock = await this.mutex.acquire();\n const { tokens, detectedTokens, ignoredTokens } = this.state;\n const newTokens: Token[] = [...tokens];\n let newDetectedTokens: Token[] = [...detectedTokens];\n\n try {\n incomingDetectedTokens.forEach((tokenToAdd) => {\n const { address, symbol, decimals, image, aggregators, isERC721 } =\n tokenToAdd;\n const checksumAddress = toChecksumHexAddress(address);\n const newEntry: Token = {\n address: checksumAddress,\n symbol,\n decimals,\n image,\n isERC721,\n aggregators,\n };\n const previousImportedEntry = newTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousImportedEntry) {\n // Update existing data of imported token\n const previousImportedIndex = newTokens.indexOf(\n previousImportedEntry,\n );\n newTokens[previousImportedIndex] = newEntry;\n } else {\n const ignoredTokenIndex = ignoredTokens.indexOf(address);\n if (ignoredTokenIndex === -1) {\n // Add detected token\n const previousDetectedEntry = newDetectedTokens.find(\n (token) =>\n token.address.toLowerCase() === checksumAddress.toLowerCase(),\n );\n if (previousDetectedEntry) {\n const previousDetectedIndex = newDetectedTokens.indexOf(\n previousDetectedEntry,\n );\n newDetectedTokens[previousDetectedIndex] = newEntry;\n } else {\n newDetectedTokens.push(newEntry);\n }\n }\n }\n });\n\n const { selectedAddress: detectionAddress, chainId: detectionChainId } =\n detectionDetails || {};\n\n const { newAllTokens, newAllDetectedTokens } = this._getNewAllTokensState(\n {\n newTokens,\n newDetectedTokens,\n detectionAddress,\n detectionChainId,\n },\n );\n\n const { chainId, selectedAddress } = this.config;\n // if the newly added detectedTokens were detected on (and therefore added to) a different chainId/selectedAddress than the currently configured combo\n // the newDetectedTokens (which should contain the detectedTokens on the current chainId/address combo) needs to be repointed to the current chainId/address pair\n // if the detectedTokens were detected on the current chainId/address then this won't change anything.\n newDetectedTokens =\n newAllDetectedTokens?.[chainId]?.[selectedAddress] || [];\n\n this.update({\n tokens: newTokens,\n allTokens: newAllTokens,\n detectedTokens: newDetectedTokens,\n allDetectedTokens: newAllDetectedTokens,\n });\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Adds isERC721 field to token object. This is called when a user attempts to add tokens that\n * were previously added which do not yet had isERC721 field.\n *\n * @param tokenAddress - The contract address of the token requiring the isERC721 field added.\n * @returns The new token object with the added isERC721 field.\n */\n async updateTokenType(tokenAddress: string) {\n const isERC721 = await this._detectIsERC721(tokenAddress);\n const { tokens } = this.state;\n const tokenIndex = tokens.findIndex((token) => {\n return token.address.toLowerCase() === tokenAddress.toLowerCase();\n });\n tokens[tokenIndex].isERC721 = isERC721;\n this.update({ tokens });\n return tokens[tokenIndex];\n }\n\n /**\n * Detects whether or not a token is ERC-721 compatible.\n *\n * @param tokenAddress - The token contract address.\n * @returns A boolean indicating whether the token address passed in supports the EIP-721\n * interface.\n */\n async _detectIsERC721(tokenAddress: string) {\n const checksumAddress = toChecksumHexAddress(tokenAddress);\n // if this token is already in our contract metadata map we don't need\n // to check against the contract\n if (contractsMap[checksumAddress]?.erc721 === true) {\n return Promise.resolve(true);\n } else if (contractsMap[checksumAddress]?.erc20 === true) {\n return Promise.resolve(false);\n }\n\n const tokenContract = this._createEthersContract(\n tokenAddress,\n abiERC721,\n this.ethersProvider,\n );\n try {\n return await tokenContract.supportsInterface(ERC721_INTERFACE_ID);\n } catch (error: any) {\n // currently we see a variety of errors across different networks when\n // token contracts are not ERC721 compatible. We need to figure out a better\n // way of differentiating token interface types but for now if we get an error\n // we have to assume the token is not ERC721 compatible.\n return false;\n }\n }\n\n _createEthersContract(\n tokenAddress: string,\n abi: string,\n ethersProvider: any,\n ): Contract {\n const tokenContract = new Contract(tokenAddress, abi, ethersProvider);\n return tokenContract;\n }\n\n _generateRandomId(): string {\n return random();\n }\n\n /**\n * Adds a new suggestedAsset to state. Parameters will be validated according to\n * asset type being watched. A `<suggestedAssetMeta.id>:pending` hub event will be emitted once added.\n *\n * @param asset - The asset to be watched. For now only ERC20 tokens are accepted.\n * @param type - The asset type.\n * @returns Object containing a Promise resolving to the suggestedAsset address if accepted.\n */\n async watchAsset(asset: Token, type: string): Promise<AssetSuggestionResult> {\n const suggestedAssetMeta = {\n asset,\n id: this._generateRandomId(),\n status: SuggestedAssetStatus.pending as SuggestedAssetStatus.pending,\n time: Date.now(),\n type,\n };\n try {\n switch (type) {\n case 'ERC20':\n validateTokenToWatch(asset);\n break;\n default:\n throw new Error(`Asset of type ${type} not supported`);\n }\n } catch (error) {\n this.failSuggestedAsset(suggestedAssetMeta, error);\n return Promise.reject(error);\n }\n\n const result: Promise<string> = new Promise((resolve, reject) => {\n this.hub.once(\n `${suggestedAssetMeta.id}:finished`,\n (meta: SuggestedAssetMeta) => {\n switch (meta.status) {\n case SuggestedAssetStatus.accepted:\n return resolve(meta.asset.address);\n case SuggestedAssetStatus.rejected:\n return reject(new Error('User rejected to watch the asset.'));\n case SuggestedAssetStatus.failed:\n return reject(new Error(meta.error.message));\n /* istanbul ignore next */\n default:\n return reject(new Error(`Unknown status: ${meta.status}`));\n }\n },\n );\n });\n\n const { suggestedAssets } = this.state;\n suggestedAssets.push(suggestedAssetMeta);\n this.update({ suggestedAssets: [...suggestedAssets] });\n this.hub.emit('pendingSuggestedAsset', suggestedAssetMeta);\n return { result, suggestedAssetMeta };\n }\n\n /**\n * Accepts to watch an asset and updates it's status and deletes the suggestedAsset from state,\n * adding the asset to corresponding asset state. In this case ERC20 tokens.\n * A `<suggestedAssetMeta.id>:finished` hub event is fired after accepted or failure.\n *\n * @param suggestedAssetID - The ID of the suggestedAsset to accept.\n */\n async acceptWatchAsset(suggestedAssetID: string): Promise<void> {\n const { suggestedAssets } = this.state;\n const index = suggestedAssets.findIndex(\n ({ id }) => suggestedAssetID === id,\n );\n const suggestedAssetMeta = suggestedAssets[index];\n try {\n switch (suggestedAssetMeta.type) {\n case 'ERC20':\n const { address, symbol, decimals, image } = suggestedAssetMeta.asset;\n await this.addToken(address, symbol, decimals, image);\n suggestedAssetMeta.status = SuggestedAssetStatus.accepted;\n this.hub.emit(\n `${suggestedAssetMeta.id}:finished`,\n suggestedAssetMeta,\n );\n break;\n default:\n throw new Error(\n `Asset of type ${suggestedAssetMeta.type} not supported`,\n );\n }\n } catch (error) {\n this.failSuggestedAsset(suggestedAssetMeta, error);\n }\n const newSuggestedAssets = suggestedAssets.filter(\n ({ id }) => id !== suggestedAssetID,\n );\n this.update({ suggestedAssets: [...newSuggestedAssets] });\n }\n\n /**\n * Rejects a watchAsset request based on its ID by setting its status to \"rejected\"\n * and emitting a `<suggestedAssetMeta.id>:finished` hub event.\n *\n * @param suggestedAssetID - The ID of the suggestedAsset to accept.\n */\n rejectWatchAsset(suggestedAssetID: string) {\n const { suggestedAssets } = this.state;\n const index = suggestedAssets.findIndex(\n ({ id }) => suggestedAssetID === id,\n );\n const suggestedAssetMeta = suggestedAssets[index];\n if (!suggestedAssetMeta) {\n return;\n }\n suggestedAssetMeta.status = SuggestedAssetStatus.rejected;\n this.hub.emit(`${suggestedAssetMeta.id}:finished`, suggestedAssetMeta);\n const newSuggestedAssets = suggestedAssets.filter(\n ({ id }) => id !== suggestedAssetID,\n );\n this.update({ suggestedAssets: [...newSuggestedAssets] });\n }\n\n /**\n * Takes a new tokens and ignoredTokens array for the current network/account combination\n * and returns new allTokens and allIgnoredTokens state to update to.\n *\n * @param params - Object that holds token params.\n * @param params.newTokens - The new tokens to set for the current network and selected account.\n * @param params.newIgnoredTokens - The new ignored tokens to set for the current network and selected account.\n * @param params.newDetectedTokens - The new detected tokens to set for the current network and selected account.\n * @param params.detectionAddress - The address on which the detected tokens to add were detected.\n * @param params.detectionChainId - The chainId on which the detected tokens to add were detected.\n * @returns The updated `allTokens` and `allIgnoredTokens` state.\n */\n _getNewAllTokensState(params: {\n newTokens?: Token[];\n newIgnoredTokens?: string[];\n newDetectedTokens?: Token[];\n detectionAddress?: string;\n detectionChainId?: string;\n }) {\n const {\n newTokens,\n newIgnoredTokens,\n newDetectedTokens,\n detectionAddress,\n detectionChainId,\n } = params;\n const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state;\n const { chainId, selectedAddress } = this.config;\n\n const userAddressToAddTokens = detectionAddress ?? selectedAddress;\n const chainIdToAddTokens = detectionChainId ?? chainId;\n\n let newAllTokens = allTokens;\n if (newTokens?.length) {\n const networkTokens = allTokens[chainIdToAddTokens];\n const newNetworkTokens = {\n ...networkTokens,\n ...{ [userAddressToAddTokens]: newTokens },\n };\n newAllTokens = {\n ...allTokens,\n ...{ [chainIdToAddTokens]: newNetworkTokens },\n };\n }\n\n let newAllIgnoredTokens = allIgnoredTokens;\n if (newIgnoredTokens?.length) {\n const networkIgnoredTokens = allIgnoredTokens[chainIdToAddTokens];\n const newIgnoredNetworkTokens = {\n ...networkIgnoredTokens,\n ...{ [userAddressToAddTokens]: newIgnoredTokens },\n };\n newAllIgnoredTokens = {\n ...allIgnoredTokens,\n ...{ [chainIdToAddTokens]: newIgnoredNetworkTokens },\n };\n }\n\n let newAllDetectedTokens = allDetectedTokens;\n if (newDetectedTokens?.length) {\n const networkDetectedTokens = allDetectedTokens[chainIdToAddTokens];\n const newDetectedNetworkTokens = {\n ...networkDetectedTokens,\n ...{ [userAddressToAddTokens]: newDetectedTokens },\n };\n newAllDetectedTokens = {\n ...allDetectedTokens,\n ...{ [chainIdToAddTokens]: newDetectedNetworkTokens },\n };\n }\n return { newAllTokens, newAllIgnoredTokens, newAllDetectedTokens };\n }\n\n /**\n * Removes all tokens from the ignored list.\n */\n clearIgnoredTokens() {\n this.update({ ignoredTokens: [], allIgnoredTokens: {} });\n }\n}\n\nexport default TokensController;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/assets-controllers",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -33,7 +33,7 @@
33
33
  "@ethersproject/bignumber": "^5.7.0",
34
34
  "@ethersproject/contracts": "^5.7.0",
35
35
  "@ethersproject/providers": "^5.7.0",
36
- "@metamask/base-controller": "~1.0.0",
36
+ "@metamask/base-controller": "~1.1.0",
37
37
  "@metamask/contract-metadata": "^1.35.0",
38
38
  "@metamask/controller-utils": "~1.0.0",
39
39
  "@metamask/metamask-eth-abis": "3.0.0",