@metamask/assets-controllers 42.0.0 → 43.1.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 (66) hide show
  1. package/CHANGELOG.md +24 -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/RatesController/RatesController.cjs +12 -1
  21. package/dist/RatesController/RatesController.cjs.map +1 -1
  22. package/dist/RatesController/RatesController.d.cts +8 -1
  23. package/dist/RatesController/RatesController.d.cts.map +1 -1
  24. package/dist/RatesController/RatesController.d.mts +8 -1
  25. package/dist/RatesController/RatesController.d.mts.map +1 -1
  26. package/dist/RatesController/RatesController.mjs +12 -1
  27. package/dist/RatesController/RatesController.mjs.map +1 -1
  28. package/dist/TokenDetectionController.cjs +191 -127
  29. package/dist/TokenDetectionController.cjs.map +1 -1
  30. package/dist/TokenDetectionController.d.cts +20 -11
  31. package/dist/TokenDetectionController.d.cts.map +1 -1
  32. package/dist/TokenDetectionController.d.mts +20 -11
  33. package/dist/TokenDetectionController.d.mts.map +1 -1
  34. package/dist/TokenDetectionController.mjs +190 -127
  35. package/dist/TokenDetectionController.mjs.map +1 -1
  36. package/dist/TokenListController.cjs +60 -53
  37. package/dist/TokenListController.cjs.map +1 -1
  38. package/dist/TokenListController.d.cts +25 -14
  39. package/dist/TokenListController.d.cts.map +1 -1
  40. package/dist/TokenListController.d.mts +25 -14
  41. package/dist/TokenListController.d.mts.map +1 -1
  42. package/dist/TokenListController.mjs +60 -53
  43. package/dist/TokenListController.mjs.map +1 -1
  44. package/dist/TokenRatesController.d.cts +4 -4
  45. package/dist/TokenRatesController.d.mts +4 -4
  46. package/dist/TokensController.cjs +7 -4
  47. package/dist/TokensController.cjs.map +1 -1
  48. package/dist/TokensController.d.cts.map +1 -1
  49. package/dist/TokensController.d.mts.map +1 -1
  50. package/dist/TokensController.mjs +7 -4
  51. package/dist/TokensController.mjs.map +1 -1
  52. package/dist/assetsUtil.cjs +13 -1
  53. package/dist/assetsUtil.cjs.map +1 -1
  54. package/dist/assetsUtil.d.cts +7 -0
  55. package/dist/assetsUtil.d.cts.map +1 -1
  56. package/dist/assetsUtil.d.mts +7 -0
  57. package/dist/assetsUtil.d.mts.map +1 -1
  58. package/dist/assetsUtil.mjs +12 -0
  59. package/dist/assetsUtil.mjs.map +1 -1
  60. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.cjs +18 -0
  61. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.cjs.map +1 -1
  62. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.d.cts.map +1 -1
  63. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.d.mts.map +1 -1
  64. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.mjs +18 -0
  65. package/dist/multi-chain-accounts-service/mocks/mock-get-balances.mjs.map +1 -1
  66. package/package.json +9 -9
@@ -13,9 +13,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- 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;
16
+ 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;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.TokenDetectionController = exports.controllerName = exports.STATIC_MAINNET_TOKEN_LIST = void 0;
18
+ exports.TokenDetectionController = exports.controllerName = exports.mapChainIdWithTokenListMap = exports.STATIC_MAINNET_TOKEN_LIST = void 0;
19
19
  const contract_metadata_1 = __importDefault(require("@metamask/contract-metadata"));
20
20
  const controller_utils_1 = require("@metamask/controller-utils");
21
21
  const polling_controller_1 = require("@metamask/polling-controller");
@@ -49,6 +49,7 @@ function mapChainIdWithTokenListMap(tokensChainsCache) {
49
49
  return value;
50
50
  });
51
51
  }
52
+ exports.mapChainIdWithTokenListMap = mapChainIdWithTokenListMap;
52
53
  exports.controllerName = 'TokenDetectionController';
53
54
  /**
54
55
  * Controller that passively polls on a set interval for Tokens auto detection
@@ -108,18 +109,15 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
108
109
  this.supportedNetworksCache = result;
109
110
  return result;
110
111
  },
111
- async getMultiChainBalances(address, chainId) {
112
- if (!this.isAccountsAPIEnabled) {
113
- throw new Error('Accounts API Feature Switch is disabled');
114
- }
115
- const chainIdNumber = (0, utils_1.hexToNumber)(chainId);
116
- const supportedNetworks = await this.getSupportedNetworks();
117
- if (!supportedNetworks || !supportedNetworks.includes(chainIdNumber)) {
112
+ async getMultiNetworksBalances(address, chainIds, supportedNetworks) {
113
+ const chainIdNumbers = chainIds.map((chainId) => (0, utils_1.hexToNumber)(chainId));
114
+ if (!supportedNetworks ||
115
+ !chainIdNumbers.every((id) => supportedNetworks.includes(id))) {
118
116
  const supportedNetworksErrStr = (supportedNetworks ?? []).toString();
119
- throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, network: ${chainIdNumber}`);
117
+ throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`);
120
118
  }
121
119
  const result = await (0, multi_chain_accounts_service_1.fetchMultiChainBalances)(address, {
122
- networks: [chainIdNumber],
120
+ networks: chainIdNumbers,
123
121
  }, this.platform);
124
122
  return result.balances;
125
123
  },
@@ -175,12 +173,12 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
175
173
  this.disable();
176
174
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_stopPolling).call(this);
177
175
  }
178
- async _executePoll({ networkClientId, address, }) {
176
+ async _executePoll({ chainIds, address, }) {
179
177
  if (!this.isActive) {
180
178
  return;
181
179
  }
182
180
  await this.detectTokens({
183
- networkClientId,
181
+ chainIds,
184
182
  selectedAddress: address,
185
183
  });
186
184
  }
@@ -189,51 +187,35 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
189
187
  * 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.
190
188
  *
191
189
  * @param options - Options for token detection.
192
- * @param options.networkClientId - The ID of the network client to use.
190
+ * @param options.chainIds - The chain IDs of the network client to use.
193
191
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances.
194
192
  */
195
- async detectTokens({ networkClientId, selectedAddress, } = {}) {
193
+ async detectTokens({ chainIds, selectedAddress, } = {}) {
196
194
  if (!this.isActive) {
197
195
  return;
198
196
  }
199
- const addressAgainstWhichToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
200
- const { chainId, networkClientId: selectedNetworkClientId } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectChainIdAndNetworkClientId).call(this, networkClientId);
201
- const chainIdAgainstWhichToDetect = chainId;
202
- const networkClientIdAgainstWhichToDetect = selectedNetworkClientId;
203
- if (!(0, assetsUtil_1.isTokenDetectionSupportedForNetwork)(chainIdAgainstWhichToDetect)) {
204
- return;
197
+ const addressToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
198
+ const clientNetworks = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectNetworkClientIdByChainId).call(this, chainIds);
199
+ let supportedNetworks;
200
+ if (__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled) {
201
+ supportedNetworks = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").getSupportedNetworks();
205
202
  }
206
- if (!__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
207
- chainIdAgainstWhichToDetect !== controller_utils_1.ChainId.mainnet) {
208
- return;
203
+ const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getChainsToDetect).call(this, clientNetworks, supportedNetworks);
204
+ // Try detecting tokens via Account API first if conditions allow
205
+ if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {
206
+ const apiResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_attemptAccountAPIDetection).call(this, chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks);
207
+ // If API succeeds and no chains are left for RPC detection, we can return early
208
+ if (apiResult?.result === 'success' &&
209
+ chainsToDetectUsingRpc.length === 0) {
210
+ return;
211
+ }
212
+ // If API fails or chainsToDetectUsingRpc still has items, add chains to RPC detection
213
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks);
209
214
  }
210
- const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
211
- chainIdAgainstWhichToDetect === controller_utils_1.ChainId.mainnet;
212
- const { tokensChainsCache } = this.messagingSystem.call('TokenListController:getState');
213
- __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, isTokenDetectionInactiveInMainnet
214
- ? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this)
215
- : tokensChainsCache ?? {}, "f");
216
- const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
217
- chainId: chainIdAgainstWhichToDetect,
218
- selectedAddress: addressAgainstWhichToDetect,
219
- });
220
- // Attempt Accounts API Detection
221
- const accountAPIResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokensViaAPI).call(this, {
222
- chainId: chainIdAgainstWhichToDetect,
223
- selectedAddress: addressAgainstWhichToDetect,
224
- tokenCandidateSlices,
225
- });
226
- if (accountAPIResult?.result === 'success') {
227
- return;
215
+ // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc
216
+ if (chainsToDetectUsingRpc.length > 0) {
217
+ await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
228
218
  }
229
- // Attempt RPC Detection
230
- const tokenDetectionPromises = tokenCandidateSlices.map((tokensSlice) => __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokens).call(this, {
231
- tokensSlice,
232
- selectedAddress: addressAgainstWhichToDetect,
233
- networkClientId: networkClientIdAgainstWhichToDetect,
234
- chainId: chainIdAgainstWhichToDetect,
235
- }));
236
- await Promise.all(tokenDetectionPromises);
237
219
  }
238
220
  }
239
221
  exports.TokenDetectionController = TokenDetectionController;
@@ -282,20 +264,6 @@ _TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_
282
264
  });
283
265
  }
284
266
  });
285
- this.messagingSystem.subscribe('NetworkController:networkDidChange',
286
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
287
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
288
- async ({ selectedNetworkClientId }) => {
289
- const isNetworkClientIdChanged = __classPrivateFieldGet(this, _TokenDetectionController_networkClientId, "f") !== selectedNetworkClientId;
290
- const { chainId: newChainId } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectChainIdAndNetworkClientId).call(this, selectedNetworkClientId);
291
- __classPrivateFieldSet(this, _TokenDetectionController_isDetectionEnabledForNetwork, (0, assetsUtil_1.isTokenDetectionSupportedForNetwork)(newChainId), "f");
292
- if (isNetworkClientIdChanged && __classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledForNetwork, "f")) {
293
- __classPrivateFieldSet(this, _TokenDetectionController_networkClientId, selectedNetworkClientId, "f");
294
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
295
- networkClientId: __classPrivateFieldGet(this, _TokenDetectionController_networkClientId, "f"),
296
- });
297
- }
298
- });
299
267
  }, _TokenDetectionController_stopPolling = function _TokenDetectionController_stopPolling() {
300
268
  if (__classPrivateFieldGet(this, _TokenDetectionController_intervalId, "f")) {
301
269
  clearInterval(__classPrivateFieldGet(this, _TokenDetectionController_intervalId, "f"));
@@ -320,16 +288,26 @@ async function _TokenDetectionController_startPolling() {
320
288
  const cleanTokensChainsCache = mapChainIdWithTokenListMap(tokensChainsCache);
321
289
  const isEqualValues = (0, lodash_1.isEqual)(cleanTokensChainsCache, cleanPreviousTokensChainsCache);
322
290
  return isEqualValues;
323
- }, _TokenDetectionController_getCorrectChainIdAndNetworkClientId = function _TokenDetectionController_getCorrectChainIdAndNetworkClientId(networkClientId) {
324
- if (networkClientId) {
325
- const networkConfiguration = this.messagingSystem.call('NetworkController:getNetworkConfigurationByNetworkClientId', networkClientId);
326
- if (networkConfiguration) {
327
- return {
328
- chainId: networkConfiguration.chainId,
329
- networkClientId,
330
- };
331
- }
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 ?? controller_utils_1.ChainId.mainnet,
298
+ networkClientId: selectedNetworkClientId,
299
+ },
300
+ ];
332
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() {
333
311
  const { selectedNetworkClientId } = this.messagingSystem.call('NetworkController:getState');
334
312
  const { configuration: { chainId }, } = this.messagingSystem.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
335
313
  return {
@@ -343,14 +321,76 @@ async function _TokenDetectionController_startPolling() {
343
321
  *
344
322
  * @param options - Options for restart token detection.
345
323
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances
346
- * @param options.networkClientId - The ID of the network client to use.
324
+ * @param options.chainIds - The chain IDs of the network client to use.
347
325
  */
348
- async function _TokenDetectionController_restartTokenDetection({ selectedAddress, networkClientId, } = {}) {
326
+ async function _TokenDetectionController_restartTokenDetection({ selectedAddress, chainIds, } = {}) {
349
327
  await this.detectTokens({
350
- networkClientId,
328
+ chainIds,
351
329
  selectedAddress,
352
330
  });
353
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((0, utils_1.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 (!(0, assetsUtil_1.isTokenDetectionSupportedForNetwork)(chainId)) {
362
+ return false;
363
+ }
364
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
365
+ chainId !== controller_utils_1.ChainId.mainnet) {
366
+ return false;
367
+ }
368
+ const isMainnetDetectionInactive = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") && chainId === controller_utils_1.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
+ }
354
394
  }, _TokenDetectionController_getSlicesOfTokensToDetect = function _TokenDetectionController_getSlicesOfTokensToDetect({ chainId, selectedAddress, }) {
355
395
  const { allTokens, allDetectedTokens, allIgnoredTokens } = this.messagingSystem.call('TokensController:getState');
356
396
  const [tokensAddresses, detectedTokensAddresses, ignoredTokensAddresses] = [
@@ -396,68 +436,92 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
396
436
  * This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances
397
437
  * @param options - method arguments
398
438
  * @param options.selectedAddress - address to check against
399
- * @param options.chainId - chainId to check tokens for
400
- * @param options.tokenCandidateSlices - these are tokens we know a user does not have (by checking the tokens controller).
401
- * 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.
402
- * 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
403
441
  * @returns a success or failed object
404
442
  */
405
- async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainId, tokenCandidateSlices, }) {
443
+ async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainIds, supportedNetworks, }) {
406
444
  return await (0, controller_utils_1.safelyExecute)(async () => {
407
- const tokenBalances = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f")
408
- .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)
409
448
  .catch(() => null);
410
- if (!tokenBalances || tokenBalances.length === 0) {
449
+ if (!tokenBalancesByChain ||
450
+ Object.keys(tokenBalancesByChain).length === 0) {
411
451
  return { result: 'failed' };
412
452
  }
413
- const tokensWithBalance = [];
414
- const eventTokensDetails = [];
415
- const tokenCandidateSet = new Set(tokenCandidateSlices.flat());
416
- tokenBalances.forEach((token) => {
417
- const tokenAddress = token.address;
418
- // Make sure that the token to add is in our candidate list
419
- // Ensures we don't add tokens we already own
420
- if (!tokenCandidateSet.has(token.address)) {
421
- return;
422
- }
423
- // We need specific data from tokensChainsCache to correctly create a token
424
- // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.
425
- if (!__classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId].data[token.address]) {
426
- return;
427
- }
428
- const { decimals, symbol, aggregators, iconUrl, name } = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId].data[token.address];
429
- eventTokensDetails.push(`${symbol} - ${tokenAddress}`);
430
- tokensWithBalance.push({
431
- address: tokenAddress,
432
- decimals,
433
- symbol,
434
- aggregators,
435
- image: iconUrl,
436
- isERC721: false,
437
- name,
438
- });
439
- });
440
- if (tokensWithBalance.length) {
441
- __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
442
- event: 'Token Detected',
443
- category: 'Wallet',
444
- properties: {
445
- tokens: eventTokensDetails,
446
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
447
- // eslint-disable-next-line @typescript-eslint/naming-convention
448
- token_standard: controller_utils_1.ERC20,
449
- // TODO: Either fix this lint violation or explain why it's necessary to ignore.
450
- // eslint-disable-next-line @typescript-eslint/naming-convention
451
- asset_type: controller_utils_1.ASSET_TYPES.TOKEN,
452
- },
453
- });
454
- await this.messagingSystem.call('TokensController:addDetectedTokens', tokensWithBalance, {
455
- selectedAddress,
453
+ // Process each chain ID individually
454
+ for (const chainId of chainIds) {
455
+ const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
456
+ chainId === controller_utils_1.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, {
456
463
  chainId,
464
+ selectedAddress,
457
465
  });
466
+ // Filter balances for the current chainId
467
+ const tokenBalances = tokenBalancesByChain.filter((balance) => balance.chainId === (0, utils_1.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: controller_utils_1.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: controller_utils_1.ASSET_TYPES.TOKEN,
485
+ },
486
+ });
487
+ await this.messagingSystem.call('TokensController:addDetectedTokens', tokensWithBalance, {
488
+ selectedAddress,
489
+ chainId,
490
+ });
491
+ }
458
492
  }
459
493
  return { result: 'success' };
460
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 };
461
525
  }, _TokenDetectionController_addDetectedTokens = async function _TokenDetectionController_addDetectedTokens({ tokensSlice, selectedAddress, networkClientId, chainId, }) {
462
526
  await (0, controller_utils_1.safelyExecute)(async () => {
463
527
  const balances = await __classPrivateFieldGet(this, _TokenDetectionController_getBalancesInSingleCall, "f").call(this, selectedAddress, tokensSlice, networkClientId);