-
Notifications
You must be signed in to change notification settings - Fork 619
[MNY-127] Dashboard: Remove unnecessary server action for fetching token list #7940
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[MNY-127] Dashboard: Remove unnecessary server action for fetching token list #7940
Conversation
|
WalkthroughIntroduces a new GET helper to fetch Universal Bridge tokens, refactors the existing tokens module to a POST-based add-token route with Bearer auth, extracts TokenMetadata into a shared types file, and updates imports in hooks and components to use the new helper and type path. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as UI (hooks/components)
participant UB as Universal Bridge API
rect rgba(200,220,255,0.25)
note over UI: Fetch token list (new helper)
UI->>UB: GET /v1/tokens?chainId&tokenAddress&limit=1000&includePrices=false<br/>Headers: x-client-id
UB-->>UI: 200 OK { data: TokenMetadata[] }
alt error
UB-->>UI: !200 + error text
UI-->>UI: Throw Error(text)
end
end
sequenceDiagram
autonumber
participant UI as UI (server/context)
participant Auth as Auth Provider
participant UB as Universal Bridge API
rect rgba(200,255,200,0.25)
note over UI: Add token (modified route)
UI->>Auth: getAuthToken()
Auth-->>UI: Bearer token
UI->>UB: POST /v1/tokens { chainId, tokenAddress }<br/>Headers: Authorization: Bearer, x-client-id: project.publishableKey
UB-->>UI: 200 OK { data: TokenMetadata[] }
alt error
UB-->>UI: !200 + error text
UI-->>UI: Throw Error(text)
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7940 +/- ##
=======================================
Coverage 56.55% 56.55%
=======================================
Files 904 904
Lines 58581 58581
Branches 4142 4142
=======================================
Hits 33128 33128
Misses 25347 25347
Partials 106 106
🚀 New features to boost your workflow:
|
size-limit report 📦
|
156f0ed to
d47a876
Compare
Merge activity
|
…ken list (#7940) <!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on refactoring the token management in the universal bridge API, including the introduction of a new `TokenMetadata` type and the relocation of the `getUniversalBridgeTokens` function to a new file. It also updates import paths for consistency. ### Detailed summary - Added `TokenMetadata` type in `apps/dashboard/src/@/api/universal-bridge/types.ts`. - Updated import path for `getUniversalBridgeTokens` in `apps/dashboard/src/@/hooks/tokens.ts` and `apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx`. - Created `getUniversalBridgeTokens` function in `apps/dashboard/src/@/api/universal-bridge/token-list.ts`. - Removed old `getUniversalBridgeTokens` function and `TokenMetadata` type from `apps/dashboard/src/@/api/universal-bridge/tokens.ts`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
d47a876 to
67616c2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/dashboard/src/@/api/universal-bridge/tokens.ts (1)
7-35: Harden server call: validate inputs, add timeout, and explicit return typeAdd minimal input checks, a fetch timeout, no-store caching, and better error messages. Also declare the return type.
import type { ProjectResponse } from "@thirdweb-dev/service-utils"; import { getAuthToken } from "@/api/auth-token"; import { UB_BASE_URL } from "./constants"; import type { TokenMetadata } from "./types"; +import { getAddress } from "thirdweb"; -export async function addUniversalBridgeTokenRoute(props: { +export async function addUniversalBridgeTokenRoute(props: { chainId: number; tokenAddress: string; project: ProjectResponse; -}) { +}): Promise<TokenMetadata[]> { + if (!Number.isInteger(props.chainId) || props.chainId <= 0) { + throw new Error("Invalid chainId"); + } + let tokenAddress: string; + try { + tokenAddress = getAddress(props.tokenAddress); + } catch { + throw new Error("Invalid tokenAddress"); + } + const authToken = await getAuthToken(); const url = new URL(`${UB_BASE_URL}/v1/tokens`); - const res = await fetch(url.toString(), { - body: JSON.stringify({ - chainId: props.chainId, - tokenAddress: props.tokenAddress, - }), - headers: { - Authorization: `Bearer ${authToken}`, - "Content-Type": "application/json", - "x-client-id": props.project.publishableKey, - } as Record<string, string>, - method: "POST", - }); + const ac = new AbortController(); + const t = setTimeout(() => ac.abort(), 15_000); + let res: Response; + try { + res = await fetch(url.toString(), { + body: JSON.stringify({ + chainId: props.chainId, + tokenAddress, + }), + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + "x-client-id": props.project.publishableKey, + }, + method: "POST", + cache: "no-store", + signal: ac.signal, + next: { revalidate: 0 }, + }); + } finally { + clearTimeout(t); + } if (!res.ok) { - const text = await res.text(); - throw new Error(text); + // Treat duplicate/exists as non-fatal (idempotent add) + if (res.status === 409) { + return []; + } + const text = await res.text().catch(() => ""); + throw new Error(`[${res.status}] ${text || res.statusText}`); } - const json = await res.json(); - return json.data as Array<TokenMetadata>; + const json = (await res.json().catch(() => ({}))) as { data?: TokenMetadata[] }; + return (json.data ?? []) as TokenMetadata[]; }apps/dashboard/src/@/hooks/tokens.ts (1)
11-15: Set React Query staleTime per guidelines (≥60s)Prevents refetch thrash and matches the dashboard guideline.
return useQuery({ enabled, queryFn: () => getUniversalBridgeTokens({ chainId }), queryKey: ["universal-bridge-tokens", chainId], + staleTime: 60_000, });
🧹 Nitpick comments (4)
apps/dashboard/src/@/components/blocks/TokenSelector.tsx (1)
52-67: Avoid duplicate native token by normalizing address comparisonIf API returns lowercase addresses, the strict equality may miss the native token and add a duplicate. Normalize using getAddress.
- const hasNativeToken = tokensQuery.data.some( - (token) => token.address === checksummedNativeTokenAddress, - ); + const hasNativeToken = tokensQuery.data.some((token) => { + try { + return getAddress(token.address) === checksummedNativeTokenAddress; + } catch { + return token.address.toLowerCase() === checksummedNativeTokenAddress.toLowerCase(); + } + });apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (1)
112-121: Optional: avoid extra network by reusing selected token’s decimalsYou already have TokenSelector; consider storing the selected TokenMetadata (or just decimals) in form state to skip this GET during submission.
apps/dashboard/src/@/api/universal-bridge/token-list.ts (2)
20-26: Clean up headers; avoid unnecessary Content-Type on GET; pass signal; omit empty client-id.Removes preflight-triggering header, adds Accept, and wires cancellation.
- const res = await fetch(url.toString(), { - headers: { - "Content-Type": "application/json", - "x-client-id": NEXT_PUBLIC_DASHBOARD_CLIENT_ID, - } as Record<string, string>, - method: "GET", - }); + const headers: HeadersInit = { Accept: "application/json" }; + if (NEXT_PUBLIC_DASHBOARD_CLIENT_ID) { + (headers as Record<string, string>)["x-client-id"] = NEXT_PUBLIC_DASHBOARD_CLIENT_ID; + } + const res = await fetch(url.toString(), { + method: "GET", + headers, + signal: props.signal, + });
28-31: Improve error surface: include status and JSON message when available.Easier debugging and fewer HTML error blobs in thrown messages.
- if (!res.ok) { - const text = await res.text(); - throw new Error(text); - } + if (!res.ok) { + let message = ""; + const ct = res.headers.get("content-type") || ""; + if (ct.includes("application/json")) { + try { + const err = await res.json(); + message = (err && (err.message || err.error)) || JSON.stringify(err); + } catch { + message = await res.text(); + } + } else { + message = await res.text(); + } + throw new Error(`${res.status} ${res.statusText}: ${message}`); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
apps/dashboard/src/@/api/universal-bridge/token-list.ts(1 hunks)apps/dashboard/src/@/api/universal-bridge/tokens.ts(1 hunks)apps/dashboard/src/@/api/universal-bridge/types.ts(1 hunks)apps/dashboard/src/@/components/blocks/TokenSelector.tsx(1 hunks)apps/dashboard/src/@/hooks/tokens.ts(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Files:
apps/dashboard/src/@/api/universal-bridge/types.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsxapps/dashboard/src/@/hooks/tokens.tsapps/dashboard/src/@/components/blocks/TokenSelector.tsxapps/dashboard/src/@/api/universal-bridge/token-list.tsapps/dashboard/src/@/api/universal-bridge/tokens.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/@/api/universal-bridge/types.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsxapps/dashboard/src/@/hooks/tokens.tsapps/dashboard/src/@/components/blocks/TokenSelector.tsxapps/dashboard/src/@/api/universal-bridge/token-list.tsapps/dashboard/src/@/api/universal-bridge/tokens.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/@/api/universal-bridge/types.tsapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsxapps/dashboard/src/@/hooks/tokens.tsapps/dashboard/src/@/components/blocks/TokenSelector.tsxapps/dashboard/src/@/api/universal-bridge/token-list.tsapps/dashboard/src/@/api/universal-bridge/tokens.ts
🧠 Learnings (10)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
📚 Learning: 2025-08-27T22:11:41.748Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/create-token-page-impl.tsx:465-473
Timestamp: 2025-08-27T22:11:41.748Z
Learning: In the token creation flow (create-token-page-impl.tsx), the createTokenOnUniversalBridge() call is intentionally not awaited (fire-and-forget pattern) to allow the token creation process to complete immediately without waiting for the bridge operation. This is a deliberate design choice to prioritize user experience by not blocking the main flow with supplementary bridge operations.
Applied to files:
apps/dashboard/src/@/hooks/tokens.tsapps/dashboard/src/@/api/universal-bridge/token-list.tsapps/dashboard/src/@/api/universal-bridge/tokens.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use design system tokens (e.g., `bg-card`, `border-border`, `text-muted-foreground`)
Applied to files:
apps/dashboard/src/@/components/blocks/TokenSelector.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/*` (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Applied to files:
apps/dashboard/src/@/components/blocks/TokenSelector.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Applied to files:
apps/dashboard/src/@/components/blocks/TokenSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/dashboard/src/@/components/blocks/TokenSelector.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Pass the token in the `Authorization: Bearer` header – never embed it in the URL.
Applied to files:
apps/dashboard/src/@/api/universal-bridge/tokens.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Use `Authorization: Bearer` header – never embed tokens in URLs
Applied to files:
apps/dashboard/src/@/api/universal-bridge/tokens.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Keep tokens secret via internal API routes or server actions
Applied to files:
apps/dashboard/src/@/api/universal-bridge/tokens.ts
🧬 Code graph analysis (1)
apps/dashboard/src/@/api/universal-bridge/token-list.ts (3)
apps/dashboard/src/@/api/universal-bridge/constants.ts (1)
UB_BASE_URL(1-1)apps/dashboard/src/@/constants/public-envs.ts (1)
NEXT_PUBLIC_DASHBOARD_CLIENT_ID(1-2)apps/dashboard/src/@/api/universal-bridge/types.ts (1)
TokenMetadata(1-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/@/api/universal-bridge/types.ts (1)
1-8: Type extraction looks goodTokenMetadata definition is concise and matches current usages.
apps/dashboard/src/@/components/blocks/TokenSelector.tsx (1)
8-8: Import path update is correctSwitching to "@/api/universal-bridge/types" aligns with the new types module.
apps/dashboard/src/@/api/universal-bridge/tokens.ts (1)
1-5: No remaining imports ofgetUniversalBridgeTokensfromtokens.ts
Removal of the GET helper is complete—no lingering imports were found.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (2)
14-15: Import now targets the client-safe GET helperLooks correct for removing server action usage here.
92-101: getUniversalBridgeTokens helper is client-safe: token-list.ts contains no"use server"directives, auth cookies, or server-only imports.apps/dashboard/src/@/hooks/tokens.ts (1)
2-2: Import path update looks goodHook now sources the client-side GET helper.
apps/dashboard/src/@/api/universal-bridge/token-list.ts (1)
5-35: Optional: add Next.js fetch revalidation
If this API is primarily called server-side, pass{ next: { revalidate: 60 } }tofetch; on the client, theuseQuerywrapper incontract-hooks.tsalready setsstaleTime: 60 * 60 * 1000.
| export async function getUniversalBridgeTokens(props: { | ||
| chainId?: number; | ||
| address?: string; | ||
| }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add explicit return type (and optional AbortSignal).
Conform to TS guidelines and make cancellation possible without breaking callers.
-export async function getUniversalBridgeTokens(props: {
- chainId?: number;
- address?: string;
-}) {
+export async function getUniversalBridgeTokens(props: {
+ chainId?: number;
+ address?: string;
+ signal?: AbortSignal;
+}): Promise<TokenMetadata[]> {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export async function getUniversalBridgeTokens(props: { | |
| chainId?: number; | |
| address?: string; | |
| }) { | |
| export async function getUniversalBridgeTokens(props: { | |
| chainId?: number; | |
| address?: string; | |
| signal?: AbortSignal; | |
| }): Promise<TokenMetadata[]> { |
🤖 Prompt for AI Agents
In apps/dashboard/src/@/api/universal-bridge/token-list.ts around lines 5–8,
update the function signature to include an explicit return type and an optional
AbortSignal parameter: e.g. export async function
getUniversalBridgeTokens(props: { chainId?: number; address?: string; signal?:
AbortSignal; }): Promise<YourTokenType[]> { ... }. Replace YourTokenType with
the appropriate token interface (or import it), ensure all internal fetch/async
calls accept/forward props.signal to enable cancellation, and update any
callers/tests if needed to satisfy the new return type and optional signal
parameter.
| const url = new URL(`${UB_BASE_URL}/v1/tokens`); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard missing UB_BASE_URL and build URL with a base.
Avoid “Invalid URL” at runtime and produce a clear config error.
- const url = new URL(`${UB_BASE_URL}/v1/tokens`);
+ if (!UB_BASE_URL) {
+ throw new Error("Missing NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST for Universal Bridge.");
+ }
+ const url = new URL("/v1/tokens", UB_BASE_URL);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const url = new URL(`${UB_BASE_URL}/v1/tokens`); | |
| // apps/dashboard/src/@/api/universal-bridge/token-list.ts | |
| // …previous code… | |
| if (!UB_BASE_URL) { | |
| throw new Error("Missing NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST for Universal Bridge."); | |
| } | |
| const url = new URL("/v1/tokens", UB_BASE_URL); | |
| // …subsequent code… |
🤖 Prompt for AI Agents
In apps/dashboard/src/@/api/universal-bridge/token-list.ts around lines 9 to 10,
the code constructs a URL with `${UB_BASE_URL}/v1/tokens` without validating
UB_BASE_URL which can cause an "Invalid URL" at runtime; add a guard that throws
a clear, descriptive configuration error if UB_BASE_URL is missing or empty, and
build the token endpoint using the URL constructor with the base parameter
(e.g., new URL('/v1/tokens', UB_BASE_URL)) to avoid malformed URL creation.
| if (props.chainId) { | ||
| url.searchParams.append("chainId", String(props.chainId)); | ||
| } | ||
| if (props.address) { | ||
| url.searchParams.append("tokenAddress", props.address); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix truthy check for chainId (0 should be valid).
Use a nullish check so chainId=0 isn’t dropped.
- if (props.chainId) {
+ if (props.chainId != null) {
url.searchParams.append("chainId", String(props.chainId));
}
- if (props.address) {
+ if (props.address) {
url.searchParams.append("tokenAddress", props.address);
}Optional: normalize props.address to lowercase if backend is case-insensitive.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (props.chainId) { | |
| url.searchParams.append("chainId", String(props.chainId)); | |
| } | |
| if (props.address) { | |
| url.searchParams.append("tokenAddress", props.address); | |
| } | |
| if (props.chainId != null) { | |
| url.searchParams.append("chainId", String(props.chainId)); | |
| } | |
| if (props.address) { | |
| url.searchParams.append("tokenAddress", props.address); | |
| } |
🤖 Prompt for AI Agents
In apps/dashboard/src/@/api/universal-bridge/token-list.ts around lines 11 to
16, the current truthy check drops chainId when it is 0; change the condition to
a nullish check (e.g., props.chainId != null) so 0 is allowed, keep appending
chainId via String(props.chainId). Also change the address check to explicitly
test for null/undefined (e.g., props.address != null) and, if the backend is
case-insensitive, normalize by using props.address.toLowerCase() before
appending tokenAddress.
| const json = await res.json(); | ||
| return json.data as Array<TokenMetadata>; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Return typed payload and validate shape.
Avoids implicit any, aligns with “return typed results”.
- const json = await res.json();
- return json.data as Array<TokenMetadata>;
+ const { data } = (await res.json()) as { data: TokenMetadata[] };
+ if (!Array.isArray(data)) {
+ throw new Error("Malformed response: expected data: TokenMetadata[].");
+ }
+ return data;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const json = await res.json(); | |
| return json.data as Array<TokenMetadata>; | |
| } | |
| const { data } = (await res.json()) as { data: TokenMetadata[] }; | |
| if (!Array.isArray(data)) { | |
| throw new Error("Malformed response: expected data: TokenMetadata[]."); | |
| } | |
| return data; | |
| } |
🤖 Prompt for AI Agents
In apps/dashboard/src/@/api/universal-bridge/token-list.ts around lines 33 to
35, the function currently returns json.data without a typed response or
validation; change it to return a properly typed payload (define or import an
interface such as { data: TokenMetadata[] } for the response) and validate the
runtime shape before returning (e.g., ensure json is an object and json.data is
an array of objects, optionally checking required TokenMetadata fields); if
validation fails, throw a descriptive error; finally return json.data typed as
Array<TokenMetadata>.

PR-Codex overview
This PR focuses on refactoring the token management functionality in the
universal-bridgeAPI by updating imports, relocating theTokenMetadatatype definition, and implementing a new token fetching function.Detailed summary
TokenMetadatatype inapps/dashboard/src/@/api/universal-bridge/types.ts.getUniversalBridgeTokensfromtokenstotoken-list.getUniversalBridgeTokensfunction inapps/dashboard/src/@/api/universal-bridge/token-list.ts.getUniversalBridgeTokensandTokenMetadatadefinition fromapps/dashboard/src/@/api/universal-bridge/tokens.ts.Summary by CodeRabbit