diff --git a/src/components/SearchModal/CurrencyList/index.tsx b/src/components/SearchModal/CurrencyList/index.tsx index 71788101..3177528a 100644 --- a/src/components/SearchModal/CurrencyList/index.tsx +++ b/src/components/SearchModal/CurrencyList/index.tsx @@ -1,6 +1,6 @@ import { SorobanContextType, useSorobanReact } from '@soroban-react/core'; import BigNumber from 'bignumber.js'; -import { CSSProperties, MutableRefObject, useCallback, useMemo } from 'react'; +import { CSSProperties, MutableRefObject, useCallback, useEffect, useMemo, useState } from 'react'; import { Check } from 'react-feather'; import { FixedSizeList } from 'react-window'; import { AccountResponse } from '@stellar/stellar-sdk/lib/horizon'; @@ -11,7 +11,7 @@ import Column, { AutoColumn } from 'components/Column'; import Loader from 'components/Icons/LoadingSpinner'; import CurrencyLogo from 'components/Logo/CurrencyLogo'; import Row, { RowFixed } from 'components/Row'; -import { TokenType } from '../../../interfaces'; +import { TokenType, TokenVolumeData } from '../../../interfaces'; import StyledRow from '../../Row'; import { LoadingRows, MenuItem } from '../styleds'; @@ -258,6 +258,34 @@ export default function CurrencyList({ isAddressSearch: string | false; isLoading?: boolean; }) { + const [tokenVolumes, setTokenVolumes] = useState(null); + + const [sortedItemData, setSortedItemData] = useState([]); + + const fetchTokenVolumes = async (network: string): Promise => { + const response = await fetch(`https://info.soroswap.finance/api/tokens?network=${network}`); + if (!response.ok) { + throw new Error('Failed to fetch token volumes'); + } + const data = await response.json(); + return data.map((token: any) => ({ + asset: token.asset, + volume24h: token.volume24h, + })); + }; + + useEffect(() => { + const getVolumes = async () => { + try { + const volumes = await fetchTokenVolumes('MAINNET'); + setTokenVolumes(volumes); + } catch (error) { + console.error(error); + } + }; + getVolumes(); + }, []); + const itemData: TokenType[] = useMemo(() => { if (otherListTokens && otherListTokens?.length > 0) { return [...currencies, ...otherListTokens]; @@ -265,6 +293,20 @@ export default function CurrencyList({ return currencies; }, [currencies, otherListTokens]); + useEffect(() => { + if (tokenVolumes) { + const sorted = [...itemData]; + sorted.sort((a, b) => { + const volumeA = + tokenVolumes.find((item) => item.asset.contract === a.contract)?.volume24h || 0; + const volumeB = + tokenVolumes.find((item) => item.asset.contract === b.contract)?.volume24h || 0; + return volumeB - volumeA; + }); + setSortedItemData(sorted); + } + }, [itemData, tokenVolumes]); + const Row = useCallback( function TokenRow({ data, index, style }: TokenRowProps) { const row: TokenType = data[index]; @@ -314,7 +356,7 @@ export default function CurrencyList({ ], ); - const itemKey = useCallback((index: number, data: typeof itemData) => { + const itemKey = useCallback((index: number, data: typeof sortedItemData) => { const currency = data[index]; return currencyKey(currency); }, []); @@ -330,8 +372,8 @@ export default function CurrencyList({ height={height} ref={fixedListRef as any} width="100%" - itemData={itemData} - itemCount={itemData.length} + itemData={sortedItemData} + itemCount={sortedItemData.length} itemSize={56} itemKey={itemKey} > diff --git a/src/hooks/tokens/useToken.ts b/src/hooks/tokens/useToken.ts index 645e95bb..4c3026e4 100644 --- a/src/hooks/tokens/useToken.ts +++ b/src/hooks/tokens/useToken.ts @@ -17,14 +17,14 @@ export const findToken = async ( if (!tokenAddress || tokenAddress === '') return undefined; const classicAssetSearch = getClassicAssetSorobanAddress(tokenAddress!, sorobanContext); - + const formattedAddress = isAddress(classicAssetSearch ? classicAssetSearch : tokenAddress); if (!formattedAddress) return undefined; - + const fromMap = tokensAsMap[formattedAddress]; - + if (fromMap) return fromMap; - + const token = await getToken(sorobanContext, formattedAddress); // const token: TokenType = { // contract: formattedAddress, @@ -33,7 +33,7 @@ export const findToken = async ( // decimals, // icon: logo, // }; - + if (!token?.name || !token?.code) return undefined; // Here from token.name we will try to understand if this is a classic asset (even if we got a soroban contracta as address). const stellarAsset = getClassicStellarAsset(token.name); @@ -51,10 +51,9 @@ export const findToken = async ( decimals: 7, icon: '', }; + } else { + return token; } - else { - return token - }; }; const revalidateKeysCondition = (key: any) => { @@ -96,8 +95,12 @@ export function useToken(tokenAddress: string | undefined) { const bothLoading = isLoading || isStellarClassicAssetLoading; const needsWrapping = !data && isStellarClassicAsset; - - const checkContractId = (contractId: string, code: string, issuer: string): boolean | undefined => { + + const checkContractId = ( + contractId: string, + code: string, + issuer: string, + ): boolean | undefined => { if (!issuer) { return undefined; } @@ -107,7 +110,7 @@ export function useToken(tokenAddress: string | undefined) { } else { return false; } - } + }; const isSafe = data ? checkContractId(data.contract, data.code, data.issuer!) : false; const needsWrappingOnAddLiquidity = (!data && isStellarClassicAsset) || !name; diff --git a/src/interfaces/tokens.ts b/src/interfaces/tokens.ts index 1e354acb..b40c52db 100644 --- a/src/interfaces/tokens.ts +++ b/src/interfaces/tokens.ts @@ -21,3 +21,14 @@ export type TokenMapType = { export type TokenBalancesMap = { [tokenAddress: string]: { usdValue: number; balance: string }; }; + +export interface TokenVolumeData { + asset: { + name: string; + contract: string; + code: string; + icon: string; + decimals: number; + }; + volume24h: number; +}