@metamask-previews/assets-controller 3.1.0-preview-1189e6b40 → 3.1.0-preview-2d89a26

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 (47) hide show
  1. package/dist/data-sources/RpcDataSource.cjs +22 -18
  2. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  3. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  4. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  5. package/dist/data-sources/RpcDataSource.mjs +22 -18
  6. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  7. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs +6 -3
  8. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -1
  9. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -1
  10. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -1
  11. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +4 -1
  12. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs.map +1 -1
  13. package/dist/data-sources/evm-rpc-services/index.cjs.map +1 -1
  14. package/dist/data-sources/evm-rpc-services/index.d.cts +1 -1
  15. package/dist/data-sources/evm-rpc-services/index.d.cts.map +1 -1
  16. package/dist/data-sources/evm-rpc-services/index.d.mts +1 -1
  17. package/dist/data-sources/evm-rpc-services/index.d.mts.map +1 -1
  18. package/dist/data-sources/evm-rpc-services/index.mjs.map +1 -1
  19. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +76 -87
  20. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  21. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +8 -20
  22. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  23. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +8 -20
  24. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  25. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +74 -85
  26. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  27. package/dist/data-sources/evm-rpc-services/types/index.cjs.map +1 -1
  28. package/dist/data-sources/evm-rpc-services/types/index.d.cts +1 -1
  29. package/dist/data-sources/evm-rpc-services/types/index.d.cts.map +1 -1
  30. package/dist/data-sources/evm-rpc-services/types/index.d.mts +1 -1
  31. package/dist/data-sources/evm-rpc-services/types/index.d.mts.map +1 -1
  32. package/dist/data-sources/evm-rpc-services/types/index.mjs.map +1 -1
  33. package/dist/data-sources/evm-rpc-services/types/services.cjs.map +1 -1
  34. package/dist/data-sources/evm-rpc-services/types/services.d.cts +17 -9
  35. package/dist/data-sources/evm-rpc-services/types/services.d.cts.map +1 -1
  36. package/dist/data-sources/evm-rpc-services/types/services.d.mts +17 -9
  37. package/dist/data-sources/evm-rpc-services/types/services.d.mts.map +1 -1
  38. package/dist/data-sources/evm-rpc-services/types/services.mjs.map +1 -1
  39. package/package.json +1 -1
  40. package/dist/utils/constants.cjs +0 -5
  41. package/dist/utils/constants.cjs.map +0 -1
  42. package/dist/utils/constants.d.cts +0 -2
  43. package/dist/utils/constants.d.cts.map +0 -1
  44. package/dist/utils/constants.d.mts +0 -2
  45. package/dist/utils/constants.d.mts.map +0 -1
  46. package/dist/utils/constants.mjs +0 -2
  47. package/dist/utils/constants.mjs.map +0 -1
@@ -10,22 +10,16 @@ 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 _BalanceFetcher_instances, _BalanceFetcher_multicallClient, _BalanceFetcher_messenger, _BalanceFetcher_config, _BalanceFetcher_onBalanceUpdate, _BalanceFetcher_getAssetsToFetch, _BalanceFetcher_fetchBalances, _BalanceFetcher_processBalanceResponses, _BalanceFetcher_formatBalance;
13
+ var _BalanceFetcher_instances, _BalanceFetcher_multicallClient, _BalanceFetcher_messenger, _BalanceFetcher_config, _BalanceFetcher_onBalanceUpdate, _BalanceFetcher_processBalanceResponses, _BalanceFetcher_formatBalance;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.BalanceFetcher = void 0;
16
16
  const polling_controller_1 = require("@metamask/polling-controller");
17
- const utils_1 = require("@metamask/utils");
18
- const constants_1 = require("../../../utils/constants.cjs");
19
- const utils_2 = require("../utils/index.cjs");
17
+ const utils_1 = require("../utils/index.cjs");
20
18
  const DEFAULT_BALANCE_INTERVAL = 30000; // 30 seconds
19
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
21
20
  /**
22
21
  * BalanceFetcher - Fetches token balances via multicall.
23
22
  * Extends StaticIntervalPollingControllerOnly for built-in polling support.
24
- *
25
- * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses
26
- * (or uses the zero address for native assets) and maps multicall responses
27
- * back to the original asset IDs. This ensures the returned balance entries
28
- * always carry the correct identifier regardless of chain.
29
23
  */
30
24
  class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingControllerOnly)() {
31
25
  constructor(multicallClient, messenger, config) {
@@ -40,6 +34,7 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
40
34
  __classPrivateFieldSet(this, _BalanceFetcher_config, {
41
35
  defaultBatchSize: config?.defaultBatchSize ?? 300,
42
36
  defaultTimeoutMs: config?.defaultTimeoutMs ?? 30000,
37
+ includeNativeByDefault: config?.includeNativeByDefault ?? true,
43
38
  }, "f");
44
39
  // Set the polling interval
45
40
  this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);
@@ -59,36 +54,69 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
59
54
  * @param input - The polling input.
60
55
  */
61
56
  async _executePoll(input) {
62
- const result = await __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_fetchBalances).call(this, input.chainId, input.accountId, input.accountAddress);
57
+ const result = await this.fetchBalances(input.chainId, input.accountId, input.accountAddress);
63
58
  if (__classPrivateFieldGet(this, _BalanceFetcher_onBalanceUpdate, "f") && result.balances.length > 0) {
64
59
  await __classPrivateFieldGet(this, _BalanceFetcher_onBalanceUpdate, "f").call(this, result);
65
60
  }
66
61
  }
67
- /**
68
- * Fetch balances for the given assets via multicall.
69
- *
70
- * Each entry bundles a CAIP-19 asset ID with its on-chain address and
71
- * optional decimals.
72
- *
73
- * @param chainId - Hex chain ID.
74
- * @param accountId - Account UUID.
75
- * @param accountAddress - On-chain address of the account.
76
- * @param assets - Asset fetch entries to fetch balances for.
77
- * @returns Balance fetch result.
78
- */
79
- async fetchBalancesForAssets(chainId, accountId, accountAddress, assets) {
62
+ getTokensToFetch(chainId, accountId) {
63
+ const state = __classPrivateFieldGet(this, _BalanceFetcher_messenger, "f").call('AssetsController:getState');
64
+ if (!state?.assetsBalance) {
65
+ return [];
66
+ }
67
+ const accountBalances = state.assetsBalance[accountId];
68
+ if (!accountBalances) {
69
+ return [];
70
+ }
71
+ // Convert hex chainId to decimal for CAIP-2 matching
72
+ const chainIdDecimal = parseInt(chainId, 16);
73
+ const caipChainPrefix = `eip155:${chainIdDecimal}/`;
74
+ const tokenMap = new Map();
75
+ for (const assetId of Object.keys(accountBalances)) {
76
+ // Only process ERC20 tokens on the current chain
77
+ if (assetId.startsWith(caipChainPrefix) && assetId.includes('/erc20:')) {
78
+ // Parse token address from CAIP-19: eip155:1/erc20:0x...
79
+ const tokenAddress = assetId.split('/erc20:')[1];
80
+ if (tokenAddress) {
81
+ const lowerAddress = tokenAddress.toLowerCase();
82
+ if (!tokenMap.has(lowerAddress)) {
83
+ tokenMap.set(lowerAddress, {
84
+ address: tokenAddress,
85
+ symbol: '',
86
+ });
87
+ }
88
+ }
89
+ }
90
+ }
91
+ return Array.from(tokenMap.values());
92
+ }
93
+ async fetchBalances(chainId, accountId, accountAddress, options) {
94
+ const tokens = this.getTokensToFetch(chainId, accountId);
95
+ const tokenAddresses = tokens.map((token) => token.address);
96
+ return this.fetchBalancesForTokens(chainId, accountId, accountAddress, tokenAddresses, options, tokens);
97
+ }
98
+ async fetchBalancesForTokens(chainId, accountId, accountAddress, tokenAddresses, options, tokenInfos) {
99
+ const batchSize = options?.batchSize ?? __classPrivateFieldGet(this, _BalanceFetcher_config, "f").defaultBatchSize;
100
+ const includeNative = options?.includeNative ?? __classPrivateFieldGet(this, _BalanceFetcher_config, "f").includeNativeByDefault;
80
101
  const timestamp = Date.now();
81
- // Build a single map keyed by lowercase address that holds all info
82
- // needed to match multicall responses back to their original entries.
83
- const balanceRequests = [];
84
- const entryByAddress = new Map();
85
- for (const entry of assets) {
86
- const lowerAddress = entry.address.toLowerCase();
87
- if (entryByAddress.has(lowerAddress)) {
88
- continue; // deduplicate
102
+ const tokenInfoMap = new Map();
103
+ if (tokenInfos) {
104
+ for (const info of tokenInfos) {
105
+ tokenInfoMap.set(info.address.toLowerCase(), info);
89
106
  }
90
- entryByAddress.set(lowerAddress, entry);
91
- balanceRequests.push({ tokenAddress: entry.address, accountAddress });
107
+ }
108
+ const balanceRequests = [];
109
+ if (includeNative) {
110
+ balanceRequests.push({
111
+ tokenAddress: ZERO_ADDRESS,
112
+ accountAddress,
113
+ });
114
+ }
115
+ for (const tokenAddress of tokenAddresses) {
116
+ balanceRequests.push({
117
+ tokenAddress,
118
+ accountAddress,
119
+ });
92
120
  }
93
121
  if (balanceRequests.length === 0) {
94
122
  return {
@@ -100,16 +128,16 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
100
128
  timestamp,
101
129
  };
102
130
  }
103
- const result = await (0, utils_2.reduceInBatchesSerially)({
131
+ const result = await (0, utils_1.reduceInBatchesSerially)({
104
132
  values: balanceRequests,
105
- batchSize: __classPrivateFieldGet(this, _BalanceFetcher_config, "f").defaultBatchSize,
133
+ batchSize,
106
134
  initialResult: {
107
135
  balances: [],
108
136
  failedAddresses: [],
109
137
  },
110
138
  eachBatch: async (workingResult, batch) => {
111
139
  const responses = await __classPrivateFieldGet(this, _BalanceFetcher_multicallClient, "f").batchBalanceOf(chainId, batch);
112
- return __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_processBalanceResponses).call(this, responses, workingResult, chainId, accountId, timestamp, entryByAddress);
140
+ return __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_processBalanceResponses).call(this, responses, workingResult, chainId, accountId, timestamp, tokenInfoMap);
113
141
  },
114
142
  });
115
143
  return {
@@ -122,76 +150,37 @@ class BalanceFetcher extends (0, polling_controller_1.StaticIntervalPollingContr
122
150
  }
123
151
  }
124
152
  exports.BalanceFetcher = BalanceFetcher;
125
- _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new WeakMap(), _BalanceFetcher_config = new WeakMap(), _BalanceFetcher_onBalanceUpdate = new WeakMap(), _BalanceFetcher_instances = new WeakSet(), _BalanceFetcher_getAssetsToFetch = function _BalanceFetcher_getAssetsToFetch(chainId, accountId) {
126
- const state = __classPrivateFieldGet(this, _BalanceFetcher_messenger, "f").call('AssetsController:getState');
127
- const accountBalances = state?.assetsBalance?.[accountId];
128
- if (!accountBalances) {
129
- return [];
130
- }
131
- // Convert hex chainId to decimal for CAIP-2 matching
132
- // This is safe because we are filtring with an accountId that is for evm balances only
133
- const chainIdDecimal = parseInt(chainId, 16).toString();
134
- const assetsToFetch = new Map();
135
- for (const assetId of Object.keys(accountBalances)) {
136
- const { chain: { reference: chainReference }, assetNamespace, assetReference, } = (0, utils_1.parseCaipAssetType)(assetId);
137
- if (chainReference === chainIdDecimal) {
138
- const assetIdLowerCase = assetId.toLowerCase();
139
- if (assetsToFetch.has(assetIdLowerCase)) {
140
- continue;
141
- }
142
- const isNative = assetNamespace === 'slip44';
143
- const tokenAddress = isNative
144
- ? constants_1.ZERO_ADDRESS
145
- : assetReference.toLowerCase();
146
- assetsToFetch.set(assetIdLowerCase, {
147
- assetId,
148
- address: tokenAddress,
149
- });
150
- }
151
- }
152
- return Array.from(assetsToFetch.values());
153
- }, _BalanceFetcher_fetchBalances =
154
- /**
155
- * Fetch balances for assets already tracked in state for the given
156
- * account and chain.
157
- *
158
- * @param chainId - Hex chain ID.
159
- * @param accountId - Account UUID.
160
- * @param accountAddress - On-chain address of the account.
161
- * @returns Balance fetch result.
162
- */
163
- async function _BalanceFetcher_fetchBalances(chainId, accountId, accountAddress) {
164
- const assets = __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_getAssetsToFetch).call(this, chainId, accountId);
165
- return this.fetchBalancesForAssets(chainId, accountId, accountAddress, assets);
166
- }, _BalanceFetcher_processBalanceResponses = function _BalanceFetcher_processBalanceResponses(responses, accumulator, chainId, accountId, timestamp, entryByAddress) {
153
+ _BalanceFetcher_multicallClient = new WeakMap(), _BalanceFetcher_messenger = new WeakMap(), _BalanceFetcher_config = new WeakMap(), _BalanceFetcher_onBalanceUpdate = new WeakMap(), _BalanceFetcher_instances = new WeakSet(), _BalanceFetcher_processBalanceResponses = function _BalanceFetcher_processBalanceResponses(responses, accumulator, chainId, accountId, timestamp, tokenInfoMap) {
167
154
  const { balances, failedAddresses } = accumulator;
168
155
  for (const response of responses) {
169
156
  if (!response.success) {
170
157
  failedAddresses.push(response.tokenAddress);
171
158
  continue;
172
159
  }
173
- const lowerAddress = response.tokenAddress.toLowerCase();
174
- const entry = entryByAddress.get(lowerAddress);
175
- if (!entry) {
176
- continue;
177
- }
178
160
  const balance = response.balance ?? '0';
179
- const isNative = lowerAddress === constants_1.ZERO_ADDRESS.toLowerCase();
161
+ const chainIdDecimal = parseInt(chainId, 16);
162
+ const isNative = response.tokenAddress.toLowerCase() === ZERO_ADDRESS.toLowerCase();
163
+ const tokenInfo = tokenInfoMap.get(response.tokenAddress.toLowerCase());
164
+ // Native uses 18. ERC-20: format when decimals are known; otherwise pass raw
165
+ // `balance` through so RpcDataSource can resolve decimals (state → list → RPC).
180
166
  let decimals;
181
167
  let formattedBalance;
182
168
  if (isNative) {
183
169
  decimals = 18;
184
170
  formattedBalance = __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_formatBalance).call(this, balance, decimals);
185
171
  }
186
- else if (entry.decimals === undefined) {
172
+ else if (tokenInfo?.decimals === undefined) {
187
173
  formattedBalance = balance;
188
174
  }
189
175
  else {
190
- decimals = entry.decimals;
176
+ decimals = tokenInfo.decimals;
191
177
  formattedBalance = __classPrivateFieldGet(this, _BalanceFetcher_instances, "m", _BalanceFetcher_formatBalance).call(this, balance, decimals);
192
178
  }
179
+ const assetId = isNative
180
+ ? `eip155:${chainIdDecimal}/slip44:60`
181
+ : `eip155:${chainIdDecimal}/erc20:${response.tokenAddress.toLowerCase()}`;
193
182
  const balanceEntry = {
194
- assetId: entry.assetId,
183
+ assetId,
195
184
  accountId,
196
185
  chainId,
197
186
  balance,
@@ -1 +1 @@
1
- {"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport { parseCaipAssetType } from '@metamask/utils';\n\nimport { ZERO_ADDRESS } from '../../../utils/constants';\nimport type { MulticallClient } from '../clients';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetFetchEntry,\n AssetsBalanceState,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n CaipAssetType,\n ChainId,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n *\n * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses\n * (or uses the zero address for native assets) and maps multicall responses\n * back to the original asset IDs. This ensures the returned balance entries\n * always carry the correct identifier regardless of chain.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<Omit<BalanceFetcherConfig, 'pollingInterval'>>;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config?: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config?.defaultBatchSize ?? 300,\n defaultTimeoutMs: config?.defaultTimeoutMs ?? 30000,\n };\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.#fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n /**\n * Return asset fetch entries tracked in state for the given account and\n * chain. Both native (`slip44:`) and ERC-20 (`erc20:`) entries are included.\n *\n * @param chainId - Hex chain ID (e.g. \"0x1\").\n * @param accountId - Account UUID.\n * @returns Array of asset fetch entries from state for the requested chain.\n */\n #getAssetsToFetch(chainId: ChainId, accountId: AccountId): AssetFetchEntry[] {\n const state = this.#messenger.call('AssetsController:getState');\n\n const accountBalances = state?.assetsBalance?.[accountId];\n if (!accountBalances) {\n return [];\n }\n\n // Convert hex chainId to decimal for CAIP-2 matching\n // This is safe because we are filtring with an accountId that is for evm balances only\n const chainIdDecimal = parseInt(chainId, 16).toString();\n\n const assetsToFetch = new Map<string, AssetFetchEntry>();\n\n for (const assetId of Object.keys(accountBalances) as CaipAssetType[]) {\n const {\n chain: { reference: chainReference },\n assetNamespace,\n assetReference,\n } = parseCaipAssetType(assetId);\n\n if (chainReference === chainIdDecimal) {\n const assetIdLowerCase = assetId.toLowerCase();\n if (assetsToFetch.has(assetIdLowerCase)) {\n continue;\n }\n\n const isNative = assetNamespace === 'slip44';\n const tokenAddress = isNative\n ? ZERO_ADDRESS\n : (assetReference.toLowerCase() as Address);\n\n assetsToFetch.set(assetIdLowerCase, {\n assetId,\n address: tokenAddress,\n });\n }\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n /**\n * Fetch balances for assets already tracked in state for the given\n * account and chain.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @returns Balance fetch result.\n */\n async #fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n ): Promise<BalanceFetchResult> {\n const assets = this.#getAssetsToFetch(chainId, accountId);\n\n return this.fetchBalancesForAssets(\n chainId,\n accountId,\n accountAddress,\n assets,\n );\n }\n\n /**\n * Fetch balances for the given assets via multicall.\n *\n * Each entry bundles a CAIP-19 asset ID with its on-chain address and\n * optional decimals.\n *\n * @param chainId - Hex chain ID.\n * @param accountId - Account UUID.\n * @param accountAddress - On-chain address of the account.\n * @param assets - Asset fetch entries to fetch balances for.\n * @returns Balance fetch result.\n */\n async fetchBalancesForAssets(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n assets: AssetFetchEntry[],\n ): Promise<BalanceFetchResult> {\n const timestamp = Date.now();\n\n // Build a single map keyed by lowercase address that holds all info\n // needed to match multicall responses back to their original entries.\n const balanceRequests: BalanceOfRequest[] = [];\n const entryByAddress = new Map<string, AssetFetchEntry>();\n\n for (const entry of assets) {\n const lowerAddress = entry.address.toLowerCase();\n if (entryByAddress.has(lowerAddress)) {\n continue; // deduplicate\n }\n\n entryByAddress.set(lowerAddress, entry);\n balanceRequests.push({ tokenAddress: entry.address, accountAddress });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize: this.#config.defaultBatchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n entryByAddress,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n entryByAddress: Map<string, AssetFetchEntry>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const lowerAddress = response.tokenAddress.toLowerCase();\n const entry = entryByAddress.get(lowerAddress);\n if (!entry) {\n continue;\n }\n\n const balance = response.balance ?? '0';\n const isNative = lowerAddress === ZERO_ADDRESS.toLowerCase();\n\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (entry.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = entry.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n\n const balanceEntry: AssetBalance = {\n assetId: entry.assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"BalanceFetcher.cjs","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { StaticIntervalPollingControllerOnly } from '@metamask/polling-controller';\nimport type { CaipAssetType } from '@metamask/utils';\n\nimport type { MulticallClient } from '../clients';\nimport type {\n AccountId,\n Address,\n AssetBalance,\n AssetsBalanceState,\n BalanceFetchOptions,\n BalanceFetchResult,\n BalanceOfRequest,\n BalanceOfResponse,\n ChainId,\n TokenFetchInfo,\n} from '../types';\nimport { reduceInBatchesSerially } from '../utils';\n\nconst DEFAULT_BALANCE_INTERVAL = 30_000; // 30 seconds\n\nconst ZERO_ADDRESS: Address =\n '0x0000000000000000000000000000000000000000' as Address;\n\n/**\n * Minimal messenger interface for BalanceFetcher.\n */\nexport type BalanceFetcherMessenger = {\n call: (action: 'AssetsController:getState') => AssetsBalanceState;\n};\n\nexport type BalanceFetcherConfig = {\n defaultBatchSize?: number;\n defaultTimeoutMs?: number;\n includeNativeByDefault?: boolean;\n /** Polling interval in ms (default: 30s) */\n pollingInterval?: number;\n};\n\n/**\n * Polling input for BalanceFetcher - identifies what to poll for.\n */\nexport type BalancePollingInput = {\n /** Chain ID (hex format) */\n chainId: ChainId;\n /** Account ID */\n accountId: AccountId;\n /** Account address */\n accountAddress: Address;\n};\n\n/**\n * Callback type for balance updates.\n */\nexport type OnBalanceUpdateCallback = (\n result: BalanceFetchResult,\n) => void | Promise<void>;\n\n/**\n * BalanceFetcher - Fetches token balances via multicall.\n * Extends StaticIntervalPollingControllerOnly for built-in polling support.\n */\nexport class BalanceFetcher extends StaticIntervalPollingControllerOnly<BalancePollingInput>() {\n readonly #multicallClient: MulticallClient;\n\n readonly #messenger: BalanceFetcherMessenger;\n\n readonly #config: Required<Omit<BalanceFetcherConfig, 'pollingInterval'>>;\n\n #onBalanceUpdate: OnBalanceUpdateCallback | undefined;\n\n constructor(\n multicallClient: MulticallClient,\n messenger: BalanceFetcherMessenger,\n config?: BalanceFetcherConfig,\n ) {\n super();\n this.#multicallClient = multicallClient;\n this.#messenger = messenger;\n this.#config = {\n defaultBatchSize: config?.defaultBatchSize ?? 300,\n defaultTimeoutMs: config?.defaultTimeoutMs ?? 30000,\n includeNativeByDefault: config?.includeNativeByDefault ?? true,\n };\n\n // Set the polling interval\n this.setIntervalLength(config?.pollingInterval ?? DEFAULT_BALANCE_INTERVAL);\n }\n\n /**\n * Set the callback to receive balance updates during polling.\n *\n * @param callback - Function to call with balance results.\n */\n setOnBalanceUpdate(callback: OnBalanceUpdateCallback): void {\n this.#onBalanceUpdate = callback;\n }\n\n /**\n * Execute a poll cycle (required by base class).\n * Fetches balances and calls the update callback.\n *\n * @param input - The polling input.\n */\n async _executePoll(input: BalancePollingInput): Promise<void> {\n const result = await this.fetchBalances(\n input.chainId,\n input.accountId,\n input.accountAddress,\n );\n\n if (this.#onBalanceUpdate && result.balances.length > 0) {\n await this.#onBalanceUpdate(result);\n }\n }\n\n getTokensToFetch(chainId: ChainId, accountId: AccountId): TokenFetchInfo[] {\n const state = this.#messenger.call('AssetsController:getState');\n\n if (!state?.assetsBalance) {\n return [];\n }\n\n const accountBalances = state.assetsBalance[accountId];\n if (!accountBalances) {\n return [];\n }\n\n // Convert hex chainId to decimal for CAIP-2 matching\n const chainIdDecimal = parseInt(chainId, 16);\n const caipChainPrefix = `eip155:${chainIdDecimal}/`;\n\n const tokenMap = new Map<string, TokenFetchInfo>();\n\n for (const assetId of Object.keys(accountBalances)) {\n // Only process ERC20 tokens on the current chain\n if (assetId.startsWith(caipChainPrefix) && assetId.includes('/erc20:')) {\n // Parse token address from CAIP-19: eip155:1/erc20:0x...\n const tokenAddress = assetId.split('/erc20:')[1] as Address;\n if (tokenAddress) {\n const lowerAddress = tokenAddress.toLowerCase();\n if (!tokenMap.has(lowerAddress)) {\n tokenMap.set(lowerAddress, {\n address: tokenAddress,\n symbol: '',\n });\n }\n }\n }\n }\n\n return Array.from(tokenMap.values());\n }\n\n async fetchBalances(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n options?: BalanceFetchOptions,\n ): Promise<BalanceFetchResult> {\n const tokens = this.getTokensToFetch(chainId, accountId);\n const tokenAddresses = tokens.map((token) => token.address);\n\n return this.fetchBalancesForTokens(\n chainId,\n accountId,\n accountAddress,\n tokenAddresses,\n options,\n tokens,\n );\n }\n\n async fetchBalancesForTokens(\n chainId: ChainId,\n accountId: AccountId,\n accountAddress: Address,\n tokenAddresses: Address[],\n options?: BalanceFetchOptions,\n tokenInfos?: TokenFetchInfo[],\n ): Promise<BalanceFetchResult> {\n const batchSize = options?.batchSize ?? this.#config.defaultBatchSize;\n const includeNative =\n options?.includeNative ?? this.#config.includeNativeByDefault;\n const timestamp = Date.now();\n\n const tokenInfoMap = new Map<string, TokenFetchInfo>();\n if (tokenInfos) {\n for (const info of tokenInfos) {\n tokenInfoMap.set(info.address.toLowerCase(), info);\n }\n }\n\n const balanceRequests: BalanceOfRequest[] = [];\n\n if (includeNative) {\n balanceRequests.push({\n tokenAddress: ZERO_ADDRESS,\n accountAddress,\n });\n }\n\n for (const tokenAddress of tokenAddresses) {\n balanceRequests.push({\n tokenAddress,\n accountAddress,\n });\n }\n\n if (balanceRequests.length === 0) {\n return {\n chainId,\n accountId,\n accountAddress,\n balances: [],\n failedAddresses: [],\n timestamp,\n };\n }\n\n type FetchAccumulator = {\n balances: AssetBalance[];\n failedAddresses: Address[];\n };\n\n const result = await reduceInBatchesSerially<\n BalanceOfRequest,\n FetchAccumulator\n >({\n values: balanceRequests,\n batchSize,\n initialResult: {\n balances: [],\n failedAddresses: [],\n },\n eachBatch: async (workingResult, batch) => {\n const responses = await this.#multicallClient.batchBalanceOf(\n chainId,\n batch,\n );\n\n return this.#processBalanceResponses(\n responses,\n workingResult as FetchAccumulator,\n chainId,\n accountId,\n timestamp,\n tokenInfoMap,\n );\n },\n });\n\n return {\n chainId,\n accountId,\n accountAddress,\n ...result,\n timestamp,\n };\n }\n\n #processBalanceResponses(\n responses: BalanceOfResponse[],\n accumulator: {\n balances: AssetBalance[];\n failedAddresses: Address[];\n },\n chainId: ChainId,\n accountId: AccountId,\n timestamp: number,\n tokenInfoMap: Map<string, TokenFetchInfo>,\n ): {\n balances: AssetBalance[];\n failedAddresses: Address[];\n } {\n const { balances, failedAddresses } = accumulator;\n\n for (const response of responses) {\n if (!response.success) {\n failedAddresses.push(response.tokenAddress);\n continue;\n }\n\n const balance = response.balance ?? '0';\n const chainIdDecimal = parseInt(chainId, 16);\n const isNative =\n response.tokenAddress.toLowerCase() === ZERO_ADDRESS.toLowerCase();\n const tokenInfo = tokenInfoMap.get(response.tokenAddress.toLowerCase());\n\n // Native uses 18. ERC-20: format when decimals are known; otherwise pass raw\n // `balance` through so RpcDataSource can resolve decimals (state → list → RPC).\n let decimals: number | undefined;\n let formattedBalance: string;\n if (isNative) {\n decimals = 18;\n formattedBalance = this.#formatBalance(balance, decimals);\n } else if (tokenInfo?.decimals === undefined) {\n formattedBalance = balance;\n } else {\n decimals = tokenInfo.decimals;\n formattedBalance = this.#formatBalance(balance, decimals);\n }\n const assetId: CaipAssetType = isNative\n ? (`eip155:${chainIdDecimal}/slip44:60` as CaipAssetType)\n : (`eip155:${chainIdDecimal}/erc20:${response.tokenAddress.toLowerCase()}` as CaipAssetType);\n\n const balanceEntry: AssetBalance = {\n assetId,\n accountId,\n chainId,\n balance,\n formattedBalance,\n timestamp,\n };\n if (typeof decimals === 'number') {\n balanceEntry.decimals = decimals;\n }\n balances.push(balanceEntry);\n }\n\n return { balances, failedAddresses };\n }\n\n #formatBalance(rawBalance: string, decimals: number): string {\n if (rawBalance === '0') {\n return '0';\n }\n\n try {\n const balanceBigInt = BigInt(rawBalance);\n const divisor = BigInt(10 ** decimals);\n\n const integerPart = balanceBigInt / divisor;\n const remainder = balanceBigInt % divisor;\n const fractionalStr = remainder.toString().padStart(decimals, '0');\n const trimmedFractional = fractionalStr.replace(/0+$/u, '');\n\n if (trimmedFractional === '') {\n return integerPart.toString();\n }\n\n return `${integerPart}.${trimmedFractional}`;\n } catch {\n return rawBalance;\n }\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { MulticallClient } from "../clients/index.cjs";
2
- import type { AccountId, Address, AssetFetchEntry, AssetsBalanceState, BalanceFetchResult, ChainId } from "../types/index.cjs";
2
+ import type { AccountId, Address, AssetsBalanceState, BalanceFetchOptions, BalanceFetchResult, ChainId, TokenFetchInfo } from "../types/index.cjs";
3
3
  /**
4
4
  * Minimal messenger interface for BalanceFetcher.
5
5
  */
@@ -9,6 +9,7 @@ export type BalanceFetcherMessenger = {
9
9
  export type BalanceFetcherConfig = {
10
10
  defaultBatchSize?: number;
11
11
  defaultTimeoutMs?: number;
12
+ includeNativeByDefault?: boolean;
12
13
  /** Polling interval in ms (default: 30s) */
13
14
  pollingInterval?: number;
14
15
  };
@@ -39,7 +40,9 @@ declare const BalanceFetcher_base: (abstract new (...args: any[]) => {
39
40
  _executePoll(input: BalancePollingInput): Promise<void>;
40
41
  startPolling(input: BalancePollingInput): string;
41
42
  stopAllPolling(): void;
42
- stopPollingByPollingToken(pollingToken: string): void;
43
+ stopPollingByPollingToken(pollingToken: string): void; /**
44
+ * Polling input for BalanceFetcher - identifies what to poll for.
45
+ */
43
46
  onPollingComplete(input: BalancePollingInput, callback: (input: BalancePollingInput) => void): void;
44
47
  }) & {
45
48
  new (): {};
@@ -47,11 +50,6 @@ declare const BalanceFetcher_base: (abstract new (...args: any[]) => {
47
50
  /**
48
51
  * BalanceFetcher - Fetches token balances via multicall.
49
52
  * Extends StaticIntervalPollingControllerOnly for built-in polling support.
50
- *
51
- * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses
52
- * (or uses the zero address for native assets) and maps multicall responses
53
- * back to the original asset IDs. This ensures the returned balance entries
54
- * always carry the correct identifier regardless of chain.
55
53
  */
56
54
  export declare class BalanceFetcher extends BalanceFetcher_base {
57
55
  #private;
@@ -69,19 +67,9 @@ export declare class BalanceFetcher extends BalanceFetcher_base {
69
67
  * @param input - The polling input.
70
68
  */
71
69
  _executePoll(input: BalancePollingInput): Promise<void>;
72
- /**
73
- * Fetch balances for the given assets via multicall.
74
- *
75
- * Each entry bundles a CAIP-19 asset ID with its on-chain address and
76
- * optional decimals.
77
- *
78
- * @param chainId - Hex chain ID.
79
- * @param accountId - Account UUID.
80
- * @param accountAddress - On-chain address of the account.
81
- * @param assets - Asset fetch entries to fetch balances for.
82
- * @returns Balance fetch result.
83
- */
84
- fetchBalancesForAssets(chainId: ChainId, accountId: AccountId, accountAddress: Address, assets: AssetFetchEntry[]): Promise<BalanceFetchResult>;
70
+ getTokensToFetch(chainId: ChainId, accountId: AccountId): TokenFetchInfo[];
71
+ fetchBalances(chainId: ChainId, accountId: AccountId, accountAddress: Address, options?: BalanceFetchOptions): Promise<BalanceFetchResult>;
72
+ fetchBalancesForTokens(chainId: ChainId, accountId: AccountId, accountAddress: Address, tokenAddresses: Address[], options?: BalanceFetchOptions, tokenInfos?: TokenFetchInfo[]): Promise<BalanceFetchResult>;
85
73
  }
86
74
  export {};
87
75
  //# sourceMappingURL=BalanceFetcher.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAIlB,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAU1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,CAAC,EAAE,oBAAoB;IAc/B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsF7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;CAyJ/B"}
1
+ {"version":3,"file":"BalanceFetcher.d.cts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAGlB,OAAO,EACP,cAAc,EACf,2BAAiB;AAQlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;2DAjB1B;;OAEG;;;;;AAiBH;;;GAGG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAU1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,CAAC,EAAE,oBAAoB;IAe/B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE;IAsCpE,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC;IAcxB,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,cAAc,EAAE,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,UAAU,CAAC,EAAE,cAAc,EAAE,GAC5B,OAAO,CAAC,kBAAkB,CAAC;CAsK/B"}
@@ -1,5 +1,5 @@
1
1
  import type { MulticallClient } from "../clients/index.mjs";
2
- import type { AccountId, Address, AssetFetchEntry, AssetsBalanceState, BalanceFetchResult, ChainId } from "../types/index.mjs";
2
+ import type { AccountId, Address, AssetsBalanceState, BalanceFetchOptions, BalanceFetchResult, ChainId, TokenFetchInfo } from "../types/index.mjs";
3
3
  /**
4
4
  * Minimal messenger interface for BalanceFetcher.
5
5
  */
@@ -9,6 +9,7 @@ export type BalanceFetcherMessenger = {
9
9
  export type BalanceFetcherConfig = {
10
10
  defaultBatchSize?: number;
11
11
  defaultTimeoutMs?: number;
12
+ includeNativeByDefault?: boolean;
12
13
  /** Polling interval in ms (default: 30s) */
13
14
  pollingInterval?: number;
14
15
  };
@@ -39,7 +40,9 @@ declare const BalanceFetcher_base: (abstract new (...args: any[]) => {
39
40
  _executePoll(input: BalancePollingInput): Promise<void>;
40
41
  startPolling(input: BalancePollingInput): string;
41
42
  stopAllPolling(): void;
42
- stopPollingByPollingToken(pollingToken: string): void;
43
+ stopPollingByPollingToken(pollingToken: string): void; /**
44
+ * Polling input for BalanceFetcher - identifies what to poll for.
45
+ */
43
46
  onPollingComplete(input: BalancePollingInput, callback: (input: BalancePollingInput) => void): void;
44
47
  }) & {
45
48
  new (): {};
@@ -47,11 +50,6 @@ declare const BalanceFetcher_base: (abstract new (...args: any[]) => {
47
50
  /**
48
51
  * BalanceFetcher - Fetches token balances via multicall.
49
52
  * Extends StaticIntervalPollingControllerOnly for built-in polling support.
50
- *
51
- * Callers provide CAIP-19 asset IDs; the fetcher extracts on-chain addresses
52
- * (or uses the zero address for native assets) and maps multicall responses
53
- * back to the original asset IDs. This ensures the returned balance entries
54
- * always carry the correct identifier regardless of chain.
55
53
  */
56
54
  export declare class BalanceFetcher extends BalanceFetcher_base {
57
55
  #private;
@@ -69,19 +67,9 @@ export declare class BalanceFetcher extends BalanceFetcher_base {
69
67
  * @param input - The polling input.
70
68
  */
71
69
  _executePoll(input: BalancePollingInput): Promise<void>;
72
- /**
73
- * Fetch balances for the given assets via multicall.
74
- *
75
- * Each entry bundles a CAIP-19 asset ID with its on-chain address and
76
- * optional decimals.
77
- *
78
- * @param chainId - Hex chain ID.
79
- * @param accountId - Account UUID.
80
- * @param accountAddress - On-chain address of the account.
81
- * @param assets - Asset fetch entries to fetch balances for.
82
- * @returns Balance fetch result.
83
- */
84
- fetchBalancesForAssets(chainId: ChainId, accountId: AccountId, accountAddress: Address, assets: AssetFetchEntry[]): Promise<BalanceFetchResult>;
70
+ getTokensToFetch(chainId: ChainId, accountId: AccountId): TokenFetchInfo[];
71
+ fetchBalances(chainId: ChainId, accountId: AccountId, accountAddress: Address, options?: BalanceFetchOptions): Promise<BalanceFetchResult>;
72
+ fetchBalancesForTokens(chainId: ChainId, accountId: AccountId, accountAddress: Address, tokenAddresses: Address[], options?: BalanceFetchOptions, tokenInfos?: TokenFetchInfo[]): Promise<BalanceFetchResult>;
85
73
  }
86
74
  export {};
87
75
  //# sourceMappingURL=BalanceFetcher.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAIlB,OAAO,EACR,2BAAiB;AAKlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;;;AAE1B;;;;;;;;GAQG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAU1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,CAAC,EAAE,oBAAoB;IAc/B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsF7D;;;;;;;;;;;OAWG;IACG,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,MAAM,EAAE,eAAe,EAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;CAyJ/B"}
1
+ {"version":3,"file":"BalanceFetcher.d.mts","sourceRoot":"","sources":["../../../../src/data-sources/evm-rpc-services/services/BalanceFetcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,6BAAmB;AAClD,OAAO,KAAK,EACV,SAAS,EACT,OAAO,EAEP,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAGlB,OAAO,EACP,cAAc,EACf,2BAAiB;AAQlB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,kBAAkB,CAAC;CACnE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,4CAA4C;IAC5C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,4BAA4B;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,sBAAsB;IACtB,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CACpC,MAAM,EAAE,kBAAkB,KACvB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;;;;;;;;;;;;;2DAjB1B;;OAEG;;;;;AAiBH;;;GAGG;AACH,qBAAa,cAAe,SAAQ,mBAA0D;;gBAU1F,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,uBAAuB,EAClC,MAAM,CAAC,EAAE,oBAAoB;IAe/B;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAI3D;;;;;OAKG;IACG,YAAY,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7D,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,cAAc,EAAE;IAsCpE,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC;IAcxB,sBAAsB,CAC1B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,SAAS,EACpB,cAAc,EAAE,OAAO,EACvB,cAAc,EAAE,OAAO,EAAE,EACzB,OAAO,CAAC,EAAE,mBAAmB,EAC7B,UAAU,CAAC,EAAE,cAAc,EAAE,GAC5B,OAAO,CAAC,kBAAkB,CAAC;CAsK/B"}