This commit is contained in:
2026-06-01 23:28:57 +03:00
parent 895bec2a50
commit b86f3209f5
22 changed files with 1036 additions and 269 deletions

View File

@@ -1,4 +1,5 @@
import { COIN_ICONS } from '@shared/assets/coins'
import type { Chain } from '@features/wallet'
export interface Token {
ticker: string
@@ -10,6 +11,10 @@ export interface Token {
bal: string
usd: string
fav: boolean
/** Stable unique key — tickers can repeat across chains (e.g. USDT on ETH/TRX/BSC). */
id?: string
/** Network this row belongs to — used to target send/receive modals. */
chain?: Chain
}
export const TOKENS: readonly Token[] = [

View File

@@ -1,4 +1,4 @@
import { useWalletBalance } from '@features/wallet'
import { useWalletBalance, usePortfolio, CHAINS } from '@features/wallet'
import type { Chain } from '@features/wallet'
import { getCoinIcon } from '@shared/assets/coins'
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
@@ -76,3 +76,65 @@ export function useChainTokenRows(chain: Chain) {
return { rows: [nativeRow, ...tokenRows], isLoading }
}
function hasBalance(amountFormatted: string): boolean {
return parseFloat(amountFormatted) > 0
}
function unitPrice(usd: number, amountFormatted: string): number | null {
const amount = parseFloat(amountFormatted)
return amount > 0 && usd > 0 ? usd / amount : null
}
export function useAllWalletTokenRows() {
const { data, isLoading } = usePortfolio()
if (!data) return { rows: [] as Token[], isLoading }
const rows: Token[] = []
for (const chain of CHAINS) {
const chainData = data.chains?.[chain]
if (!chainData) continue
const nativeTicker = NATIVE_TICKER[chain]
if (chainData.native && hasBalance(chainData.native.amountFormatted)) {
const nativeStatic = lookupStatic(nativeTicker)
rows.push({
id: `${chain}-${nativeTicker}`,
chain,
ticker: nativeTicker,
name: NATIVE_NAME[chain],
logo: getCoinIcon(nativeTicker) ?? nativeStatic?.logo,
color: nativeStatic?.color ?? DEFAULT_TOKEN_COLOR,
price: formatPrice(unitPrice(chainData.native.usd, chainData.native.amountFormatted)),
change: 0,
bal: truncateDecimals(chainData.native.amountFormatted),
usd: formatUsd(chainData.native.usd),
fav: false,
})
}
for (const token of chainData.tokens ?? []) {
if (!hasBalance(token.amountFormatted)) continue
const staticToken = lookupStatic(token.symbol)
rows.push({
id: `${chain}-${token.symbol}`,
chain,
ticker: token.symbol,
name: staticToken?.name ?? token.symbol,
logo: getCoinIcon(token.symbol) ?? staticToken?.logo,
color: staticToken?.color ?? DEFAULT_TOKEN_COLOR,
price: formatPrice(unitPrice(token.usd, token.amountFormatted)),
change: 0,
bal: truncateDecimals(token.amountFormatted),
usd: formatUsd(token.usd),
fav: false,
})
}
}
rows.sort((a, b) => (parseFloat(b.usd.replace(/[$,—]/g, '')) || 0) - (parseFloat(a.usd.replace(/[$,—]/g, '')) || 0))
return { rows, isLoading }
}