@metamask/assets-controller 11.0.0 → 11.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 (78) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/dist/AssetsController-method-action-types.cjs.map +1 -1
  3. package/dist/AssetsController-method-action-types.d.cts +23 -1
  4. package/dist/AssetsController-method-action-types.d.cts.map +1 -1
  5. package/dist/AssetsController-method-action-types.d.mts +23 -1
  6. package/dist/AssetsController-method-action-types.d.mts.map +1 -1
  7. package/dist/AssetsController-method-action-types.mjs.map +1 -1
  8. package/dist/AssetsController.cjs +99 -51
  9. package/dist/AssetsController.cjs.map +1 -1
  10. package/dist/AssetsController.d.cts +21 -1
  11. package/dist/AssetsController.d.cts.map +1 -1
  12. package/dist/AssetsController.d.mts +21 -1
  13. package/dist/AssetsController.d.mts.map +1 -1
  14. package/dist/AssetsController.mjs +99 -51
  15. package/dist/AssetsController.mjs.map +1 -1
  16. package/dist/data-sources/AccountsApiDataSource.cjs +95 -9
  17. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  18. package/dist/data-sources/AccountsApiDataSource.d.cts +8 -1
  19. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  20. package/dist/data-sources/AccountsApiDataSource.d.mts +8 -1
  21. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  22. package/dist/data-sources/AccountsApiDataSource.mjs +95 -9
  23. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  24. package/dist/data-sources/TokenDataSource.cjs +73 -12
  25. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  26. package/dist/data-sources/TokenDataSource.d.cts +4 -1
  27. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  28. package/dist/data-sources/TokenDataSource.d.mts +4 -1
  29. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  30. package/dist/data-sources/TokenDataSource.mjs +73 -12
  31. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  32. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.cjs +86 -27
  33. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.cjs.map +1 -1
  34. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.d.cts +4 -3
  35. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.d.cts.map +1 -1
  36. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.d.mts +4 -3
  37. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.d.mts.map +1 -1
  38. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.mjs +86 -27
  39. package/dist/data-sources/evm-rpc-services/clients/TokensApiClient.mjs.map +1 -1
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +2 -2
  42. package/dist/index.d.cts.map +1 -1
  43. package/dist/index.d.mts +2 -2
  44. package/dist/index.d.mts.map +1 -1
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/utils/formatExchangeRatesForBridge.cjs +36 -7
  47. package/dist/utils/formatExchangeRatesForBridge.cjs.map +1 -1
  48. package/dist/utils/formatExchangeRatesForBridge.d.cts +20 -14
  49. package/dist/utils/formatExchangeRatesForBridge.d.cts.map +1 -1
  50. package/dist/utils/formatExchangeRatesForBridge.d.mts +20 -14
  51. package/dist/utils/formatExchangeRatesForBridge.d.mts.map +1 -1
  52. package/dist/utils/formatExchangeRatesForBridge.mjs +34 -5
  53. package/dist/utils/formatExchangeRatesForBridge.mjs.map +1 -1
  54. package/dist/utils/formatStateForTransactionPay.cjs +56 -9
  55. package/dist/utils/formatStateForTransactionPay.cjs.map +1 -1
  56. package/dist/utils/formatStateForTransactionPay.d.cts +23 -17
  57. package/dist/utils/formatStateForTransactionPay.d.cts.map +1 -1
  58. package/dist/utils/formatStateForTransactionPay.d.mts +23 -17
  59. package/dist/utils/formatStateForTransactionPay.d.mts.map +1 -1
  60. package/dist/utils/formatStateForTransactionPay.mjs +54 -7
  61. package/dist/utils/formatStateForTransactionPay.mjs.map +1 -1
  62. package/dist/utils/index.cjs +4 -1
  63. package/dist/utils/index.cjs.map +1 -1
  64. package/dist/utils/index.d.cts +5 -5
  65. package/dist/utils/index.d.cts.map +1 -1
  66. package/dist/utils/index.d.mts +5 -5
  67. package/dist/utils/index.d.mts.map +1 -1
  68. package/dist/utils/index.mjs +3 -3
  69. package/dist/utils/index.mjs.map +1 -1
  70. package/dist/utils/normalizeAssetId.cjs +17 -3
  71. package/dist/utils/normalizeAssetId.cjs.map +1 -1
  72. package/dist/utils/normalizeAssetId.d.cts +10 -1
  73. package/dist/utils/normalizeAssetId.d.cts.map +1 -1
  74. package/dist/utils/normalizeAssetId.d.mts +10 -1
  75. package/dist/utils/normalizeAssetId.d.mts.map +1 -1
  76. package/dist/utils/normalizeAssetId.mjs +19 -1
  77. package/dist/utils/normalizeAssetId.mjs.map +1 -1
  78. package/package.json +7 -4
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  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");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _AccountsApiDataSource_instances, _AccountsApiDataSource_onActiveChainsUpdated, _AccountsApiDataSource_pollInterval, _AccountsApiDataSource_fetchTimeoutMs, _AccountsApiDataSource_tokenDetectionEnabled, _AccountsApiDataSource_apiClient, _AccountsApiDataSource_chainsRefreshTimer, _AccountsApiDataSource_getAssetsState, _AccountsApiDataSource_initializeActiveChains, _AccountsApiDataSource_refreshActiveChains, _AccountsApiDataSource_fetchActiveChains, _AccountsApiDataSource_processV5Balances;
13
+ var _AccountsApiDataSource_instances, _AccountsApiDataSource_onActiveChainsUpdated, _AccountsApiDataSource_pollInterval, _AccountsApiDataSource_fetchTimeoutMs, _AccountsApiDataSource_tokenDetectionEnabled, _AccountsApiDataSource_messenger, _AccountsApiDataSource_apiClient, _AccountsApiDataSource_chainsRefreshTimer, _AccountsApiDataSource_getAssetsState, _AccountsApiDataSource_isBalanceV6Enabled, _AccountsApiDataSource_initializeActiveChains, _AccountsApiDataSource_refreshActiveChains, _AccountsApiDataSource_fetchActiveChains, _AccountsApiDataSource_fetchV5Balances, _AccountsApiDataSource_fetchV6Balances, _AccountsApiDataSource_buildAddressToAccountIdMap, _AccountsApiDataSource_processV5Balances, _AccountsApiDataSource_processV6Balances;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.AccountsApiDataSource = exports.filterResponseToKnownAssets = void 0;
16
16
  const core_backend_1 = require("@metamask/core-backend");
@@ -112,6 +112,8 @@ class AccountsApiDataSource extends AbstractDataSource_1.AbstractDataSource {
112
112
  _AccountsApiDataSource_fetchTimeoutMs.set(this, void 0);
113
113
  /** Getter avoids stale value when user toggles token detection at runtime. */
114
114
  _AccountsApiDataSource_tokenDetectionEnabled.set(this, void 0);
115
+ /** Shared AssetsController messenger, used to read remote feature flags. */
116
+ _AccountsApiDataSource_messenger.set(this, void 0);
115
117
  /** ApiPlatformClient for cached API calls */
116
118
  _AccountsApiDataSource_apiClient.set(this, void 0);
117
119
  /** Chains refresh timer */
@@ -122,6 +124,7 @@ class AccountsApiDataSource extends AbstractDataSource_1.AbstractDataSource {
122
124
  __classPrivateFieldSet(this, _AccountsApiDataSource_pollInterval, options.pollInterval ?? DEFAULT_POLL_INTERVAL, "f");
123
125
  __classPrivateFieldSet(this, _AccountsApiDataSource_fetchTimeoutMs, options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS, "f");
124
126
  __classPrivateFieldSet(this, _AccountsApiDataSource_tokenDetectionEnabled, options.tokenDetectionEnabled ?? (() => true), "f");
127
+ __classPrivateFieldSet(this, _AccountsApiDataSource_messenger, options.messenger, "f");
125
128
  __classPrivateFieldSet(this, _AccountsApiDataSource_apiClient, options.queryApiClient, "f");
126
129
  __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_initializeActiveChains).call(this).catch(console.error);
127
130
  }
@@ -169,17 +172,20 @@ class AccountsApiDataSource extends AbstractDataSource_1.AbstractDataSource {
169
172
  const fetchOptions = request.forceUpdate
170
173
  ? { staleTime: 0, gcTime: 0 }
171
174
  : undefined;
172
- const apiResponse = await (0, utils_2.fetchWithTimeout)(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV5MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
175
+ // Feature-flagged: v6 endpoint with a fallback to legacy v5. The flag is
176
+ // read here (not cached) so a runtime toggle can revert v6 -> v5.
177
+ const { unprocessedNetworks, assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_isBalanceV6Enabled).call(this)
178
+ ? await __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_fetchV6Balances).call(this, accountIds, fetchOptions, request)
179
+ : await __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_fetchV5Balances).call(this, accountIds, fetchOptions, request);
173
180
  // Handle unprocessed networks - these will be passed to next middleware
174
- if (apiResponse.unprocessedNetworks.length > 0) {
175
- const unprocessedChainIds = apiResponse.unprocessedNetworks.map(caipChainIdToChainId);
181
+ if (unprocessedNetworks.length > 0) {
182
+ const unprocessedChainIds = unprocessedNetworks.map(caipChainIdToChainId);
176
183
  // Add unprocessed chains to errors so middleware passes them to next data source
177
184
  response.errors = response.errors ?? {};
178
185
  for (const chainId of unprocessedChainIds) {
179
186
  response.errors[chainId] = 'Unprocessed by Accounts API';
180
187
  }
181
188
  }
182
- const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
183
189
  response.assetsBalance = assetsBalance;
184
190
  response.updateMode = 'merge';
185
191
  }
@@ -344,7 +350,18 @@ class AccountsApiDataSource extends AbstractDataSource_1.AbstractDataSource {
344
350
  }
345
351
  }
346
352
  exports.AccountsApiDataSource = AccountsApiDataSource;
347
- _AccountsApiDataSource_onActiveChainsUpdated = new WeakMap(), _AccountsApiDataSource_pollInterval = new WeakMap(), _AccountsApiDataSource_fetchTimeoutMs = new WeakMap(), _AccountsApiDataSource_tokenDetectionEnabled = new WeakMap(), _AccountsApiDataSource_apiClient = new WeakMap(), _AccountsApiDataSource_chainsRefreshTimer = new WeakMap(), _AccountsApiDataSource_getAssetsState = new WeakMap(), _AccountsApiDataSource_instances = new WeakSet(), _AccountsApiDataSource_initializeActiveChains =
353
+ _AccountsApiDataSource_onActiveChainsUpdated = new WeakMap(), _AccountsApiDataSource_pollInterval = new WeakMap(), _AccountsApiDataSource_fetchTimeoutMs = new WeakMap(), _AccountsApiDataSource_tokenDetectionEnabled = new WeakMap(), _AccountsApiDataSource_messenger = new WeakMap(), _AccountsApiDataSource_apiClient = new WeakMap(), _AccountsApiDataSource_chainsRefreshTimer = new WeakMap(), _AccountsApiDataSource_getAssetsState = new WeakMap(), _AccountsApiDataSource_instances = new WeakSet(), _AccountsApiDataSource_isBalanceV6Enabled = function _AccountsApiDataSource_isBalanceV6Enabled() {
354
+ try {
355
+ const { remoteFeatureFlags } = __classPrivateFieldGet(this, _AccountsApiDataSource_messenger, "f").call('RemoteFeatureFlagController:getState');
356
+ const flag = remoteFeatureFlags?.assetsAccountsApiV6;
357
+ return (typeof flag === 'object' &&
358
+ flag !== null &&
359
+ Boolean(flag.value));
360
+ }
361
+ catch {
362
+ return false;
363
+ }
364
+ }, _AccountsApiDataSource_initializeActiveChains =
348
365
  // ============================================================================
349
366
  // INITIALIZATION
350
367
  // ============================================================================
@@ -384,15 +401,50 @@ async function _AccountsApiDataSource_initializeActiveChains() {
384
401
  .map(decimalToChainId)
385
402
  // TODO Restore solana when there is a fix for how we handle non-evm chains here
386
403
  .filter((chainId) => chainId.startsWith('eip155:')));
387
- }, _AccountsApiDataSource_processV5Balances = function _AccountsApiDataSource_processV5Balances(balances, request) {
388
- const assetsBalance = {};
389
- // Build a map of lowercase addresses to account IDs for efficient lookup
404
+ }, _AccountsApiDataSource_fetchV5Balances =
405
+ /**
406
+ * Fetch balances from the legacy v5 endpoint and process them.
407
+ *
408
+ * @param accountIds - CAIP-10 account IDs to fetch balances for.
409
+ * @param fetchOptions - Cache/fetch options (e.g. force update settings).
410
+ * @param request - The original data request containing accounts to map.
411
+ * @returns Unprocessed networks and processed asset balances by account.
412
+ */
413
+ async function _AccountsApiDataSource_fetchV5Balances(accountIds, fetchOptions, request) {
414
+ const apiResponse = await (0, utils_2.fetchWithTimeout)(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV5MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
415
+ const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
416
+ return {
417
+ unprocessedNetworks: apiResponse.unprocessedNetworks,
418
+ assetsBalance,
419
+ };
420
+ }, _AccountsApiDataSource_fetchV6Balances =
421
+ /**
422
+ * Fetch balances from the v6 endpoint and process them.
423
+ *
424
+ * @param accountIds - CAIP-10 account IDs to fetch balances for.
425
+ * @param fetchOptions - Cache/fetch options (e.g. force update settings).
426
+ * @param request - The original data request containing accounts to map.
427
+ * @returns Unprocessed networks and processed asset balances by account.
428
+ */
429
+ async function _AccountsApiDataSource_fetchV6Balances(accountIds, fetchOptions, request) {
430
+ const apiResponse = await (0, utils_2.fetchWithTimeout)(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV6MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
431
+ const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV6Balances).call(this, apiResponse.accounts, request);
432
+ return {
433
+ unprocessedNetworks: apiResponse.unprocessedNetworks,
434
+ assetsBalance,
435
+ };
436
+ }, _AccountsApiDataSource_buildAddressToAccountIdMap = function _AccountsApiDataSource_buildAddressToAccountIdMap(request) {
390
437
  const addressToAccountId = new Map();
391
438
  for (const { account } of request.accountsWithSupportedChains) {
392
439
  if (account.address) {
393
440
  addressToAccountId.set(account.address.toLowerCase(), account.id);
394
441
  }
395
442
  }
443
+ return addressToAccountId;
444
+ }, _AccountsApiDataSource_processV5Balances = function _AccountsApiDataSource_processV5Balances(balances, request) {
445
+ const assetsBalance = {};
446
+ // Build a map of lowercase addresses to account IDs for efficient lookup
447
+ const addressToAccountId = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_buildAddressToAccountIdMap).call(this, request);
396
448
  // V5 response: array of { accountId, assetId, balance, ... }
397
449
  for (const item of balances) {
398
450
  // Extract address from CAIP-10 account ID (e.g., "eip155:1:0x1234..." -> "0x1234...")
@@ -418,5 +470,39 @@ async function _AccountsApiDataSource_initializeActiveChains() {
418
470
  };
419
471
  }
420
472
  return { assetsBalance };
473
+ }, _AccountsApiDataSource_processV6Balances = function _AccountsApiDataSource_processV6Balances(accounts, request) {
474
+ const assetsBalance = Object.create(null);
475
+ // Build a map of lowercase addresses to account IDs for efficient lookup
476
+ const addressToAccountId = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_buildAddressToAccountIdMap).call(this, request);
477
+ for (const entry of accounts) {
478
+ // Extract address from CAIP-10 account ID (e.g., "eip155:1:0x1234..." -> "0x1234...")
479
+ const addressParts = entry.accountId.split(':');
480
+ if (addressParts.length < 3) {
481
+ continue;
482
+ }
483
+ const address = addressParts[2].toLowerCase();
484
+ // Find the matching account ID from request
485
+ const accountId = addressToAccountId.get(address);
486
+ if (!accountId) {
487
+ // This is normal - API returns balances for all chains, but request may only have one account
488
+ continue;
489
+ }
490
+ for (const item of entry.balances) {
491
+ // Only consume token balances; DeFi positions are handled elsewhere.
492
+ if (item.category !== 'token') {
493
+ continue;
494
+ }
495
+ if (!assetsBalance[accountId]) {
496
+ assetsBalance[accountId] = Object.create(null);
497
+ }
498
+ // Normalize asset ID (checksum EVM addresses for ERC20 tokens)
499
+ const normalizedAssetId = (0, utils_2.normalizeAssetId)(item.assetId);
500
+ // Store balance as returned by API
501
+ assetsBalance[accountId][normalizedAssetId] = {
502
+ amount: item.balance,
503
+ };
504
+ }
505
+ }
506
+ return { assetsBalance };
421
507
  };
422
508
  //# sourceMappingURL=AccountsApiDataSource.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"AccountsApiDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { V5BalanceItem } from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call (none - uses callbacks).\n// Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed\nexport type AccountsApiDataSourceAllowedActions = never;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n /**\n * Re-fetch supported networks from the Accounts API and update `activeChains`\n * when the list changed. Used when the selected EVM network switches so\n * chain claiming is not stuck on an empty init-time list.\n *\n * @returns Resolves when supported networks have been re-fetched.\n */\n refreshActiveChains(): Promise<void> {\n return this.#refreshActiveChains();\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const fetchOptions = request.forceUpdate\n ? { staleTime: 0, gcTime: 0 }\n : undefined;\n\n const apiResponse = await fetchWithTimeout(\n () =>\n this.#apiClient.accounts.fetchV5MultiAccountBalances(\n accountIds,\n undefined,\n fetchOptions,\n ),\n this.#fetchTimeoutMs,\n );\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (apiResponse.unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n apiResponse.unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'merge';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
1
+ {"version":3,"file":"AccountsApiDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n V5BalanceItem,\n V6AccountBalancesEntry,\n} from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type { RemoteFeatureFlagControllerGetStateAction } from '@metamask/remote-feature-flag-controller';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetBalance,\n DataRequest,\n DataResponse,\n Middleware,\n AssetsControllerStateInternal,\n} from '../types';\nimport { fetchWithTimeout, normalizeAssetId } from '../utils';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'AccountsApiDataSource';\nconst DEFAULT_POLL_INTERVAL = 30_000;\nconst DEFAULT_FETCH_TIMEOUT_MS = 15_000;\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that AccountsApiDataSource can call. Balances are fetched via\n// ApiPlatformClient directly (no BackendApiClient actions needed); the messenger\n// is only used to read the Accounts API v6 balances feature flag.\nexport type AccountsApiDataSourceAllowedActions =\n RemoteFeatureFlagControllerGetStateAction;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type AccountsApiDataSourceState = DataSourceState;\n\nconst defaultState: AccountsApiDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\n/** Optional configuration for AccountsApiDataSource. */\nexport type AccountsApiDataSourceConfig = {\n /** Polling interval in ms (default: 30000) */\n pollInterval?: number;\n /**\n * Function returning whether token detection is enabled (default: () => true).\n * When it returns false, balances are only returned for tokens already in state.\n * Using a getter avoids stale values when the user toggles the preference at runtime.\n */\n tokenDetectionEnabled?: () => boolean;\n /**\n * Timeout in ms for a single balances fetch call (default: 15000).\n * When it fires, every requested chain is marked as errored so the\n * middleware hands them off to the next data source (e.g. RPC fallback).\n */\n fetchTimeoutMs?: number;\n};\n\nexport type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {\n /**\n * The AssetsController messenger (shared by all data sources). Used to read\n * the `assetsAccountsApiV6` remote feature flag.\n */\n messenger: AssetsControllerMessenger;\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n state?: Partial<AccountsApiDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nfunction decimalToChainId(decimalChainId: number | string): ChainId {\n // Handle both decimal numbers and already-formatted CAIP chain IDs\n if (typeof decimalChainId === 'string') {\n if (isCaipChainId(decimalChainId)) {\n return decimalChainId;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, decimalChainId);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(decimalChainId));\n}\n\n/**\n * Convert a CAIP-2 chain ID from the API response to our ChainId type.\n * Handles both formats: \"eip155:1\" or just \"1\" (decimal).\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdStr - The chain ID string to convert.\n * @returns The normalized ChainId.\n */\nfunction caipChainIdToChainId(chainIdStr: string): ChainId {\n if (isCaipChainId(chainIdStr)) {\n return chainIdStr;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdStr);\n}\n\n/**\n * Filter a response to only include balances for assets already in state.\n * Used when tokenDetectionEnabled is false to prevent adding new tokens.\n *\n * @param response - The fetch response to filter.\n * @param assetsState - Current assets controller state to check existing balances against.\n * @returns A new response with only known asset balances.\n */\nexport function filterResponseToKnownAssets(\n response: DataResponse,\n assetsState: AssetsControllerStateInternal,\n): DataResponse {\n if (!response.assetsBalance) {\n return response;\n }\n\n const filteredBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n const existingBalances = assetsState.assetsBalance[accountId];\n if (!existingBalances) {\n // Account has no balances in state yet — skip all its tokens\n continue;\n }\n\n const filtered: Record<Caip19AssetId, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(accountBalances)) {\n // Only include assets already tracked in state\n if (assetId in existingBalances) {\n filtered[assetId as Caip19AssetId] = balance;\n }\n }\n\n if (Object.keys(filtered).length > 0) {\n filteredBalance[accountId] = filtered;\n }\n }\n\n return {\n ...response,\n assetsBalance:\n Object.keys(filteredBalance).length > 0 ? filteredBalance : undefined,\n };\n}\n\n// ============================================================================\n// ACCOUNTS API DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for fetching balances from the MetaMask Accounts API.\n *\n * Uses ApiPlatformClient (queryApiClient) for all API calls. Does not use the\n * messenger. Reports active chains via onActiveChainsUpdated callback.\n */\nexport class AccountsApiDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n AccountsApiDataSourceState\n> {\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #fetchTimeoutMs: number;\n\n /** Getter avoids stale value when user toggles token detection at runtime. */\n readonly #tokenDetectionEnabled: () => boolean;\n\n /** Shared AssetsController messenger, used to read remote feature flags. */\n readonly #messenger: AssetsControllerMessenger;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** State accessor from subscriptions (for filtering when tokenDetectionEnabled is false) */\n #getAssetsState?: () => AssetsControllerStateInternal;\n\n constructor(options: AccountsApiDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#fetchTimeoutMs = options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS;\n this.#tokenDetectionEnabled =\n options.tokenDetectionEnabled ?? ((): boolean => true);\n this.#messenger = options.messenger;\n this.#apiClient = options.queryApiClient;\n\n this.#initializeActiveChains().catch(console.error);\n }\n\n /**\n * Whether the Accounts API v6 balances endpoint is enabled, read from the\n * RemoteFeatureFlagController (`assetsAccountsApiV6`). Read on demand (per\n * fetch) rather than cached so the value can be toggled at runtime, and behaves\n * the same across clients (extension, mobile). Defaults to `false` when the\n * flag is unset or the controller is unavailable.\n *\n * The flag is a LaunchDarkly JSON variation shaped `{ value: boolean }` (same\n * shape as `backendWebSocketConnection`), so the nested `value` is read rather\n * than treating the flag as a plain boolean.\n *\n * @returns `true` when the v6 balances endpoint should be used.\n */\n #isBalanceV6Enabled(): boolean {\n try {\n const { remoteFeatureFlags } = this.#messenger.call(\n 'RemoteFeatureFlagController:getState',\n );\n const flag = remoteFeatureFlags?.assetsAccountsApiV6;\n return (\n typeof flag === 'object' &&\n flag !== null &&\n Boolean((flag as { value?: unknown }).value)\n );\n } catch {\n return false;\n }\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n\n // Periodically refresh active chains (every 20 minutes)\n this.#chainsRefreshTimer = setInterval(\n () => {\n this.#refreshActiveChains().catch(console.error);\n },\n 20 * 60 * 1000,\n );\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n // Check if chains changed\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n /**\n * Re-fetch supported networks from the Accounts API and update `activeChains`\n * when the list changed. Used when the selected EVM network switches so\n * chain claiming is not stuck on an empty init-time list.\n *\n * @returns Resolves when supported networks have been re-fetched.\n */\n refreshActiveChains(): Promise<void> {\n return this.#refreshActiveChains();\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n\n // Use fullSupport networks as active chains\n return (\n response.fullSupport\n .map(decimalToChainId)\n // TODO Restore solana when there is a fix for how we handle non-evm chains here\n .filter((chainId) => chainId.startsWith('eip155:'))\n );\n }\n\n // ============================================================================\n // ACCOUNT SCOPE HELPERS\n // ============================================================================\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n let response: DataResponse = {};\n\n // Filter to only chains supported by Accounts API\n const supportedChains = new Set(this.state.activeChains);\n const chainsToFetch = request.chainIds.filter((chainId) =>\n supportedChains.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n return response;\n }\n\n try {\n // Build CAIP-10 account IDs (e.g., \"eip155:1:0x1234...\")\n // Use pre-computed supportedChains per account from the request\n const accountIds = request.accountsWithSupportedChains.flatMap(\n ({ account, supportedChains: accountChains }) =>\n chainsToFetch\n .filter((chainId) => accountChains.includes(chainId))\n .map((chainId) => `${chainId}:${account.address}`),\n );\n\n // Skip API call if no valid account-chain combinations\n if (accountIds.length === 0) {\n return response;\n }\n\n const fetchOptions = request.forceUpdate\n ? { staleTime: 0, gcTime: 0 }\n : undefined;\n\n // Feature-flagged: v6 endpoint with a fallback to legacy v5. The flag is\n // read here (not cached) so a runtime toggle can revert v6 -> v5.\n const { unprocessedNetworks, assetsBalance } = this.#isBalanceV6Enabled()\n ? await this.#fetchV6Balances(accountIds, fetchOptions, request)\n : await this.#fetchV5Balances(accountIds, fetchOptions, request);\n\n // Handle unprocessed networks - these will be passed to next middleware\n if (unprocessedNetworks.length > 0) {\n const unprocessedChainIds =\n unprocessedNetworks.map(caipChainIdToChainId);\n\n // Add unprocessed chains to errors so middleware passes them to next data source\n response.errors = response.errors ?? {};\n for (const chainId of unprocessedChainIds) {\n response.errors[chainId] = 'Unprocessed by Accounts API';\n }\n }\n\n response.assetsBalance = assetsBalance;\n response.updateMode = 'merge';\n } catch (error) {\n log('Fetch FAILED', { error, chains: chainsToFetch });\n\n // On error, mark all chains as errors so they can be handled by next middleware\n response.errors = response.errors ?? {};\n for (const chainId of chainsToFetch) {\n response.errors[chainId] =\n `Fetch failed: ${error instanceof Error ? error.message : String(error)}`;\n }\n }\n\n // Mark unsupported chains as errors so they pass to next middleware\n for (const chainId of request.chainIds) {\n if (!supportedChains.has(chainId)) {\n response.errors = response.errors ?? {};\n response.errors[chainId] = 'Chain not supported by Accounts API';\n }\n }\n\n // When token detection is disabled, filter out tokens not already in state\n if (!this.#tokenDetectionEnabled() && this.#getAssetsState) {\n response = filterResponseToKnownAssets(response, this.#getAssetsState());\n }\n\n return response;\n }\n\n /**\n * Fetch balances from the legacy v5 endpoint and process them.\n *\n * @param accountIds - CAIP-10 account IDs to fetch balances for.\n * @param fetchOptions - Cache/fetch options (e.g. force update settings).\n * @param request - The original data request containing accounts to map.\n * @returns Unprocessed networks and processed asset balances by account.\n */\n async #fetchV5Balances(\n accountIds: string[],\n fetchOptions: { staleTime: number; gcTime: number } | undefined,\n request: DataRequest,\n ): Promise<{\n unprocessedNetworks: string[];\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n }> {\n const apiResponse = await fetchWithTimeout(\n () =>\n this.#apiClient.accounts.fetchV5MultiAccountBalances(\n accountIds,\n undefined,\n fetchOptions,\n ),\n this.#fetchTimeoutMs,\n );\n\n const { assetsBalance } = this.#processV5Balances(\n apiResponse.balances,\n request,\n );\n\n return {\n unprocessedNetworks: apiResponse.unprocessedNetworks,\n assetsBalance,\n };\n }\n\n /**\n * Fetch balances from the v6 endpoint and process them.\n *\n * @param accountIds - CAIP-10 account IDs to fetch balances for.\n * @param fetchOptions - Cache/fetch options (e.g. force update settings).\n * @param request - The original data request containing accounts to map.\n * @returns Unprocessed networks and processed asset balances by account.\n */\n async #fetchV6Balances(\n accountIds: string[],\n fetchOptions: { staleTime: number; gcTime: number } | undefined,\n request: DataRequest,\n ): Promise<{\n unprocessedNetworks: string[];\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n }> {\n const apiResponse = await fetchWithTimeout(\n () =>\n this.#apiClient.accounts.fetchV6MultiAccountBalances(\n accountIds,\n undefined,\n fetchOptions,\n ),\n this.#fetchTimeoutMs,\n );\n\n const { assetsBalance } = this.#processV6Balances(\n apiResponse.accounts,\n request,\n );\n\n return {\n unprocessedNetworks: apiResponse.unprocessedNetworks,\n assetsBalance,\n };\n }\n\n /**\n * Build a lookup of lowercased account address to the request's account ID.\n *\n * @param request - The original data request containing accounts to map.\n * @returns Map of lowercase address to account ID.\n */\n #buildAddressToAccountIdMap(request: DataRequest): Map<string, string> {\n const addressToAccountId = new Map<string, string>();\n for (const { account } of request.accountsWithSupportedChains) {\n if (account.address) {\n addressToAccountId.set(account.address.toLowerCase(), account.id);\n }\n }\n return addressToAccountId;\n }\n\n /**\n * Process V5 API balances response.\n * V5 returns a flat array of balance items, each with accountId and assetId.\n *\n * @param balances - Array of balance items from the V5 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV5Balances(\n balances: V5BalanceItem[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance: Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = this.#buildAddressToAccountIdMap(request);\n\n // V5 response: array of { accountId, assetId, balance, ... }\n for (const item of balances) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = item.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = {};\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(item.assetId as Caip19AssetId);\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n\n return { assetsBalance };\n }\n\n /**\n * Process V6 API balances response.\n * V6 groups balances per account (`accounts: [{ accountId, balances }]`).\n * Only `category: 'token'` rows are consumed here to preserve parity with\n * the v5 token-balance behavior; DeFi positions are ignored.\n *\n * @param accounts - Per-account balance entries from the V6 API response.\n * @param request - The original data request containing accounts to map.\n * @returns Object containing processed asset balances by account.\n */\n #processV6Balances(\n accounts: V6AccountBalancesEntry[],\n request: DataRequest,\n ): {\n assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>>;\n } {\n const assetsBalance = Object.create(null) as Record<\n string,\n Record<Caip19AssetId, AssetBalance>\n >;\n\n // Build a map of lowercase addresses to account IDs for efficient lookup\n const addressToAccountId = this.#buildAddressToAccountIdMap(request);\n\n for (const entry of accounts) {\n // Extract address from CAIP-10 account ID (e.g., \"eip155:1:0x1234...\" -> \"0x1234...\")\n const addressParts = entry.accountId.split(':');\n if (addressParts.length < 3) {\n continue;\n }\n const address = addressParts[2].toLowerCase();\n\n // Find the matching account ID from request\n const accountId = addressToAccountId.get(address);\n if (!accountId) {\n // This is normal - API returns balances for all chains, but request may only have one account\n continue;\n }\n\n for (const item of entry.balances) {\n // Only consume token balances; DeFi positions are handled elsewhere.\n if (item.category !== 'token') {\n continue;\n }\n\n if (!assetsBalance[accountId]) {\n assetsBalance[accountId] = Object.create(null) as Record<\n Caip19AssetId,\n AssetBalance\n >;\n }\n\n // Normalize asset ID (checksum EVM addresses for ERC20 tokens)\n const normalizedAssetId = normalizeAssetId(\n item.assetId as Caip19AssetId,\n );\n\n // Store balance as returned by API\n assetsBalance[accountId][normalizedAssetId] = {\n amount: item.balance,\n };\n }\n }\n\n return { assetsBalance };\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Accounts API.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Uses unprocessedNetworks from API response to determine what to pass to next middleware\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // If no chains requested, skip to next middleware\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n const response = await this.fetch(request);\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n\n // Determine successfully handled chains (exclude unprocessed/error chains)\n const unprocessedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = request.chainIds.filter(\n (chainId) => !unprocessedChains.has(chainId),\n );\n\n // When token detection is off and we filtered out all balance data (e.g. new\n // account with empty state), do not claim any chain as handled so that RPC\n // middleware can still process them and fetch native balances (ETH, MATIC, etc.).\n if (\n !this.#tokenDetectionEnabled() &&\n (!response.assetsBalance ||\n Object.keys(response.assetsBalance).length === 0)\n ) {\n successfullyHandledChains = [];\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Remove successfully handled chains from request for next middleware\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n\n return next({\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n });\n }\n\n // No chains handled - pass context unchanged\n return next(context);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Store state accessor for filtering when tokenDetectionEnabled is false\n if (subscriptionRequest.getAssetsState) {\n this.#getAssetsState = subscriptionRequest.getAssetsState;\n }\n\n // Try all requested chains - API will handle unsupported ones via unprocessedNetworks\n const chainsToSubscribe = request.chainIds;\n\n if (chainsToSubscribe.length === 0) {\n return;\n }\n\n // Handle subscription update - update both chains AND request (for accounts)\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.chains = chainsToSubscribe;\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function for this subscription\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n if (!subscription?.request) {\n return;\n }\n\n // Use stored request (which gets updated on account changes)\n const fetchResponse = await this.fetch({\n ...subscription.request,\n chainIds: subscription.chains,\n });\n\n // Report update to AssetsController via callback\n await subscription.onAssetsUpdate(fetchResponse);\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription with request for account updates\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // Clean up timers\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n }\n\n // Clean up subscriptions\n super.destroy();\n }\n}\n"]}
@@ -1,9 +1,11 @@
1
1
  import { ApiPlatformClient } from "@metamask/core-backend";
2
+ import type { RemoteFeatureFlagControllerGetStateAction } from "@metamask/remote-feature-flag-controller";
3
+ import type { AssetsControllerMessenger } from "../AssetsController.cjs";
2
4
  import type { ChainId, DataRequest, DataResponse, Middleware, AssetsControllerStateInternal } from "../types.cjs";
3
5
  import type { DataSourceState, SubscriptionRequest } from "./AbstractDataSource.cjs";
4
6
  import { AbstractDataSource } from "./AbstractDataSource.cjs";
5
7
  declare const CONTROLLER_NAME = "AccountsApiDataSource";
6
- export type AccountsApiDataSourceAllowedActions = never;
8
+ export type AccountsApiDataSourceAllowedActions = RemoteFeatureFlagControllerGetStateAction;
7
9
  export type AccountsApiDataSourceState = DataSourceState;
8
10
  /** Optional configuration for AccountsApiDataSource. */
9
11
  export type AccountsApiDataSourceConfig = {
@@ -23,6 +25,11 @@ export type AccountsApiDataSourceConfig = {
23
25
  fetchTimeoutMs?: number;
24
26
  };
25
27
  export type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {
28
+ /**
29
+ * The AssetsController messenger (shared by all data sources). Used to read
30
+ * the `assetsAccountsApiV6` remote feature flag.
31
+ */
32
+ messenger: AssetsControllerMessenger;
26
33
  /** ApiPlatformClient for API calls with caching */
27
34
  queryApiClient: ApiPlatformClient;
28
35
  /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */
@@ -1 +1 @@
1
- {"version":3,"file":"AccountsApiDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAQ3D,OAAO,KAAK,EACV,OAAO,EAGP,WAAW,EACX,YAAY,EACZ,UAAU,EACV,6BAA6B,EAC9B,qBAAiB;AAElB,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAC9B,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAM1D,QAAA,MAAM,eAAe,0BAA0B,CAAC;AAYhD,MAAM,MAAM,mCAAmC,GAAG,KAAK,CAAC;AAMxD,MAAM,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAUzD,wDAAwD;AACxD,MAAM,MAAM,2BAA2B,GAAG;IACxC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,2BAA2B,GAAG;IACvE,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,6BAA6B,GACzC,YAAY,CAqCd;AAMD;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,kBAAkB,CAC3D,OAAO,eAAe,EACtB,0BAA0B,CAC3B;;gBAuBa,OAAO,EAAE,4BAA4B;IA+DjD;;;;;;OAMG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA8JxD;;;;;;;;;OASG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkEjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ExE,OAAO,IAAI,IAAI;CAShB"}
1
+ {"version":3,"file":"AccountsApiDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAAE,yCAAyC,EAAE,iDAAiD;AAO1G,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EAGP,WAAW,EACX,YAAY,EACZ,UAAU,EACV,6BAA6B,EAC9B,qBAAiB;AAElB,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAC9B,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAM1D,QAAA,MAAM,eAAe,0BAA0B,CAAC;AAahD,MAAM,MAAM,mCAAmC,GAC7C,yCAAyC,CAAC;AAM5C,MAAM,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAUzD,wDAAwD;AACxD,MAAM,MAAM,2BAA2B,GAAG;IACxC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,2BAA2B,GAAG;IACvE;;;OAGG;IACH,SAAS,EAAE,yBAAyB,CAAC;IACrC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,6BAA6B,GACzC,YAAY,CAqCd;AAMD;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,kBAAkB,CAC3D,OAAO,eAAe,EACtB,0BAA0B,CAC3B;;gBA0Ba,OAAO,EAAE,4BAA4B;IA6FjD;;;;;;OAMG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA6SxD;;;;;;;;;OASG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkEjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ExE,OAAO,IAAI,IAAI;CAShB"}
@@ -1,9 +1,11 @@
1
1
  import { ApiPlatformClient } from "@metamask/core-backend";
2
+ import type { RemoteFeatureFlagControllerGetStateAction } from "@metamask/remote-feature-flag-controller";
3
+ import type { AssetsControllerMessenger } from "../AssetsController.mjs";
2
4
  import type { ChainId, DataRequest, DataResponse, Middleware, AssetsControllerStateInternal } from "../types.mjs";
3
5
  import type { DataSourceState, SubscriptionRequest } from "./AbstractDataSource.mjs";
4
6
  import { AbstractDataSource } from "./AbstractDataSource.mjs";
5
7
  declare const CONTROLLER_NAME = "AccountsApiDataSource";
6
- export type AccountsApiDataSourceAllowedActions = never;
8
+ export type AccountsApiDataSourceAllowedActions = RemoteFeatureFlagControllerGetStateAction;
7
9
  export type AccountsApiDataSourceState = DataSourceState;
8
10
  /** Optional configuration for AccountsApiDataSource. */
9
11
  export type AccountsApiDataSourceConfig = {
@@ -23,6 +25,11 @@ export type AccountsApiDataSourceConfig = {
23
25
  fetchTimeoutMs?: number;
24
26
  };
25
27
  export type AccountsApiDataSourceOptions = AccountsApiDataSourceConfig & {
28
+ /**
29
+ * The AssetsController messenger (shared by all data sources). Used to read
30
+ * the `assetsAccountsApiV6` remote feature flag.
31
+ */
32
+ messenger: AssetsControllerMessenger;
26
33
  /** ApiPlatformClient for API calls with caching */
27
34
  queryApiClient: ApiPlatformClient;
28
35
  /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */
@@ -1 +1 @@
1
- {"version":3,"file":"AccountsApiDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAQ3D,OAAO,KAAK,EACV,OAAO,EAGP,WAAW,EACX,YAAY,EACZ,UAAU,EACV,6BAA6B,EAC9B,qBAAiB;AAElB,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAC9B,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAM1D,QAAA,MAAM,eAAe,0BAA0B,CAAC;AAYhD,MAAM,MAAM,mCAAmC,GAAG,KAAK,CAAC;AAMxD,MAAM,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAUzD,wDAAwD;AACxD,MAAM,MAAM,2BAA2B,GAAG;IACxC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,2BAA2B,GAAG;IACvE,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,6BAA6B,GACzC,YAAY,CAqCd;AAMD;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,kBAAkB,CAC3D,OAAO,eAAe,EACtB,0BAA0B,CAC3B;;gBAuBa,OAAO,EAAE,4BAA4B;IA+DjD;;;;;;OAMG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA8JxD;;;;;;;;;OASG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkEjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ExE,OAAO,IAAI,IAAI;CAShB"}
1
+ {"version":3,"file":"AccountsApiDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/AccountsApiDataSource.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAAE,yCAAyC,EAAE,iDAAiD;AAO1G,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EAGP,WAAW,EACX,YAAY,EACZ,UAAU,EACV,6BAA6B,EAC9B,qBAAiB;AAElB,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAC9B,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAM1D,QAAA,MAAM,eAAe,0BAA0B,CAAC;AAahD,MAAM,MAAM,mCAAmC,GAC7C,yCAAyC,CAAC;AAM5C,MAAM,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAUzD,wDAAwD;AACxD,MAAM,MAAM,2BAA2B,GAAG;IACxC,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,OAAO,CAAC;IACtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,2BAA2B,GAAG;IACvE;;;OAGG;IACH,SAAS,EAAE,yBAAyB,CAAC;IACrC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,6BAA6B,GACzC,YAAY,CAqCd;AAMD;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,kBAAkB,CAC3D,OAAO,eAAe,EACtB,0BAA0B,CAC3B;;gBA0Ba,OAAO,EAAE,4BAA4B;IA6FjD;;;;;;OAMG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA6SxD;;;;;;;;;OASG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAkEjC;IAMK,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA0ExE,OAAO,IAAI,IAAI;CAShB"}
@@ -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 _AccountsApiDataSource_instances, _AccountsApiDataSource_onActiveChainsUpdated, _AccountsApiDataSource_pollInterval, _AccountsApiDataSource_fetchTimeoutMs, _AccountsApiDataSource_tokenDetectionEnabled, _AccountsApiDataSource_apiClient, _AccountsApiDataSource_chainsRefreshTimer, _AccountsApiDataSource_getAssetsState, _AccountsApiDataSource_initializeActiveChains, _AccountsApiDataSource_refreshActiveChains, _AccountsApiDataSource_fetchActiveChains, _AccountsApiDataSource_processV5Balances;
12
+ var _AccountsApiDataSource_instances, _AccountsApiDataSource_onActiveChainsUpdated, _AccountsApiDataSource_pollInterval, _AccountsApiDataSource_fetchTimeoutMs, _AccountsApiDataSource_tokenDetectionEnabled, _AccountsApiDataSource_messenger, _AccountsApiDataSource_apiClient, _AccountsApiDataSource_chainsRefreshTimer, _AccountsApiDataSource_getAssetsState, _AccountsApiDataSource_isBalanceV6Enabled, _AccountsApiDataSource_initializeActiveChains, _AccountsApiDataSource_refreshActiveChains, _AccountsApiDataSource_fetchActiveChains, _AccountsApiDataSource_fetchV5Balances, _AccountsApiDataSource_fetchV6Balances, _AccountsApiDataSource_buildAddressToAccountIdMap, _AccountsApiDataSource_processV5Balances, _AccountsApiDataSource_processV6Balances;
13
13
  import { ApiPlatformClient } from "@metamask/core-backend";
14
14
  import { isCaipChainId, KnownCaipNamespace, toCaipChainId } from "@metamask/utils";
15
15
  import { projectLogger, createModuleLogger } from "../logger.mjs";
@@ -108,6 +108,8 @@ export class AccountsApiDataSource extends AbstractDataSource {
108
108
  _AccountsApiDataSource_fetchTimeoutMs.set(this, void 0);
109
109
  /** Getter avoids stale value when user toggles token detection at runtime. */
110
110
  _AccountsApiDataSource_tokenDetectionEnabled.set(this, void 0);
111
+ /** Shared AssetsController messenger, used to read remote feature flags. */
112
+ _AccountsApiDataSource_messenger.set(this, void 0);
111
113
  /** ApiPlatformClient for cached API calls */
112
114
  _AccountsApiDataSource_apiClient.set(this, void 0);
113
115
  /** Chains refresh timer */
@@ -118,6 +120,7 @@ export class AccountsApiDataSource extends AbstractDataSource {
118
120
  __classPrivateFieldSet(this, _AccountsApiDataSource_pollInterval, options.pollInterval ?? DEFAULT_POLL_INTERVAL, "f");
119
121
  __classPrivateFieldSet(this, _AccountsApiDataSource_fetchTimeoutMs, options.fetchTimeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS, "f");
120
122
  __classPrivateFieldSet(this, _AccountsApiDataSource_tokenDetectionEnabled, options.tokenDetectionEnabled ?? (() => true), "f");
123
+ __classPrivateFieldSet(this, _AccountsApiDataSource_messenger, options.messenger, "f");
121
124
  __classPrivateFieldSet(this, _AccountsApiDataSource_apiClient, options.queryApiClient, "f");
122
125
  __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_initializeActiveChains).call(this).catch(console.error);
123
126
  }
@@ -165,17 +168,20 @@ export class AccountsApiDataSource extends AbstractDataSource {
165
168
  const fetchOptions = request.forceUpdate
166
169
  ? { staleTime: 0, gcTime: 0 }
167
170
  : undefined;
168
- const apiResponse = await fetchWithTimeout(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV5MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
171
+ // Feature-flagged: v6 endpoint with a fallback to legacy v5. The flag is
172
+ // read here (not cached) so a runtime toggle can revert v6 -> v5.
173
+ const { unprocessedNetworks, assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_isBalanceV6Enabled).call(this)
174
+ ? await __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_fetchV6Balances).call(this, accountIds, fetchOptions, request)
175
+ : await __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_fetchV5Balances).call(this, accountIds, fetchOptions, request);
169
176
  // Handle unprocessed networks - these will be passed to next middleware
170
- if (apiResponse.unprocessedNetworks.length > 0) {
171
- const unprocessedChainIds = apiResponse.unprocessedNetworks.map(caipChainIdToChainId);
177
+ if (unprocessedNetworks.length > 0) {
178
+ const unprocessedChainIds = unprocessedNetworks.map(caipChainIdToChainId);
172
179
  // Add unprocessed chains to errors so middleware passes them to next data source
173
180
  response.errors = response.errors ?? {};
174
181
  for (const chainId of unprocessedChainIds) {
175
182
  response.errors[chainId] = 'Unprocessed by Accounts API';
176
183
  }
177
184
  }
178
- const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
179
185
  response.assetsBalance = assetsBalance;
180
186
  response.updateMode = 'merge';
181
187
  }
@@ -339,7 +345,18 @@ export class AccountsApiDataSource extends AbstractDataSource {
339
345
  super.destroy();
340
346
  }
341
347
  }
342
- _AccountsApiDataSource_onActiveChainsUpdated = new WeakMap(), _AccountsApiDataSource_pollInterval = new WeakMap(), _AccountsApiDataSource_fetchTimeoutMs = new WeakMap(), _AccountsApiDataSource_tokenDetectionEnabled = new WeakMap(), _AccountsApiDataSource_apiClient = new WeakMap(), _AccountsApiDataSource_chainsRefreshTimer = new WeakMap(), _AccountsApiDataSource_getAssetsState = new WeakMap(), _AccountsApiDataSource_instances = new WeakSet(), _AccountsApiDataSource_initializeActiveChains =
348
+ _AccountsApiDataSource_onActiveChainsUpdated = new WeakMap(), _AccountsApiDataSource_pollInterval = new WeakMap(), _AccountsApiDataSource_fetchTimeoutMs = new WeakMap(), _AccountsApiDataSource_tokenDetectionEnabled = new WeakMap(), _AccountsApiDataSource_messenger = new WeakMap(), _AccountsApiDataSource_apiClient = new WeakMap(), _AccountsApiDataSource_chainsRefreshTimer = new WeakMap(), _AccountsApiDataSource_getAssetsState = new WeakMap(), _AccountsApiDataSource_instances = new WeakSet(), _AccountsApiDataSource_isBalanceV6Enabled = function _AccountsApiDataSource_isBalanceV6Enabled() {
349
+ try {
350
+ const { remoteFeatureFlags } = __classPrivateFieldGet(this, _AccountsApiDataSource_messenger, "f").call('RemoteFeatureFlagController:getState');
351
+ const flag = remoteFeatureFlags?.assetsAccountsApiV6;
352
+ return (typeof flag === 'object' &&
353
+ flag !== null &&
354
+ Boolean(flag.value));
355
+ }
356
+ catch {
357
+ return false;
358
+ }
359
+ }, _AccountsApiDataSource_initializeActiveChains =
343
360
  // ============================================================================
344
361
  // INITIALIZATION
345
362
  // ============================================================================
@@ -379,15 +396,50 @@ async function _AccountsApiDataSource_initializeActiveChains() {
379
396
  .map(decimalToChainId)
380
397
  // TODO Restore solana when there is a fix for how we handle non-evm chains here
381
398
  .filter((chainId) => chainId.startsWith('eip155:')));
382
- }, _AccountsApiDataSource_processV5Balances = function _AccountsApiDataSource_processV5Balances(balances, request) {
383
- const assetsBalance = {};
384
- // Build a map of lowercase addresses to account IDs for efficient lookup
399
+ }, _AccountsApiDataSource_fetchV5Balances =
400
+ /**
401
+ * Fetch balances from the legacy v5 endpoint and process them.
402
+ *
403
+ * @param accountIds - CAIP-10 account IDs to fetch balances for.
404
+ * @param fetchOptions - Cache/fetch options (e.g. force update settings).
405
+ * @param request - The original data request containing accounts to map.
406
+ * @returns Unprocessed networks and processed asset balances by account.
407
+ */
408
+ async function _AccountsApiDataSource_fetchV5Balances(accountIds, fetchOptions, request) {
409
+ const apiResponse = await fetchWithTimeout(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV5MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
410
+ const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV5Balances).call(this, apiResponse.balances, request);
411
+ return {
412
+ unprocessedNetworks: apiResponse.unprocessedNetworks,
413
+ assetsBalance,
414
+ };
415
+ }, _AccountsApiDataSource_fetchV6Balances =
416
+ /**
417
+ * Fetch balances from the v6 endpoint and process them.
418
+ *
419
+ * @param accountIds - CAIP-10 account IDs to fetch balances for.
420
+ * @param fetchOptions - Cache/fetch options (e.g. force update settings).
421
+ * @param request - The original data request containing accounts to map.
422
+ * @returns Unprocessed networks and processed asset balances by account.
423
+ */
424
+ async function _AccountsApiDataSource_fetchV6Balances(accountIds, fetchOptions, request) {
425
+ const apiResponse = await fetchWithTimeout(() => __classPrivateFieldGet(this, _AccountsApiDataSource_apiClient, "f").accounts.fetchV6MultiAccountBalances(accountIds, undefined, fetchOptions), __classPrivateFieldGet(this, _AccountsApiDataSource_fetchTimeoutMs, "f"));
426
+ const { assetsBalance } = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_processV6Balances).call(this, apiResponse.accounts, request);
427
+ return {
428
+ unprocessedNetworks: apiResponse.unprocessedNetworks,
429
+ assetsBalance,
430
+ };
431
+ }, _AccountsApiDataSource_buildAddressToAccountIdMap = function _AccountsApiDataSource_buildAddressToAccountIdMap(request) {
385
432
  const addressToAccountId = new Map();
386
433
  for (const { account } of request.accountsWithSupportedChains) {
387
434
  if (account.address) {
388
435
  addressToAccountId.set(account.address.toLowerCase(), account.id);
389
436
  }
390
437
  }
438
+ return addressToAccountId;
439
+ }, _AccountsApiDataSource_processV5Balances = function _AccountsApiDataSource_processV5Balances(balances, request) {
440
+ const assetsBalance = {};
441
+ // Build a map of lowercase addresses to account IDs for efficient lookup
442
+ const addressToAccountId = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_buildAddressToAccountIdMap).call(this, request);
391
443
  // V5 response: array of { accountId, assetId, balance, ... }
392
444
  for (const item of balances) {
393
445
  // Extract address from CAIP-10 account ID (e.g., "eip155:1:0x1234..." -> "0x1234...")
@@ -413,5 +465,39 @@ async function _AccountsApiDataSource_initializeActiveChains() {
413
465
  };
414
466
  }
415
467
  return { assetsBalance };
468
+ }, _AccountsApiDataSource_processV6Balances = function _AccountsApiDataSource_processV6Balances(accounts, request) {
469
+ const assetsBalance = Object.create(null);
470
+ // Build a map of lowercase addresses to account IDs for efficient lookup
471
+ const addressToAccountId = __classPrivateFieldGet(this, _AccountsApiDataSource_instances, "m", _AccountsApiDataSource_buildAddressToAccountIdMap).call(this, request);
472
+ for (const entry of accounts) {
473
+ // Extract address from CAIP-10 account ID (e.g., "eip155:1:0x1234..." -> "0x1234...")
474
+ const addressParts = entry.accountId.split(':');
475
+ if (addressParts.length < 3) {
476
+ continue;
477
+ }
478
+ const address = addressParts[2].toLowerCase();
479
+ // Find the matching account ID from request
480
+ const accountId = addressToAccountId.get(address);
481
+ if (!accountId) {
482
+ // This is normal - API returns balances for all chains, but request may only have one account
483
+ continue;
484
+ }
485
+ for (const item of entry.balances) {
486
+ // Only consume token balances; DeFi positions are handled elsewhere.
487
+ if (item.category !== 'token') {
488
+ continue;
489
+ }
490
+ if (!assetsBalance[accountId]) {
491
+ assetsBalance[accountId] = Object.create(null);
492
+ }
493
+ // Normalize asset ID (checksum EVM addresses for ERC20 tokens)
494
+ const normalizedAssetId = normalizeAssetId(item.assetId);
495
+ // Store balance as returned by API
496
+ assetsBalance[accountId][normalizedAssetId] = {
497
+ amount: item.balance,
498
+ };
499
+ }
500
+ }
501
+ return { assetsBalance };
416
502
  };
417
503
  //# sourceMappingURL=AccountsApiDataSource.mjs.map