From fd06c60e532d3f19b4ee302db7675604207967a8 Mon Sep 17 00:00:00 2001 From: enny791 Date: Sun, 30 Aug 2026 13:03:41 +0100 Subject: [PATCH] Fix issue 1264: Centralize token-symbol resolution --- .../app/streams/[id]/stream-details-content.tsx | 9 ++------- frontend/src/lib/api/streams.ts | 12 ++---------- frontend/src/lib/dashboard.ts | 16 ++-------------- frontend/src/lib/soroban.ts | 14 ++++++++++++++ 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/frontend/src/app/streams/[id]/stream-details-content.tsx b/frontend/src/app/streams/[id]/stream-details-content.tsx index 63879898..6ae142e8 100644 --- a/frontend/src/app/streams/[id]/stream-details-content.tsx +++ b/frontend/src/app/streams/[id]/stream-details-content.tsx @@ -20,6 +20,7 @@ import { resumeStream, toBaseUnits, toSorobanErrorMessage, + resolveTokenSymbol, } from "@/lib/soroban"; import { CancelConfirmModal } from "@/components/stream-creation/CancelConfirmModal"; import type { BackendStreamEvent } from "@/lib/api-types"; @@ -51,12 +52,6 @@ interface StreamDetail { const API_BASE_URL = `${getApiBaseUrl()}/v1`; const EVENTS_PER_PAGE = 10; -const TOKEN_SYMBOLS: Record = { - "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCN": "XLM", - "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA": "USDC", - "CCWAMYJME4YOIUNAKVYEBYOG5I65QMKEX2NMN4OJAPXRPIF24ONPSHY": "EURC", -}; - const EVENT_STYLES: Record = { CREATED: { color: "#22c55e", icon: "✓", label: "Created" }, TOPPED_UP: { color: "#3b82f6", icon: "+", label: "Topped Up" }, @@ -203,7 +198,7 @@ export default function StreamDetailsContent({ streamId }: { streamId: string }) const tokenSymbol = useMemo(() => { if (!stream) return "??"; - return TOKEN_SYMBOLS[stream.tokenAddress] || stream.tokenAddress.slice(0, 4); + return resolveTokenSymbol(stream.tokenAddress); }, [stream]); const handleWithdraw = async () => { diff --git a/frontend/src/lib/api/streams.ts b/frontend/src/lib/api/streams.ts index d9a596c3..7103a251 100644 --- a/frontend/src/lib/api/streams.ts +++ b/frontend/src/lib/api/streams.ts @@ -1,5 +1,5 @@ import type { BackendStream } from "@/lib/api-types"; -import { TOKEN_ADDRESSES } from "@/lib/soroban"; +import { TOKEN_ADDRESSES, resolveTokenSymbol } from "@/lib/soroban"; import { shortenPublicKey } from "@/lib/wallet"; import { DEFAULT_FETCH_TIMEOUT_MS, @@ -33,14 +33,6 @@ interface StreamListResponse { data?: BackendStream[]; } -function resolveTokenLabel(tokenAddress: string): string { - const entry = Object.entries(TOKEN_ADDRESSES).find( - ([, address]) => address === tokenAddress, - ); - - return entry?.[0] ?? `${tokenAddress.slice(0, 6)}...${tokenAddress.slice(-4)}`; -} - function toIncomingStreamStatus(stream: BackendStream): IncomingStreamStatus { if (stream.isPaused) return "Paused"; if (stream.isActive) return "Active"; @@ -53,7 +45,7 @@ function mapBackendStream(stream: BackendStream): IncomingStreamRecord { streamId: stream.streamId, sender: stream.sender, senderDisplay: shortenPublicKey(stream.sender), - token: resolveTokenLabel(stream.tokenAddress), + token: resolveTokenSymbol(stream.tokenAddress), tokenAddress: stream.tokenAddress, ratePerSecond: toTokenAmount(stream.ratePerSecond), deposited: toTokenAmount(stream.depositedAmount), diff --git a/frontend/src/lib/dashboard.ts b/frontend/src/lib/dashboard.ts index 448e7185..44f05b27 100644 --- a/frontend/src/lib/dashboard.ts +++ b/frontend/src/lib/dashboard.ts @@ -1,7 +1,7 @@ import { useQuery } from "@tanstack/react-query"; import type { BackendStream } from "./api-types"; import { getStreamsEndpointCandidates, toTokenAmount } from "./api/_shared"; -import { TOKEN_ADDRESSES } from "./soroban"; +import { TOKEN_ADDRESSES, resolveTokenSymbol } from "./soroban"; import { logger } from "./logger"; export interface ActivityItem { @@ -64,18 +64,6 @@ function shortenAddress(address: string): string { return `${address.slice(0, 6)}...${address.slice(-4)}`; } -/** - * Resolves a token contract address to its symbol (XLM/USDC/EURC), falling - * back to a shortened address when the token is unknown. - */ -function resolveTokenLabel(tokenAddress: string): string { - const entry = Object.entries(TOKEN_ADDRESSES).find( - ([, address]) => address === tokenAddress, - ); - - return entry?.[0] ?? shortenAddress(tokenAddress); -} - /** * Derives the display status from the backend flags. A paused stream reads * "Paused"; an active one "Active". An inactive stream is "Cancelled" when a @@ -137,7 +125,7 @@ export function mapBackendStreamToFrontend(s: BackendStream, counterparty: strin id: s.streamId.toString(), recipient: shortenAddress(counterparty), amount: deposited, - token: resolveTokenLabel(s.tokenAddress), + token: resolveTokenSymbol(s.tokenAddress), status: mapStreamStatus(s), deposited, withdrawn, diff --git a/frontend/src/lib/soroban.ts b/frontend/src/lib/soroban.ts index 5c394bec..b6384dda 100644 --- a/frontend/src/lib/soroban.ts +++ b/frontend/src/lib/soroban.ts @@ -141,6 +141,20 @@ export function getTokenAddress(symbol: string): string { return address; } +/** + * Resolves a token contract address to its symbol (XLM/USDC/EURC), falling + * back to a shortened address when the token is unknown. + */ +export function resolveTokenSymbol(tokenAddress: string): string { + const entry = Object.entries(TOKEN_ADDRESSES).find( + ([, address]) => address === tokenAddress, + ); + if (entry) return entry[0]; + + if (!tokenAddress || tokenAddress.length < 10) return tokenAddress; + return `${tokenAddress.slice(0, 6)}...${tokenAddress.slice(-4)}`; +} + export async function fetchTokenBalance( publicKey: string, tokenSymbol: string,