@metamask-previews/assets-controllers 73.0.1-preview-bf50b46b → 73.0.1-preview-e4e5ca5c
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.
- package/CHANGELOG.md +1 -13
- package/dist/AccountTrackerController.cjs +5 -167
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +2 -14
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +2 -14
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +5 -167
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/TokenBalancesController.cjs +321 -267
- package/dist/TokenBalancesController.cjs.map +1 -1
- package/dist/TokenBalancesController.d.cts +93 -51
- package/dist/TokenBalancesController.d.cts.map +1 -1
- package/dist/TokenBalancesController.d.mts +93 -51
- package/dist/TokenBalancesController.d.mts.map +1 -1
- package/dist/TokenBalancesController.mjs +320 -270
- package/dist/TokenBalancesController.mjs.map +1 -1
- package/dist/assetsUtil.cjs +1 -13
- package/dist/assetsUtil.cjs.map +1 -1
- package/dist/assetsUtil.d.cts +0 -8
- package/dist/assetsUtil.d.cts.map +1 -1
- package/dist/assetsUtil.d.mts +0 -8
- package/dist/assetsUtil.d.mts.map +1 -1
- package/dist/assetsUtil.mjs +1 -12
- package/dist/assetsUtil.mjs.map +1 -1
- package/dist/constants.cjs +1 -12
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +0 -1
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +0 -1
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +0 -11
- package/dist/constants.mjs.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs +1 -35
- package/dist/multi-chain-accounts-service/multi-chain-accounts.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts +0 -16
- package/dist/multi-chain-accounts-service/multi-chain-accounts.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts +0 -16
- package/dist/multi-chain-accounts-service/multi-chain-accounts.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs +0 -33
- package/dist/multi-chain-accounts-service/multi-chain-accounts.mjs.map +1 -1
- package/dist/multi-chain-accounts-service/types.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/types.d.cts +0 -8
- package/dist/multi-chain-accounts-service/types.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/types.d.mts +0 -8
- package/dist/multi-chain-accounts-service/types.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/types.mjs.map +1 -1
- package/dist/multicall.cjs +22 -397
- package/dist/multicall.cjs.map +1 -1
- package/dist/multicall.d.cts +0 -39
- package/dist/multicall.d.cts.map +1 -1
- package/dist/multicall.d.mts +0 -39
- package/dist/multicall.d.mts.map +1 -1
- package/dist/multicall.mjs +21 -398
- package/dist/multicall.mjs.map +1 -1
- package/dist/selectors/balanceSelectors.cjs +275 -0
- package/dist/selectors/balanceSelectors.cjs.map +1 -0
- package/dist/selectors/balanceSelectors.d.cts +248 -0
- package/dist/selectors/balanceSelectors.d.cts.map +1 -0
- package/dist/selectors/balanceSelectors.d.mts +248 -0
- package/dist/selectors/balanceSelectors.d.mts.map +1 -0
- package/dist/selectors/balanceSelectors.mjs +268 -0
- package/dist/selectors/balanceSelectors.mjs.map +1 -0
- package/package.json +6 -3
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +0 -98
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +0 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts +0 -28
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +0 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts +0 -28
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +0 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +0 -98
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +0 -1
- package/dist/rpc-service/rpc-balance-fetcher.cjs +0 -128
- package/dist/rpc-service/rpc-balance-fetcher.cjs.map +0 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.cts +0 -34
- package/dist/rpc-service/rpc-balance-fetcher.d.cts.map +0 -1
- package/dist/rpc-service/rpc-balance-fetcher.d.mts +0 -34
- package/dist/rpc-service/rpc-balance-fetcher.d.mts.map +0 -1
- package/dist/rpc-service/rpc-balance-fetcher.mjs +0 -124
- package/dist/rpc-service/rpc-balance-fetcher.mjs.map +0 -1
- package/dist/selectors.cjs +0 -64
- package/dist/selectors.cjs.map +0 -1
- package/dist/selectors.d.cts +0 -51
- package/dist/selectors.d.cts.map +0 -1
- package/dist/selectors.d.mts +0 -51
- package/dist/selectors.d.mts.map +0 -1
- package/dist/selectors.mjs +0 -61
- package/dist/selectors.mjs.map +0 -1
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { isEvmAccountType } from "@metamask/keyring-api";
|
|
2
|
+
import { createSelector } from "reselect";
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to get internal accounts for a specific group.
|
|
5
|
+
* Uses AccountTreeController state to find accounts.
|
|
6
|
+
*
|
|
7
|
+
* @param accountTreeState - AccountTreeController state
|
|
8
|
+
* @param accountsState - AccountsController state
|
|
9
|
+
* @param groupId - The account group ID (format: "walletId/groupIndex")
|
|
10
|
+
* @returns Array of internal accounts in the group
|
|
11
|
+
*/
|
|
12
|
+
const getInternalAccountsForGroup = (accountTreeState, accountsState, groupId) => {
|
|
13
|
+
// Extract walletId from groupId (format: "walletId/groupIndex")
|
|
14
|
+
const walletId = groupId.split('/')[0];
|
|
15
|
+
const wallet = accountTreeState.accountTree.wallets[walletId];
|
|
16
|
+
if (!wallet) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const group = wallet.groups[groupId];
|
|
20
|
+
if (!group) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
// Map account IDs to actual account objects
|
|
24
|
+
return group.accounts
|
|
25
|
+
.map((accountId) => accountsState.internalAccounts.accounts[accountId])
|
|
26
|
+
.filter(Boolean);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Selector to get aggregated balances for a specific account group.
|
|
30
|
+
* Returns total balance in user's selected currency, aggregating all tokens across accounts in the group.
|
|
31
|
+
*
|
|
32
|
+
* @param groupId - The account group ID (format: "walletId/groupIndex", e.g., "entropy:entropy-source-1/0")
|
|
33
|
+
* @returns Aggregated balance for the account group
|
|
34
|
+
*/
|
|
35
|
+
export const selectBalanceByAccountGroup = (groupId) => createSelector([
|
|
36
|
+
(state) => state.AccountTreeController,
|
|
37
|
+
(state) => state.AccountsController,
|
|
38
|
+
(state) => state.TokenBalancesController,
|
|
39
|
+
(state) => state.TokenRatesController,
|
|
40
|
+
(state) => state.MultichainAssetsRatesController,
|
|
41
|
+
(state) => state.MultichainBalancesController,
|
|
42
|
+
(state) => state.TokensController,
|
|
43
|
+
(state) => state.CurrencyRateController,
|
|
44
|
+
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
45
|
+
// Extract walletId from groupId
|
|
46
|
+
const walletId = groupId.split('/')[0];
|
|
47
|
+
const accounts = getInternalAccountsForGroup(accountTreeState, accountsState, groupId);
|
|
48
|
+
if (accounts.length === 0) {
|
|
49
|
+
return {
|
|
50
|
+
walletId,
|
|
51
|
+
groupId,
|
|
52
|
+
totalBalanceInUserCurrency: 0,
|
|
53
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
let totalBalanceInUserCurrency = 0;
|
|
57
|
+
// Process each account's balances
|
|
58
|
+
for (const account of accounts) {
|
|
59
|
+
const isEvmAccount = isEvmAccountType(account.type);
|
|
60
|
+
if (isEvmAccount) {
|
|
61
|
+
// Handle EVM account balances from TokenBalancesController
|
|
62
|
+
// Structure: tokenBalances[chainId][accountAddress][tokenAddress] = balance
|
|
63
|
+
for (const [chainId, chainBalances] of Object.entries(tokenBalancesState.tokenBalances)) {
|
|
64
|
+
const accountBalances = chainBalances[account.address];
|
|
65
|
+
if (accountBalances) {
|
|
66
|
+
for (const [tokenAddress, balance] of Object.entries(accountBalances)) {
|
|
67
|
+
// Find token in TokensController state
|
|
68
|
+
const chainTokens = tokensState.allTokens[chainId];
|
|
69
|
+
const accountTokens = chainTokens?.[account.address];
|
|
70
|
+
const token = accountTokens?.find((t) => t.address === tokenAddress);
|
|
71
|
+
if (!token) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const decimals = token.decimals || 18;
|
|
75
|
+
const balanceInSmallestUnit = parseInt(balance, 16);
|
|
76
|
+
// Skip invalid balance values to prevent NaN propagation
|
|
77
|
+
if (Number.isNaN(balanceInSmallestUnit)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const balanceInTokenUnits = balanceInSmallestUnit / Math.pow(10, decimals);
|
|
81
|
+
// Get token rate in native currency from TokenRatesController
|
|
82
|
+
const chainMarketData = tokenRatesState.marketData[chainId];
|
|
83
|
+
const tokenMarketData = chainMarketData?.[tokenAddress];
|
|
84
|
+
if (tokenMarketData?.price) {
|
|
85
|
+
// Convert token price to user currency using native currency conversion rate
|
|
86
|
+
const nativeCurrency = tokenMarketData.currency;
|
|
87
|
+
const nativeToUserRate = currencyRateState.currencyRates[nativeCurrency]
|
|
88
|
+
?.conversionRate;
|
|
89
|
+
if (nativeToUserRate) {
|
|
90
|
+
// Convert token price to user currency: tokenPrice * nativeToUserRate
|
|
91
|
+
const tokenPriceInUserCurrency = tokenMarketData.price * nativeToUserRate;
|
|
92
|
+
const balanceInUserCurrency = balanceInTokenUnits * tokenPriceInUserCurrency;
|
|
93
|
+
totalBalanceInUserCurrency += balanceInUserCurrency;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// Handle non-EVM account balances from MultichainBalancesController
|
|
102
|
+
const accountBalances = multichainBalancesState.balances[account.id];
|
|
103
|
+
if (accountBalances) {
|
|
104
|
+
for (const [assetId, balanceData] of Object.entries(accountBalances)) {
|
|
105
|
+
const balanceAmount = parseFloat(balanceData.amount);
|
|
106
|
+
// Skip invalid balance values to prevent NaN propagation
|
|
107
|
+
if (Number.isNaN(balanceAmount)) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
// Get conversion rate for this asset (already in user currency)
|
|
111
|
+
const conversionRate = multichainRatesState.conversionRates[assetId];
|
|
112
|
+
if (conversionRate) {
|
|
113
|
+
const conversionRateValue = parseFloat(conversionRate.rate);
|
|
114
|
+
// Skip invalid conversion rate values to prevent NaN propagation
|
|
115
|
+
if (Number.isNaN(conversionRateValue)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// MultichainAssetsRatesController already provides rates in user currency
|
|
119
|
+
const balanceInUserCurrency = balanceAmount * conversionRateValue;
|
|
120
|
+
totalBalanceInUserCurrency += balanceInUserCurrency;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
walletId,
|
|
128
|
+
groupId,
|
|
129
|
+
totalBalanceInUserCurrency,
|
|
130
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* Selector to get aggregated balances for all account groups in a wallet.
|
|
135
|
+
* Returns total balance in user's selected currency, aggregating all tokens across all groups in the wallet.
|
|
136
|
+
*
|
|
137
|
+
* @param walletId - The wallet ID (entropy source)
|
|
138
|
+
* @returns Aggregated balance for all groups in the wallet
|
|
139
|
+
*/
|
|
140
|
+
export const selectBalanceByWallet = (walletId) => createSelector([
|
|
141
|
+
(state) => state.AccountTreeController,
|
|
142
|
+
(state) => state.AccountsController,
|
|
143
|
+
(state) => state.TokenBalancesController,
|
|
144
|
+
(state) => state.TokenRatesController,
|
|
145
|
+
(state) => state.MultichainAssetsRatesController,
|
|
146
|
+
(state) => state.MultichainBalancesController,
|
|
147
|
+
(state) => state.TokensController,
|
|
148
|
+
(state) => state.CurrencyRateController,
|
|
149
|
+
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
151
|
+
const wallet = accountTreeState.accountTree.wallets[walletId];
|
|
152
|
+
if (!wallet) {
|
|
153
|
+
return {
|
|
154
|
+
walletId,
|
|
155
|
+
groups: {},
|
|
156
|
+
totalBalanceInUserCurrency: 0,
|
|
157
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const groupBalances = {};
|
|
161
|
+
let totalBalanceInUserCurrency = 0;
|
|
162
|
+
const groups = Object.keys(wallet.groups || {});
|
|
163
|
+
for (const groupId of groups) {
|
|
164
|
+
const groupBalance = selectBalanceByAccountGroup(groupId)({
|
|
165
|
+
AccountTreeController: accountTreeState,
|
|
166
|
+
AccountsController: accountsState,
|
|
167
|
+
TokenBalancesController: tokenBalancesState,
|
|
168
|
+
TokenRatesController: tokenRatesState,
|
|
169
|
+
MultichainAssetsRatesController: multichainRatesState,
|
|
170
|
+
MultichainBalancesController: multichainBalancesState,
|
|
171
|
+
TokensController: tokensState,
|
|
172
|
+
CurrencyRateController: currencyRateState,
|
|
173
|
+
});
|
|
174
|
+
groupBalances[groupId] = groupBalance;
|
|
175
|
+
totalBalanceInUserCurrency += groupBalance.totalBalanceInUserCurrency;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
walletId,
|
|
179
|
+
groups: groupBalances,
|
|
180
|
+
totalBalanceInUserCurrency,
|
|
181
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
182
|
+
};
|
|
183
|
+
});
|
|
184
|
+
/**
|
|
185
|
+
* Selector to get aggregated balances for all wallets and their account groups.
|
|
186
|
+
* Returns total balance in user's selected currency, aggregating all tokens across all wallets.
|
|
187
|
+
*
|
|
188
|
+
* @returns Aggregated balance for all wallets
|
|
189
|
+
*/
|
|
190
|
+
export const selectBalanceForAllWallets = () => createSelector([
|
|
191
|
+
(state) => state.AccountTreeController,
|
|
192
|
+
(state) => state.AccountsController,
|
|
193
|
+
(state) => state.TokenBalancesController,
|
|
194
|
+
(state) => state.TokenRatesController,
|
|
195
|
+
(state) => state.MultichainAssetsRatesController,
|
|
196
|
+
(state) => state.MultichainBalancesController,
|
|
197
|
+
(state) => state.TokensController,
|
|
198
|
+
(state) => state.CurrencyRateController,
|
|
199
|
+
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
200
|
+
const walletBalances = {};
|
|
201
|
+
let totalBalanceInUserCurrency = 0;
|
|
202
|
+
const walletIds = Object.keys(accountTreeState.accountTree.wallets);
|
|
203
|
+
for (const walletId of walletIds) {
|
|
204
|
+
const walletBalance = selectBalanceByWallet(walletId)({
|
|
205
|
+
AccountTreeController: accountTreeState,
|
|
206
|
+
AccountsController: accountsState,
|
|
207
|
+
TokenBalancesController: tokenBalancesState,
|
|
208
|
+
TokenRatesController: tokenRatesState,
|
|
209
|
+
MultichainAssetsRatesController: multichainRatesState,
|
|
210
|
+
MultichainBalancesController: multichainBalancesState,
|
|
211
|
+
TokensController: tokensState,
|
|
212
|
+
CurrencyRateController: currencyRateState,
|
|
213
|
+
});
|
|
214
|
+
walletBalances[walletId] = walletBalance;
|
|
215
|
+
totalBalanceInUserCurrency += walletBalance.totalBalanceInUserCurrency;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
wallets: walletBalances,
|
|
219
|
+
totalBalanceInUserCurrency,
|
|
220
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
/**
|
|
224
|
+
* Selector to get aggregated balances for the currently selected account group.
|
|
225
|
+
* Returns total balance in user's selected currency, aggregating all tokens in the selected group.
|
|
226
|
+
*
|
|
227
|
+
* @returns Aggregated balance for the currently selected group
|
|
228
|
+
*/
|
|
229
|
+
export const selectBalanceForSelectedAccountGroup = () => createSelector([
|
|
230
|
+
(state) => state.AccountTreeController,
|
|
231
|
+
(state) => state.AccountsController,
|
|
232
|
+
(state) => state.TokenBalancesController,
|
|
233
|
+
(state) => state.TokenRatesController,
|
|
234
|
+
(state) => state.MultichainAssetsRatesController,
|
|
235
|
+
(state) => state.MultichainBalancesController,
|
|
236
|
+
(state) => state.TokensController,
|
|
237
|
+
(state) => state.CurrencyRateController,
|
|
238
|
+
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
239
|
+
const selectedGroupId = accountTreeState.accountTree.selectedAccountGroup;
|
|
240
|
+
if (!selectedGroupId) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
// Validate group ID format
|
|
244
|
+
const parts = selectedGroupId.split('/');
|
|
245
|
+
if (parts.length !== 2) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return selectBalanceByAccountGroup(selectedGroupId)({
|
|
249
|
+
AccountTreeController: accountTreeState,
|
|
250
|
+
AccountsController: accountsState,
|
|
251
|
+
TokenBalancesController: tokenBalancesState,
|
|
252
|
+
TokenRatesController: tokenRatesState,
|
|
253
|
+
MultichainAssetsRatesController: multichainRatesState,
|
|
254
|
+
MultichainBalancesController: multichainBalancesState,
|
|
255
|
+
TokensController: tokensState,
|
|
256
|
+
CurrencyRateController: currencyRateState,
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
/**
|
|
260
|
+
* Collection of balance-related selectors for assets controllers
|
|
261
|
+
*/
|
|
262
|
+
export const balanceSelectors = {
|
|
263
|
+
selectBalanceByAccountGroup,
|
|
264
|
+
selectBalanceByWallet,
|
|
265
|
+
selectBalanceForAllWallets,
|
|
266
|
+
selectBalanceForSelectedAccountGroup,
|
|
267
|
+
};
|
|
268
|
+
//# sourceMappingURL=balanceSelectors.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balanceSelectors.mjs","sourceRoot":"","sources":["../../src/selectors/balanceSelectors.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport type { AccountWalletObject } from '@metamask/account-tree-controller';\nimport type { AccountGroupObject } from '@metamask/account-tree-controller';\nimport type { AccountsControllerState } from '@metamask/accounts-controller';\nimport type { EntropySourceId } from '@metamask/keyring-api';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { Hex } from '@metamask/utils';\nimport type { CaipAssetType } from '@metamask/utils';\nimport { createSelector } from 'reselect';\n\nimport type { CurrencyRateState } from '../CurrencyRateController';\nimport type { MultichainAssetsRatesControllerState } from '../MultichainAssetsRatesController';\nimport type { MultichainBalancesControllerState } from '../MultichainBalancesController';\nimport type { TokenBalancesControllerState } from '../TokenBalancesController';\nimport type { TokenRatesControllerState } from '../TokenRatesController';\nimport type { TokensControllerState } from '../TokensController';\n\n/**\n * Root state type for all controllers used in selectors\n */\nexport type RootState = {\n TokenBalancesController: TokenBalancesControllerState;\n CurrencyRateController: CurrencyRateState;\n TokenRatesController: TokenRatesControllerState;\n MultichainAssetsRatesController: MultichainAssetsRatesControllerState;\n MultichainBalancesController: MultichainBalancesControllerState;\n TokensController: TokensControllerState;\n AccountsController: AccountsControllerState;\n AccountTreeController: AccountTreeControllerState;\n};\n\n/**\n * Helper function to get internal accounts for a specific group.\n * Uses AccountTreeController state to find accounts.\n *\n * @param accountTreeState - AccountTreeController state\n * @param accountsState - AccountsController state\n * @param groupId - The account group ID (format: \"walletId/groupIndex\")\n * @returns Array of internal accounts in the group\n */\nconst getInternalAccountsForGroup = (\n accountTreeState: AccountTreeControllerState,\n accountsState: AccountsControllerState,\n groupId: string,\n) => {\n // Extract walletId from groupId (format: \"walletId/groupIndex\")\n const walletId = groupId.split('/')[0] as EntropySourceId;\n\n const wallet = (\n accountTreeState.accountTree.wallets as Record<string, AccountWalletObject>\n )[walletId];\n if (!wallet) {\n return [];\n }\n\n const group = (wallet.groups as Record<string, AccountGroupObject>)[groupId];\n if (!group) {\n return [];\n }\n\n // Map account IDs to actual account objects\n return group.accounts\n .map(\n (accountId: string) => accountsState.internalAccounts.accounts[accountId],\n )\n .filter(Boolean);\n};\n\n/**\n * Selector to get aggregated balances for a specific account group.\n * Returns total balance in user's selected currency, aggregating all tokens across accounts in the group.\n *\n * @param groupId - The account group ID (format: \"walletId/groupIndex\", e.g., \"entropy:entropy-source-1/0\")\n * @returns Aggregated balance for the account group\n */\nexport const selectBalanceByAccountGroup = (groupId: string) =>\n createSelector(\n [\n (state: RootState) => state.AccountTreeController,\n (state: RootState) => state.AccountsController,\n (state: RootState) => state.TokenBalancesController,\n (state: RootState) => state.TokenRatesController,\n (state: RootState) => state.MultichainAssetsRatesController,\n (state: RootState) => state.MultichainBalancesController,\n (state: RootState) => state.TokensController,\n (state: RootState) => state.CurrencyRateController,\n ],\n (\n accountTreeState,\n accountsState,\n tokenBalancesState,\n tokenRatesState,\n multichainRatesState,\n multichainBalancesState,\n tokensState,\n currencyRateState,\n ): AccountGroupBalance => {\n // Extract walletId from groupId\n const walletId = groupId.split('/')[0] as EntropySourceId;\n\n const accounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsState,\n groupId,\n );\n\n if (accounts.length === 0) {\n return {\n walletId,\n groupId,\n totalBalanceInUserCurrency: 0,\n userCurrency: currencyRateState.currentCurrency,\n };\n }\n\n let totalBalanceInUserCurrency = 0;\n\n // Process each account's balances\n for (const account of accounts) {\n const isEvmAccount = isEvmAccountType(account.type);\n\n if (isEvmAccount) {\n // Handle EVM account balances from TokenBalancesController\n // Structure: tokenBalances[chainId][accountAddress][tokenAddress] = balance\n for (const [chainId, chainBalances] of Object.entries(\n tokenBalancesState.tokenBalances,\n )) {\n const accountBalances = chainBalances[account.address as Hex];\n if (accountBalances) {\n for (const [tokenAddress, balance] of Object.entries(\n accountBalances,\n )) {\n // Find token in TokensController state\n const chainTokens = tokensState.allTokens[chainId as Hex];\n const accountTokens = chainTokens?.[account.address];\n const token = accountTokens?.find(\n (t) => t.address === tokenAddress,\n );\n if (!token) {\n continue;\n }\n\n const decimals = token.decimals || 18;\n const balanceInSmallestUnit = parseInt(balance as string, 16);\n\n // Skip invalid balance values to prevent NaN propagation\n if (Number.isNaN(balanceInSmallestUnit)) {\n continue;\n }\n\n const balanceInTokenUnits =\n balanceInSmallestUnit / Math.pow(10, decimals);\n\n // Get token rate in native currency from TokenRatesController\n const chainMarketData =\n tokenRatesState.marketData[chainId as Hex];\n const tokenMarketData = chainMarketData?.[tokenAddress as Hex];\n if (tokenMarketData?.price) {\n // Convert token price to user currency using native currency conversion rate\n const nativeCurrency = tokenMarketData.currency;\n const nativeToUserRate =\n currencyRateState.currencyRates[nativeCurrency]\n ?.conversionRate;\n\n if (nativeToUserRate) {\n // Convert token price to user currency: tokenPrice * nativeToUserRate\n const tokenPriceInUserCurrency =\n tokenMarketData.price * nativeToUserRate;\n const balanceInUserCurrency =\n balanceInTokenUnits * tokenPriceInUserCurrency;\n totalBalanceInUserCurrency += balanceInUserCurrency;\n }\n }\n }\n }\n }\n } else {\n // Handle non-EVM account balances from MultichainBalancesController\n const accountBalances = multichainBalancesState.balances[account.id];\n if (accountBalances) {\n for (const [assetId, balanceData] of Object.entries(\n accountBalances,\n )) {\n const balanceAmount = parseFloat(balanceData.amount);\n\n // Skip invalid balance values to prevent NaN propagation\n if (Number.isNaN(balanceAmount)) {\n continue;\n }\n\n // Get conversion rate for this asset (already in user currency)\n const conversionRate =\n multichainRatesState.conversionRates[assetId as CaipAssetType];\n if (conversionRate) {\n const conversionRateValue = parseFloat(conversionRate.rate);\n\n // Skip invalid conversion rate values to prevent NaN propagation\n if (Number.isNaN(conversionRateValue)) {\n continue;\n }\n\n // MultichainAssetsRatesController already provides rates in user currency\n const balanceInUserCurrency =\n balanceAmount * conversionRateValue;\n totalBalanceInUserCurrency += balanceInUserCurrency;\n }\n }\n }\n }\n }\n\n return {\n walletId,\n groupId,\n totalBalanceInUserCurrency,\n userCurrency: currencyRateState.currentCurrency,\n };\n },\n );\n\n/**\n * Aggregated balance for an account group\n */\nexport type AccountGroupBalance = {\n walletId: string;\n groupId: string;\n totalBalanceInUserCurrency: number; // not formatted\n userCurrency: string;\n};\n\n/**\n * Aggregated balance for a wallet (all groups)\n */\nexport type WalletBalance = {\n walletId: string;\n groups: Record<string, AccountGroupBalance>;\n totalBalanceInUserCurrency: number; // not formatted\n userCurrency: string;\n};\n\n/**\n * Aggregated balance for all wallets\n */\nexport type AllWalletsBalance = {\n wallets: Record<string, WalletBalance>;\n totalBalanceInUserCurrency: number; // not formatted\n userCurrency: string;\n};\n\n/**\n * Selector to get aggregated balances for all account groups in a wallet.\n * Returns total balance in user's selected currency, aggregating all tokens across all groups in the wallet.\n *\n * @param walletId - The wallet ID (entropy source)\n * @returns Aggregated balance for all groups in the wallet\n */\nexport const selectBalanceByWallet = (walletId: EntropySourceId) =>\n createSelector(\n [\n (state: RootState) => state.AccountTreeController,\n (state: RootState) => state.AccountsController,\n (state: RootState) => state.TokenBalancesController,\n (state: RootState) => state.TokenRatesController,\n (state: RootState) => state.MultichainAssetsRatesController,\n (state: RootState) => state.MultichainBalancesController,\n (state: RootState) => state.TokensController,\n (state: RootState) => state.CurrencyRateController,\n ],\n (\n accountTreeState,\n accountsState,\n tokenBalancesState,\n tokenRatesState,\n multichainRatesState,\n multichainBalancesState,\n tokensState,\n currencyRateState,\n ): WalletBalance => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const wallet = (accountTreeState.accountTree.wallets as any)[walletId];\n if (!wallet) {\n return {\n walletId,\n groups: {},\n totalBalanceInUserCurrency: 0,\n userCurrency: currencyRateState.currentCurrency,\n };\n }\n\n const groupBalances: Record<string, AccountGroupBalance> = {};\n let totalBalanceInUserCurrency = 0;\n\n const groups = Object.keys(wallet.groups || {}) as string[];\n\n for (const groupId of groups) {\n const groupBalance = selectBalanceByAccountGroup(groupId)({\n AccountTreeController: accountTreeState,\n AccountsController: accountsState,\n TokenBalancesController: tokenBalancesState,\n TokenRatesController: tokenRatesState,\n MultichainAssetsRatesController: multichainRatesState,\n MultichainBalancesController: multichainBalancesState,\n TokensController: tokensState,\n CurrencyRateController: currencyRateState,\n });\n\n groupBalances[groupId] = groupBalance;\n totalBalanceInUserCurrency += groupBalance.totalBalanceInUserCurrency;\n }\n\n return {\n walletId,\n groups: groupBalances,\n totalBalanceInUserCurrency,\n userCurrency: currencyRateState.currentCurrency,\n };\n },\n );\n\n/**\n * Selector to get aggregated balances for all wallets and their account groups.\n * Returns total balance in user's selected currency, aggregating all tokens across all wallets.\n *\n * @returns Aggregated balance for all wallets\n */\nexport const selectBalanceForAllWallets = () =>\n createSelector(\n [\n (state: RootState) => state.AccountTreeController,\n (state: RootState) => state.AccountsController,\n (state: RootState) => state.TokenBalancesController,\n (state: RootState) => state.TokenRatesController,\n (state: RootState) => state.MultichainAssetsRatesController,\n (state: RootState) => state.MultichainBalancesController,\n (state: RootState) => state.TokensController,\n (state: RootState) => state.CurrencyRateController,\n ],\n (\n accountTreeState,\n accountsState,\n tokenBalancesState,\n tokenRatesState,\n multichainRatesState,\n multichainBalancesState,\n tokensState,\n currencyRateState,\n ): AllWalletsBalance => {\n const walletBalances: Record<string, WalletBalance> = {};\n let totalBalanceInUserCurrency = 0;\n\n const walletIds = Object.keys(\n accountTreeState.accountTree.wallets,\n ) as string[];\n\n for (const walletId of walletIds) {\n const walletBalance = selectBalanceByWallet(walletId)({\n AccountTreeController: accountTreeState,\n AccountsController: accountsState,\n TokenBalancesController: tokenBalancesState,\n TokenRatesController: tokenRatesState,\n MultichainAssetsRatesController: multichainRatesState,\n MultichainBalancesController: multichainBalancesState,\n TokensController: tokensState,\n CurrencyRateController: currencyRateState,\n });\n\n walletBalances[walletId] = walletBalance;\n totalBalanceInUserCurrency += walletBalance.totalBalanceInUserCurrency;\n }\n\n return {\n wallets: walletBalances,\n totalBalanceInUserCurrency,\n userCurrency: currencyRateState.currentCurrency,\n };\n },\n );\n\n/**\n * Selector to get aggregated balances for the currently selected account group.\n * Returns total balance in user's selected currency, aggregating all tokens in the selected group.\n *\n * @returns Aggregated balance for the currently selected group\n */\nexport const selectBalanceForSelectedAccountGroup = () =>\n createSelector(\n [\n (state: RootState) => state.AccountTreeController,\n (state: RootState) => state.AccountsController,\n (state: RootState) => state.TokenBalancesController,\n (state: RootState) => state.TokenRatesController,\n (state: RootState) => state.MultichainAssetsRatesController,\n (state: RootState) => state.MultichainBalancesController,\n (state: RootState) => state.TokensController,\n (state: RootState) => state.CurrencyRateController,\n ],\n (\n accountTreeState,\n accountsState,\n tokenBalancesState,\n tokenRatesState,\n multichainRatesState,\n multichainBalancesState,\n tokensState,\n currencyRateState,\n ): AccountGroupBalance | null => {\n const selectedGroupId = accountTreeState.accountTree.selectedAccountGroup;\n\n if (!selectedGroupId) {\n return null;\n }\n\n // Validate group ID format\n const parts = selectedGroupId.split('/');\n if (parts.length !== 2) {\n return null;\n }\n\n return selectBalanceByAccountGroup(selectedGroupId)({\n AccountTreeController: accountTreeState,\n AccountsController: accountsState,\n TokenBalancesController: tokenBalancesState,\n TokenRatesController: tokenRatesState,\n MultichainAssetsRatesController: multichainRatesState,\n MultichainBalancesController: multichainBalancesState,\n TokensController: tokensState,\n CurrencyRateController: currencyRateState,\n });\n },\n );\n\n/**\n * Collection of balance-related selectors for assets controllers\n */\nexport const balanceSelectors = {\n selectBalanceByAccountGroup,\n selectBalanceByWallet,\n selectBalanceForAllWallets,\n selectBalanceForSelectedAccountGroup,\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controllers",
|
|
3
|
-
"version": "73.0.1-preview-
|
|
3
|
+
"version": "73.0.1-preview-e4e5ca5c",
|
|
4
4
|
"description": "Controllers which manage interactions involving ERC-20, ERC-721, and ERC-1155 tokens (including NFTs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MetaMask",
|
|
@@ -73,11 +73,14 @@
|
|
|
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",
|
|
82
|
+
"@metamask/account-api": "^0.7.0",
|
|
83
|
+
"@metamask/account-tree-controller": "^0.7.0",
|
|
81
84
|
"@metamask/accounts-controller": "^32.0.1",
|
|
82
85
|
"@metamask/approval-controller": "^7.1.3",
|
|
83
86
|
"@metamask/auto-changelog": "^3.4.4",
|
|
@@ -91,7 +94,7 @@
|
|
|
91
94
|
"@metamask/preferences-controller": "^18.4.1",
|
|
92
95
|
"@metamask/providers": "^22.1.0",
|
|
93
96
|
"@metamask/snaps-controllers": "^14.0.1",
|
|
94
|
-
"@metamask/transaction-controller": "^59.
|
|
97
|
+
"@metamask/transaction-controller": "^59.1.0",
|
|
95
98
|
"@types/jest": "^27.4.1",
|
|
96
99
|
"@types/lodash": "^4.14.191",
|
|
97
100
|
"@types/node": "^16.18.54",
|
|
@@ -99,7 +102,6 @@
|
|
|
99
102
|
"jest": "^27.5.1",
|
|
100
103
|
"jest-environment-jsdom": "^27.5.1",
|
|
101
104
|
"nock": "^13.3.1",
|
|
102
|
-
"reselect": "^5.1.1",
|
|
103
105
|
"sinon": "^9.2.4",
|
|
104
106
|
"ts-jest": "^27.1.4",
|
|
105
107
|
"typedoc": "^0.24.8",
|
|
@@ -108,6 +110,7 @@
|
|
|
108
110
|
"webextension-polyfill": "^0.12.0"
|
|
109
111
|
},
|
|
110
112
|
"peerDependencies": {
|
|
113
|
+
"@metamask/account-tree-controller": "^0.7.0",
|
|
111
114
|
"@metamask/accounts-controller": "^32.0.0",
|
|
112
115
|
"@metamask/approval-controller": "^7.0.0",
|
|
113
116
|
"@metamask/keyring-controller": "^22.0.0",
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
-
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");
|
|
6
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
-
};
|
|
8
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
-
};
|
|
13
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
-
};
|
|
16
|
-
var _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_fetchBalances;
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.AccountsApiBalanceFetcher = void 0;
|
|
19
|
-
const controller_utils_1 = require("@metamask/controller-utils");
|
|
20
|
-
const bn_js_1 = __importDefault(require("bn.js"));
|
|
21
|
-
const multi_chain_accounts_1 = require("./multi-chain-accounts.cjs");
|
|
22
|
-
const assetsUtil_1 = require("../assetsUtil.cjs");
|
|
23
|
-
const constants_1 = require("../constants.cjs");
|
|
24
|
-
// Maximum number of account addresses that can be sent to the accounts API in a single request
|
|
25
|
-
const ACCOUNTS_API_BATCH_SIZE = 50;
|
|
26
|
-
const checksum = (addr) => (0, controller_utils_1.toChecksumHexAddress)(addr);
|
|
27
|
-
const toCaipAccount = (chainId, account) => (0, assetsUtil_1.accountAddressToCaipReference)(chainId, account);
|
|
28
|
-
class AccountsApiBalanceFetcher {
|
|
29
|
-
constructor(platform = 'extension') {
|
|
30
|
-
_AccountsApiBalanceFetcher_instances.add(this);
|
|
31
|
-
_AccountsApiBalanceFetcher_platform.set(this, 'extension');
|
|
32
|
-
__classPrivateFieldSet(this, _AccountsApiBalanceFetcher_platform, platform, "f");
|
|
33
|
-
}
|
|
34
|
-
supports(chainId) {
|
|
35
|
-
return constants_1.SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);
|
|
36
|
-
}
|
|
37
|
-
async fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }) {
|
|
38
|
-
const caipAddrs = [];
|
|
39
|
-
for (const chainId of chainIds.filter((c) => this.supports(c))) {
|
|
40
|
-
if (queryAllAccounts) {
|
|
41
|
-
allAccounts.forEach((a) => caipAddrs.push(toCaipAccount(chainId, a.address)));
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
caipAddrs.push(toCaipAccount(chainId, selectedAccount));
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (!caipAddrs.length) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
const balances = await (0, controller_utils_1.safelyExecute)(() => __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_instances, "m", _AccountsApiBalanceFetcher_fetchBalances).call(this, caipAddrs));
|
|
51
|
-
if (!balances) {
|
|
52
|
-
return [];
|
|
53
|
-
}
|
|
54
|
-
return balances.flatMap((b) => {
|
|
55
|
-
const account = b.accountAddress?.split(':')[2];
|
|
56
|
-
if (!account) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
const token = checksum(b.address);
|
|
60
|
-
const chainId = (0, controller_utils_1.toHex)(b.chainId);
|
|
61
|
-
let value;
|
|
62
|
-
try {
|
|
63
|
-
value = new bn_js_1.default((parseFloat(b.balance) * 10 ** b.decimals).toFixed(0));
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
value = undefined;
|
|
67
|
-
}
|
|
68
|
-
return [
|
|
69
|
-
{
|
|
70
|
-
success: value !== undefined,
|
|
71
|
-
value,
|
|
72
|
-
account,
|
|
73
|
-
token,
|
|
74
|
-
chainId,
|
|
75
|
-
},
|
|
76
|
-
];
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
exports.AccountsApiBalanceFetcher = AccountsApiBalanceFetcher;
|
|
81
|
-
_AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchBalances = async function _AccountsApiBalanceFetcher_fetchBalances(addrs) {
|
|
82
|
-
// If we have fewer than or equal to the batch size, make a single request
|
|
83
|
-
if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {
|
|
84
|
-
const { balances } = await (0, multi_chain_accounts_1.fetchMultiChainBalancesV4)({ accountAddresses: addrs }, __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_platform, "f"));
|
|
85
|
-
return balances;
|
|
86
|
-
}
|
|
87
|
-
const allBalances = await (0, assetsUtil_1.reduceInBatchesSerially)({
|
|
88
|
-
values: addrs,
|
|
89
|
-
batchSize: ACCOUNTS_API_BATCH_SIZE,
|
|
90
|
-
eachBatch: async (workingResult, batch) => {
|
|
91
|
-
const { balances } = await (0, multi_chain_accounts_1.fetchMultiChainBalancesV4)({ accountAddresses: batch }, __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_platform, "f"));
|
|
92
|
-
return [...(workingResult || []), ...balances];
|
|
93
|
-
},
|
|
94
|
-
initialResult: [],
|
|
95
|
-
});
|
|
96
|
-
return allBalances;
|
|
97
|
-
};
|
|
98
|
-
//# sourceMappingURL=api-balance-fetcher.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.cjs","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n safelyExecute,\n toHex,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipAccountAddress, Hex } from '@metamask/utils';\nimport BN from 'bn.js';\n\nimport { fetchMultiChainBalancesV4 } from './multi-chain-accounts';\nimport {\n accountAddressToCaipReference,\n reduceInBatchesSerially,\n} from '../assetsUtil';\nimport { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from '../constants';\n\n// Maximum number of account addresses that can be sent to the accounts API in a single request\nconst ACCOUNTS_API_BATCH_SIZE = 50;\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 checksum = (addr: string): ChecksumAddress =>\n toChecksumHexAddress(addr) as ChecksumAddress;\n\nconst toCaipAccount = (\n chainId: ChainIdHex,\n account: ChecksumAddress,\n): CaipAccountAddress => accountAddressToCaipReference(chainId, account);\n\nexport class AccountsApiBalanceFetcher implements BalanceFetcher {\n readonly #platform: 'extension' | 'mobile' = 'extension';\n\n constructor(platform: 'extension' | 'mobile' = 'extension') {\n this.#platform = platform;\n }\n\n supports(chainId: ChainIdHex): boolean {\n return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);\n }\n\n async #fetchBalances(addrs: CaipAccountAddress[]) {\n // If we have fewer than or equal to the batch size, make a single request\n if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: addrs },\n this.#platform,\n );\n return balances;\n }\n\n // Otherwise, batch the requests to respect the 50-element limit\n type BalanceData = Awaited<\n ReturnType<typeof fetchMultiChainBalancesV4>\n >['balances'][number];\n\n const allBalances = await reduceInBatchesSerially<\n CaipAccountAddress,\n BalanceData[]\n >({\n values: addrs,\n batchSize: ACCOUNTS_API_BATCH_SIZE,\n eachBatch: async (workingResult, batch) => {\n const { balances } = await fetchMultiChainBalancesV4(\n { accountAddresses: batch },\n this.#platform,\n );\n return [...(workingResult || []), ...balances];\n },\n initialResult: [],\n });\n\n return allBalances;\n }\n\n async fetch({\n chainIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]> {\n const caipAddrs: CaipAccountAddress[] = [];\n\n for (const chainId of chainIds.filter((c) => this.supports(c))) {\n if (queryAllAccounts) {\n allAccounts.forEach((a) =>\n caipAddrs.push(toCaipAccount(chainId, a.address as ChecksumAddress)),\n );\n } else {\n caipAddrs.push(toCaipAccount(chainId, selectedAccount));\n }\n }\n\n if (!caipAddrs.length) {\n return [];\n }\n\n const balances = await safelyExecute(() => this.#fetchBalances(caipAddrs));\n if (!balances) {\n return [];\n }\n\n return balances.flatMap((b) => {\n const account = b.accountAddress?.split(':')[2] as ChecksumAddress;\n if (!account) {\n return [];\n }\n const token = checksum(b.address);\n const chainId = toHex(b.chainId) as ChainIdHex;\n\n let value: BN | undefined;\n try {\n value = new BN((parseFloat(b.balance) * 10 ** b.decimals).toFixed(0));\n } catch {\n value = undefined;\n }\n\n return [\n {\n success: value !== undefined,\n value,\n account,\n token,\n chainId,\n },\n ];\n });\n }\n}\n"]}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
2
|
-
import type { Hex } from "@metamask/utils";
|
|
3
|
-
import BN from "bn.js";
|
|
4
|
-
export type ChainIdHex = Hex;
|
|
5
|
-
export type ChecksumAddress = Hex;
|
|
6
|
-
export type ProcessedBalance = {
|
|
7
|
-
success: boolean;
|
|
8
|
-
value?: BN;
|
|
9
|
-
account: ChecksumAddress;
|
|
10
|
-
token: ChecksumAddress;
|
|
11
|
-
chainId: ChainIdHex;
|
|
12
|
-
};
|
|
13
|
-
export type BalanceFetcher = {
|
|
14
|
-
supports(chainId: ChainIdHex): boolean;
|
|
15
|
-
fetch(input: {
|
|
16
|
-
chainIds: ChainIdHex[];
|
|
17
|
-
queryAllAccounts: boolean;
|
|
18
|
-
selectedAccount: ChecksumAddress;
|
|
19
|
-
allAccounts: InternalAccount[];
|
|
20
|
-
}): Promise<ProcessedBalance[]>;
|
|
21
|
-
};
|
|
22
|
-
export declare class AccountsApiBalanceFetcher implements BalanceFetcher {
|
|
23
|
-
#private;
|
|
24
|
-
constructor(platform?: 'extension' | 'mobile');
|
|
25
|
-
supports(chainId: ChainIdHex): boolean;
|
|
26
|
-
fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]>;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=api-balance-fetcher.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.d.cts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAYvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;KAChC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CACjC,CAAC;AAUF,qBAAa,yBAA0B,YAAW,cAAc;;gBAGlD,QAAQ,GAAE,WAAW,GAAG,QAAsB;IAI1D,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAsChC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAgDxE"}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { InternalAccount } from "@metamask/keyring-internal-api";
|
|
2
|
-
import type { Hex } from "@metamask/utils";
|
|
3
|
-
import BN from "bn.js";
|
|
4
|
-
export type ChainIdHex = Hex;
|
|
5
|
-
export type ChecksumAddress = Hex;
|
|
6
|
-
export type ProcessedBalance = {
|
|
7
|
-
success: boolean;
|
|
8
|
-
value?: BN;
|
|
9
|
-
account: ChecksumAddress;
|
|
10
|
-
token: ChecksumAddress;
|
|
11
|
-
chainId: ChainIdHex;
|
|
12
|
-
};
|
|
13
|
-
export type BalanceFetcher = {
|
|
14
|
-
supports(chainId: ChainIdHex): boolean;
|
|
15
|
-
fetch(input: {
|
|
16
|
-
chainIds: ChainIdHex[];
|
|
17
|
-
queryAllAccounts: boolean;
|
|
18
|
-
selectedAccount: ChecksumAddress;
|
|
19
|
-
allAccounts: InternalAccount[];
|
|
20
|
-
}): Promise<ProcessedBalance[]>;
|
|
21
|
-
};
|
|
22
|
-
export declare class AccountsApiBalanceFetcher implements BalanceFetcher {
|
|
23
|
-
#private;
|
|
24
|
-
constructor(platform?: 'extension' | 'mobile');
|
|
25
|
-
supports(chainId: ChainIdHex): boolean;
|
|
26
|
-
fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }: Parameters<BalanceFetcher['fetch']>[0]): Promise<ProcessedBalance[]>;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=api-balance-fetcher.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"api-balance-fetcher.d.mts","sourceRoot":"","sources":["../../src/multi-chain-accounts-service/api-balance-fetcher.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAsB,GAAG,EAAE,wBAAwB;AAC/D,OAAO,EAAE,cAAc;AAYvB,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC;AAC7B,MAAM,MAAM,eAAe,GAAG,GAAG,CAAC;AAElC,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,EAAE,CAAC;IACX,OAAO,EAAE,eAAe,CAAC;IACzB,KAAK,EAAE,eAAe,CAAC;IACvB,OAAO,EAAE,UAAU,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvC,KAAK,CAAC,KAAK,EAAE;QACX,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,gBAAgB,EAAE,OAAO,CAAC;QAC1B,eAAe,EAAE,eAAe,CAAC;QACjC,WAAW,EAAE,eAAe,EAAE,CAAC;KAChC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;CACjC,CAAC;AAUF,qBAAa,yBAA0B,YAAW,cAAc;;gBAGlD,QAAQ,GAAE,WAAW,GAAG,QAAsB;IAI1D,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO;IAsChC,KAAK,CAAC,EACV,QAAQ,EACR,gBAAgB,EAChB,eAAe,EACf,WAAW,GACZ,EAAE,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAgDxE"}
|
|
@@ -1,98 +0,0 @@
|
|
|
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 _AccountsApiBalanceFetcher_instances, _AccountsApiBalanceFetcher_platform, _AccountsApiBalanceFetcher_fetchBalances;
|
|
13
|
-
function $importDefault(module) {
|
|
14
|
-
if (module?.__esModule) {
|
|
15
|
-
return module.default;
|
|
16
|
-
}
|
|
17
|
-
return module;
|
|
18
|
-
}
|
|
19
|
-
import { safelyExecute, toHex, toChecksumHexAddress } from "@metamask/controller-utils";
|
|
20
|
-
import $BN from "bn.js";
|
|
21
|
-
const BN = $importDefault($BN);
|
|
22
|
-
import { fetchMultiChainBalancesV4 } from "./multi-chain-accounts.mjs";
|
|
23
|
-
import { accountAddressToCaipReference, reduceInBatchesSerially } from "../assetsUtil.mjs";
|
|
24
|
-
import { SUPPORTED_NETWORKS_ACCOUNTS_API_V4 } from "../constants.mjs";
|
|
25
|
-
// Maximum number of account addresses that can be sent to the accounts API in a single request
|
|
26
|
-
const ACCOUNTS_API_BATCH_SIZE = 50;
|
|
27
|
-
const checksum = (addr) => toChecksumHexAddress(addr);
|
|
28
|
-
const toCaipAccount = (chainId, account) => accountAddressToCaipReference(chainId, account);
|
|
29
|
-
export class AccountsApiBalanceFetcher {
|
|
30
|
-
constructor(platform = 'extension') {
|
|
31
|
-
_AccountsApiBalanceFetcher_instances.add(this);
|
|
32
|
-
_AccountsApiBalanceFetcher_platform.set(this, 'extension');
|
|
33
|
-
__classPrivateFieldSet(this, _AccountsApiBalanceFetcher_platform, platform, "f");
|
|
34
|
-
}
|
|
35
|
-
supports(chainId) {
|
|
36
|
-
return SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId);
|
|
37
|
-
}
|
|
38
|
-
async fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }) {
|
|
39
|
-
const caipAddrs = [];
|
|
40
|
-
for (const chainId of chainIds.filter((c) => this.supports(c))) {
|
|
41
|
-
if (queryAllAccounts) {
|
|
42
|
-
allAccounts.forEach((a) => caipAddrs.push(toCaipAccount(chainId, a.address)));
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
caipAddrs.push(toCaipAccount(chainId, selectedAccount));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
if (!caipAddrs.length) {
|
|
49
|
-
return [];
|
|
50
|
-
}
|
|
51
|
-
const balances = await safelyExecute(() => __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_instances, "m", _AccountsApiBalanceFetcher_fetchBalances).call(this, caipAddrs));
|
|
52
|
-
if (!balances) {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
return balances.flatMap((b) => {
|
|
56
|
-
const account = b.accountAddress?.split(':')[2];
|
|
57
|
-
if (!account) {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
const token = checksum(b.address);
|
|
61
|
-
const chainId = toHex(b.chainId);
|
|
62
|
-
let value;
|
|
63
|
-
try {
|
|
64
|
-
value = new BN((parseFloat(b.balance) * 10 ** b.decimals).toFixed(0));
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
value = undefined;
|
|
68
|
-
}
|
|
69
|
-
return [
|
|
70
|
-
{
|
|
71
|
-
success: value !== undefined,
|
|
72
|
-
value,
|
|
73
|
-
account,
|
|
74
|
-
token,
|
|
75
|
-
chainId,
|
|
76
|
-
},
|
|
77
|
-
];
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
_AccountsApiBalanceFetcher_platform = new WeakMap(), _AccountsApiBalanceFetcher_instances = new WeakSet(), _AccountsApiBalanceFetcher_fetchBalances = async function _AccountsApiBalanceFetcher_fetchBalances(addrs) {
|
|
82
|
-
// If we have fewer than or equal to the batch size, make a single request
|
|
83
|
-
if (addrs.length <= ACCOUNTS_API_BATCH_SIZE) {
|
|
84
|
-
const { balances } = await fetchMultiChainBalancesV4({ accountAddresses: addrs }, __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_platform, "f"));
|
|
85
|
-
return balances;
|
|
86
|
-
}
|
|
87
|
-
const allBalances = await reduceInBatchesSerially({
|
|
88
|
-
values: addrs,
|
|
89
|
-
batchSize: ACCOUNTS_API_BATCH_SIZE,
|
|
90
|
-
eachBatch: async (workingResult, batch) => {
|
|
91
|
-
const { balances } = await fetchMultiChainBalancesV4({ accountAddresses: batch }, __classPrivateFieldGet(this, _AccountsApiBalanceFetcher_platform, "f"));
|
|
92
|
-
return [...(workingResult || []), ...balances];
|
|
93
|
-
},
|
|
94
|
-
initialResult: [],
|
|
95
|
-
});
|
|
96
|
-
return allBalances;
|
|
97
|
-
};
|
|
98
|
-
//# sourceMappingURL=api-balance-fetcher.mjs.map
|