@metamask-previews/assets-controllers 93.1.0-preview-d717276a → 94.0.0-preview-cd26c284

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 (36) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/TokenBalancesController.cjs +342 -378
  3. package/dist/TokenBalancesController.cjs.map +1 -1
  4. package/dist/TokenBalancesController.d.cts +17 -38
  5. package/dist/TokenBalancesController.d.cts.map +1 -1
  6. package/dist/TokenBalancesController.d.mts +17 -38
  7. package/dist/TokenBalancesController.d.mts.map +1 -1
  8. package/dist/TokenBalancesController.mjs +342 -378
  9. package/dist/TokenBalancesController.mjs.map +1 -1
  10. package/dist/TokenDetectionController.cjs +131 -207
  11. package/dist/TokenDetectionController.cjs.map +1 -1
  12. package/dist/TokenDetectionController.d.cts +38 -12
  13. package/dist/TokenDetectionController.d.cts.map +1 -1
  14. package/dist/TokenDetectionController.d.mts +38 -12
  15. package/dist/TokenDetectionController.d.mts.map +1 -1
  16. package/dist/TokenDetectionController.mjs +132 -208
  17. package/dist/TokenDetectionController.mjs.map +1 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +1 -1
  20. package/dist/index.d.cts.map +1 -1
  21. package/dist/index.d.mts +1 -1
  22. package/dist/index.d.mts.map +1 -1
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +13 -2
  25. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
  26. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
  27. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
  28. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +13 -2
  29. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
  30. package/dist/multi-chain-accounts-service/types.cjs.map +1 -1
  31. package/dist/multi-chain-accounts-service/types.d.cts +2 -1
  32. package/dist/multi-chain-accounts-service/types.d.cts.map +1 -1
  33. package/dist/multi-chain-accounts-service/types.d.mts +2 -1
  34. package/dist/multi-chain-accounts-service/types.d.mts.map +1 -1
  35. package/dist/multi-chain-accounts-service/types.mjs.map +1 -1
  36. package/package.json +1 -1
@@ -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_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;
12
+ 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;
13
13
  function $importDefault(module) {
14
14
  if (module?.__esModule) {
15
15
  return module.default;
@@ -18,15 +18,13 @@ function $importDefault(module) {
18
18
  }
19
19
  import $contractMap from "@metamask/contract-metadata";
20
20
  const contractMap = $importDefault($contractMap);
21
- import { ASSET_TYPES, ChainId, ERC20, safelyExecute, safelyExecuteWithTimeout, isEqualCaseInsensitive, toChecksumHexAddress, toHex } from "@metamask/controller-utils";
21
+ import { ASSET_TYPES, ChainId, ERC20, safelyExecute, isEqualCaseInsensitive, toChecksumHexAddress } from "@metamask/controller-utils";
22
22
  import { StaticIntervalPollingController } from "@metamask/polling-controller";
23
- import { hexToNumber } from "@metamask/utils";
24
23
  import $lodash from "lodash";
25
24
  const { isEqual, mapValues, isObject, get } = $lodash;
26
25
  import { isTokenDetectionSupportedForNetwork } from "./assetsUtil.mjs";
27
- import { fetchMultiChainBalances, fetchSupportedNetworks } from "./multi-chain-accounts-service/index.mjs";
26
+ import { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from "./constants.mjs";
28
27
  const DEFAULT_INTERVAL = 180000;
29
- const ACCOUNTS_API_TIMEOUT_MS = 10000;
30
28
  export const STATIC_MAINNET_TOKEN_LIST = Object.entries(contractMap).reduce((acc, [base, contract]) => {
31
29
  const { logo, erc20, erc721, ...tokenMetadata } = contract;
32
30
  return {
@@ -80,12 +78,10 @@ export class TokenDetectionController extends StaticIntervalPollingController()
80
78
  * @param options.interval - Polling interval used to fetch new token rates
81
79
  * @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.
82
80
  * @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.
83
- * @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)
84
81
  * @param options.useTokenDetection - Feature Switch for using token detection (default: true)
85
82
  * @param options.useExternalServices - Feature Switch for using external services (default: false)
86
- * @param options.platform - Indicates whether the platform is extension or mobile
87
83
  */
88
- constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useAccountsAPI = true, useTokenDetection = () => true, useExternalServices = () => true, platform, }) {
84
+ constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useTokenDetection = () => true, useExternalServices = () => true, }) {
89
85
  super({
90
86
  name: controllerName,
91
87
  messenger,
@@ -103,38 +99,9 @@ export class TokenDetectionController extends StaticIntervalPollingController()
103
99
  _TokenDetectionController_useExternalServices.set(this, void 0);
104
100
  _TokenDetectionController_getBalancesInSingleCall.set(this, void 0);
105
101
  _TokenDetectionController_trackMetaMetricsEvent.set(this, void 0);
106
- _TokenDetectionController_accountsAPI.set(this, {
107
- isAccountsAPIEnabled: true,
108
- supportedNetworksCache: null,
109
- platform: '',
110
- async getSupportedNetworks() {
111
- /* istanbul ignore next */
112
- if (!this.isAccountsAPIEnabled) {
113
- throw new Error('Accounts API Feature Switch is disabled');
114
- }
115
- /* istanbul ignore next */
116
- if (this.supportedNetworksCache) {
117
- return this.supportedNetworksCache;
118
- }
119
- const result = await fetchSupportedNetworks().catch(() => null);
120
- this.supportedNetworksCache = result;
121
- return result;
122
- },
123
- async getMultiNetworksBalances(address, chainIds, supportedNetworks, jwtToken) {
124
- const chainIdNumbers = chainIds.map((chainId) => hexToNumber(chainId));
125
- if (!supportedNetworks ||
126
- !chainIdNumbers.every((id) => supportedNetworks.includes(id))) {
127
- const supportedNetworksErrStr = (supportedNetworks ?? []).toString();
128
- throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`);
129
- }
130
- const result = await fetchMultiChainBalances(address, {
131
- networks: chainIdNumbers,
132
- }, this.platform, jwtToken);
133
- // Return the full response including unprocessedNetworks
134
- return result;
135
- },
136
- });
137
102
  this.messenger.registerActionHandler(`${controllerName}:addDetectedTokensViaWs`, this.addDetectedTokensViaWs.bind(this));
103
+ this.messenger.registerActionHandler(`${controllerName}:addDetectedTokensViaPolling`, this.addDetectedTokensViaPolling.bind(this));
104
+ this.messenger.registerActionHandler(`${controllerName}:detectTokens`, this.detectTokens.bind(this));
138
105
  __classPrivateFieldSet(this, _TokenDetectionController_disabled, disabled, "f");
139
106
  this.setIntervalLength(interval);
140
107
  __classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this).id, "f");
@@ -146,10 +113,8 @@ export class TokenDetectionController extends StaticIntervalPollingController()
146
113
  __classPrivateFieldSet(this, _TokenDetectionController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
147
114
  const { isUnlocked } = this.messenger.call('KeyringController:getState');
148
115
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, isUnlocked, "f");
149
- __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled = useAccountsAPI;
150
116
  __classPrivateFieldSet(this, _TokenDetectionController_useTokenDetection, useTokenDetection, "f");
151
117
  __classPrivateFieldSet(this, _TokenDetectionController_useExternalServices, useExternalServices, "f");
152
- __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").platform = platform;
153
118
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_registerEventListeners).call(this);
154
119
  }
155
120
  /**
@@ -202,48 +167,40 @@ export class TokenDetectionController extends StaticIntervalPollingController()
202
167
  * @param options - Options for token detection.
203
168
  * @param options.chainIds - The chain IDs of the network client to use.
204
169
  * @param options.selectedAddress - the selectedAddress against which to detect for token balances.
170
+ * @param options.forceRpc - Force RPC-based token detection for all specified chains,
171
+ * bypassing external services check and ensuring RPC is used even for chains
172
+ * that might otherwise be handled by the Accounts API.
205
173
  */
206
- async detectTokens({ chainIds, selectedAddress, } = {}) {
174
+ async detectTokens({ chainIds, selectedAddress, forceRpc = false, } = {}) {
207
175
  if (!this.isActive) {
208
176
  return;
209
177
  }
210
- if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
178
+ // When forceRpc is true, bypass the useTokenDetection check to ensure RPC detection runs
179
+ if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
180
+ return;
181
+ }
182
+ // If external services are disabled and not forcing RPC, skip all detection
183
+ if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
211
184
  return;
212
185
  }
213
186
  const addressToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
214
187
  const clientNetworks = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectNetworkClientIdByChainId).call(this, chainIds);
215
- const jwtToken = await safelyExecuteWithTimeout(() => {
216
- return this.messenger.call('AuthenticationController:getBearerToken');
217
- }, false, 5000);
218
- let supportedNetworks;
219
- if (__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled && __classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
220
- supportedNetworks = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").getSupportedNetworks();
221
- }
222
- const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getChainsToDetect).call(this, clientNetworks, supportedNetworks);
223
- // Try detecting tokens via Account API first if conditions allow
224
- if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {
225
- const apiResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_attemptAccountAPIDetection).call(this, chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks, jwtToken);
226
- // If the account API call failed or returned undefined, have those chains fall back to RPC detection
227
- if (!apiResult || apiResult.result === 'failed') {
228
- __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks);
229
- }
230
- else if (apiResult?.result === 'success' &&
231
- apiResult.unprocessedNetworks &&
232
- apiResult.unprocessedNetworks.length > 0) {
233
- // Handle unprocessed networks by adding them to RPC detection
234
- const unprocessedChainIds = apiResult.unprocessedNetworks.map((chainId) => toHex(chainId));
235
- __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, unprocessedChainIds, clientNetworks);
236
- }
237
- }
238
- // Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc
239
- if (chainsToDetectUsingRpc.length > 0) {
240
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
188
+ // If forceRpc is true, use RPC for all chains
189
+ // Otherwise, skip chains supported by Accounts API (they are handled by TokenBalancesController)
190
+ const chainsToDetectUsingRpc = forceRpc
191
+ ? clientNetworks
192
+ : clientNetworks.filter(({ chainId }) => !SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId));
193
+ if (chainsToDetectUsingRpc.length === 0) {
194
+ return;
241
195
  }
196
+ await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
242
197
  }
243
198
  /**
244
199
  * Add tokens detected from websocket balance updates
245
- * This method assumes:
246
- * - Tokens are already in the tokensChainsCache with full metadata
200
+ * This method:
201
+ * - Checks if useTokenDetection preference is enabled (skips if disabled)
202
+ * - Checks if external services are enabled (skips if disabled)
203
+ * - Tokens are expected to be in the tokensChainsCache with full metadata
247
204
  * - Balance fetching is skipped since balances are provided by the websocket
248
205
  * - Ignored tokens have been filtered out by the caller
249
206
  *
@@ -253,6 +210,14 @@ export class TokenDetectionController extends StaticIntervalPollingController()
253
210
  * @returns Promise that resolves when tokens are added
254
211
  */
255
212
  async addDetectedTokensViaWs({ tokensSlice, chainId, }) {
213
+ // Check if token detection is enabled via preferences
214
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
215
+ return;
216
+ }
217
+ // Check if external services are enabled (websocket requires external services)
218
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
219
+ return;
220
+ }
256
221
  const tokensWithBalance = [];
257
222
  const eventTokensDetails = [];
258
223
  for (const tokenAddress of tokensSlice) {
@@ -293,47 +258,131 @@ export class TokenDetectionController extends StaticIntervalPollingController()
293
258
  await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
294
259
  }
295
260
  }
261
+ /**
262
+ * Add tokens detected from polling balance updates
263
+ * This method:
264
+ * - Checks if useTokenDetection preference is enabled (skips if disabled)
265
+ * - Checks if external services are enabled (skips if disabled)
266
+ * - Filters out tokens already in allTokens or allIgnoredTokens
267
+ * - Tokens are expected to be in the tokensChainsCache with full metadata
268
+ * - Balance fetching is skipped since balances are provided by the caller
269
+ *
270
+ * @param options - The options object
271
+ * @param options.tokensSlice - Array of token addresses detected from polling
272
+ * @param options.chainId - Hex chain ID
273
+ * @returns Promise that resolves when tokens are added
274
+ */
275
+ async addDetectedTokensViaPolling({ tokensSlice, chainId, }) {
276
+ // Check if token detection is enabled via preferences
277
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
278
+ return;
279
+ }
280
+ // Check if external services are enabled (polling via API requires external services)
281
+ if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
282
+ return;
283
+ }
284
+ const selectedAddress = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
285
+ // Get current token states to filter out already tracked/ignored tokens
286
+ const { allTokens, allIgnoredTokens } = this.messenger.call('TokensController:getState');
287
+ const existingTokenAddresses = (allTokens[chainId]?.[selectedAddress] ?? []).map((token) => token.address.toLowerCase());
288
+ const ignoredTokenAddresses = (allIgnoredTokens[chainId]?.[selectedAddress] ?? []).map((address) => address.toLowerCase());
289
+ const tokensWithBalance = [];
290
+ const eventTokensDetails = [];
291
+ for (const tokenAddress of tokensSlice) {
292
+ const lowercaseTokenAddress = tokenAddress.toLowerCase();
293
+ const checksummedTokenAddress = toChecksumHexAddress(tokenAddress);
294
+ // Skip tokens already in allTokens
295
+ if (existingTokenAddresses.includes(lowercaseTokenAddress)) {
296
+ continue;
297
+ }
298
+ // Skip tokens in allIgnoredTokens
299
+ if (ignoredTokenAddresses.includes(lowercaseTokenAddress)) {
300
+ continue;
301
+ }
302
+ // Check map of validated tokens (cache keys are lowercase)
303
+ const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data?.[lowercaseTokenAddress];
304
+ if (!tokenData) {
305
+ console.warn(`Token metadata not found in cache for ${tokenAddress} on chain ${chainId}`);
306
+ continue;
307
+ }
308
+ const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
309
+ eventTokensDetails.push(`${symbol} - ${checksummedTokenAddress}`);
310
+ tokensWithBalance.push({
311
+ address: checksummedTokenAddress,
312
+ decimals,
313
+ symbol,
314
+ aggregators,
315
+ image: iconUrl,
316
+ isERC721: false,
317
+ name,
318
+ });
319
+ }
320
+ // Perform addition
321
+ if (tokensWithBalance.length) {
322
+ __classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
323
+ event: 'Token Detected',
324
+ category: 'Wallet',
325
+ properties: {
326
+ tokens: eventTokensDetails,
327
+ token_standard: ERC20,
328
+ asset_type: ASSET_TYPES.TOKEN,
329
+ },
330
+ });
331
+ const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
332
+ await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
333
+ }
334
+ }
296
335
  }
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 () => {
336
+ _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() {
337
+ this.messenger.subscribe('KeyringController:unlock', () => {
299
338
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, true, "f");
300
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this);
339
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
340
+ // Silently handle token detection errors
341
+ });
301
342
  });
302
343
  this.messenger.subscribe('KeyringController:lock', () => {
303
344
  __classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, false, "f");
304
345
  __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_stopPolling).call(this);
305
346
  });
306
- this.messenger.subscribe('TokenListController:stateChange', async ({ tokensChainsCache }) => {
347
+ this.messenger.subscribe('TokenListController:stateChange', ({ tokensChainsCache }) => {
307
348
  const isEqualValues = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_compareTokensChainsCache).call(this, tokensChainsCache, __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f"));
308
349
  if (!isEqualValues) {
309
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this);
350
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
351
+ // Silently handle token detection errors
352
+ });
310
353
  }
311
354
  });
312
- this.messenger.subscribe('PreferencesController:stateChange', async ({ useTokenDetection }) => {
355
+ this.messenger.subscribe('PreferencesController:stateChange', ({ useTokenDetection }) => {
313
356
  const selectedAccount = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this);
314
357
  const isDetectionChangedFromPreferences = __classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") !== useTokenDetection;
315
358
  __classPrivateFieldSet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, useTokenDetection, "f");
316
359
  if (isDetectionChangedFromPreferences) {
317
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
360
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
318
361
  selectedAddress: selectedAccount.address,
362
+ }).catch(() => {
363
+ // Silently handle token detection errors
319
364
  });
320
365
  }
321
366
  });
322
- this.messenger.subscribe('AccountsController:selectedEvmAccountChange', async (selectedAccount) => {
367
+ this.messenger.subscribe('AccountsController:selectedEvmAccountChange', (selectedAccount) => {
323
368
  const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
324
369
  const chainIds = Object.keys(networkConfigurationsByChainId);
325
370
  const isSelectedAccountIdChanged = __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f") !== selectedAccount.id;
326
371
  if (isSelectedAccountIdChanged) {
327
372
  __classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, selectedAccount.id, "f");
328
- await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
373
+ __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
329
374
  selectedAddress: selectedAccount.address,
330
375
  chainIds,
376
+ }).catch(() => {
377
+ // Silently handle token detection errors
331
378
  });
332
379
  }
333
380
  });
334
- this.messenger.subscribe('TransactionController:transactionConfirmed', async (transactionMeta) => {
335
- await this.detectTokens({
381
+ this.messenger.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
382
+ this.detectTokens({
336
383
  chainIds: [transactionMeta.chainId],
384
+ }).catch(() => {
385
+ // Silently handle token detection errors
337
386
  });
338
387
  });
339
388
  }, _TokenDetectionController_stopPolling = function _TokenDetectionController_stopPolling() {
@@ -394,41 +443,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
394
443
  selectedAddress,
395
444
  });
396
445
  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(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 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
446
  }, _TokenDetectionController_shouldDetectTokens = function _TokenDetectionController_shouldDetectTokens(chainId) {
433
447
  if (!isTokenDetectionSupportedForNetwork(chainId)) {
434
448
  return false;
@@ -503,96 +517,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
503
517
  timestamp: 0,
504
518
  },
505
519
  };
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 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 === 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 === 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: ERC20,
554
- asset_type: 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
520
  }, _TokenDetectionController_addDetectedTokens = async function _TokenDetectionController_addDetectedTokens({ tokensSlice, selectedAddress, networkClientId, chainId, }) {
597
521
  await safelyExecute(async () => {
598
522
  const balances = await __classPrivateFieldGet(this, _TokenDetectionController_getBalancesInSingleCall, "f").call(this, selectedAddress, tokensSlice, networkClientId);
@@ -629,7 +553,7 @@ async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddre
629
553
  }, _TokenDetectionController_getSelectedAddress = function _TokenDetectionController_getSelectedAddress() {
630
554
  // If the address is not defined (or empty), we fallback to the currently selected account's address
631
555
  const account = this.messenger.call('AccountsController:getAccount', __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f"));
632
- return account?.address || '';
556
+ return account?.address ?? '';
633
557
  };
634
558
  export default TokenDetectionController;
635
559
  //# sourceMappingURL=TokenDetectionController.mjs.map