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>
90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { getTokenAggregationApiBase } from '@/services/api/tokenAggregation'
|
|
|
|
export interface WrappedTransportTokenRow {
|
|
chainId: number
|
|
chainName: string
|
|
symbol: string
|
|
address: string
|
|
assetClass?: string
|
|
familyKey?: string
|
|
}
|
|
|
|
export interface CwRegistryChainRow {
|
|
chainId: number
|
|
chainIdText?: string
|
|
name: string
|
|
tokens: Array<{
|
|
symbol: string
|
|
address: string
|
|
assetClass?: string
|
|
familyKey?: string
|
|
}>
|
|
}
|
|
|
|
export interface CwRegistryResponse {
|
|
generatedAt: string
|
|
source: string
|
|
complete: boolean
|
|
chains: CwRegistryChainRow[]
|
|
}
|
|
|
|
export function externalChainExplorerUrl(chainId: number, address: string): string | undefined {
|
|
const normalized = address.trim()
|
|
if (!/^0x[a-fA-F0-9]{40}$/.test(normalized)) return undefined
|
|
switch (chainId) {
|
|
case 138:
|
|
return `/tokens/${normalized}`
|
|
case 1:
|
|
return `https://etherscan.io/token/${normalized}`
|
|
case 56:
|
|
return `https://bscscan.com/token/${normalized}`
|
|
case 137:
|
|
return `https://polygonscan.com/token/${normalized}`
|
|
case 100:
|
|
return `https://gnosisscan.io/token/${normalized}`
|
|
case 10:
|
|
return `https://optimistic.etherscan.io/token/${normalized}`
|
|
case 42161:
|
|
return `https://arbiscan.io/token/${normalized}`
|
|
case 8453:
|
|
return `https://basescan.org/token/${normalized}`
|
|
case 43114:
|
|
return `https://snowtrace.io/token/${normalized}`
|
|
case 25:
|
|
return `https://cronoscan.com/token/${normalized}`
|
|
case 42220:
|
|
return `https://celoscan.io/token/${normalized}`
|
|
case 1111:
|
|
return `https://scan.wemix.com/token/${normalized}`
|
|
case 651940:
|
|
return `https://alltra.global/address/${normalized}`
|
|
default:
|
|
return undefined
|
|
}
|
|
}
|
|
|
|
export async function fetchCwRegistry(): Promise<CwRegistryChainRow[]> {
|
|
const response = await fetch(`${getTokenAggregationApiBase()}/report/cw-registry`, { cache: 'no-store' })
|
|
if (!response.ok) return []
|
|
const body = (await response.json()) as CwRegistryResponse
|
|
return Array.isArray(body.chains) ? body.chains : []
|
|
}
|
|
|
|
export function flattenCwRegistry(chains: CwRegistryChainRow[]): WrappedTransportTokenRow[] {
|
|
const rows: WrappedTransportTokenRow[] = []
|
|
for (const chain of chains) {
|
|
for (const token of chain.tokens ?? []) {
|
|
if (!token.address?.startsWith('0x')) continue
|
|
rows.push({
|
|
chainId: chain.chainId,
|
|
chainName: chain.name || `Chain ${chain.chainId}`,
|
|
symbol: token.symbol,
|
|
address: token.address,
|
|
assetClass: token.assetClass,
|
|
familyKey: token.familyKey,
|
|
})
|
|
}
|
|
}
|
|
return rows
|
|
}
|