feat(explorer): dual-chain wallet metadata, native coin pricing, and UI refresh.
Some checks failed
Deploy Explorer Live / deploy (push) Failing after 20s
Validate Explorer / frontend (push) Failing after 24s
Validate Explorer / smoke-e2e (push) Has been skipped

Add Chain 138 wallet network metadata and stats coin-price enrichment; sync frontend explorer SPA, command center, and address/token pages with backend config.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-06-19 16:16:17 -07:00
parent 0f02e6e54f
commit b87ebee6a1
94 changed files with 7648 additions and 1124 deletions

View File

@@ -0,0 +1,109 @@
import type { AddressTokenBalance } from '@/services/api/addresses'
import type { TokenAggregationMarketSnapshot, TokenAggregationTokenSnapshot } from '@/services/api/tokenAggregation'
export interface ResolvedTokenMarket {
priceUsd?: number
liquidityUsd?: number
source?: 'token-aggregation' | 'blockscout' | 'derived'
pricingKind?: 'spot' | 'lp-share'
isCanonicalClone?: boolean
}
export function isLikelyLpReceiptSymbol(symbol: string | undefined): boolean {
if (!symbol) return false
const upper = symbol.toUpperCase()
return upper.includes('DLP') || upper.endsWith('-LP') || upper.startsWith('LP-') || upper === 'LP'
}
export function formatBalanceUsdLabel(
priceUsd: number | undefined,
balanceUsd: number | undefined,
options?: { pricingKind?: 'spot' | 'lp-share'; atTransfer?: boolean },
): string {
if (options?.pricingKind === 'lp-share') {
return 'LP share — USD N/A'
}
if (balanceUsd != null) {
return options?.atTransfer ? `${formatUsd(balanceUsd)} (at transfer)` : `${formatUsd(balanceUsd)}`
}
if (priceUsd == null) {
return 'USD unavailable'
}
return 'USD unavailable'
}
function formatUsd(value: number): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: value >= 100 ? 0 : 2,
}).format(value)
}
function parseUsd(value: string | number | null | undefined): number | undefined {
if (value == null) return undefined
const numeric = typeof value === 'number' ? value : Number(value)
return Number.isFinite(numeric) && numeric > 0 ? numeric : undefined
}
export function resolveTokenMarketForBalance(
balance: Pick<AddressTokenBalance, 'token_address' | 'exchange_rate' | 'token_symbol'>,
tokenMarkets: Record<string, TokenAggregationTokenSnapshot>,
): ResolvedTokenMarket {
const key = balance.token_address.toLowerCase()
const aggregationSnapshot = tokenMarkets[key]
const aggregationMarket: TokenAggregationMarketSnapshot | null | undefined = aggregationSnapshot?.market
const aggregationPrice = aggregationMarket?.priceUsd
const blockscoutPrice = parseUsd(balance.exchange_rate)
const pricingKind = aggregationMarket?.pricingKind
?? (isLikelyLpReceiptSymbol(balance.token_symbol ?? aggregationSnapshot?.symbol) ? 'lp-share' : 'spot')
const isCanonicalClone = aggregationMarket?.isCanonicalClone
if (aggregationPrice != null && aggregationPrice > 0) {
return {
priceUsd: aggregationPrice,
liquidityUsd: aggregationMarket?.liquidityUsd,
source: 'token-aggregation',
pricingKind,
isCanonicalClone,
}
}
if (blockscoutPrice != null) {
return {
priceUsd: blockscoutPrice,
liquidityUsd: aggregationMarket?.liquidityUsd,
source: 'blockscout',
pricingKind,
isCanonicalClone,
}
}
return {
priceUsd: undefined,
liquidityUsd: aggregationMarket?.liquidityUsd,
source: 'derived',
pricingKind,
isCanonicalClone,
}
}
export function estimateTokenBalanceUsd(
rawAmount: string,
decimals: number,
priceUsd: number | undefined,
): number | undefined {
if (priceUsd == null || !(priceUsd > 0) || !rawAmount) return undefined
try {
const raw = BigInt(rawAmount)
if (raw <= 0n) return 0
const scale = 10n ** BigInt(decimals)
const whole = raw / scale
const fraction = raw % scale
const amount = Number(whole) + Number(fraction) / Number(scale)
if (!Number.isFinite(amount)) return undefined
return amount * priceUsd
} catch {
return undefined
}
}