From 5fc1164e459b3936e2ac0dafb6d68e03614ad7bb Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Fri, 25 Apr 2025 19:42:51 +0200 Subject: [PATCH 1/3] fix: fix solana token list render --- .../UI/Bridge/hooks/useLatestBalance/index.ts | 11 ++- app/components/UI/Tokens/index.tsx | 10 +- app/selectors/multichain/multichain.test.ts | 96 ------------------- app/selectors/multichain/multichain.ts | 9 -- 4 files changed, 15 insertions(+), 111 deletions(-) diff --git a/app/components/UI/Bridge/hooks/useLatestBalance/index.ts b/app/components/UI/Bridge/hooks/useLatestBalance/index.ts index 096707ca0ab6..bbfddff701cf 100644 --- a/app/components/UI/Bridge/hooks/useLatestBalance/index.ts +++ b/app/components/UI/Bridge/hooks/useLatestBalance/index.ts @@ -4,13 +4,14 @@ import { abiERC20 } from '@metamask/metamask-eth-abis'; import { Web3Provider } from '@ethersproject/providers'; import { formatUnits, getAddress, parseUnits } from 'ethers/lib/utils'; import { useSelector } from 'react-redux'; -import { selectSelectedInternalAccountFormattedAddress } from '../../../../../selectors/accountsController'; +import { selectSelectedInternalAccount, selectSelectedInternalAccountFormattedAddress } from '../../../../../selectors/accountsController'; import { getProviderByChainId } from '../../../../../util/notifications/methods/common'; import { BigNumber, constants, Contract } from 'ethers'; import usePrevious from '../../../../hooks/usePrevious'; ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) import { isSolanaChainId } from '@metamask/bridge-controller'; -import { selectMultichainTokenList } from '../../../../../selectors/multichain/multichain'; +import { selectMultichainTokenListForAccountId } from '../../../../../selectors/multichain/multichain'; +import { RootState } from '../../../../../reducers'; ///: END:ONLY_INCLUDE_IF export async function fetchAtomicTokenBalance( @@ -66,10 +67,14 @@ export const useLatestBalance = ( const selectedAddress = useSelector(selectSelectedInternalAccountFormattedAddress); const previousToken = usePrevious(token); + const selectedAccount = useSelector(selectSelectedInternalAccount); + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) // Returns native SOL and SPL tokens, contains balance and fiat values // Balance and fiat values are not truncated - const nonEvmTokens = useSelector(selectMultichainTokenList); + const nonEvmTokens = useSelector((state: RootState) => + selectMultichainTokenListForAccountId(state, selectedAccount?.id), + ); ///: END:ONLY_INCLUDE_IF const chainId = token.chainId; diff --git a/app/components/UI/Tokens/index.tsx b/app/components/UI/Tokens/index.tsx index 07df7e63fdd4..2513141d9a10 100644 --- a/app/components/UI/Tokens/index.tsx +++ b/app/components/UI/Tokens/index.tsx @@ -35,7 +35,7 @@ import { selectEvmTokenFiatBalances, selectEvmTokens, ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) - selectMultichainTokenList, + selectMultichainTokenListForAccountId, ///: END:ONLY_INCLUDE_IF } from '../../../selectors/multichain'; import { TraceName, endTrace, trace } from '../../../util/trace'; @@ -45,6 +45,7 @@ import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetwork import { AssetPollingProvider } from '../../hooks/AssetPolling/AssetPollingProvider'; import { TokenListControlBar } from './TokenListControlBar'; import { selectSelectedInternalAccount } from '../../../selectors/accountsController'; +import { RootState } from '../../../reducers'; interface TokenListNavigationParamList { AddAsset: { assetType: string }; @@ -74,12 +75,15 @@ const Tokens = memo(() => { const [tokenToRemove, setTokenToRemove] = useState(); const [refreshing, setRefreshing] = useState(false); const [isAddTokenEnabled, setIsAddTokenEnabled] = useState(true); + const selectedAccount = useSelector(selectSelectedInternalAccount); // non-evm ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) - const nonEvmTokens = useSelector(selectMultichainTokenList); + const nonEvmTokens = useSelector((state: RootState) => + selectMultichainTokenListForAccountId(state, selectedAccount?.id), +); ///: END:ONLY_INCLUDE_IF - const selectedAccount = useSelector(selectSelectedInternalAccount); + const tokenListData = isEvmSelected ? evmTokens : nonEvmTokens; diff --git a/app/selectors/multichain/multichain.test.ts b/app/selectors/multichain/multichain.test.ts index 1d799a980fee..bd27f0b9b882 100644 --- a/app/selectors/multichain/multichain.test.ts +++ b/app/selectors/multichain/multichain.test.ts @@ -10,7 +10,6 @@ import { selectMultichainBalances, MULTICHAIN_NETWORK_TO_ASSET_TYPES, selectMultichainTransactions, - selectMultichainTokenList, selectSelectedAccountMultichainNetworkAggregatedBalance, selectSolanaAccountTransactions, selectMultichainHistoricalPrices, @@ -588,101 +587,6 @@ describe('MultichainNonEvm Selectors', () => { }); }); - describe('selectMultichainTokenList', () => { - it('returns a list of tokens', () => { - const selectedInternalAccountId = 'ae247df6-3911-47f7-9e36-28e6a7d96078'; - const state = getNonEvmState(); - const mockBalances = { - [selectedInternalAccountId]: { - [MultichainNativeAssets.Bitcoin]: { amount: '10', unit: 'BTC' }, - }, - }; - const mockAssets = { - [selectedInternalAccountId]: [MultichainNativeAssets.Bitcoin], - }; - const mockAssetsMetadata = { - [MultichainNativeAssets.Bitcoin]: { - name: 'Bitcoin', - symbol: 'BTC', - units: [{ name: 'Bitcoin', symbol: 'BTC', decimals: 8 }], - iconUrl: 'https://example.com/btc.png', - fungible: true as const, - }, - }; - const mockAssetsRates = { - [MultichainNativeAssets.Bitcoin]: { rate: '2000', conversionTime: 0 }, - }; - state.engine.backgroundState.MultichainBalancesController.balances = - mockBalances; - state.engine.backgroundState.MultichainAssetsController.accountsAssets = - mockAssets; - state.engine.backgroundState.MultichainAssetsController.assetsMetadata = - mockAssetsMetadata; - state.engine.backgroundState.MultichainAssetsRatesController.conversionRates = - mockAssetsRates; - - const tokenList = selectMultichainTokenList(state); - - expect(tokenList.length).toEqual(1); - expect(tokenList[0].name).toEqual('Bitcoin'); - expect(tokenList[0].symbol).toEqual('BTC'); - expect(tokenList[0].balance).toEqual('10'); - }); - - it('filters out tokens not matching nonEVM network chain ID', () => { - const selectedInternalAccountId = 'ae247df6-3911-47f7-9e36-28e6a7d96078'; - const state = getNonEvmState(); - - const nonMatchingAssetId = - 'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f'; // Ethereum Mainnet - - state.engine.backgroundState.MultichainBalancesController.balances = { - [selectedInternalAccountId]: { - [nonMatchingAssetId]: { amount: '5', unit: 'DAI' }, - }, - }; - state.engine.backgroundState.MultichainAssetsController.accountsAssets = { - [selectedInternalAccountId]: [nonMatchingAssetId], - }; - - const tokenList = selectMultichainTokenList(state); - expect(tokenList).toEqual([]); - }); - - it('returns an empty array if selected account is undefined', () => { - const state = getNonEvmState(); - state.engine.backgroundState.AccountsController.internalAccounts.selectedAccount = - 'foo'; - - const tokenList = selectMultichainTokenList(state); - - expect(tokenList).toEqual([]); - }); - - it('uses fallback metadata when asset metadata is missing', () => { - const selectedInternalAccountId = 'ae247df6-3911-47f7-9e36-28e6a7d96078'; - const state = getNonEvmState(); - - const btcCaip = 'bip122:000000000019d6689c085ae165831e93/slip44:0'; - - state.engine.backgroundState.MultichainBalancesController.balances = { - [selectedInternalAccountId]: { - [btcCaip]: { amount: '1', unit: 'BTC' }, - }, - }; - state.engine.backgroundState.MultichainAssetsController.accountsAssets = { - [selectedInternalAccountId]: [btcCaip], - }; - state.engine.backgroundState.MultichainAssetsController.assetsMetadata = - {}; // fallback will be used - - const tokenList = selectMultichainTokenList(state); - expect(tokenList[0].name).toBe('BTC'); - expect(tokenList[0].symbol).toBe('BTC'); - expect(tokenList[0].balance).toBe('1'); - }); - }); - describe('selectMultichainNetworkAggregatedBalance', () => { beforeEach(() => { jest.clearAllMocks(); diff --git a/app/selectors/multichain/multichain.ts b/app/selectors/multichain/multichain.ts index 5949a3738431..1e4258d95a00 100644 --- a/app/selectors/multichain/multichain.ts +++ b/app/selectors/multichain/multichain.ts @@ -283,15 +283,6 @@ export const selectMultichainTokenListForAccountId = createDeepEqualSelector( return tokens; }, ); - -export const selectMultichainTokenList = createDeepEqualSelector( - (state: RootState) => state, - selectSelectedInternalAccount, - (state, selectedAccount) => { - return selectMultichainTokenListForAccountId(state, selectedAccount?.id); - }, -); - export interface MultichainNetworkAggregatedBalance { totalNativeTokenBalance: Balance | undefined; totalBalanceFiat: number | undefined; From 93649f98a668fa82b51a6b06d601392b64b03707 Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Fri, 25 Apr 2025 20:32:54 +0200 Subject: [PATCH 2/3] fix: code fence --- app/components/UI/Tokens/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/UI/Tokens/index.tsx b/app/components/UI/Tokens/index.tsx index 2513141d9a10..d59f0aad05e1 100644 --- a/app/components/UI/Tokens/index.tsx +++ b/app/components/UI/Tokens/index.tsx @@ -45,7 +45,9 @@ import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetwork import { AssetPollingProvider } from '../../hooks/AssetPolling/AssetPollingProvider'; import { TokenListControlBar } from './TokenListControlBar'; import { selectSelectedInternalAccount } from '../../../selectors/accountsController'; +///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) import { RootState } from '../../../reducers'; +///: END:ONLY_INCLUDE_IF interface TokenListNavigationParamList { AddAsset: { assetType: string }; From f89efa68f6737b3ca50d8d1b907bb9509650fb35 Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Fri, 25 Apr 2025 20:52:18 +0200 Subject: [PATCH 3/3] fix: code fence --- .../UI/Bridge/hooks/useLatestBalance/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/components/UI/Bridge/hooks/useLatestBalance/index.ts b/app/components/UI/Bridge/hooks/useLatestBalance/index.ts index bbfddff701cf..93e7d0f64107 100644 --- a/app/components/UI/Bridge/hooks/useLatestBalance/index.ts +++ b/app/components/UI/Bridge/hooks/useLatestBalance/index.ts @@ -4,7 +4,12 @@ import { abiERC20 } from '@metamask/metamask-eth-abis'; import { Web3Provider } from '@ethersproject/providers'; import { formatUnits, getAddress, parseUnits } from 'ethers/lib/utils'; import { useSelector } from 'react-redux'; -import { selectSelectedInternalAccount, selectSelectedInternalAccountFormattedAddress } from '../../../../../selectors/accountsController'; +import { + ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) + selectSelectedInternalAccount, + ///: END:ONLY_INCLUDE_IF + selectSelectedInternalAccountFormattedAddress, +} from '../../../../../selectors/accountsController'; import { getProviderByChainId } from '../../../../../util/notifications/methods/common'; import { BigNumber, constants, Contract } from 'ethers'; import usePrevious from '../../../../hooks/usePrevious'; @@ -67,11 +72,10 @@ export const useLatestBalance = ( const selectedAddress = useSelector(selectSelectedInternalAccountFormattedAddress); const previousToken = usePrevious(token); - const selectedAccount = useSelector(selectSelectedInternalAccount); - ///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps) // Returns native SOL and SPL tokens, contains balance and fiat values // Balance and fiat values are not truncated + const selectedAccount = useSelector(selectSelectedInternalAccount); const nonEvmTokens = useSelector((state: RootState) => selectMultichainTokenListForAccountId(state, selectedAccount?.id), );