@metamask/assets-controllers 73.0.2 → 73.2.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 (92) hide show
  1. package/CHANGELOG.md +45 -1
  2. package/dist/AccountTrackerController.cjs +69 -12
  3. package/dist/AccountTrackerController.cjs.map +1 -1
  4. package/dist/AccountTrackerController.d.cts +40 -1
  5. package/dist/AccountTrackerController.d.cts.map +1 -1
  6. package/dist/AccountTrackerController.d.mts +40 -1
  7. package/dist/AccountTrackerController.d.mts.map +1 -1
  8. package/dist/AccountTrackerController.mjs +69 -12
  9. package/dist/AccountTrackerController.mjs.map +1 -1
  10. package/dist/DeFiPositionsController/DeFiPositionsController.cjs +1 -1
  11. package/dist/DeFiPositionsController/DeFiPositionsController.cjs.map +1 -1
  12. package/dist/DeFiPositionsController/DeFiPositionsController.mjs +1 -1
  13. package/dist/DeFiPositionsController/DeFiPositionsController.mjs.map +1 -1
  14. package/dist/TokenBalancesController.cjs +278 -319
  15. package/dist/TokenBalancesController.cjs.map +1 -1
  16. package/dist/TokenBalancesController.d.cts +51 -93
  17. package/dist/TokenBalancesController.d.cts.map +1 -1
  18. package/dist/TokenBalancesController.d.mts +51 -93
  19. package/dist/TokenBalancesController.d.mts.map +1 -1
  20. package/dist/TokenBalancesController.mjs +277 -317
  21. package/dist/TokenBalancesController.mjs.map +1 -1
  22. package/dist/assetsUtil.cjs +13 -1
  23. package/dist/assetsUtil.cjs.map +1 -1
  24. package/dist/assetsUtil.d.cts +8 -0
  25. package/dist/assetsUtil.d.cts.map +1 -1
  26. package/dist/assetsUtil.d.mts +8 -0
  27. package/dist/assetsUtil.d.mts.map +1 -1
  28. package/dist/assetsUtil.mjs +12 -1
  29. package/dist/assetsUtil.mjs.map +1 -1
  30. package/dist/balances.cjs +447 -0
  31. package/dist/balances.cjs.map +1 -0
  32. package/dist/balances.d.cts +88 -0
  33. package/dist/balances.d.cts.map +1 -0
  34. package/dist/balances.d.mts +88 -0
  35. package/dist/balances.d.mts.map +1 -0
  36. package/dist/balances.mjs +441 -0
  37. package/dist/balances.mjs.map +1 -0
  38. package/dist/constants.cjs +13 -1
  39. package/dist/constants.cjs.map +1 -1
  40. package/dist/constants.d.cts +1 -0
  41. package/dist/constants.d.cts.map +1 -1
  42. package/dist/constants.d.mts +1 -0
  43. package/dist/constants.d.mts.map +1 -1
  44. package/dist/constants.mjs +12 -0
  45. package/dist/constants.mjs.map +1 -1
  46. package/dist/index.cjs +6 -1
  47. package/dist/index.cjs.map +1 -1
  48. package/dist/index.d.cts +6 -2
  49. package/dist/index.d.cts.map +1 -1
  50. package/dist/index.d.mts +6 -2
  51. package/dist/index.d.mts.map +1 -1
  52. package/dist/index.mjs +2 -0
  53. package/dist/index.mjs.map +1 -1
  54. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +247 -0
  55. package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -0
  56. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts +30 -0
  57. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -0
  58. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts +30 -0
  59. package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -0
  60. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +247 -0
  61. package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -0
  62. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs +35 -1
  63. package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs.map +1 -1
  64. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts +16 -0
  65. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts.map +1 -1
  66. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts +16 -0
  67. package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts.map +1 -1
  68. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs +33 -0
  69. package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs.map +1 -1
  70. package/dist/multi-chain-accounts-service/types.cjs.map +1 -1
  71. package/dist/multi-chain-accounts-service/types.d.cts +8 -0
  72. package/dist/multi-chain-accounts-service/types.d.cts.map +1 -1
  73. package/dist/multi-chain-accounts-service/types.d.mts +8 -0
  74. package/dist/multi-chain-accounts-service/types.d.mts.map +1 -1
  75. package/dist/multi-chain-accounts-service/types.mjs.map +1 -1
  76. package/dist/multicall.cjs +457 -1
  77. package/dist/multicall.cjs.map +1 -1
  78. package/dist/multicall.d.cts +51 -0
  79. package/dist/multicall.d.cts.map +1 -1
  80. package/dist/multicall.d.mts +51 -0
  81. package/dist/multicall.d.mts.map +1 -1
  82. package/dist/multicall.mjs +457 -0
  83. package/dist/multicall.mjs.map +1 -1
  84. package/dist/rpc-service/rpc-balance-fetcher.cjs +184 -0
  85. package/dist/rpc-service/rpc-balance-fetcher.cjs.map +1 -0
  86. package/dist/rpc-service/rpc-balance-fetcher.d.cts +34 -0
  87. package/dist/rpc-service/rpc-balance-fetcher.d.cts.map +1 -0
  88. package/dist/rpc-service/rpc-balance-fetcher.d.mts +34 -0
  89. package/dist/rpc-service/rpc-balance-fetcher.d.mts.map +1 -0
  90. package/dist/rpc-service/rpc-balance-fetcher.mjs +184 -0
  91. package/dist/rpc-service/rpc-balance-fetcher.mjs.map +1 -0
  92. package/package.json +15 -10
@@ -0,0 +1,184 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
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
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _RpcBalanceFetcher_instances, _RpcBalanceFetcher_getProvider, _RpcBalanceFetcher_getNetworkClient, _RpcBalanceFetcher_getTokensState, _RpcBalanceFetcher_getStakingContractAddress, _RpcBalanceFetcher_ensureFreshBlockData;
13
+ function $importDefault(module) {
14
+ if (module?.__esModule) {
15
+ return module.default;
16
+ }
17
+ return module;
18
+ }
19
+ import { toChecksumHexAddress } from "@metamask/controller-utils";
20
+ import $BN from "bn.js";
21
+ const BN = $importDefault($BN);
22
+ import { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from "../AssetsContractController.mjs";
23
+ import { getTokenBalancesForMultipleAddresses } from "../multicall.mjs";
24
+ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
25
+ const checksum = (addr) => toChecksumHexAddress(addr);
26
+ export class RpcBalanceFetcher {
27
+ constructor(getProvider, getNetworkClient, getTokensState) {
28
+ _RpcBalanceFetcher_instances.add(this);
29
+ _RpcBalanceFetcher_getProvider.set(this, void 0);
30
+ _RpcBalanceFetcher_getNetworkClient.set(this, void 0);
31
+ _RpcBalanceFetcher_getTokensState.set(this, void 0);
32
+ __classPrivateFieldSet(this, _RpcBalanceFetcher_getProvider, getProvider, "f");
33
+ __classPrivateFieldSet(this, _RpcBalanceFetcher_getNetworkClient, getNetworkClient, "f");
34
+ __classPrivateFieldSet(this, _RpcBalanceFetcher_getTokensState, getTokensState, "f");
35
+ }
36
+ supports() {
37
+ return true; // fallback – supports every chain
38
+ }
39
+ async fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }) {
40
+ const results = [];
41
+ for (const chainId of chainIds) {
42
+ const tokensState = __classPrivateFieldGet(this, _RpcBalanceFetcher_getTokensState, "f").call(this);
43
+ const accountTokenGroups = buildAccountTokenGroupsStatic(chainId, queryAllAccounts, selectedAccount, allAccounts, tokensState.allTokens, tokensState.allDetectedTokens);
44
+ if (!accountTokenGroups.length) {
45
+ continue;
46
+ }
47
+ const provider = __classPrivateFieldGet(this, _RpcBalanceFetcher_getProvider, "f").call(this, chainId);
48
+ await __classPrivateFieldGet(this, _RpcBalanceFetcher_instances, "m", _RpcBalanceFetcher_ensureFreshBlockData).call(this, chainId);
49
+ const { tokenBalances, stakedBalances } = await getTokenBalancesForMultipleAddresses(accountTokenGroups, chainId, provider, true, // include native
50
+ true);
51
+ // Add native token entries for all addresses being processed
52
+ const allAddressesForNative = new Set();
53
+ accountTokenGroups.forEach((group) => {
54
+ allAddressesForNative.add(group.accountAddress);
55
+ });
56
+ // Ensure native token entries exist for all addresses
57
+ allAddressesForNative.forEach((address) => {
58
+ const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;
59
+ results.push({
60
+ success: true,
61
+ value: nativeBalance ? nativeBalance : new BN('0'),
62
+ account: address,
63
+ token: ZERO_ADDRESS,
64
+ chainId,
65
+ });
66
+ });
67
+ // Add other token balances
68
+ Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {
69
+ // Skip native token since we handled it explicitly above
70
+ if (tokenAddr === ZERO_ADDRESS) {
71
+ return;
72
+ }
73
+ Object.entries(balances).forEach(([acct, bn]) => {
74
+ results.push({
75
+ success: bn !== null,
76
+ value: bn,
77
+ account: acct,
78
+ token: checksum(tokenAddr),
79
+ chainId,
80
+ });
81
+ });
82
+ });
83
+ // Add staked balances for all addresses being processed
84
+ const stakingContractAddress = __classPrivateFieldGet(this, _RpcBalanceFetcher_instances, "m", _RpcBalanceFetcher_getStakingContractAddress).call(this, chainId);
85
+ if (stakingContractAddress) {
86
+ // Get all unique addresses being processed for this chain
87
+ const allAddresses = new Set();
88
+ accountTokenGroups.forEach((group) => {
89
+ allAddresses.add(group.accountAddress);
90
+ });
91
+ // Add staked balance entry for each address
92
+ const checksummedStakingAddress = checksum(stakingContractAddress);
93
+ allAddresses.forEach((address) => {
94
+ const stakedBalance = stakedBalances?.[address] || null;
95
+ results.push({
96
+ success: true,
97
+ value: stakedBalance ? stakedBalance : new BN('0'),
98
+ account: address,
99
+ token: checksummedStakingAddress,
100
+ chainId,
101
+ });
102
+ });
103
+ }
104
+ }
105
+ return results;
106
+ }
107
+ }
108
+ _RpcBalanceFetcher_getProvider = new WeakMap(), _RpcBalanceFetcher_getNetworkClient = new WeakMap(), _RpcBalanceFetcher_getTokensState = new WeakMap(), _RpcBalanceFetcher_instances = new WeakSet(), _RpcBalanceFetcher_getStakingContractAddress = function _RpcBalanceFetcher_getStakingContractAddress(chainId) {
109
+ return STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainId];
110
+ }, _RpcBalanceFetcher_ensureFreshBlockData =
111
+ /**
112
+ * Ensures that the block tracker has the latest block data before performing multicall operations.
113
+ * This is a temporary fix to ensure that the block number is up to date.
114
+ *
115
+ * @param chainId - The chain id to update block data for.
116
+ */
117
+ async function _RpcBalanceFetcher_ensureFreshBlockData(chainId) {
118
+ // Force fresh block data before multicall
119
+ // TODO: This is a temporary fix to ensure that the block number is up to date.
120
+ // We should remove this once we have a better solution for this on the block tracker controller.
121
+ const networkClient = __classPrivateFieldGet(this, _RpcBalanceFetcher_getNetworkClient, "f").call(this, chainId);
122
+ await networkClient.blockTracker?.checkForLatestBlock?.();
123
+ };
124
+ /**
125
+ * Merges imported & detected tokens for the requested chain and returns a list
126
+ * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.
127
+ *
128
+ * @param chainId - The chain ID to build account token groups for
129
+ * @param queryAllAccounts - Whether to query all accounts or just the selected one
130
+ * @param selectedAccount - The currently selected account
131
+ * @param allAccounts - All available accounts
132
+ * @param allTokens - All tokens from TokensController
133
+ * @param allDetectedTokens - All detected tokens from TokensController
134
+ * @returns Array of account/token groups for multicall
135
+ */
136
+ function buildAccountTokenGroupsStatic(chainId, queryAllAccounts, selectedAccount, allAccounts, allTokens, allDetectedTokens) {
137
+ const pairs = [];
138
+ const add = ([account, tokens]) => {
139
+ const shouldInclude = queryAllAccounts || checksum(account) === checksum(selectedAccount);
140
+ if (!shouldInclude) {
141
+ return;
142
+ }
143
+ tokens.forEach((t) => pairs.push({
144
+ accountAddress: account,
145
+ tokenAddress: checksum(t.address),
146
+ }));
147
+ };
148
+ Object.entries(allTokens[chainId] ?? {}).forEach(add);
149
+ Object.entries(allDetectedTokens[chainId] ?? {}).forEach(add);
150
+ // Always include native token for relevant accounts
151
+ if (queryAllAccounts) {
152
+ allAccounts.forEach((a) => {
153
+ pairs.push({
154
+ accountAddress: a.address,
155
+ tokenAddress: ZERO_ADDRESS,
156
+ });
157
+ });
158
+ }
159
+ else {
160
+ pairs.push({
161
+ accountAddress: selectedAccount,
162
+ tokenAddress: ZERO_ADDRESS,
163
+ });
164
+ }
165
+ if (!pairs.length) {
166
+ return [];
167
+ }
168
+ // group by account
169
+ const map = new Map();
170
+ pairs.forEach(({ accountAddress, tokenAddress }) => {
171
+ if (!map.has(accountAddress)) {
172
+ map.set(accountAddress, []);
173
+ }
174
+ const tokens = map.get(accountAddress);
175
+ if (tokens) {
176
+ tokens.push(tokenAddress);
177
+ }
178
+ });
179
+ return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({
180
+ accountAddress,
181
+ tokenAddresses,
182
+ }));
183
+ }
184
+ //# sourceMappingURL=rpc-balance-fetcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc-balance-fetcher.mjs","sourceRoot":"","sources":["../../src/rpc-service/rpc-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Web3Provider } from '@ethersproject/providers';\nimport { toChecksumHexAddress } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkClient } from '@metamask/network-controller';\nimport type { Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from '../AssetsContractController';\nimport { getTokenBalancesForMultipleAddresses } from '../multicall';\nimport type { TokensControllerState } from '../TokensController';\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nexport type ProcessedBalance = {\n success: boolean;\n value?: BN;\n account: ChecksumAddress;\n token: ChecksumAddress;\n chainId: ChainIdHex;\n};\n\nexport type BalanceFetcher = {\n supports(chainId: ChainIdHex): boolean;\n fetch(input: {\n chainIds: ChainIdHex[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<ProcessedBalance[]>;\n};\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\nconst checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nexport class RpcBalanceFetcher implements BalanceFetcher {\n readonly #getProvider: (chainId: ChainIdHex) => Web3Provider;\n\n readonly #getNetworkClient: (chainId: ChainIdHex) => NetworkClient;\n\n readonly #getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n };\n\n constructor(\n getProvider: (chainId: ChainIdHex) => Web3Provider,\n getNetworkClient: (chainId: ChainIdHex) => NetworkClient,\n getTokensState: () => {\n allTokens: TokensControllerState['allTokens'];\n allDetectedTokens: TokensControllerState['allDetectedTokens'];\n },\n ) {\n this.#getProvider = getProvider;\n this.#getNetworkClient = getNetworkClient;\n this.#getTokensState = getTokensState;\n }\n\n supports(): boolean {\n return true; // fallback – supports every chain\n }\n\n #getStakingContractAddress(chainId: ChainIdHex): string | undefined {\n return STAKING_CONTRACT_ADDRESS_BY_CHAINID[\n chainId as keyof typeof STAKING_CONTRACT_ADDRESS_BY_CHAINID\n ];\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const results: ProcessedBalance[] = [];\n\n for (const chainId of chainIds) {\n const tokensState = this.#getTokensState();\n const accountTokenGroups = buildAccountTokenGroupsStatic(\n chainId,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n tokensState.allTokens,\n tokensState.allDetectedTokens,\n );\n if (!accountTokenGroups.length) {\n continue;\n }\n\n const provider = this.#getProvider(chainId);\n await this.#ensureFreshBlockData(chainId);\n\n const { tokenBalances, stakedBalances } =\n await getTokenBalancesForMultipleAddresses(\n accountTokenGroups,\n chainId,\n provider,\n true, // include native\n true, // include staked\n );\n\n // Add native token entries for all addresses being processed\n const allAddressesForNative = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddressesForNative.add(group.accountAddress);\n });\n\n // Ensure native token entries exist for all addresses\n allAddressesForNative.forEach((address) => {\n const nativeBalance = tokenBalances[ZERO_ADDRESS]?.[address] || null;\n results.push({\n success: true,\n value: nativeBalance ? (nativeBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: ZERO_ADDRESS,\n chainId,\n });\n });\n\n // Add other token balances\n Object.entries(tokenBalances).forEach(([tokenAddr, balances]) => {\n // Skip native token since we handled it explicitly above\n if (tokenAddr === ZERO_ADDRESS) {\n return;\n }\n Object.entries(balances).forEach(([acct, bn]) => {\n results.push({\n success: bn !== null,\n value: bn as BN,\n account: acct as ChecksumAddress,\n token: checksum(tokenAddr),\n chainId,\n });\n });\n });\n\n // Add staked balances for all addresses being processed\n const stakingContractAddress = this.#getStakingContractAddress(chainId);\n if (stakingContractAddress) {\n // Get all unique addresses being processed for this chain\n const allAddresses = new Set<string>();\n accountTokenGroups.forEach((group) => {\n allAddresses.add(group.accountAddress);\n });\n\n // Add staked balance entry for each address\n const checksummedStakingAddress = checksum(stakingContractAddress);\n allAddresses.forEach((address) => {\n const stakedBalance = stakedBalances?.[address] || null;\n results.push({\n success: true,\n value: stakedBalance ? (stakedBalance as BN) : new BN('0'),\n account: address as ChecksumAddress,\n token: checksummedStakingAddress,\n chainId,\n });\n });\n }\n }\n\n return results;\n }\n\n /**\n * Ensures that the block tracker has the latest block data before performing multicall operations.\n * This is a temporary fix to ensure that the block number is up to date.\n *\n * @param chainId - The chain id to update block data for.\n */\n async #ensureFreshBlockData(chainId: Hex): Promise<void> {\n // Force fresh block data before multicall\n // TODO: This is a temporary fix to ensure that the block number is up to date.\n // We should remove this once we have a better solution for this on the block tracker controller.\n const networkClient = this.#getNetworkClient(chainId);\n await networkClient.blockTracker?.checkForLatestBlock?.();\n }\n}\n\n/**\n * Merges imported & detected tokens for the requested chain and returns a list\n * of `{ accountAddress, tokenAddresses[] }` suitable for getTokenBalancesForMultipleAddresses.\n *\n * @param chainId - The chain ID to build account token groups for\n * @param queryAllAccounts - Whether to query all accounts or just the selected one\n * @param selectedAccount - The currently selected account\n * @param allAccounts - All available accounts\n * @param allTokens - All tokens from TokensController\n * @param allDetectedTokens - All detected tokens from TokensController\n * @returns Array of account/token groups for multicall\n */\nfunction buildAccountTokenGroupsStatic(\n chainId: ChainIdHex,\n queryAllAccounts: boolean,\n selectedAccount: ChecksumAddress,\n allAccounts: InternalAccount[],\n allTokens: TokensControllerState['allTokens'],\n allDetectedTokens: TokensControllerState['allDetectedTokens'],\n): { accountAddress: ChecksumAddress; tokenAddresses: ChecksumAddress[] }[] {\n const pairs: {\n accountAddress: ChecksumAddress;\n tokenAddress: ChecksumAddress;\n }[] = [];\n\n const add = ([account, tokens]: [string, unknown[]]) => {\n const shouldInclude =\n queryAllAccounts || checksum(account) === checksum(selectedAccount);\n if (!shouldInclude) {\n return;\n }\n (tokens as unknown[]).forEach((t: unknown) =>\n pairs.push({\n accountAddress: account as ChecksumAddress,\n tokenAddress: checksum((t as { address: string }).address),\n }),\n );\n };\n\n Object.entries(allTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n Object.entries(allDetectedTokens[chainId] ?? {}).forEach(\n add as (entry: [string, unknown]) => void,\n );\n\n // Always include native token for relevant accounts\n if (queryAllAccounts) {\n allAccounts.forEach((a) => {\n pairs.push({\n accountAddress: a.address as ChecksumAddress,\n tokenAddress: ZERO_ADDRESS,\n });\n });\n } else {\n pairs.push({\n accountAddress: selectedAccount,\n tokenAddress: ZERO_ADDRESS,\n });\n }\n\n if (!pairs.length) {\n return [];\n }\n\n // group by account\n const map = new Map<ChecksumAddress, ChecksumAddress[]>();\n pairs.forEach(({ accountAddress, tokenAddress }) => {\n if (!map.has(accountAddress)) {\n map.set(accountAddress, []);\n }\n const tokens = map.get(accountAddress);\n if (tokens) {\n tokens.push(tokenAddress);\n }\n });\n\n return Array.from(map.entries()).map(([accountAddress, tokenAddresses]) => ({\n accountAddress,\n tokenAddresses,\n }));\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/assets-controllers",
3
- "version": "73.0.2",
3
+ "version": "73.2.0",
4
4
  "description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -54,11 +54,11 @@
54
54
  "@ethersproject/contracts": "^5.7.0",
55
55
  "@ethersproject/providers": "^5.7.0",
56
56
  "@metamask/abi-utils": "^2.0.3",
57
- "@metamask/base-controller": "^8.0.1",
57
+ "@metamask/base-controller": "^8.1.0",
58
58
  "@metamask/contract-metadata": "^2.4.0",
59
- "@metamask/controller-utils": "^11.11.0",
59
+ "@metamask/controller-utils": "^11.12.0",
60
60
  "@metamask/eth-query": "^4.0.0",
61
- "@metamask/keyring-api": "^19.0.0",
61
+ "@metamask/keyring-api": "^20.0.0",
62
62
  "@metamask/metamask-eth-abis": "^3.1.1",
63
63
  "@metamask/polling-controller": "^14.0.0",
64
64
  "@metamask/rpc-errors": "^7.0.2",
@@ -73,25 +73,29 @@
73
73
  "immer": "^9.0.6",
74
74
  "lodash": "^4.17.21",
75
75
  "multiformats": "^13.1.0",
76
+ "reselect": "^5.1.1",
76
77
  "single-call-balance-checker-abi": "^1.0.0",
77
78
  "uuid": "^8.3.2"
78
79
  },
79
80
  "devDependencies": {
80
81
  "@babel/runtime": "^7.23.9",
81
- "@metamask/accounts-controller": "^32.0.1",
82
+ "@metamask/account-api": "^0.9.0",
83
+ "@metamask/account-tree-controller": "^0.8.0",
84
+ "@metamask/accounts-controller": "^32.0.2",
82
85
  "@metamask/approval-controller": "^7.1.3",
83
86
  "@metamask/auto-changelog": "^3.4.4",
84
87
  "@metamask/ethjs-provider-http": "^0.3.0",
85
- "@metamask/keyring-controller": "^22.1.0",
86
- "@metamask/keyring-internal-api": "^7.0.0",
87
- "@metamask/keyring-snap-client": "^6.0.0",
88
- "@metamask/network-controller": "^24.0.1",
88
+ "@metamask/keyring-controller": "^22.1.1",
89
+ "@metamask/keyring-internal-api": "^8.0.0",
90
+ "@metamask/keyring-snap-client": "^7.0.0",
91
+ "@metamask/multichain-account-service": "^0.4.0",
92
+ "@metamask/network-controller": "^24.1.0",
89
93
  "@metamask/permission-controller": "^11.0.6",
90
94
  "@metamask/phishing-controller": "^13.1.0",
91
95
  "@metamask/preferences-controller": "^18.4.1",
92
96
  "@metamask/providers": "^22.1.0",
93
97
  "@metamask/snaps-controllers": "^14.0.1",
94
- "@metamask/transaction-controller": "^59.1.0",
98
+ "@metamask/transaction-controller": "^59.2.0",
95
99
  "@types/jest": "^27.4.1",
96
100
  "@types/lodash": "^4.14.191",
97
101
  "@types/node": "^16.18.54",
@@ -107,6 +111,7 @@
107
111
  "webextension-polyfill": "^0.12.0"
108
112
  },
109
113
  "peerDependencies": {
114
+ "@metamask/account-tree-controller": "^0.7.0",
110
115
  "@metamask/accounts-controller": "^32.0.0",
111
116
  "@metamask/approval-controller": "^7.0.0",
112
117
  "@metamask/keyring-controller": "^22.0.0",