@metamask-previews/assets-controllers 73.0.2-preview-115d10e → 73.0.2-preview-b31794c
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/dist/selectors/balanceSelectors.cjs +147 -176
- package/dist/selectors/balanceSelectors.cjs.map +1 -1
- package/dist/selectors/balanceSelectors.d.cts +758 -597
- package/dist/selectors/balanceSelectors.d.cts.map +1 -1
- package/dist/selectors/balanceSelectors.d.mts +758 -597
- package/dist/selectors/balanceSelectors.d.mts.map +1 -1
- package/dist/selectors/balanceSelectors.mjs +145 -174
- package/dist/selectors/balanceSelectors.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.balanceSelectors = exports.selectBalanceForSelectedAccountGroup = exports.
|
|
3
|
+
exports.balanceSelectors = exports.selectBalanceForSelectedAccountGroup = exports.selectBalanceByWallet = exports.selectBalanceByAccountGroup = exports.selectBalanceForAllWallets = void 0;
|
|
4
4
|
const keyring_api_1 = require("@metamask/keyring-api");
|
|
5
5
|
const reselect_1 = require("reselect");
|
|
6
6
|
/**
|
|
@@ -116,13 +116,13 @@ const getInternalAccountsForGroup = (accountTreeState, accountsState, groupId) =
|
|
|
116
116
|
.filter(Boolean);
|
|
117
117
|
};
|
|
118
118
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
119
|
+
* Comprehensive selector that calculates all balances for all wallets and groups.
|
|
120
|
+
* This is the single source of truth for all balance calculations.
|
|
121
|
+
* Other selectors will derive from this to ensure proper memoization.
|
|
121
122
|
*
|
|
122
|
-
* @
|
|
123
|
-
* @returns Aggregated balance for the account group
|
|
123
|
+
* @returns Aggregated balance for all wallets
|
|
124
124
|
*/
|
|
125
|
-
const
|
|
125
|
+
const selectBalanceForAllWallets = () => (0, reselect_1.createSelector)([
|
|
126
126
|
selectAccountTreeControllerState,
|
|
127
127
|
selectAccountsControllerState,
|
|
128
128
|
selectTokenBalancesControllerState,
|
|
@@ -132,217 +132,188 @@ const selectBalanceByAccountGroup = (groupId) => (0, reselect_1.createSelector)(
|
|
|
132
132
|
selectTokensControllerState,
|
|
133
133
|
selectCurrencyRateControllerState,
|
|
134
134
|
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
135
|
-
|
|
136
|
-
const walletId = groupId.split('/')[0];
|
|
137
|
-
const accounts = getInternalAccountsForGroup(accountTreeState, accountsState, groupId);
|
|
138
|
-
if (accounts.length === 0) {
|
|
139
|
-
return {
|
|
140
|
-
walletId,
|
|
141
|
-
groupId,
|
|
142
|
-
totalBalanceInUserCurrency: 0,
|
|
143
|
-
userCurrency: currencyRateState.currentCurrency,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
135
|
+
const walletBalances = {};
|
|
146
136
|
let totalBalanceInUserCurrency = 0;
|
|
147
|
-
|
|
148
|
-
for (const
|
|
149
|
-
const
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
137
|
+
const walletIds = Object.keys(accountTreeState.accountTree.wallets);
|
|
138
|
+
for (const walletId of walletIds) {
|
|
139
|
+
const wallet = accountTreeState.accountTree.wallets[walletId];
|
|
140
|
+
if (!wallet) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const groupBalances = {};
|
|
144
|
+
let walletTotalBalance = 0;
|
|
145
|
+
const groups = Object.keys(wallet.groups || {});
|
|
146
|
+
for (const groupId of groups) {
|
|
147
|
+
const accounts = getInternalAccountsForGroup(accountTreeState, accountsState, groupId);
|
|
148
|
+
if (accounts.length === 0) {
|
|
149
|
+
groupBalances[groupId] = {
|
|
150
|
+
walletId,
|
|
151
|
+
groupId,
|
|
152
|
+
totalBalanceInUserCurrency: 0,
|
|
153
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
154
|
+
};
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
let groupTotalBalance = 0;
|
|
158
|
+
// Process each account's balances
|
|
159
|
+
for (const account of accounts) {
|
|
160
|
+
const isEvmAccount = (0, keyring_api_1.isEvmAccountType)(account.type);
|
|
161
|
+
if (isEvmAccount) {
|
|
162
|
+
// Handle EVM account balances from TokenBalancesController
|
|
163
|
+
const accountBalances = tokenBalancesState.tokenBalances[account.address];
|
|
164
|
+
if (accountBalances) {
|
|
165
|
+
for (const [chainId, chainBalances] of Object.entries(accountBalances)) {
|
|
166
|
+
for (const [tokenAddress, balance] of Object.entries(chainBalances)) {
|
|
167
|
+
// Find token in TokensController state
|
|
168
|
+
const chainTokens = tokensState.allTokens[chainId];
|
|
169
|
+
const accountTokens = chainTokens?.[account.address];
|
|
170
|
+
const token = accountTokens?.find((t) => t.address === tokenAddress);
|
|
171
|
+
if (!token) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
// Use nullish coalescing to handle 0 decimals correctly
|
|
175
|
+
// and ensure decimals is a valid number to prevent NaN propagation
|
|
176
|
+
const decimals = typeof token.decimals === 'number' &&
|
|
177
|
+
!Number.isNaN(token.decimals)
|
|
178
|
+
? token.decimals
|
|
179
|
+
: 18;
|
|
180
|
+
const balanceInSmallestUnit = parseInt(balance, 16);
|
|
181
|
+
// Skip invalid balance values to prevent NaN propagation
|
|
182
|
+
if (Number.isNaN(balanceInSmallestUnit)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const balanceInTokenUnits = balanceInSmallestUnit / Math.pow(10, decimals);
|
|
186
|
+
// Get token rate in native currency from TokenRatesController
|
|
187
|
+
const chainMarketData = tokenRatesState.marketData[chainId];
|
|
188
|
+
const tokenMarketData = chainMarketData?.[tokenAddress];
|
|
189
|
+
if (tokenMarketData?.price) {
|
|
190
|
+
// Convert token price to user currency using native currency conversion rate
|
|
191
|
+
const nativeCurrency = tokenMarketData.currency;
|
|
192
|
+
const nativeToUserRate = currencyRateState.currencyRates[nativeCurrency]
|
|
193
|
+
?.conversionRate;
|
|
194
|
+
if (nativeToUserRate) {
|
|
195
|
+
// Convert token price to user currency: tokenPrice * nativeToUserRate
|
|
196
|
+
const tokenPriceInUserCurrency = tokenMarketData.price * nativeToUserRate;
|
|
197
|
+
const balanceInUserCurrency = balanceInTokenUnits * tokenPriceInUserCurrency;
|
|
198
|
+
groupTotalBalance += balanceInUserCurrency;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
184
201
|
}
|
|
185
202
|
}
|
|
186
203
|
}
|
|
187
204
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
205
|
+
else {
|
|
206
|
+
// Handle non-EVM account balances from MultichainBalancesController
|
|
207
|
+
const accountBalances = multichainBalancesState.balances[account.id];
|
|
208
|
+
if (accountBalances) {
|
|
209
|
+
for (const [assetId, balanceData] of Object.entries(accountBalances)) {
|
|
210
|
+
const balanceAmount = parseFloat(balanceData.amount);
|
|
211
|
+
// Skip invalid balance values to prevent NaN propagation
|
|
212
|
+
if (Number.isNaN(balanceAmount)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
// Get conversion rate for this asset (already in user currency)
|
|
216
|
+
const conversionRate = multichainRatesState.conversionRates[assetId];
|
|
217
|
+
if (conversionRate) {
|
|
218
|
+
const conversionRateValue = parseFloat(conversionRate.rate);
|
|
219
|
+
// Skip invalid conversion rate values to prevent NaN propagation
|
|
220
|
+
if (Number.isNaN(conversionRateValue)) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
// MultichainAssetsRatesController already provides rates in user currency
|
|
224
|
+
const balanceInUserCurrency = balanceAmount * conversionRateValue;
|
|
225
|
+
groupTotalBalance += balanceInUserCurrency;
|
|
226
|
+
}
|
|
207
227
|
}
|
|
208
|
-
// MultichainAssetsRatesController already provides rates in user currency
|
|
209
|
-
const balanceInUserCurrency = balanceAmount * conversionRateValue;
|
|
210
|
-
totalBalanceInUserCurrency += balanceInUserCurrency;
|
|
211
228
|
}
|
|
212
229
|
}
|
|
213
230
|
}
|
|
231
|
+
groupBalances[groupId] = {
|
|
232
|
+
walletId,
|
|
233
|
+
groupId,
|
|
234
|
+
totalBalanceInUserCurrency: groupTotalBalance,
|
|
235
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
236
|
+
};
|
|
237
|
+
walletTotalBalance += groupTotalBalance;
|
|
214
238
|
}
|
|
239
|
+
walletBalances[walletId] = {
|
|
240
|
+
walletId,
|
|
241
|
+
groups: groupBalances,
|
|
242
|
+
totalBalanceInUserCurrency: walletTotalBalance,
|
|
243
|
+
userCurrency: currencyRateState.currentCurrency,
|
|
244
|
+
};
|
|
245
|
+
totalBalanceInUserCurrency += walletTotalBalance;
|
|
215
246
|
}
|
|
216
247
|
return {
|
|
217
|
-
|
|
218
|
-
groupId,
|
|
248
|
+
wallets: walletBalances,
|
|
219
249
|
totalBalanceInUserCurrency,
|
|
220
250
|
userCurrency: currencyRateState.currentCurrency,
|
|
221
251
|
};
|
|
222
252
|
});
|
|
253
|
+
exports.selectBalanceForAllWallets = selectBalanceForAllWallets;
|
|
254
|
+
/**
|
|
255
|
+
* Selector to get aggregated balances for a specific account group.
|
|
256
|
+
* Derives from the comprehensive selector to ensure proper memoization.
|
|
257
|
+
*
|
|
258
|
+
* @param groupId - The account group ID (format: "walletId/groupIndex", e.g., "entropy:entropy-source-1/0")
|
|
259
|
+
* @returns Aggregated balance for the account group
|
|
260
|
+
*/
|
|
261
|
+
const selectBalanceByAccountGroup = (groupId) => (0, reselect_1.createSelector)([(0, exports.selectBalanceForAllWallets)()], (allBalances) => {
|
|
262
|
+
const walletId = groupId.split('/')[0];
|
|
263
|
+
const wallet = allBalances.wallets[walletId];
|
|
264
|
+
if (!wallet || !wallet.groups[groupId]) {
|
|
265
|
+
return {
|
|
266
|
+
walletId,
|
|
267
|
+
groupId,
|
|
268
|
+
totalBalanceInUserCurrency: 0,
|
|
269
|
+
userCurrency: allBalances.userCurrency,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
return wallet.groups[groupId];
|
|
273
|
+
});
|
|
223
274
|
exports.selectBalanceByAccountGroup = selectBalanceByAccountGroup;
|
|
224
275
|
/**
|
|
225
276
|
* Selector to get aggregated balances for all account groups in a wallet.
|
|
226
|
-
*
|
|
277
|
+
* Derives from the comprehensive selector to ensure proper memoization.
|
|
227
278
|
*
|
|
228
279
|
* @param walletId - The wallet ID (entropy source)
|
|
229
280
|
* @returns Aggregated balance for all groups in the wallet
|
|
230
281
|
*/
|
|
231
|
-
const selectBalanceByWallet = (walletId) => (0, reselect_1.createSelector)([
|
|
232
|
-
|
|
233
|
-
selectAccountsControllerState,
|
|
234
|
-
selectTokenBalancesControllerState,
|
|
235
|
-
selectTokenRatesControllerState,
|
|
236
|
-
selectMultichainAssetsRatesControllerState,
|
|
237
|
-
selectMultichainBalancesControllerState,
|
|
238
|
-
selectTokensControllerState,
|
|
239
|
-
selectCurrencyRateControllerState,
|
|
240
|
-
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
241
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
242
|
-
const wallet = accountTreeState.accountTree.wallets[walletId];
|
|
282
|
+
const selectBalanceByWallet = (walletId) => (0, reselect_1.createSelector)([(0, exports.selectBalanceForAllWallets)()], (allBalances) => {
|
|
283
|
+
const wallet = allBalances.wallets[walletId];
|
|
243
284
|
if (!wallet) {
|
|
244
285
|
return {
|
|
245
286
|
walletId,
|
|
246
287
|
groups: {},
|
|
247
288
|
totalBalanceInUserCurrency: 0,
|
|
248
|
-
userCurrency:
|
|
289
|
+
userCurrency: allBalances.userCurrency,
|
|
249
290
|
};
|
|
250
291
|
}
|
|
251
|
-
|
|
252
|
-
let totalBalanceInUserCurrency = 0;
|
|
253
|
-
const groups = Object.keys(wallet.groups || {});
|
|
254
|
-
for (const groupId of groups) {
|
|
255
|
-
const groupBalance = (0, exports.selectBalanceByAccountGroup)(groupId)({
|
|
256
|
-
AccountTreeController: accountTreeState,
|
|
257
|
-
AccountsController: accountsState,
|
|
258
|
-
TokenBalancesController: tokenBalancesState,
|
|
259
|
-
TokenRatesController: tokenRatesState,
|
|
260
|
-
MultichainAssetsRatesController: multichainRatesState,
|
|
261
|
-
MultichainBalancesController: multichainBalancesState,
|
|
262
|
-
TokensController: tokensState,
|
|
263
|
-
CurrencyRateController: currencyRateState,
|
|
264
|
-
});
|
|
265
|
-
groupBalances[groupId] = groupBalance;
|
|
266
|
-
totalBalanceInUserCurrency += groupBalance.totalBalanceInUserCurrency;
|
|
267
|
-
}
|
|
268
|
-
return {
|
|
269
|
-
walletId,
|
|
270
|
-
groups: groupBalances,
|
|
271
|
-
totalBalanceInUserCurrency,
|
|
272
|
-
userCurrency: currencyRateState.currentCurrency,
|
|
273
|
-
};
|
|
292
|
+
return wallet;
|
|
274
293
|
});
|
|
275
294
|
exports.selectBalanceByWallet = selectBalanceByWallet;
|
|
276
|
-
/**
|
|
277
|
-
* Selector to get aggregated balances for all wallets and their account groups.
|
|
278
|
-
* Returns total balance in user's selected currency, aggregating all tokens across all wallets.
|
|
279
|
-
*
|
|
280
|
-
* @returns Aggregated balance for all wallets
|
|
281
|
-
*/
|
|
282
|
-
const selectBalanceForAllWallets = () => (0, reselect_1.createSelector)([
|
|
283
|
-
selectAccountTreeControllerState,
|
|
284
|
-
selectAccountsControllerState,
|
|
285
|
-
selectTokenBalancesControllerState,
|
|
286
|
-
selectTokenRatesControllerState,
|
|
287
|
-
selectMultichainAssetsRatesControllerState,
|
|
288
|
-
selectMultichainBalancesControllerState,
|
|
289
|
-
selectTokensControllerState,
|
|
290
|
-
selectCurrencyRateControllerState,
|
|
291
|
-
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
292
|
-
const walletBalances = {};
|
|
293
|
-
let totalBalanceInUserCurrency = 0;
|
|
294
|
-
const walletIds = Object.keys(accountTreeState.accountTree.wallets);
|
|
295
|
-
for (const walletId of walletIds) {
|
|
296
|
-
const walletBalance = (0, exports.selectBalanceByWallet)(walletId)({
|
|
297
|
-
AccountTreeController: accountTreeState,
|
|
298
|
-
AccountsController: accountsState,
|
|
299
|
-
TokenBalancesController: tokenBalancesState,
|
|
300
|
-
TokenRatesController: tokenRatesState,
|
|
301
|
-
MultichainAssetsRatesController: multichainRatesState,
|
|
302
|
-
MultichainBalancesController: multichainBalancesState,
|
|
303
|
-
TokensController: tokensState,
|
|
304
|
-
CurrencyRateController: currencyRateState,
|
|
305
|
-
});
|
|
306
|
-
walletBalances[walletId] = walletBalance;
|
|
307
|
-
totalBalanceInUserCurrency += walletBalance.totalBalanceInUserCurrency;
|
|
308
|
-
}
|
|
309
|
-
return {
|
|
310
|
-
wallets: walletBalances,
|
|
311
|
-
totalBalanceInUserCurrency,
|
|
312
|
-
userCurrency: currencyRateState.currentCurrency,
|
|
313
|
-
};
|
|
314
|
-
});
|
|
315
|
-
exports.selectBalanceForAllWallets = selectBalanceForAllWallets;
|
|
316
295
|
/**
|
|
317
296
|
* Selector to get aggregated balances for the currently selected account group.
|
|
318
|
-
*
|
|
297
|
+
* Derives from the comprehensive selector to ensure proper memoization.
|
|
319
298
|
*
|
|
320
299
|
* @returns Aggregated balance for the currently selected group
|
|
321
300
|
*/
|
|
322
|
-
const selectBalanceForSelectedAccountGroup = () => (0, reselect_1.createSelector)([
|
|
323
|
-
selectAccountTreeControllerState,
|
|
324
|
-
selectAccountsControllerState,
|
|
325
|
-
selectTokenBalancesControllerState,
|
|
326
|
-
selectTokenRatesControllerState,
|
|
327
|
-
selectMultichainAssetsRatesControllerState,
|
|
328
|
-
selectMultichainBalancesControllerState,
|
|
329
|
-
selectTokensControllerState,
|
|
330
|
-
selectCurrencyRateControllerState,
|
|
331
|
-
], (accountTreeState, accountsState, tokenBalancesState, tokenRatesState, multichainRatesState, multichainBalancesState, tokensState, currencyRateState) => {
|
|
301
|
+
const selectBalanceForSelectedAccountGroup = () => (0, reselect_1.createSelector)([selectAccountTreeControllerState, (0, exports.selectBalanceForAllWallets)()], (accountTreeState, allBalances) => {
|
|
332
302
|
const selectedGroupId = accountTreeState.accountTree.selectedAccountGroup;
|
|
333
303
|
if (!selectedGroupId) {
|
|
334
304
|
return null;
|
|
335
305
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
306
|
+
const walletId = selectedGroupId.split('/')[0];
|
|
307
|
+
const wallet = allBalances.wallets[walletId];
|
|
308
|
+
if (!wallet || !wallet.groups[selectedGroupId]) {
|
|
309
|
+
return {
|
|
310
|
+
walletId,
|
|
311
|
+
groupId: selectedGroupId,
|
|
312
|
+
totalBalanceInUserCurrency: 0,
|
|
313
|
+
userCurrency: allBalances.userCurrency,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
return wallet.groups[selectedGroupId];
|
|
346
317
|
});
|
|
347
318
|
exports.selectBalanceForSelectedAccountGroup = selectBalanceForSelectedAccountGroup;
|
|
348
319
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balanceSelectors.cjs","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 * Individual controller state selectors using direct state access\n * This avoids new object creation and provides stable references\n * Supports both mobile (state.engine.backgroundState) and extension (state.metamask) structures\n */\n\n/**\n * Helper function to get controller state from different state structures\n *\n * @param state - The application state\n * @param controllerName - The name of the controller\n * @returns The controller state or undefined if not found\n */\n\nconst getControllerState = <T>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n state: any,\n controllerName: string,\n): T => {\n // Mobile structure: state.engine.backgroundState.ControllerName\n if (state?.engine?.backgroundState?.[controllerName]) {\n return state.engine.backgroundState[controllerName];\n }\n\n // Extension structure: state.metamask.ControllerName\n if (state?.metamask?.[controllerName]) {\n return state.metamask[controllerName];\n }\n\n // Flat structure (default assets-controllers structure)\n if (state?.[controllerName]) {\n return state[controllerName];\n }\n\n // Since controllers always have default states, this should never happen\n // but we need to return something for TypeScript\n return state?.[controllerName] as T;\n};\n\n/**\n * Selector for AccountTreeController state using direct state access\n *\n * @param state - The application state\n * @returns AccountTreeController state\n */\nconst selectAccountTreeControllerState = createSelector(\n [(state: unknown) => state],\n (state): AccountTreeControllerState =>\n getControllerState<AccountTreeControllerState>(\n state,\n 'AccountTreeController',\n ),\n);\n\n/**\n * Selector for AccountsController state using direct state access\n *\n * @param state - The application state\n * @returns AccountsController state\n */\nconst selectAccountsControllerState = createSelector(\n [(state: unknown) => state],\n (state): AccountsControllerState =>\n getControllerState<AccountsControllerState>(state, 'AccountsController'),\n);\n\n/**\n * Selector for TokenBalancesController state using direct state access\n *\n * @param state - The application state\n * @returns TokenBalancesController state\n */\nconst selectTokenBalancesControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokenBalancesControllerState =>\n getControllerState<TokenBalancesControllerState>(\n state,\n 'TokenBalancesController',\n ),\n);\n\n/**\n * Selector for TokenRatesController state using direct state access\n *\n * @param state - The application state\n * @returns TokenRatesController state\n */\nconst selectTokenRatesControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokenRatesControllerState =>\n getControllerState<TokenRatesControllerState>(\n state,\n 'TokenRatesController',\n ),\n);\n\n/**\n * Selector for MultichainAssetsRatesController state using direct state access\n *\n * @param state - The application state\n * @returns MultichainAssetsRatesController state\n */\nconst selectMultichainAssetsRatesControllerState = createSelector(\n [(state: unknown) => state],\n (state): MultichainAssetsRatesControllerState =>\n getControllerState<MultichainAssetsRatesControllerState>(\n state,\n 'MultichainAssetsRatesController',\n ),\n);\n\n/**\n * Selector for MultichainBalancesController state using direct state access\n *\n * @param state - The application state\n * @returns MultichainBalancesController state\n */\nconst selectMultichainBalancesControllerState = createSelector(\n [(state: unknown) => state],\n (state): MultichainBalancesControllerState =>\n getControllerState<MultichainBalancesControllerState>(\n state,\n 'MultichainBalancesController',\n ),\n);\n\n/**\n * Selector for TokensController state using direct state access\n *\n * @param state - The application state\n * @returns TokensController state\n */\nconst selectTokensControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokensControllerState =>\n getControllerState<TokensControllerState>(state, 'TokensController'),\n);\n\n/**\n * Selector for CurrencyRateController state using direct state access\n *\n * @param state - The application state\n * @returns CurrencyRateController state\n */\nconst selectCurrencyRateControllerState = createSelector(\n [(state: unknown) => state],\n (state): CurrencyRateState =>\n getControllerState<CurrencyRateState>(state, 'CurrencyRateController'),\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 selectAccountTreeControllerState,\n selectAccountsControllerState,\n selectTokenBalancesControllerState,\n selectTokenRatesControllerState,\n selectMultichainAssetsRatesControllerState,\n selectMultichainBalancesControllerState,\n selectTokensControllerState,\n selectCurrencyRateControllerState,\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 selectAccountTreeControllerState,\n selectAccountsControllerState,\n selectTokenBalancesControllerState,\n selectTokenRatesControllerState,\n selectMultichainAssetsRatesControllerState,\n selectMultichainBalancesControllerState,\n selectTokensControllerState,\n selectCurrencyRateControllerState,\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 selectAccountTreeControllerState,\n selectAccountsControllerState,\n selectTokenBalancesControllerState,\n selectTokenRatesControllerState,\n selectMultichainAssetsRatesControllerState,\n selectMultichainBalancesControllerState,\n selectTokensControllerState,\n selectCurrencyRateControllerState,\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 selectAccountTreeControllerState,\n selectAccountsControllerState,\n selectTokenBalancesControllerState,\n selectTokenRatesControllerState,\n selectMultichainAssetsRatesControllerState,\n selectMultichainBalancesControllerState,\n selectTokensControllerState,\n selectCurrencyRateControllerState,\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 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"]}
|
|
1
|
+
{"version":3,"file":"balanceSelectors.cjs","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 * Individual controller state selectors using direct state access\n * This avoids new object creation and provides stable references\n * Supports both mobile (state.engine.backgroundState) and extension (state.metamask) structures\n */\n\n/**\n * Helper function to get controller state from different state structures\n *\n * @param state - The application state\n * @param controllerName - The name of the controller\n * @returns The controller state or undefined if not found\n */\n\nconst getControllerState = <T>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n state: any,\n controllerName: string,\n): T => {\n // Mobile structure: state.engine.backgroundState.ControllerName\n if (state?.engine?.backgroundState?.[controllerName]) {\n return state.engine.backgroundState[controllerName];\n }\n\n // Extension structure: state.metamask.ControllerName\n if (state?.metamask?.[controllerName]) {\n return state.metamask[controllerName];\n }\n\n // Flat structure (default assets-controllers structure)\n if (state?.[controllerName]) {\n return state[controllerName];\n }\n\n // Since controllers always have default states, this should never happen\n // but we need to return something for TypeScript\n return state?.[controllerName] as T;\n};\n\n/**\n * Selector for AccountTreeController state using direct state access\n *\n * @param state - The application state\n * @returns AccountTreeController state\n */\nconst selectAccountTreeControllerState = createSelector(\n [(state: unknown) => state],\n (state): AccountTreeControllerState =>\n getControllerState<AccountTreeControllerState>(\n state,\n 'AccountTreeController',\n ),\n);\n\n/**\n * Selector for AccountsController state using direct state access\n *\n * @param state - The application state\n * @returns AccountsController state\n */\nconst selectAccountsControllerState = createSelector(\n [(state: unknown) => state],\n (state): AccountsControllerState =>\n getControllerState<AccountsControllerState>(state, 'AccountsController'),\n);\n\n/**\n * Selector for TokenBalancesController state using direct state access\n *\n * @param state - The application state\n * @returns TokenBalancesController state\n */\nconst selectTokenBalancesControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokenBalancesControllerState =>\n getControllerState<TokenBalancesControllerState>(\n state,\n 'TokenBalancesController',\n ),\n);\n\n/**\n * Selector for TokenRatesController state using direct state access\n *\n * @param state - The application state\n * @returns TokenRatesController state\n */\nconst selectTokenRatesControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokenRatesControllerState =>\n getControllerState<TokenRatesControllerState>(\n state,\n 'TokenRatesController',\n ),\n);\n\n/**\n * Selector for MultichainAssetsRatesController state using direct state access\n *\n * @param state - The application state\n * @returns MultichainAssetsRatesController state\n */\nconst selectMultichainAssetsRatesControllerState = createSelector(\n [(state: unknown) => state],\n (state): MultichainAssetsRatesControllerState =>\n getControllerState<MultichainAssetsRatesControllerState>(\n state,\n 'MultichainAssetsRatesController',\n ),\n);\n\n/**\n * Selector for MultichainBalancesController state using direct state access\n *\n * @param state - The application state\n * @returns MultichainBalancesController state\n */\nconst selectMultichainBalancesControllerState = createSelector(\n [(state: unknown) => state],\n (state): MultichainBalancesControllerState =>\n getControllerState<MultichainBalancesControllerState>(\n state,\n 'MultichainBalancesController',\n ),\n);\n\n/**\n * Selector for TokensController state using direct state access\n *\n * @param state - The application state\n * @returns TokensController state\n */\nconst selectTokensControllerState = createSelector(\n [(state: unknown) => state],\n (state): TokensControllerState =>\n getControllerState<TokensControllerState>(state, 'TokensController'),\n);\n\n/**\n * Selector for CurrencyRateController state using direct state access\n *\n * @param state - The application state\n * @returns CurrencyRateController state\n */\nconst selectCurrencyRateControllerState = createSelector(\n [(state: unknown) => state],\n (state): CurrencyRateState =>\n getControllerState<CurrencyRateState>(state, 'CurrencyRateController'),\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 * Comprehensive selector that calculates all balances for all wallets and groups.\n * This is the single source of truth for all balance calculations.\n * Other selectors will derive from this to ensure proper memoization.\n *\n * @returns Aggregated balance for all wallets\n */\nexport const selectBalanceForAllWallets = () =>\n createSelector(\n [\n selectAccountTreeControllerState,\n selectAccountsControllerState,\n selectTokenBalancesControllerState,\n selectTokenRatesControllerState,\n selectMultichainAssetsRatesControllerState,\n selectMultichainBalancesControllerState,\n selectTokensControllerState,\n selectCurrencyRateControllerState,\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 wallet = (\n accountTreeState.accountTree.wallets as Record<\n string,\n AccountWalletObject\n >\n )[walletId];\n if (!wallet) {\n continue;\n }\n\n const groupBalances: Record<string, AccountGroupBalance> = {};\n let walletTotalBalance = 0;\n\n const groups = Object.keys(wallet.groups || {}) as string[];\n\n for (const groupId of groups) {\n const accounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsState,\n groupId,\n );\n\n if (accounts.length === 0) {\n groupBalances[groupId] = {\n walletId,\n groupId,\n totalBalanceInUserCurrency: 0,\n userCurrency: currencyRateState.currentCurrency,\n };\n continue;\n }\n\n let groupTotalBalance = 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 const accountBalances =\n tokenBalancesState.tokenBalances[account.address as Hex];\n if (accountBalances) {\n for (const [chainId, chainBalances] of Object.entries(\n accountBalances,\n )) {\n for (const [tokenAddress, balance] of Object.entries(\n chainBalances,\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 // Use nullish coalescing to handle 0 decimals correctly\n // and ensure decimals is a valid number to prevent NaN propagation\n const decimals =\n typeof token.decimals === 'number' &&\n !Number.isNaN(token.decimals)\n ? token.decimals\n : 18;\n const balanceInSmallestUnit = parseInt(\n balance as string,\n 16,\n );\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 =\n 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 groupTotalBalance += balanceInUserCurrency;\n }\n }\n }\n }\n }\n } else {\n // Handle non-EVM account balances from MultichainBalancesController\n const accountBalances =\n 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[\n assetId as CaipAssetType\n ];\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 groupTotalBalance += balanceInUserCurrency;\n }\n }\n }\n }\n }\n\n groupBalances[groupId] = {\n walletId,\n groupId,\n totalBalanceInUserCurrency: groupTotalBalance,\n userCurrency: currencyRateState.currentCurrency,\n };\n walletTotalBalance += groupTotalBalance;\n }\n\n walletBalances[walletId] = {\n walletId,\n groups: groupBalances,\n totalBalanceInUserCurrency: walletTotalBalance,\n userCurrency: currencyRateState.currentCurrency,\n };\n totalBalanceInUserCurrency += walletTotalBalance;\n }\n\n return {\n wallets: walletBalances,\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 a specific account group.\n * Derives from the comprehensive selector to ensure proper memoization.\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 [selectBalanceForAllWallets()],\n (allBalances): AccountGroupBalance => {\n const walletId = groupId.split('/')[0] as EntropySourceId;\n const wallet = allBalances.wallets[walletId];\n\n if (!wallet || !wallet.groups[groupId]) {\n return {\n walletId,\n groupId,\n totalBalanceInUserCurrency: 0,\n userCurrency: allBalances.userCurrency,\n };\n }\n\n return wallet.groups[groupId];\n },\n );\n\n/**\n * Selector to get aggregated balances for all account groups in a wallet.\n * Derives from the comprehensive selector to ensure proper memoization.\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 [selectBalanceForAllWallets()],\n (allBalances): WalletBalance => {\n const wallet = allBalances.wallets[walletId];\n\n if (!wallet) {\n return {\n walletId,\n groups: {},\n totalBalanceInUserCurrency: 0,\n userCurrency: allBalances.userCurrency,\n };\n }\n\n return wallet;\n },\n );\n\n/**\n * Selector to get aggregated balances for the currently selected account group.\n * Derives from the comprehensive selector to ensure proper memoization.\n *\n * @returns Aggregated balance for the currently selected group\n */\nexport const selectBalanceForSelectedAccountGroup = () =>\n createSelector(\n [selectAccountTreeControllerState, selectBalanceForAllWallets()],\n (accountTreeState, allBalances): AccountGroupBalance | null => {\n const selectedGroupId = accountTreeState.accountTree.selectedAccountGroup;\n\n if (!selectedGroupId) {\n return null;\n }\n\n const walletId = selectedGroupId.split('/')[0] as EntropySourceId;\n const wallet = allBalances.wallets[walletId];\n\n if (!wallet || !wallet.groups[selectedGroupId]) {\n return {\n walletId,\n groupId: selectedGroupId,\n totalBalanceInUserCurrency: 0,\n userCurrency: allBalances.userCurrency,\n };\n }\n\n return wallet.groups[selectedGroupId];\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"]}
|