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.

175 lines (153 loc) 4.88 kB
import type { TokenExtended, WalletTokenExtended } from '@lifi/sdk' import { formatUnits } from 'viem' import type { TokenAmount, TokenAmountExtended } from '../types/token.js' import type { WidgetTokens } from '../types/widget.js' const sortByBalances = (a: TokenAmount, b: TokenAmount) => Number.parseFloat(formatUnits(b.amount ?? 0n, b.decimals)) * Number.parseFloat(b.priceUSD ?? '0') - Number.parseFloat(formatUnits(a.amount ?? 0n, a.decimals)) * Number.parseFloat(a.priceUSD ?? '0') const sortByVolume = (a: TokenExtended, b: TokenExtended) => (b.volumeUSD24H ?? 0) - (a.volumeUSD24H ?? 0) export const processTokenBalances = ( isBalanceLoading: boolean, noCategories: boolean, configTokens?: WidgetTokens, selectedChainId?: number, tokens?: TokenExtended[], tokensWithBalances?: TokenAmount[] ) => { if (isBalanceLoading) { if (noCategories) { const sortedTokens = [...(tokens ?? [])].sort(sortByVolume) return { processedTokens: sortedTokens, withCategories: false, } } else { return processedTypedTokens( tokens ?? [], [], selectedChainId, configTokens ) } } const sortedTokensWithBalances = [...(tokensWithBalances ?? [])].sort( sortByBalances ) const tokensWithBalancesSet = new Set( sortedTokensWithBalances.map( (token) => `${token.chainId}-${token.address.toLowerCase()}` ) ) const tokensWithoutBalances = tokens ?.filter((token) => { const tokenKey = `${token.chainId}-${token.address.toLowerCase()}` return !tokensWithBalancesSet.has(tokenKey) }) .sort(sortByVolume) ?? [] if (noCategories) { return { processedTokens: [...sortedTokensWithBalances, ...tokensWithoutBalances], withCategories: false, } } else { return processedTypedTokens( tokensWithoutBalances, sortedTokensWithBalances, selectedChainId, configTokens ) } } // NB: only for non-all-networks const processedTypedTokens = ( tokens: TokenAmount[], tokensWithBalances: TokenAmount[], selectedChainId?: number, configTokens?: WidgetTokens ) => { const filteredTokensMap = new Map( tokens.map((token) => [token.address, token]) ) const featuredTokensFromConfig: TokenAmount[] = [] const popularTokensFromConfig: TokenAmount[] = [] ;(['popular', 'featured'] as const).forEach((tokenType) => { const typedTokens = configTokens?.[tokenType]?.filter( (token) => token.chainId === selectedChainId ) typedTokens?.forEach((token) => { const tokenAmount = { ...token } as TokenAmount tokenAmount[tokenType] = true // Config tokens are explicitly set by integrator, mark as verified tokenAmount.verified = true const match = filteredTokensMap.get(token.address) if (match?.priceUSD) { tokenAmount.priceUSD = match.priceUSD } if (!token.logoURI && match?.logoURI) { tokenAmount.logoURI = match.logoURI } if (tokenType === 'popular') { popularTokensFromConfig.push(tokenAmount) } else { featuredTokensFromConfig.push(tokenAmount) } }) }) // Filter out config-added tokens from main list const configTokenAddresses = new Set( [...popularTokensFromConfig, ...featuredTokensFromConfig].map((t) => t.address.toLowerCase() ) ) const remainingTokens = tokens.filter( (token) => !configTokenAddresses.has(token.address.toLowerCase()) ) const otherTokens: TokenAmount[] = [] for (const token of remainingTokens) { if (token.featured) { featuredTokensFromConfig.push(token) } else if (token.popular) { popularTokensFromConfig.push(token) } else { otherTokens.push(token) } } const sortedFeaturedTokens = [...featuredTokensFromConfig].sort(sortByVolume) const sortedPopularTokens = [...popularTokensFromConfig].sort(sortByVolume) const sortedOtherTokens = [...otherTokens].sort(sortByVolume) return { processedTokens: [ ...sortedFeaturedTokens, ...tokensWithBalances, ...sortedPopularTokens, ...sortedOtherTokens, ], withCategories: Boolean( featuredTokensFromConfig?.length || popularTokensFromConfig?.length ), } } export const isSearchMatch = ( token: TokenExtended | TokenAmountExtended, search?: string ) => { if (!search) { return true } const searchLowerCase = search.toLowerCase() return ( token.name?.toLowerCase().includes(searchLowerCase) || token.symbol ?.replaceAll('₮', 'T') .toLowerCase() .includes(searchLowerCase) || token.address?.toLowerCase().includes(searchLowerCase) ) } export const isSupportedToken = (token: WalletTokenExtended) => { return token.name && token.symbol && token.priceUSD && token.chainId }