UNPKG

@lifi/widget

Version:

LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.

85 lines 4.25 kB
import { ChainType, getWalletBalances, } from '@lifi/sdk'; import { useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'; import { getConfigItemSets, isFormItemAllowed } from '../utils/item.js'; import { isSupportedToken } from '../utils/tokenList.js'; export const useFilteredTokensByBalance = (accountsWithTokens, formType) => { const { tokens: configTokens } = useWidgetConfig(); const evmAddress = useMemo(() => { const evmAccount = Object.entries(accountsWithTokens ?? {}).find(([_, { chainType }]) => chainType === ChainType.EVM); return evmAccount?.[0]; }, [accountsWithTokens]); const { data: existingBalances, isLoading } = useQuery({ queryKey: ['existing-evm-balances', evmAddress], queryFn: () => getWalletBalances(evmAddress ?? ''), enabled: !!evmAddress, refetchInterval: 30000, // 30 seconds staleTime: 30000, // 30 seconds retry: false, }); const accountsWithFilteredTokens = useMemo(() => { if (!accountsWithTokens) { return undefined; } // Early return if no existing balances - return all tokens const result = {}; if (!existingBalances) { for (const [address, { tokens }] of Object.entries(accountsWithTokens)) { result[address] = tokens; } return result; } for (const [address, { tokens }] of Object.entries(accountsWithTokens)) { result[address] = {}; for (const [chainIdStr, chainTokens] of Object.entries(tokens)) { const chainId = Number(chainIdStr); // Get balances for this specific chain const balances = existingBalances?.[chainId]; // If no balances, RPC all tokens of the chain if (!balances?.length) { if (chainTokens.length) { result[address][chainId] = chainTokens; } continue; } // Optimize token matching with Set for O(1) lookup const balanceSet = new Set(balances.map((balance) => balance.address.toLowerCase())); // Get tokens that are in chainTokens and have balances const filteredTokens = chainTokens.filter((token) => { const tokenKey = token.address.toLowerCase(); return balanceSet.has(tokenKey); }); // Get tokens that are in balances but not in chainTokens const chainTokenSet = new Set(chainTokens.map((token) => token.address.toLowerCase())); // Get allowed addresses from config tokens const allowedAddressesConfig = getConfigItemSets(configTokens, (tokens) => new Set(tokens .filter((t) => Number(t.chainId) === chainId) .map((t) => t.address.toLowerCase())), formType); const additionalTokens = balances .filter((balance) => { const balanceKey = balance.address.toLowerCase(); return (!chainTokenSet.has(balanceKey) && isSupportedToken(balance) && isFormItemAllowed(balance, allowedAddressesConfig, formType, (t) => t.address.toLowerCase())); }) // Mark tokens from wallet balances as unverified .map((token) => ({ ...token, verified: false, })); // Combine both sets of tokens - convert WalletTokenExtended to TokenAmount const allTokens = [ ...filteredTokens, ...additionalTokens, ]; if (allTokens.length) { result[address][chainId] = allTokens; } } } return result; }, [accountsWithTokens, existingBalances, configTokens, formType]); return { data: accountsWithFilteredTokens, isLoading }; }; //# sourceMappingURL=useFilteredByTokenBalances.js.map