@metamask/assets-controllers 94.0.0 → 94.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 (60) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/dist/AccountTrackerController.cjs +71 -57
  3. package/dist/AccountTrackerController.cjs.map +1 -1
  4. package/dist/AccountTrackerController.d.cts +3 -2
  5. package/dist/AccountTrackerController.d.cts.map +1 -1
  6. package/dist/AccountTrackerController.d.mts +3 -2
  7. package/dist/AccountTrackerController.d.mts.map +1 -1
  8. package/dist/AccountTrackerController.mjs +71 -57
  9. package/dist/AccountTrackerController.mjs.map +1 -1
  10. package/dist/TokenBalancesController.cjs +351 -382
  11. package/dist/TokenBalancesController.cjs.map +1 -1
  12. package/dist/TokenBalancesController.d.cts +20 -39
  13. package/dist/TokenBalancesController.d.cts.map +1 -1
  14. package/dist/TokenBalancesController.d.mts +20 -39
  15. package/dist/TokenBalancesController.d.mts.map +1 -1
  16. package/dist/TokenBalancesController.mjs +351 -382
  17. package/dist/TokenBalancesController.mjs.map +1 -1
  18. package/dist/TokenDetectionController.cjs +139 -207
  19. package/dist/TokenDetectionController.cjs.map +1 -1
  20. package/dist/TokenDetectionController.d.cts +38 -12
  21. package/dist/TokenDetectionController.d.cts.map +1 -1
  22. package/dist/TokenDetectionController.d.mts +38 -12
  23. package/dist/TokenDetectionController.d.mts.map +1 -1
  24. package/dist/TokenDetectionController.mjs +140 -208
  25. package/dist/TokenDetectionController.mjs.map +1 -1
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +1 -1
  28. package/dist/index.d.cts.map +1 -1
  29. package/dist/index.d.mts +1 -1
  30. package/dist/index.d.mts.map +1 -1
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +13 -2
  33. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
  34. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
  35. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
  36. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +13 -2
  37. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
  38. package/dist/multi-chain-accounts-service/types.cjs.map +1 -1
  39. package/dist/multi-chain-accounts-service/types.d.cts +2 -1
  40. package/dist/multi-chain-accounts-service/types.d.cts.map +1 -1
  41. package/dist/multi-chain-accounts-service/types.d.mts +2 -1
  42. package/dist/multi-chain-accounts-service/types.d.mts.map +1 -1
  43. package/dist/multi-chain-accounts-service/types.mjs.map +1 -1
  44. package/dist/token-prices-service/codefi-v2.cjs +12 -0
  45. package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
  46. package/dist/token-prices-service/codefi-v2.d.cts +12 -2
  47. package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
  48. package/dist/token-prices-service/codefi-v2.d.mts +12 -2
  49. package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
  50. package/dist/token-prices-service/codefi-v2.mjs +12 -0
  51. package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
  52. package/dist/token-service.cjs +11 -3
  53. package/dist/token-service.cjs.map +1 -1
  54. package/dist/token-service.d.cts +3 -1
  55. package/dist/token-service.d.cts.map +1 -1
  56. package/dist/token-service.d.mts +3 -1
  57. package/dist/token-service.d.mts.map +1 -1
  58. package/dist/token-service.mjs +11 -3
  59. package/dist/token-service.mjs.map +1 -1
  60. package/package.json +1 -1
@@ -13,18 +13,16 @@ 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_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_useTokenDetection, _TokenDetectionController_useExternalServices, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent, _TokenDetectionController_accountsAPI, _TokenDetectionController_registerEventListeners, _TokenDetectionController_stopPolling, _TokenDetectionController_startPolling, _TokenDetectionController_compareTokensChainsCache, _TokenDetectionController_getCorrectNetworkClientIdByChainId, _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;
16
+ var _TokenDetectionController_instances, _TokenDetectionController_intervalId, _TokenDetectionController_selectedAccountId, _TokenDetectionController_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_useTokenDetection, _TokenDetectionController_useExternalServices, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent, _TokenDetectionController_registerEventListeners, _TokenDetectionController_stopPolling, _TokenDetectionController_startPolling, _TokenDetectionController_compareTokensChainsCache, _TokenDetectionController_getCorrectNetworkClientIdByChainId, _TokenDetectionController_restartTokenDetection, _TokenDetectionController_shouldDetectTokens, _TokenDetectionController_detectTokensUsingRpc, _TokenDetectionController_getSlicesOfTokensToDetect, _TokenDetectionController_getConvertedStaticMainnetTokenList, _TokenDetectionController_addDetectedTokens, _TokenDetectionController_getSelectedAccount, _TokenDetectionController_getSelectedAddress;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
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");
22
- const utils_1 = require("@metamask/utils");
23
22
  const lodash_1 = require("lodash");
24
23
  const assetsUtil_1 = require("./assetsUtil.cjs");
25
- const multi_chain_accounts_service_1 = require("./multi-chain-accounts-service/index.cjs");
24
+ const constants_1 = require("./constants.cjs");
26
25
  const DEFAULT_INTERVAL = 180000;
27
- const ACCOUNTS_API_TIMEOUT_MS = 10000;
28
26
  exports.STATIC_MAINNET_TOKEN_LIST = Object.entries(contract_metadata_1.default).reduce((acc, [base, contract]) => {
29
27
  const { logo, erc20, erc721, ...tokenMetadata } = contract;
30
28
  return {
@@ -79,12 +77,10 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
79
77
  * @param options.interval - Polling interval used to fetch new token rates
80
78
  * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.
81
79
  * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.
82
- * @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)
83
80
  * @param options.useTokenDetection - Feature Switch for using token detection (default: true)
84
81
  * @param options.useExternalServices - Feature Switch for using external services (default: false)
85
- * @param options.platform - Indicates whether the platform is extension or mobile
86
82
  */
87
- constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useAccountsAPI = true, useTokenDetection = () => true, useExternalServices = () => true, platform, }) {
83
+ constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useTokenDetection = () => true, useExternalServices = () => true, }) {
88
84
  super({
89
85
  name: exports.controllerName,
90
86
  messenger,
@@ -102,38 +98,9 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
102
98
  _TokenDetectionController_useExternalServices.set(this, void 0);
103
99
  _TokenDetectionController_getBalancesInSingleCall.set(this, void 0);
104
100
  _TokenDetectionController_trackMetaMetricsEvent.set(this, void 0);
105
- _TokenDetectionController_accountsAPI.set(this, {
106
- isAccountsAPIEnabled: true,
107
- supportedNetworksCache: null,
108
- platform: '',
109
- async getSupportedNetworks() {
110
- /* istanbul ignore next */
111
- if (!this.isAccountsAPIEnabled) {
112
- throw new Error('Accounts API Feature Switch is disabled');
113
- }
114
- /* istanbul ignore next */
115
- if (this.supportedNetworksCache) {
116
- return this.supportedNetworksCache;
117
- }
118
- const result = await (0, multi_chain_accounts_service_1.fetchSupportedNetworks)().catch(() => null);
119
- this.supportedNetworksCache = result;
120
- return result;
121
- },
122
- async getMultiNetworksBalances(address, chainIds, supportedNetworks, jwtToken) {
123
- const chainIdNumbers = chainIds.map((chainId) => (0, utils_1.hexToNumber)(chainId));
124
- if (!supportedNetworks ||
125
- !chainIdNumbers.every((id) => supportedNetworks.includes(id))) {
126
- const supportedNetworksErrStr = (supportedNetworks ?? []).toString();
127
- throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`);
128
- }
129
- const result = await (0, multi_chain_accounts_service_1.fetchMultiChainBalances)(address, {
130
- networks: chainIdNumbers,
131
- }, this.platform, jwtToken);
132
- // Return the full response including unprocessedNetworks
133
- return result;
134
- },
135
- });
136
101
  this.messenger.registerActionHandler(`${exports.controllerName}:addDetectedTokensViaWs`, this.addDetectedTokensViaWs.bind(this));
102
+ this.messenger.registerActionHandler(`${exports.controllerName}:addDetectedTokensViaPolling`, this.addDetectedTokensViaPolling.bind(this));
103
+ this.messenger.registerActionHandler(`${exports.controllerName}:detectTokens`, this.detectTokens.bind(this));
137
104
  __classPrivateFieldSet(this, _TokenDetectionController_disabled, disabled, "f");
138
105
  this.setIntervalLength(interval);
139
106
  __classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this).id, "f");
@@ -145,10 +112,8 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
145
112
  __classPrivateFieldSet(this, _TokenDetectionController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
146
113
  const { isUnlocked } = this.messenger.call('KeyringController:getState');
147
114
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, isUnlocked, "f");
148
- __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled = useAccountsAPI;
149
115
  __classPrivateFieldSet(this, _TokenDetectionController_useTokenDetection, useTokenDetection, "f");
150
116
  __classPrivateFieldSet(this, _TokenDetectionController_useExternalServices, useExternalServices, "f");
151
- __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").platform = platform;
152
117
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_registerEventListeners).call(this);
153
118
  }
154
119
  /**
@@ -201,48 +166,40 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
201
166
  * @param options - Options for token detection.
202
167
  * @param options.chainIds - The chain IDs of the network client to use.
203
168
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances.
169
+ * @param options.forceRpc - Force RPC-based token detection for all specified chains,
170
+ * bypassing external services check and ensuring RPC is used even for chains
171
+ * that might otherwise be handled by the Accounts API.
204
172
  */
205
- async detectTokens({ chainIds, selectedAddress, } = {}) {
173
+ async detectTokens({ chainIds, selectedAddress, forceRpc = false, } = {}) {
206
174
  if (!this.isActive) {
207
175
  return;
208
176
  }
209
- if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
177
+ // When forceRpc is true, bypass the useTokenDetection check to ensure RPC detection runs
178
+ if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
179
+ return;
180
+ }
181
+ // If external services are disabled and not forcing RPC, skip all detection
182
+ if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
210
183
  return;
211
184
  }
212
185
  const addressToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
213
186
  const clientNetworks = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectNetworkClientIdByChainId).call(this, chainIds);
214
- const jwtToken = await (0, controller_utils_1.safelyExecuteWithTimeout)(() => {
215
- return this.messenger.call('AuthenticationController:getBearerToken');
216
- }, false, 5000);
217
- let supportedNetworks;
218
- if (__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled && __classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
219
- supportedNetworks = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").getSupportedNetworks();
220
- }
221
- const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getChainsToDetect).call(this, clientNetworks, supportedNetworks);
222
- // Try detecting tokens via Account API first if conditions allow
223
- if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {
224
- const apiResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_attemptAccountAPIDetection).call(this, chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks, jwtToken);
225
- // If the account API call failed or returned undefined, have those chains fall back to RPC detection
226
- if (!apiResult || apiResult.result === 'failed') {
227
- __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks);
228
- }
229
- else if (apiResult?.result === 'success' &&
230
- apiResult.unprocessedNetworks &&
231
- apiResult.unprocessedNetworks.length > 0) {
232
- // Handle unprocessed networks by adding them to RPC detection
233
- const unprocessedChainIds = apiResult.unprocessedNetworks.map((chainId) => (0, controller_utils_1.toHex)(chainId));
234
- __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, unprocessedChainIds, clientNetworks);
235
- }
236
- }
237
- // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc
238
- if (chainsToDetectUsingRpc.length > 0) {
239
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
187
+ // If forceRpc is true, use RPC for all chains
188
+ // Otherwise, skip chains supported by Accounts API (they are handled by TokenBalancesController)
189
+ const chainsToDetectUsingRpc = forceRpc
190
+ ? clientNetworks
191
+ : clientNetworks.filter(({ chainId }) => !constants_1.SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId));
192
+ if (chainsToDetectUsingRpc.length === 0) {
193
+ return;
240
194
  }
195
+ await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
241
196
  }
242
197
  /**
243
198
  * Add tokens detected from websocket balance updates
244
- * This method assumes:
245
- * - Tokens are already in the tokensChainsCache with full metadata
199
+ * This method:
200
+ * - Checks if useTokenDetection preference is enabled (skips if disabled)
201
+ * - Checks if external services are enabled (skips if disabled)
202
+ * - Tokens are expected to be in the tokensChainsCache with full metadata
246
203
  * - Balance fetching is skipped since balances are provided by the websocket
247
204
  * - Ignored tokens have been filtered out by the caller
248
205
  *
@@ -252,6 +209,18 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
252
209
  * @returns Promise that resolves when tokens are added
253
210
  */
254
211
  async addDetectedTokensViaWs({ tokensSlice, chainId, }) {
212
+ // Check if token detection is enabled via preferences
213
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
214
+ return;
215
+ }
216
+ // Check if external services are enabled (websocket requires external services)
217
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
218
+ return;
219
+ }
220
+ // Refresh the token cache to ensure we have the latest token metadata
221
+ // This fixes a bug where the cache from construction time could be stale/empty
222
+ const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
223
+ __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, tokensChainsCache ?? {}, "f");
255
224
  const tokensWithBalance = [];
256
225
  const eventTokensDetails = [];
257
226
  for (const tokenAddress of tokensSlice) {
@@ -292,48 +261,136 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
292
261
  await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
293
262
  }
294
263
  }
264
+ /**
265
+ * Add tokens detected from polling balance updates
266
+ * This method:
267
+ * - Checks if useTokenDetection preference is enabled (skips if disabled)
268
+ * - Checks if external services are enabled (skips if disabled)
269
+ * - Filters out tokens already in allTokens or allIgnoredTokens
270
+ * - Tokens are expected to be in the tokensChainsCache with full metadata
271
+ * - Balance fetching is skipped since balances are provided by the caller
272
+ *
273
+ * @param options - The options object
274
+ * @param options.tokensSlice - Array of token addresses detected from polling
275
+ * @param options.chainId - Hex chain ID
276
+ * @returns Promise that resolves when tokens are added
277
+ */
278
+ async addDetectedTokensViaPolling({ tokensSlice, chainId, }) {
279
+ // Check if token detection is enabled via preferences
280
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
281
+ return;
282
+ }
283
+ // Check if external services are enabled (polling via API requires external services)
284
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
285
+ return;
286
+ }
287
+ // Refresh the token cache to ensure we have the latest token metadata
288
+ // This fixes a bug where the cache from construction time could be stale/empty
289
+ const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
290
+ __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, tokensChainsCache ?? {}, "f");
291
+ const selectedAddress = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
292
+ // Get current token states to filter out already tracked/ignored tokens
293
+ const { allTokens, allIgnoredTokens } = this.messenger.call('TokensController:getState');
294
+ const existingTokenAddresses = (allTokens[chainId]?.[selectedAddress] ?? []).map((token) => token.address.toLowerCase());
295
+ const ignoredTokenAddresses = (allIgnoredTokens[chainId]?.[selectedAddress] ?? []).map((address) => address.toLowerCase());
296
+ const tokensWithBalance = [];
297
+ const eventTokensDetails = [];
298
+ for (const tokenAddress of tokensSlice) {
299
+ const lowercaseTokenAddress = tokenAddress.toLowerCase();
300
+ const checksummedTokenAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress);
301
+ // Skip tokens already in allTokens
302
+ if (existingTokenAddresses.includes(lowercaseTokenAddress)) {
303
+ continue;
304
+ }
305
+ // Skip tokens in allIgnoredTokens
306
+ if (ignoredTokenAddresses.includes(lowercaseTokenAddress)) {
307
+ continue;
308
+ }
309
+ // Check map of validated tokens (cache keys are lowercase)
310
+ const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data?.[lowercaseTokenAddress];
311
+ if (!tokenData) {
312
+ console.warn(`Token metadata not found in cache for ${tokenAddress} on chain ${chainId}`);
313
+ continue;
314
+ }
315
+ const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
316
+ eventTokensDetails.push(`${symbol} - ${checksummedTokenAddress}`);
317
+ tokensWithBalance.push({
318
+ address: checksummedTokenAddress,
319
+ decimals,
320
+ symbol,
321
+ aggregators,
322
+ image: iconUrl,
323
+ isERC721: false,
324
+ name,
325
+ });
326
+ }
327
+ // Perform addition
328
+ if (tokensWithBalance.length) {
329
+ __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
330
+ event: 'Token Detected',
331
+ category: 'Wallet',
332
+ properties: {
333
+ tokens: eventTokensDetails,
334
+ token_standard: controller_utils_1.ERC20,
335
+ asset_type: controller_utils_1.ASSET_TYPES.TOKEN,
336
+ },
337
+ });
338
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
339
+ await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
340
+ }
341
+ }
295
342
  }
296
343
  exports.TokenDetectionController = TokenDetectionController;
297
- _TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_selectedAccountId = new WeakMap(), _TokenDetectionController_tokensChainsCache = new WeakMap(), _TokenDetectionController_disabled = new WeakMap(), _TokenDetectionController_isUnlocked = new WeakMap(), _TokenDetectionController_isDetectionEnabledFromPreferences = new WeakMap(), _TokenDetectionController_useTokenDetection = new WeakMap(), _TokenDetectionController_useExternalServices = new WeakMap(), _TokenDetectionController_getBalancesInSingleCall = new WeakMap(), _TokenDetectionController_trackMetaMetricsEvent = new WeakMap(), _TokenDetectionController_accountsAPI = new WeakMap(), _TokenDetectionController_instances = new WeakSet(), _TokenDetectionController_registerEventListeners = function _TokenDetectionController_registerEventListeners() {
298
- this.messenger.subscribe('KeyringController:unlock', async () => {
344
+ _TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_selectedAccountId = new WeakMap(), _TokenDetectionController_tokensChainsCache = new WeakMap(), _TokenDetectionController_disabled = new WeakMap(), _TokenDetectionController_isUnlocked = new WeakMap(), _TokenDetectionController_isDetectionEnabledFromPreferences = new WeakMap(), _TokenDetectionController_useTokenDetection = new WeakMap(), _TokenDetectionController_useExternalServices = new WeakMap(), _TokenDetectionController_getBalancesInSingleCall = new WeakMap(), _TokenDetectionController_trackMetaMetricsEvent = new WeakMap(), _TokenDetectionController_instances = new WeakSet(), _TokenDetectionController_registerEventListeners = function _TokenDetectionController_registerEventListeners() {
345
+ this.messenger.subscribe('KeyringController:unlock', () => {
299
346
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, true, "f");
300
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this);
347
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
348
+ // Silently handle token detection errors
349
+ });
301
350
  });
302
351
  this.messenger.subscribe('KeyringController:lock', () => {
303
352
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, false, "f");
304
353
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_stopPolling).call(this);
305
354
  });
306
- this.messenger.subscribe('TokenListController:stateChange', async ({ tokensChainsCache }) => {
355
+ this.messenger.subscribe('TokenListController:stateChange', ({ tokensChainsCache }) => {
307
356
  const isEqualValues = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_compareTokensChainsCache).call(this, tokensChainsCache, __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f"));
308
357
  if (!isEqualValues) {
309
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this);
358
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
359
+ // Silently handle token detection errors
360
+ });
310
361
  }
311
362
  });
312
- this.messenger.subscribe('PreferencesController:stateChange', async ({ useTokenDetection }) => {
363
+ this.messenger.subscribe('PreferencesController:stateChange', ({ useTokenDetection }) => {
313
364
  const selectedAccount = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this);
314
365
  const isDetectionChangedFromPreferences = __classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") !== useTokenDetection;
315
366
  __classPrivateFieldSet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, useTokenDetection, "f");
316
367
  if (isDetectionChangedFromPreferences) {
317
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
368
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
318
369
  selectedAddress: selectedAccount.address,
370
+ }).catch(() => {
371
+ // Silently handle token detection errors
319
372
  });
320
373
  }
321
374
  });
322
- this.messenger.subscribe('AccountsController:selectedEvmAccountChange', async (selectedAccount) => {
375
+ this.messenger.subscribe('AccountsController:selectedEvmAccountChange', (selectedAccount) => {
323
376
  const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
324
377
  const chainIds = Object.keys(networkConfigurationsByChainId);
325
378
  const isSelectedAccountIdChanged = __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f") !== selectedAccount.id;
326
379
  if (isSelectedAccountIdChanged) {
327
380
  __classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, selectedAccount.id, "f");
328
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
381
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
329
382
  selectedAddress: selectedAccount.address,
330
383
  chainIds,
384
+ }).catch(() => {
385
+ // Silently handle token detection errors
331
386
  });
332
387
  }
333
388
  });
334
- this.messenger.subscribe('TransactionController:transactionConfirmed', async (transactionMeta) => {
335
- await this.detectTokens({
389
+ this.messenger.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
390
+ this.detectTokens({
336
391
  chainIds: [transactionMeta.chainId],
392
+ }).catch(() => {
393
+ // Silently handle token detection errors
337
394
  });
338
395
  });
339
396
  }, _TokenDetectionController_stopPolling = function _TokenDetectionController_stopPolling() {
@@ -394,41 +451,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
394
451
  selectedAddress,
395
452
  });
396
453
  this.setIntervalLength(DEFAULT_INTERVAL);
397
- }, _TokenDetectionController_getChainsToDetect = function _TokenDetectionController_getChainsToDetect(clientNetworks, supportedNetworks) {
398
- const chainsToDetectUsingAccountAPI = [];
399
- const chainsToDetectUsingRpc = [];
400
- clientNetworks.forEach(({ chainId, networkClientId }) => {
401
- if (supportedNetworks?.includes((0, utils_1.hexToNumber)(chainId))) {
402
- chainsToDetectUsingAccountAPI.push(chainId);
403
- }
404
- else {
405
- chainsToDetectUsingRpc.push({ chainId, networkClientId });
406
- }
407
- });
408
- return { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI };
409
- }, _TokenDetectionController_attemptAccountAPIDetection = async function _TokenDetectionController_attemptAccountAPIDetection(chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks, jwtToken) {
410
- const result = await (0, controller_utils_1.safelyExecuteWithTimeout)(async () => {
411
- return __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokensViaAPI).call(this, {
412
- chainIds: chainsToDetectUsingAccountAPI,
413
- selectedAddress: addressToDetect,
414
- supportedNetworks,
415
- jwtToken,
416
- });
417
- }, false, ACCOUNTS_API_TIMEOUT_MS);
418
- if (!result) {
419
- return { result: 'failed' };
420
- }
421
- return result;
422
- }, _TokenDetectionController_addChainsToRpcDetection = function _TokenDetectionController_addChainsToRpcDetection(chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks) {
423
- chainsToDetectUsingAccountAPI.forEach((chainId) => {
424
- const networkEntry = clientNetworks.find((network) => network.chainId === chainId);
425
- if (networkEntry) {
426
- chainsToDetectUsingRpc.push({
427
- chainId: networkEntry.chainId,
428
- networkClientId: networkEntry.networkClientId,
429
- });
430
- }
431
- });
432
454
  }, _TokenDetectionController_shouldDetectTokens = function _TokenDetectionController_shouldDetectTokens(chainId) {
433
455
  if (!(0, assetsUtil_1.isTokenDetectionSupportedForNetwork)(chainId)) {
434
456
  return false;
@@ -503,96 +525,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
503
525
  timestamp: 0,
504
526
  },
505
527
  };
506
- }, _TokenDetectionController_addDetectedTokensViaAPI =
507
- /**
508
- * This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances
509
- *
510
- * @param options - method arguments
511
- * @param options.selectedAddress - address to check against
512
- * @param options.chainIds - array of chainIds to check tokens for
513
- * @param options.supportedNetworks - array of chainIds to check tokens for
514
- * @param options.jwtToken - JWT token for authentication
515
- * @returns a success or failed object
516
- */
517
- async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainIds, supportedNetworks, jwtToken, }) {
518
- return await (0, controller_utils_1.safelyExecute)(async () => {
519
- // Fetch balances for multiple chain IDs at once
520
- const apiResponse = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f")
521
- .getMultiNetworksBalances(selectedAddress, chainIds, supportedNetworks, jwtToken)
522
- .catch(() => null);
523
- if (apiResponse === null) {
524
- return { result: 'failed' };
525
- }
526
- const tokenBalancesByChain = apiResponse.balances;
527
- // Process each chain ID individually
528
- for (const chainId of chainIds) {
529
- const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
530
- chainId === controller_utils_1.ChainId.mainnet;
531
- const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
532
- __classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, isTokenDetectionInactiveInMainnet
533
- ? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this)
534
- : (tokensChainsCache ?? {}), "f");
535
- // Generate token candidates based on chainId and selectedAddress
536
- const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
537
- chainId,
538
- selectedAddress,
539
- });
540
- // Filter balances for the current chainId
541
- const tokenBalances = tokenBalancesByChain.filter((balance) => balance.chainId === (0, utils_1.hexToNumber)(chainId));
542
- if (!tokenBalances || tokenBalances.length === 0) {
543
- continue;
544
- }
545
- // Use helper function to filter tokens with balance for this chainId
546
- const { tokensWithBalance, eventTokensDetails } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_filterAndBuildTokensWithBalance).call(this, tokenCandidateSlices, tokenBalances, chainId);
547
- if (tokensWithBalance.length) {
548
- __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
549
- event: 'Token Detected',
550
- category: 'Wallet',
551
- properties: {
552
- tokens: eventTokensDetails,
553
- token_standard: controller_utils_1.ERC20,
554
- asset_type: controller_utils_1.ASSET_TYPES.TOKEN,
555
- },
556
- });
557
- const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
558
- await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
559
- }
560
- }
561
- return {
562
- result: 'success',
563
- unprocessedNetworks: apiResponse.unprocessedNetworks,
564
- };
565
- });
566
- }, _TokenDetectionController_filterAndBuildTokensWithBalance = function _TokenDetectionController_filterAndBuildTokensWithBalance(tokenCandidateSlices, tokenBalances, chainId) {
567
- const tokensWithBalance = [];
568
- const eventTokensDetails = [];
569
- const tokenCandidateSet = new Set(tokenCandidateSlices.flat());
570
- tokenBalances?.forEach((token) => {
571
- const tokenAddress = token.address;
572
- // Make sure the token to add is in our candidate list
573
- if (!tokenCandidateSet.has(tokenAddress)) {
574
- return;
575
- }
576
- // Retrieve token data from cache to safely add it
577
- const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data[tokenAddress];
578
- // We need specific data from tokensChainsCache to correctly create a token
579
- // So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.
580
- if (!tokenData) {
581
- return;
582
- }
583
- const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
584
- eventTokensDetails.push(`${symbol} - ${tokenAddress}`);
585
- tokensWithBalance.push({
586
- address: tokenAddress,
587
- decimals,
588
- symbol,
589
- aggregators,
590
- image: iconUrl,
591
- isERC721: false,
592
- name,
593
- });
594
- });
595
- return { tokensWithBalance, eventTokensDetails };
596
528
  }, _TokenDetectionController_addDetectedTokens = async function _TokenDetectionController_addDetectedTokens({ tokensSlice, selectedAddress, networkClientId, chainId, }) {
597
529
  await (0, controller_utils_1.safelyExecute)(async () => {
598
530
  const balances = await __classPrivateFieldGet(this, _TokenDetectionController_getBalancesInSingleCall, "f").call(this, selectedAddress, tokensSlice, networkClientId);
@@ -629,7 +561,7 @@ async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddre
629
561
  }, _TokenDetectionController_getSelectedAddress = function _TokenDetectionController_getSelectedAddress() {
630
562
  // If the address is not defined (or empty), we fallback to the currently selected account's address
631
563
  const account = this.messenger.call('AccountsController:getAccount', __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f"));
632
- return account?.address || '';
564
+ return account?.address ?? '';
633
565
  };
634
566
  exports.default = TokenDetectionController;
635
567
  //# sourceMappingURL=TokenDetectionController.cjs.map