@metamask/assets-controllers 41.0.0 → 43.0.0

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.
Files changed (90) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/dist/AccountTrackerController.cjs +30 -10
  3. package/dist/AccountTrackerController.cjs.map +1 -1
  4. package/dist/AccountTrackerController.d.cts +14 -9
  5. package/dist/AccountTrackerController.d.cts.map +1 -1
  6. package/dist/AccountTrackerController.d.mts +14 -9
  7. package/dist/AccountTrackerController.d.mts.map +1 -1
  8. package/dist/AccountTrackerController.mjs +30 -10
  9. package/dist/AccountTrackerController.mjs.map +1 -1
  10. package/dist/AssetsContractController.cjs +61 -1
  11. package/dist/AssetsContractController.cjs.map +1 -1
  12. package/dist/AssetsContractController.d.cts +13 -0
  13. package/dist/AssetsContractController.d.cts.map +1 -1
  14. package/dist/AssetsContractController.d.mts +13 -0
  15. package/dist/AssetsContractController.d.mts.map +1 -1
  16. package/dist/AssetsContractController.mjs +61 -1
  17. package/dist/AssetsContractController.mjs.map +1 -1
  18. package/dist/CurrencyRateController.d.cts +4 -4
  19. package/dist/CurrencyRateController.d.mts +4 -4
  20. package/dist/NftController.cjs +8 -0
  21. package/dist/NftController.cjs.map +1 -1
  22. package/dist/NftController.d.cts +4 -0
  23. package/dist/NftController.d.cts.map +1 -1
  24. package/dist/NftController.d.mts +4 -0
  25. package/dist/NftController.d.mts.map +1 -1
  26. package/dist/NftController.mjs +8 -0
  27. package/dist/NftController.mjs.map +1 -1
  28. package/dist/TokenBalancesController.cjs +8 -0
  29. package/dist/TokenBalancesController.cjs.map +1 -1
  30. package/dist/TokenBalancesController.d.cts +4 -0
  31. package/dist/TokenBalancesController.d.cts.map +1 -1
  32. package/dist/TokenBalancesController.d.mts +4 -0
  33. package/dist/TokenBalancesController.d.mts.map +1 -1
  34. package/dist/TokenBalancesController.mjs +8 -0
  35. package/dist/TokenBalancesController.mjs.map +1 -1
  36. package/dist/TokenDetectionController.cjs +196 -129
  37. package/dist/TokenDetectionController.cjs.map +1 -1
  38. package/dist/TokenDetectionController.d.cts +23 -12
  39. package/dist/TokenDetectionController.d.cts.map +1 -1
  40. package/dist/TokenDetectionController.d.mts +23 -12
  41. package/dist/TokenDetectionController.d.mts.map +1 -1
  42. package/dist/TokenDetectionController.mjs +195 -129
  43. package/dist/TokenDetectionController.mjs.map +1 -1
  44. package/dist/TokenListController.cjs +60 -53
  45. package/dist/TokenListController.cjs.map +1 -1
  46. package/dist/TokenListController.d.cts +25 -14
  47. package/dist/TokenListController.d.cts.map +1 -1
  48. package/dist/TokenListController.d.mts +25 -14
  49. package/dist/TokenListController.d.mts.map +1 -1
  50. package/dist/TokenListController.mjs +60 -53
  51. package/dist/TokenListController.mjs.map +1 -1
  52. package/dist/TokenRatesController.cjs +43 -13
  53. package/dist/TokenRatesController.cjs.map +1 -1
  54. package/dist/TokenRatesController.d.cts +12 -8
  55. package/dist/TokenRatesController.d.cts.map +1 -1
  56. package/dist/TokenRatesController.d.mts +12 -8
  57. package/dist/TokenRatesController.d.mts.map +1 -1
  58. package/dist/TokenRatesController.mjs +43 -13
  59. package/dist/TokenRatesController.mjs.map +1 -1
  60. package/dist/TokensController.cjs +15 -4
  61. package/dist/TokensController.cjs.map +1 -1
  62. package/dist/TokensController.d.cts +4 -0
  63. package/dist/TokensController.d.cts.map +1 -1
  64. package/dist/TokensController.d.mts +4 -0
  65. package/dist/TokensController.d.mts.map +1 -1
  66. package/dist/TokensController.mjs +15 -4
  67. package/dist/TokensController.mjs.map +1 -1
  68. package/dist/assetsUtil.cjs +13 -1
  69. package/dist/assetsUtil.cjs.map +1 -1
  70. package/dist/assetsUtil.d.cts +7 -0
  71. package/dist/assetsUtil.d.cts.map +1 -1
  72. package/dist/assetsUtil.d.mts +7 -0
  73. package/dist/assetsUtil.d.mts.map +1 -1
  74. package/dist/assetsUtil.mjs +12 -0
  75. package/dist/assetsUtil.mjs.map +1 -1
  76. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.cjs +18 -0
  77. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.cjs.map +1 -1
  78. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.d.cts.map +1 -1
  79. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.d.mts.map +1 -1
  80. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.mjs +18 -0
  81. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.mjs.map +1 -1
  82. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs +7 -2
  83. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs.map +1 -1
  84. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts +3 -2
  85. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts.map +1 -1
  86. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts +3 -2
  87. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts.map +1 -1
  88. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs +7 -2
  89. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs.map +1 -1
  90. package/package.json +9 -9
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _TokenDetectionController_instances, _TokenDetectionController_intervalId, _TokenDetectionController_selectedAccountId, _TokenDetectionController_networkClientId, _TokenDetectionController_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_isDetectionEnabledForNetwork, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent, _TokenDetectionController_accountsAPI, _TokenDetectionController_registerEventListeners, _TokenDetectionController_stopPolling, _TokenDetectionController_startPolling, _TokenDetectionController_compareTokensChainsCache, _TokenDetectionController_getCorrectChainIdAndNetworkClientId, _TokenDetectionController_restartTokenDetection, _TokenDetectionController_getSlicesOfTokensToDetect, _TokenDetectionController_getConvertedStaticMainnetTokenList, _TokenDetectionController_addDetectedTokensViaAPI, _TokenDetectionController_addDetectedTokens, _TokenDetectionController_getSelectedAccount, _TokenDetectionController_getSelectedAddress;
12
+ var _TokenDetectionController_instances, _TokenDetectionController_intervalId, _TokenDetectionController_selectedAccountId, _TokenDetectionController_networkClientId, _TokenDetectionController_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_isDetectionEnabledForNetwork, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent, _TokenDetectionController_accountsAPI, _TokenDetectionController_registerEventListeners, _TokenDetectionController_stopPolling, _TokenDetectionController_startPolling, _TokenDetectionController_compareTokensChainsCache, _TokenDetectionController_getCorrectNetworkClientIdByChainId, _TokenDetectionController_getCorrectChainIdAndNetworkClientId, _TokenDetectionController_restartTokenDetection, _TokenDetectionController_getChainsToDetect, _TokenDetectionController_attemptAccountAPIDetection, _TokenDetectionController_addChainsToRpcDetection, _TokenDetectionController_shouldDetectTokens, _TokenDetectionController_detectTokensUsingRpc, _TokenDetectionController_getSlicesOfTokensToDetect, _TokenDetectionController_getConvertedStaticMainnetTokenList, _TokenDetectionController_addDetectedTokensViaAPI, _TokenDetectionController_filterAndBuildTokensWithBalance, _TokenDetectionController_addDetectedTokens, _TokenDetectionController_getSelectedAccount, _TokenDetectionController_getSelectedAddress;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -43,7 +43,7 @@ export const STATIC_MAINNET_TOKEN_LIST = Object.entries(contractMap).reduce((acc
43
43
  * @param tokensChainsCache - TokensChainsCache input object
44
44
  * @returns returns the map of chainId with TokenListMap
45
45
  */
46
- function mapChainIdWithTokenListMap(tokensChainsCache) {
46
+ export function mapChainIdWithTokenListMap(tokensChainsCache) {
47
47
  return mapValues(tokensChainsCache, (value) => {
48
48
  if (isObject(value) && 'data' in value) {
49
49
  return get(value, ['data']);
@@ -73,8 +73,9 @@ export class TokenDetectionController extends StaticIntervalPollingController()
73
73
  * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.
74
74
  * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.
75
75
  * @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)
76
+ * @param options.platform - Indicates whether the platform is extension or mobile
76
77
  */
77
- constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useAccountsAPI = true, }) {
78
+ constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useAccountsAPI = true, platform, }) {
78
79
  super({
79
80
  name: controllerName,
80
81
  messenger,
@@ -95,6 +96,7 @@ export class TokenDetectionController extends StaticIntervalPollingController()
95
96
  _TokenDetectionController_accountsAPI.set(this, {
96
97
  isAccountsAPIEnabled: true,
97
98
  supportedNetworksCache: null,
99
+ platform: '',
98
100
  async getSupportedNetworks() {
99
101
  /* istanbul ignore next */
100
102
  if (!this.isAccountsAPIEnabled) {
@@ -108,19 +110,16 @@ export class TokenDetectionController extends StaticIntervalPollingController()
108
110
  this.supportedNetworksCache = result;
109
111
  return result;
110
112
  },
111
- async getMultiChainBalances(address, chainId) {
112
- if (!this.isAccountsAPIEnabled) {
113
- throw new Error('Accounts API Feature Switch is disabled');
114
- }
115
- const chainIdNumber = hexToNumber(chainId);
116
- const supportedNetworks = await this.getSupportedNetworks();
117
- if (!supportedNetworks || !supportedNetworks.includes(chainIdNumber)) {
113
+ async getMultiNetworksBalances(address, chainIds, supportedNetworks) {
114
+ const chainIdNumbers = chainIds.map((chainId) => hexToNumber(chainId));
115
+ if (!supportedNetworks ||
116
+ !chainIdNumbers.every((id) => supportedNetworks.includes(id))) {
118
117
  const supportedNetworksErrStr = (supportedNetworks ?? []).toString();
119
- throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, network: ${chainIdNumber}`);
118
+ throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`);
120
119
  }
121
120
  const result = await fetchMultiChainBalances(address, {
122
- networks: [chainIdNumber],
123
- });
121
+ networks: chainIdNumbers,
122
+ }, this.platform);
124
123
  return result.balances;
125
124
  },
126
125
  });
@@ -139,6 +138,7 @@ export class TokenDetectionController extends StaticIntervalPollingController()
139
138
  const { isUnlocked } = this.messagingSystem.call('KeyringController:getState');
140
139
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, isUnlocked, "f");
141
140
  __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled = useAccountsAPI;
141
+ __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").platform = platform;
142
142
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_registerEventListeners).call(this);
143
143
  }
144
144
  /**
@@ -174,12 +174,12 @@ export class TokenDetectionController extends StaticIntervalPollingController()
174
174
  this.disable();
175
175
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_stopPolling).call(this);
176
176
  }
177
- async _executePoll({ networkClientId, address, }) {
177
+ async _executePoll({ chainIds, address, }) {
178
178
  if (!this.isActive) {
179
179
  return;
180
180
  }
181
181
  await this.detectTokens({
182
- networkClientId,
182
+ chainIds,
183
183
  selectedAddress: address,
184
184
  });
185
185
  }
@@ -188,51 +188,35 @@ export class TokenDetectionController extends StaticIntervalPollingController()
188
188
  * On mainnet, if token detection is disabled in preferences, ERC20 token auto detection will be triggered for each contract address in the legacy token list from the @metamask/contract-metadata repo.
189
189
  *
190
190
  * @param options - Options for token detection.
191
- * @param options.networkClientId - The ID of the network client to use.
191
+ * @param options.chainIds - The chain IDs of the network client to use.
192
192
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances.
193
193
  */
194
- async detectTokens({ networkClientId, selectedAddress, } = {}) {
194
+ async detectTokens({ chainIds, selectedAddress, } = {}) {
195
195
  if (!this.isActive) {
196
196
  return;
197
197
  }
198
- const addressAgainstWhichToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
199
- const { chainId, networkClientId: selectedNetworkClientId } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectChainIdAndNetworkClientId).call(this, networkClientId);
200
- const chainIdAgainstWhichToDetect = chainId;
201
- const networkClientIdAgainstWhichToDetect = selectedNetworkClientId;
202
- if (!isTokenDetectionSupportedForNetwork(chainIdAgainstWhichToDetect)) {
203
- return;
198
+ const addressToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
199
+ const clientNetworks = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectNetworkClientIdByChainId).call(this, chainIds);
200
+ let supportedNetworks;
201
+ if (__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled) {
202
+ supportedNetworks = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").getSupportedNetworks();
204
203
  }
205
- if (!__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
206
- chainIdAgainstWhichToDetect !== ChainId.mainnet) {
207
- return;
204
+ const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getChainsToDetect).call(this, clientNetworks, supportedNetworks);
205
+ // Try detecting tokens via Account API first if conditions allow
206
+ if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {
207
+ const apiResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_attemptAccountAPIDetection).call(this, chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks);
208
+ // If API succeeds and no chains are left for RPC detection, we can return early
209
+ if (apiResult?.result === 'success' &&
210
+ chainsToDetectUsingRpc.length === 0) {
211
+ return;
212
+ }
213
+ // If API fails or chainsToDetectUsingRpc still has items, add chains to RPC detection
214
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks);
208
215
  }
209
- const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
210
- chainIdAgainstWhichToDetect === ChainId.mainnet;
211
- const { tokensChainsCache } = this.messagingSystem.call('TokenListController:getState');
212
- __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, isTokenDetectionInactiveInMainnet
213
- ? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this)
214
- : tokensChainsCache ?? {}, "f");
215
- const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
216
- chainId: chainIdAgainstWhichToDetect,
217
- selectedAddress: addressAgainstWhichToDetect,
218
- });
219
- // Attempt Accounts API Detection
220
- const accountAPIResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokensViaAPI).call(this, {
221
- chainId: chainIdAgainstWhichToDetect,
222
- selectedAddress: addressAgainstWhichToDetect,
223
- tokenCandidateSlices,
224
- });
225
- if (accountAPIResult?.result === 'success') {
226
- return;
216
+ // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc
217
+ if (chainsToDetectUsingRpc.length > 0) {
218
+ await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
227
219
  }
228
- // Attempt RPC Detection
229
- const tokenDetectionPromises = tokenCandidateSlices.map((tokensSlice) => __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokens).call(this, {
230
- tokensSlice,
231
- selectedAddress: addressAgainstWhichToDetect,
232
- networkClientId: networkClientIdAgainstWhichToDetect,
233
- chainId: chainIdAgainstWhichToDetect,
234
- }));
235
- await Promise.all(tokenDetectionPromises);
236
220
  }
237
221
  }
238
222
  _TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_selectedAccountId = new WeakMap(), _TokenDetectionController_networkClientId = new WeakMap(), _TokenDetectionController_tokensChainsCache = new WeakMap(), _TokenDetectionController_disabled = new WeakMap(), _TokenDetectionController_isUnlocked = new WeakMap(), _TokenDetectionController_isDetectionEnabledFromPreferences = new WeakMap(), _TokenDetectionController_isDetectionEnabledForNetwork = new WeakMap(), _TokenDetectionController_getBalancesInSingleCall = new WeakMap(), _TokenDetectionController_trackMetaMetricsEvent = new WeakMap(), _TokenDetectionController_accountsAPI = new WeakMap(), _TokenDetectionController_instances = new WeakSet(), _TokenDetectionController_registerEventListeners = function _TokenDetectionController_registerEventListeners() {
@@ -280,20 +264,6 @@ _TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_
280
264
  });
281
265
  }
282
266
  });
283
- this.messagingSystem.subscribe('NetworkController:networkDidChange',
284
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
285
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
286
- async ({ selectedNetworkClientId }) => {
287
- const isNetworkClientIdChanged = __classPrivateFieldGet(this, _TokenDetectionController_networkClientId, "f") !== selectedNetworkClientId;
288
- const { chainId: newChainId } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectChainIdAndNetworkClientId).call(this, selectedNetworkClientId);
289
- __classPrivateFieldSet(this, _TokenDetectionController_isDetectionEnabledForNetwork, isTokenDetectionSupportedForNetwork(newChainId), "f");
290
- if (isNetworkClientIdChanged && __classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledForNetwork, "f")) {
291
- __classPrivateFieldSet(this, _TokenDetectionController_networkClientId, selectedNetworkClientId, "f");
292
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
293
- networkClientId: __classPrivateFieldGet(this, _TokenDetectionController_networkClientId, "f"),
294
- });
295
- }
296
- });
297
267
  }, _TokenDetectionController_stopPolling = function _TokenDetectionController_stopPolling() {
298
268
  if (__classPrivateFieldGet(this, _TokenDetectionController_intervalId, "f")) {
299
269
  clearInterval(__classPrivateFieldGet(this, _TokenDetectionController_intervalId, "f"));
@@ -318,16 +288,26 @@ async function _TokenDetectionController_startPolling() {
318
288
  const cleanTokensChainsCache = mapChainIdWithTokenListMap(tokensChainsCache);
319
289
  const isEqualValues = isEqual(cleanTokensChainsCache, cleanPreviousTokensChainsCache);
320
290
  return isEqualValues;
321
- }, _TokenDetectionController_getCorrectChainIdAndNetworkClientId = function _TokenDetectionController_getCorrectChainIdAndNetworkClientId(networkClientId) {
322
- if (networkClientId) {
323
- const networkConfiguration = this.messagingSystem.call('NetworkController:getNetworkConfigurationByNetworkClientId', networkClientId);
324
- if (networkConfiguration) {
325
- return {
326
- chainId: networkConfiguration.chainId,
327
- networkClientId,
328
- };
329
- }
291
+ }, _TokenDetectionController_getCorrectNetworkClientIdByChainId = function _TokenDetectionController_getCorrectNetworkClientIdByChainId(chainIds) {
292
+ const { networkConfigurationsByChainId, selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
293
+ if (!chainIds) {
294
+ const networkConfiguration = this.messagingSystem.call('NetworkController:getNetworkConfigurationByNetworkClientId', selectedNetworkClientId);
295
+ return [
296
+ {
297
+ chainId: networkConfiguration?.chainId ?? ChainId.mainnet,
298
+ networkClientId: selectedNetworkClientId,
299
+ },
300
+ ];
330
301
  }
302
+ return chainIds.map((chainId) => {
303
+ const configuration = networkConfigurationsByChainId[chainId];
304
+ return {
305
+ chainId,
306
+ networkClientId: configuration.rpcEndpoints[configuration.defaultRpcEndpointIndex]
307
+ .networkClientId,
308
+ };
309
+ });
310
+ }, _TokenDetectionController_getCorrectChainIdAndNetworkClientId = function _TokenDetectionController_getCorrectChainIdAndNetworkClientId() {
331
311
  const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
332
312
  const { configuration: { chainId }, } = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
333
313
  return {
@@ -341,14 +321,76 @@ async function _TokenDetectionController_startPolling() {
341
321
  *
342
322
  * @param options - Options for restart token detection.
343
323
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances
344
- * @param options.networkClientId - The ID of the network client to use.
324
+ * @param options.chainIds - The chain IDs of the network client to use.
345
325
  */
346
- async function _TokenDetectionController_restartTokenDetection({ selectedAddress, networkClientId, } = {}) {
326
+ async function _TokenDetectionController_restartTokenDetection({ selectedAddress, chainIds, } = {}) {
347
327
  await this.detectTokens({
348
- networkClientId,
328
+ chainIds,
349
329
  selectedAddress,
350
330
  });
351
331
  this.setIntervalLength(DEFAULT_INTERVAL);
332
+ }, _TokenDetectionController_getChainsToDetect = function _TokenDetectionController_getChainsToDetect(clientNetworks, supportedNetworks) {
333
+ const chainsToDetectUsingAccountAPI = [];
334
+ const chainsToDetectUsingRpc = [];
335
+ clientNetworks.forEach(({ chainId, networkClientId }) => {
336
+ if (supportedNetworks?.includes(hexToNumber(chainId))) {
337
+ chainsToDetectUsingAccountAPI.push(chainId);
338
+ }
339
+ else {
340
+ chainsToDetectUsingRpc.push({ chainId, networkClientId });
341
+ }
342
+ });
343
+ return { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI };
344
+ }, _TokenDetectionController_attemptAccountAPIDetection = async function _TokenDetectionController_attemptAccountAPIDetection(chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks) {
345
+ return await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokensViaAPI).call(this, {
346
+ chainIds: chainsToDetectUsingAccountAPI,
347
+ selectedAddress: addressToDetect,
348
+ supportedNetworks,
349
+ });
350
+ }, _TokenDetectionController_addChainsToRpcDetection = function _TokenDetectionController_addChainsToRpcDetection(chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks) {
351
+ chainsToDetectUsingAccountAPI.forEach((chainId) => {
352
+ const networkEntry = clientNetworks.find((network) => network.chainId === chainId);
353
+ if (networkEntry) {
354
+ chainsToDetectUsingRpc.push({
355
+ chainId: networkEntry.chainId,
356
+ networkClientId: networkEntry.networkClientId,
357
+ });
358
+ }
359
+ });
360
+ }, _TokenDetectionController_shouldDetectTokens = function _TokenDetectionController_shouldDetectTokens(chainId) {
361
+ if (!isTokenDetectionSupportedForNetwork(chainId)) {
362
+ return false;
363
+ }
364
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
365
+ chainId !== ChainId.mainnet) {
366
+ return false;
367
+ }
368
+ const isMainnetDetectionInactive = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") && chainId === ChainId.mainnet;
369
+ if (isMainnetDetectionInactive) {
370
+ __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this), "f");
371
+ }
372
+ else {
373
+ const { tokensChainsCache } = this.messagingSystem.call('TokenListController:getState');
374
+ __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, tokensChainsCache ?? {}, "f");
375
+ }
376
+ return true;
377
+ }, _TokenDetectionController_detectTokensUsingRpc = async function _TokenDetectionController_detectTokensUsingRpc(chainsToDetectUsingRpc, addressToDetect) {
378
+ for (const { chainId, networkClientId } of chainsToDetectUsingRpc) {
379
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_shouldDetectTokens).call(this, chainId)) {
380
+ continue;
381
+ }
382
+ const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
383
+ chainId,
384
+ selectedAddress: addressToDetect,
385
+ });
386
+ const tokenDetectionPromises = tokenCandidateSlices.map((tokensSlice) => __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokens).call(this, {
387
+ tokensSlice,
388
+ selectedAddress: addressToDetect,
389
+ networkClientId,
390
+ chainId,
391
+ }));
392
+ await Promise.all(tokenDetectionPromises);
393
+ }
352
394
  }, _TokenDetectionController_getSlicesOfTokensToDetect = function _TokenDetectionController_getSlicesOfTokensToDetect({ chainId, selectedAddress, }) {
353
395
  const { allTokens, allDetectedTokens, allIgnoredTokens } = this.messagingSystem.call('TokensController:getState');
354
396
  const [tokensAddresses, detectedTokensAddresses, ignoredTokensAddresses] = [
@@ -394,68 +436,92 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
394
436
  * This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances
395
437
  * @param options - method arguments
396
438
  * @param options.selectedAddress - address to check against
397
- * @param options.chainId - chainId to check tokens for
398
- * @param options.tokenCandidateSlices - these are tokens we know a user does not have (by checking the tokens controller).
399
- * We will use these these token candidates to determine if a token found from the API is valid to be added on the users wallet.
400
- * It will also prevent us to adding tokens a user already has
439
+ * @param options.chainIds - array of chainIds to check tokens for
440
+ * @param options.supportedNetworks - array of chainIds to check tokens for
401
441
  * @returns a success or failed object
402
442
  */
403
- async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainId, tokenCandidateSlices, }) {
443
+ async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainIds, supportedNetworks, }) {
404
444
  return await safelyExecute(async () => {
405
- const tokenBalances = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f")
406
- .getMultiChainBalances(selectedAddress, chainId)
445
+ // Fetch balances for multiple chain IDs at once
446
+ const tokenBalancesByChain = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f")
447
+ .getMultiNetworksBalances(selectedAddress, chainIds, supportedNetworks)
407
448
  .catch(() => null);
408
- if (!tokenBalances || tokenBalances.length === 0) {
449
+ if (!tokenBalancesByChain ||
450
+ Object.keys(tokenBalancesByChain).length === 0) {
409
451
  return { result: 'failed' };
410
452
  }
411
- const tokensWithBalance = [];
412
- const eventTokensDetails = [];
413
- const tokenCandidateSet = new Set(tokenCandidateSlices.flat());
414
- tokenBalances.forEach((token) => {
415
- const tokenAddress = token.address;
416
- // Make sure that the token to add is in our candidate list
417
- // Ensures we don't add tokens we already own
418
- if (!tokenCandidateSet.has(token.address)) {
419
- return;
420
- }
421
- // We need specific data from tokensChainsCache to correctly create a token
422
- // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.
423
- if (!__classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId].data[token.address]) {
424
- return;
425
- }
426
- const { decimals, symbol, aggregators, iconUrl, name } = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId].data[token.address];
427
- eventTokensDetails.push(`${symbol} - ${tokenAddress}`);
428
- tokensWithBalance.push({
429
- address: tokenAddress,
430
- decimals,
431
- symbol,
432
- aggregators,
433
- image: iconUrl,
434
- isERC721: false,
435
- name,
436
- });
437
- });
438
- if (tokensWithBalance.length) {
439
- __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
440
- event: 'Token Detected',
441
- category: 'Wallet',
442
- properties: {
443
- tokens: eventTokensDetails,
444
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
445
- // eslint-disable-next-line @typescript-eslint/naming-convention
446
- token_standard: ERC20,
447
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
448
- // eslint-disable-next-line @typescript-eslint/naming-convention
449
- asset_type: ASSET_TYPES.TOKEN,
450
- },
451
- });
452
- await this.messagingSystem.call('TokensController:addDetectedTokens', tokensWithBalance, {
453
- selectedAddress,
453
+ // Process each chain ID individually
454
+ for (const chainId of chainIds) {
455
+ const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
456
+ chainId === ChainId.mainnet;
457
+ const { tokensChainsCache } = this.messagingSystem.call('TokenListController:getState');
458
+ __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, isTokenDetectionInactiveInMainnet
459
+ ? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this)
460
+ : tokensChainsCache ?? {}, "f");
461
+ // Generate token candidates based on chainId and selectedAddress
462
+ const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
454
463
  chainId,
464
+ selectedAddress,
455
465
  });
466
+ // Filter balances for the current chainId
467
+ const tokenBalances = tokenBalancesByChain.filter((balance) => balance.chainId === hexToNumber(chainId));
468
+ if (!tokenBalances || tokenBalances.length === 0) {
469
+ continue;
470
+ }
471
+ // Use helper function to filter tokens with balance for this chainId
472
+ const { tokensWithBalance, eventTokensDetails } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_filterAndBuildTokensWithBalance).call(this, tokenCandidateSlices, tokenBalances, chainId);
473
+ if (tokensWithBalance.length) {
474
+ __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
475
+ event: 'Token Detected',
476
+ category: 'Wallet',
477
+ properties: {
478
+ tokens: eventTokensDetails,
479
+ // TODO: Either fix this lint violation or explain why it's necessary to ignore.
480
+ // eslint-disable-next-line @typescript-eslint/naming-convention
481
+ token_standard: ERC20,
482
+ // TODO: Either fix this lint violation or explain why it's necessary to ignore.
483
+ // eslint-disable-next-line @typescript-eslint/naming-convention
484
+ asset_type: ASSET_TYPES.TOKEN,
485
+ },
486
+ });
487
+ await this.messagingSystem.call('TokensController:addDetectedTokens', tokensWithBalance, {
488
+ selectedAddress,
489
+ chainId,
490
+ });
491
+ }
456
492
  }
457
493
  return { result: 'success' };
458
494
  });
495
+ }, _TokenDetectionController_filterAndBuildTokensWithBalance = function _TokenDetectionController_filterAndBuildTokensWithBalance(tokenCandidateSlices, tokenBalances, chainId) {
496
+ const tokensWithBalance = [];
497
+ const eventTokensDetails = [];
498
+ const tokenCandidateSet = new Set(tokenCandidateSlices.flat());
499
+ tokenBalances?.forEach((token) => {
500
+ const tokenAddress = token.address;
501
+ // Make sure the token to add is in our candidate list
502
+ if (!tokenCandidateSet.has(tokenAddress)) {
503
+ return;
504
+ }
505
+ // Retrieve token data from cache to safely add it
506
+ const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data[tokenAddress];
507
+ // We need specific data from tokensChainsCache to correctly create a token
508
+ // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.
509
+ if (!tokenData) {
510
+ return;
511
+ }
512
+ const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
513
+ eventTokensDetails.push(`${symbol} - ${tokenAddress}`);
514
+ tokensWithBalance.push({
515
+ address: tokenAddress,
516
+ decimals,
517
+ symbol,
518
+ aggregators,
519
+ image: iconUrl,
520
+ isERC721: false,
521
+ name,
522
+ });
523
+ });
524
+ return { tokensWithBalance, eventTokensDetails };
459
525
  }, _TokenDetectionController_addDetectedTokens = async function _TokenDetectionController_addDetectedTokens({ tokensSlice, selectedAddress, networkClientId, chainId, }) {
460
526
  await safelyExecute(async () => {
461
527
  const balances = await __classPrivateFieldGet(this, _TokenDetectionController_getBalancesInSingleCall, "f").call(this, selectedAddress, tokensSlice, networkClientId);