@metamask-previews/assets-controllers 73.0.1-preview-2e90d98e → 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.
@@ -28,28 +28,6 @@ const getInternalAccountsForGroup = (accountTreeState, accountsState, groupId) =
28
28
  .map((accountId) => accountsState.internalAccounts.accounts[accountId])
29
29
  .filter(Boolean);
30
30
  };
31
- /**
32
- * Helper function to convert USD amount to user's selected currency
33
- *
34
- * @param usdAmount - Amount in USD
35
- * @param currencyRateState - CurrencyRateController state
36
- * @returns Amount converted to user's selected currency
37
- */
38
- const convertUsdToUserCurrency = (usdAmount, currencyRateState) => {
39
- // If user currency is USD, no conversion needed
40
- if (currencyRateState.currentCurrency.toLowerCase() === 'usd') {
41
- return usdAmount;
42
- }
43
- // Get USD conversion rate for the user's currency
44
- // We need to find a currency that has usdConversionRate set
45
- const currencyWithUsdRate = Object.values(currencyRateState.currencyRates).find((rate) => rate.usdConversionRate !== null);
46
- if (!currencyWithUsdRate?.usdConversionRate) {
47
- // If no USD conversion rate is available, return USD amount as fallback
48
- return usdAmount;
49
- }
50
- // Convert USD to user currency using the USD conversion rate
51
- return usdAmount * currencyWithUsdRate.usdConversionRate;
52
- };
53
31
  /**
54
32
  * Selector to get aggregated balances for a specific account group.
55
33
  * Returns total balance in user's selected currency, aggregating all tokens across accounts in the group.
@@ -78,7 +56,7 @@ const selectBalanceByAccountGroup = (groupId) => (0, reselect_1.createSelector)(
78
56
  userCurrency: currencyRateState.currentCurrency,
79
57
  };
80
58
  }
81
- let totalBalanceInUSD = 0;
59
+ let totalBalanceInUserCurrency = 0;
82
60
  // Process each account's balances
83
61
  for (const account of accounts) {
84
62
  const isEvmAccount = (0, keyring_api_1.isEvmAccountType)(account.type);
@@ -98,18 +76,25 @@ const selectBalanceByAccountGroup = (groupId) => (0, reselect_1.createSelector)(
98
76
  }
99
77
  const decimals = token.decimals || 18;
100
78
  const balanceInSmallestUnit = parseInt(balance, 16);
79
+ // Skip invalid balance values to prevent NaN propagation
80
+ if (Number.isNaN(balanceInSmallestUnit)) {
81
+ continue;
82
+ }
101
83
  const balanceInTokenUnits = balanceInSmallestUnit / Math.pow(10, decimals);
102
84
  // Get token rate in native currency from TokenRatesController
103
85
  const chainMarketData = tokenRatesState.marketData[chainId];
104
86
  const tokenMarketData = chainMarketData?.[tokenAddress];
105
87
  if (tokenMarketData?.price) {
106
- // Convert native currency price to USD using the appropriate native currency rate
88
+ // Convert token price to user currency using native currency conversion rate
107
89
  const nativeCurrency = tokenMarketData.currency;
108
- const nativeRate = currencyRateState.currencyRates[nativeCurrency];
109
- const nativeToUsdRate = nativeRate?.conversionRate || 1;
110
- const tokenPriceInUSD = tokenMarketData.price * nativeToUsdRate;
111
- const balanceInUSD = balanceInTokenUnits * tokenPriceInUSD;
112
- totalBalanceInUSD += balanceInUSD;
90
+ const nativeToUserRate = currencyRateState.currencyRates[nativeCurrency]
91
+ ?.conversionRate;
92
+ if (nativeToUserRate) {
93
+ // Convert token price to user currency: tokenPrice * nativeToUserRate
94
+ const tokenPriceInUserCurrency = tokenMarketData.price * nativeToUserRate;
95
+ const balanceInUserCurrency = balanceInTokenUnits * tokenPriceInUserCurrency;
96
+ totalBalanceInUserCurrency += balanceInUserCurrency;
97
+ }
113
98
  }
114
99
  }
115
100
  }
@@ -121,18 +106,26 @@ const selectBalanceByAccountGroup = (groupId) => (0, reselect_1.createSelector)(
121
106
  if (accountBalances) {
122
107
  for (const [assetId, balanceData] of Object.entries(accountBalances)) {
123
108
  const balanceAmount = parseFloat(balanceData.amount);
124
- // Get conversion rate for this asset
109
+ // Skip invalid balance values to prevent NaN propagation
110
+ if (Number.isNaN(balanceAmount)) {
111
+ continue;
112
+ }
113
+ // Get conversion rate for this asset (already in user currency)
125
114
  const conversionRate = multichainRatesState.conversionRates[assetId];
126
115
  if (conversionRate) {
127
- const balanceInUSD = balanceAmount * parseFloat(conversionRate.rate);
128
- totalBalanceInUSD += balanceInUSD;
116
+ const conversionRateValue = parseFloat(conversionRate.rate);
117
+ // Skip invalid conversion rate values to prevent NaN propagation
118
+ if (Number.isNaN(conversionRateValue)) {
119
+ continue;
120
+ }
121
+ // MultichainAssetsRatesController already provides rates in user currency
122
+ const balanceInUserCurrency = balanceAmount * conversionRateValue;
123
+ totalBalanceInUserCurrency += balanceInUserCurrency;
129
124
  }
130
125
  }
131
126
  }
132
127
  }
133
128
  }
134
- // Convert USD balance to user's selected currency
135
- const totalBalanceInUserCurrency = convertUsdToUserCurrency(totalBalanceInUSD, currencyRateState);
136
129
  return {
137
130
  walletId,
138
131
  groupId,
@@ -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 * 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 * Helper function to convert USD amount to user's selected currency\n *\n * @param usdAmount - Amount in USD\n * @param currencyRateState - CurrencyRateController state\n * @returns Amount converted to user's selected currency\n */\nconst convertUsdToUserCurrency = (\n usdAmount: number,\n currencyRateState: CurrencyRateState,\n): number => {\n // If user currency is USD, no conversion needed\n if (currencyRateState.currentCurrency.toLowerCase() === 'usd') {\n return usdAmount;\n }\n\n // Get USD conversion rate for the user's currency\n // We need to find a currency that has usdConversionRate set\n const currencyWithUsdRate = Object.values(\n currencyRateState.currencyRates,\n ).find((rate) => rate.usdConversionRate !== null);\n\n if (!currencyWithUsdRate?.usdConversionRate) {\n // If no USD conversion rate is available, return USD amount as fallback\n return usdAmount;\n }\n\n // Convert USD to user currency using the USD conversion rate\n return usdAmount * currencyWithUsdRate.usdConversionRate;\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 totalBalanceInUSD = 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 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 native currency price to USD using the appropriate native currency rate\n const nativeCurrency = tokenMarketData.currency;\n const nativeRate =\n currencyRateState.currencyRates[nativeCurrency];\n const nativeToUsdRate = nativeRate?.conversionRate || 1;\n const tokenPriceInUSD =\n tokenMarketData.price * nativeToUsdRate;\n const balanceInUSD = balanceInTokenUnits * tokenPriceInUSD;\n totalBalanceInUSD += balanceInUSD;\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 // Get conversion rate for this asset\n const conversionRate =\n multichainRatesState.conversionRates[assetId as CaipAssetType];\n if (conversionRate) {\n const balanceInUSD =\n balanceAmount * parseFloat(conversionRate.rate);\n totalBalanceInUSD += balanceInUSD;\n }\n }\n }\n }\n }\n\n // Convert USD balance to user's selected currency\n const totalBalanceInUserCurrency = convertUsdToUserCurrency(\n totalBalanceInUSD,\n currencyRateState,\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"]}
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 * 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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"balanceSelectors.d.cts","sourceRoot":"","sources":["../../src/selectors/balanceSelectors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"balanceSelectors.d.cts","sourceRoot":"","sources":["../../src/selectors/balanceSelectors.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"balanceSelectors.d.mts","sourceRoot":"","sources":["../../src/selectors/balanceSelectors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"balanceSelectors.d.mts","sourceRoot":"","sources":["../../src/selectors/balanceSelectors.ts"],"names":[],"mappings":"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"}
@@ -25,28 +25,6 @@ const getInternalAccountsForGroup = (accountTreeState, accountsState, groupId) =
25
25
  .map((accountId) => accountsState.internalAccounts.accounts[accountId])
26
26
  .filter(Boolean);
27
27
  };
28
- /**
29
- * Helper function to convert USD amount to user's selected currency
30
- *
31
- * @param usdAmount - Amount in USD
32
- * @param currencyRateState - CurrencyRateController state
33
- * @returns Amount converted to user's selected currency
34
- */
35
- const convertUsdToUserCurrency = (usdAmount, currencyRateState) => {
36
- // If user currency is USD, no conversion needed
37
- if (currencyRateState.currentCurrency.toLowerCase() === 'usd') {
38
- return usdAmount;
39
- }
40
- // Get USD conversion rate for the user's currency
41
- // We need to find a currency that has usdConversionRate set
42
- const currencyWithUsdRate = Object.values(currencyRateState.currencyRates).find((rate) => rate.usdConversionRate !== null);
43
- if (!currencyWithUsdRate?.usdConversionRate) {
44
- // If no USD conversion rate is available, return USD amount as fallback
45
- return usdAmount;
46
- }
47
- // Convert USD to user currency using the USD conversion rate
48
- return usdAmount * currencyWithUsdRate.usdConversionRate;
49
- };
50
28
  /**
51
29
  * Selector to get aggregated balances for a specific account group.
52
30
  * Returns total balance in user's selected currency, aggregating all tokens across accounts in the group.
@@ -75,7 +53,7 @@ export const selectBalanceByAccountGroup = (groupId) => createSelector([
75
53
  userCurrency: currencyRateState.currentCurrency,
76
54
  };
77
55
  }
78
- let totalBalanceInUSD = 0;
56
+ let totalBalanceInUserCurrency = 0;
79
57
  // Process each account's balances
80
58
  for (const account of accounts) {
81
59
  const isEvmAccount = isEvmAccountType(account.type);
@@ -95,18 +73,25 @@ export const selectBalanceByAccountGroup = (groupId) => createSelector([
95
73
  }
96
74
  const decimals = token.decimals || 18;
97
75
  const balanceInSmallestUnit = parseInt(balance, 16);
76
+ // Skip invalid balance values to prevent NaN propagation
77
+ if (Number.isNaN(balanceInSmallestUnit)) {
78
+ continue;
79
+ }
98
80
  const balanceInTokenUnits = balanceInSmallestUnit / Math.pow(10, decimals);
99
81
  // Get token rate in native currency from TokenRatesController
100
82
  const chainMarketData = tokenRatesState.marketData[chainId];
101
83
  const tokenMarketData = chainMarketData?.[tokenAddress];
102
84
  if (tokenMarketData?.price) {
103
- // Convert native currency price to USD using the appropriate native currency rate
85
+ // Convert token price to user currency using native currency conversion rate
104
86
  const nativeCurrency = tokenMarketData.currency;
105
- const nativeRate = currencyRateState.currencyRates[nativeCurrency];
106
- const nativeToUsdRate = nativeRate?.conversionRate || 1;
107
- const tokenPriceInUSD = tokenMarketData.price * nativeToUsdRate;
108
- const balanceInUSD = balanceInTokenUnits * tokenPriceInUSD;
109
- totalBalanceInUSD += balanceInUSD;
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
+ }
110
95
  }
111
96
  }
112
97
  }
@@ -118,18 +103,26 @@ export const selectBalanceByAccountGroup = (groupId) => createSelector([
118
103
  if (accountBalances) {
119
104
  for (const [assetId, balanceData] of Object.entries(accountBalances)) {
120
105
  const balanceAmount = parseFloat(balanceData.amount);
121
- // Get conversion rate for this asset
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)
122
111
  const conversionRate = multichainRatesState.conversionRates[assetId];
123
112
  if (conversionRate) {
124
- const balanceInUSD = balanceAmount * parseFloat(conversionRate.rate);
125
- totalBalanceInUSD += balanceInUSD;
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;
126
121
  }
127
122
  }
128
123
  }
129
124
  }
130
125
  }
131
- // Convert USD balance to user's selected currency
132
- const totalBalanceInUserCurrency = convertUsdToUserCurrency(totalBalanceInUSD, currencyRateState);
133
126
  return {
134
127
  walletId,
135
128
  groupId,
@@ -1 +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 * Helper function to convert USD amount to user's selected currency\n *\n * @param usdAmount - Amount in USD\n * @param currencyRateState - CurrencyRateController state\n * @returns Amount converted to user's selected currency\n */\nconst convertUsdToUserCurrency = (\n usdAmount: number,\n currencyRateState: CurrencyRateState,\n): number => {\n // If user currency is USD, no conversion needed\n if (currencyRateState.currentCurrency.toLowerCase() === 'usd') {\n return usdAmount;\n }\n\n // Get USD conversion rate for the user's currency\n // We need to find a currency that has usdConversionRate set\n const currencyWithUsdRate = Object.values(\n currencyRateState.currencyRates,\n ).find((rate) => rate.usdConversionRate !== null);\n\n if (!currencyWithUsdRate?.usdConversionRate) {\n // If no USD conversion rate is available, return USD amount as fallback\n return usdAmount;\n }\n\n // Convert USD to user currency using the USD conversion rate\n return usdAmount * currencyWithUsdRate.usdConversionRate;\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 totalBalanceInUSD = 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 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 native currency price to USD using the appropriate native currency rate\n const nativeCurrency = tokenMarketData.currency;\n const nativeRate =\n currencyRateState.currencyRates[nativeCurrency];\n const nativeToUsdRate = nativeRate?.conversionRate || 1;\n const tokenPriceInUSD =\n tokenMarketData.price * nativeToUsdRate;\n const balanceInUSD = balanceInTokenUnits * tokenPriceInUSD;\n totalBalanceInUSD += balanceInUSD;\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 // Get conversion rate for this asset\n const conversionRate =\n multichainRatesState.conversionRates[assetId as CaipAssetType];\n if (conversionRate) {\n const balanceInUSD =\n balanceAmount * parseFloat(conversionRate.rate);\n totalBalanceInUSD += balanceInUSD;\n }\n }\n }\n }\n }\n\n // Convert USD balance to user's selected currency\n const totalBalanceInUserCurrency = convertUsdToUserCurrency(\n totalBalanceInUSD,\n currencyRateState,\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"]}
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-2e90d98e",
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",