-
Notifications
You must be signed in to change notification settings - Fork 619
[MNY-274] Dashboard: Generate swap token pages for popular tokens #8278
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
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
4 Skipped Deployments
💡 Enable Vercel Agent with $100 free credit for automated AI reviews |
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. |
WalkthroughReplace flat buy/sell props with structured Changes
Sequence Diagram(s)sequenceDiagram
participant StaticGen as Next build
participant SlugMap as slug-map.ts
participant PageBuild as [token-pair]/page.tsx (generateMetadata)
participant TokenAPI as Token metadata source
rect rgb(235,245,255)
Note over StaticGen,SlugMap: Build-time static params
StaticGen->>SlugMap: generateTokenPairSlugs()
SlugMap-->>StaticGen: list of route slugs
end
rect rgb(235,245,255)
Note over PageBuild,TokenAPI: Build-time metadata resolution
PageBuild->>SlugMap: getTokenPairData(slug)
SlugMap-->>PageBuild: TokenPairData
PageBuild->>TokenAPI: fetch token metadata
TokenAPI-->>PageBuild: token metadata -> Next.js metadata
end
sequenceDiagram
participant Caller as Page/Component
participant BridgeUI as BridgePageUI
participant UniversalEmbed as UniversalBridgeEmbed
participant BuySwap as BuyAndSwapEmbed
Caller->>BridgeUI: render(title, buyTab?, swapTab?)
BridgeUI->>UniversalEmbed: pass buyTab/swapTab
UniversalEmbed->>BuySwap: forward buyTab/swapTab
BuySwap->>BuySwap: derive chainId / tokenAddress / amount (guards) and handle events
BuySwap-->>Caller: embedded UI rendered
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8278 +/- ##
=======================================
Coverage 54.89% 54.89%
=======================================
Files 919 919
Lines 60622 60622
Branches 4126 4126
=======================================
Hits 33278 33278
Misses 27242 27242
Partials 102 102
🚀 New features to boost your workflow:
|
size-limit report 📦
|
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: 9
🧹 Nitpick comments (7)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
17-39: Prop unification looks good; consider extracting wallet list.The new buy/sell shape aligns with BuyAndSwapEmbed. Extract bridgeWallets to a small shared module (no "use client") so both header and embed can import without pulling a client module into server code paths.
apps/dashboard/src/app/bridge/components/bridge-page.tsx (2)
1-1: Unify cn import to project-standard path.Import cn from "@/lib/utils" for consistency with our dashboard guidelines. As per coding guidelines.
25-28: Reuse shared DotsBackgroundPattern; remove local duplicate.We already expose a DotsBackgroundPattern in "@/components/ui/background-patterns". Import and use it, then delete the local implementation to avoid drift.
-import { cn } from "@workspace/ui/lib/utils"; +import { cn } from "@/lib/utils"; +import { DotsBackgroundPattern } from "@/components/ui/background-patterns"; @@ - <div className="flex grow items-center justify-center px-4 relative pt-12 pb-20 lg:py-28 min-h-[calc(100dvh-60px)]"> - <DotsBackgroundPattern /> + <div className="flex grow items-center justify-center px-4 relative pt-12 pb-20 lg:py-28 min-h-[calc(100dvh-60px)]"> + <DotsBackgroundPattern className="-inset-x-36 -inset-y-24 hidden lg:block text-foreground/20 dark:text-muted-foreground/20" /> <UniversalBridgeEmbed buy={props.buy} sell={props.sell} /> </div> @@ -function DotsBackgroundPattern(props: { className?: string }) { - return ( - <div - className={cn( - "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block", - props.className, - )} - style={{ - backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)", - backgroundSize: "24px 24px", - maskImage: - "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)", - }} - /> - ); -} +// removed local DotsBackgroundPattern in favor of shared componentAlso applies to: 60-66, 68-83
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)
18-22: Constrain static generation to a curated set (avoid explosion).generateStaticParams over all tokens can explode build time/size. Start with a curated list (top queries), and fallback dynamic for the rest, or paginate the static set.
87-93: Deduplicate cleanedChainName; import shared util instead.We already have a cleanedChainName in packages/thirdweb (swap-widget/utils). Reuse it or extract a small shared util in the dashboard to avoid divergence.
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
123-123: Add explicit return type annotation.The function should explicitly declare its return type for better type safety and documentation.
Apply this diff:
-export function generateTokenPairSlugs() { +export function generateTokenPairSlugs(): string[] { const tokenIds = Object.keys(tokens);apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
116-125: Consider extracting buyChainId resolution.The same buyChainId extraction pattern is repeated in three callbacks (onError, onCancel, onSuccess). Consider extracting this to a helper function to reduce duplication.
Example helper function to add above the component:
function extractBuyChainId(quote: { type: string; intent: any } | undefined): number | undefined { return quote?.type === "buy" ? quote.intent.destinationChainId : quote?.type === "onramp" ? quote.intent.chainId : undefined; }Then use it in the callbacks:
- const buyChainId = - quote?.type === "buy" - ? quote.intent.destinationChainId - : quote?.type === "onramp" - ? quote.intent.chainId - : undefined; + const buyChainId = extractBuyChainId(quote);Also applies to: 149-158, 181-190
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.pngis excluded by!**/*.png
📒 Files selected for processing (8)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(8 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/components/bridge-page.tsx(1 hunks)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts(1 hunks)apps/dashboard/src/app/bridge/page.tsx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
**/*.{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/app/bridge/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
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/app/bridge/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧠 Learnings (1)
📚 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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧬 Code graph analysis (7)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
Page(53-85)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(6-39)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (3)
apps/dashboard/src/@/components/blocks/grid-pattern-embed-container.tsx (1)
GridPatternEmbedContainer(3-23)apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbed(35-277)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/app/bridge/components/header.tsx (1)
BridgePageHeader(14-68)apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
DotsBackgroundPattern(4-19)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
UniversalBridgeEmbed(17-41)apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
FaqAccordion(8-23)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
generateTokenPairSlugs(123-150)getTokenPairData(72-89)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(6-39)packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
cleanedChainName(1-3)apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
serverThirdwebClient(8-11)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
reportTokenBuyFailed(264-266)reportTokenBuyCancelled(276-278)reportTokenBuySuccessful(252-254)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbed(35-277)
⏰ 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). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/dashboard/src/app/bridge/page.tsx (1)
17-27: LGTM on simplified Bridge page.Clean wrapper around BridgePageUI; metadata is consistent with copy.
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
53-55: Verify Next.js params-as-Promise pattern.Typing params as Promise and awaiting it is non-standard in many routes. Confirm this is intended for your Next version/setup; otherwise switch to { params }: { params: Params } and drop await.
Also applies to: 24-31
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
1-10: LGTM: Clean type definitions.The import and type structure appropriately supports both native and ERC20 tokens with proper undefined guards.
91-121: LGTM: Proper token resolution with guards.The helper correctly handles both native tokens (single slug) and ERC20 tokens (hyphenated slug) with appropriate undefined guards.
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
36-52: LGTM: Clean prop structure refactor.The new buy/sell object structure provides better clarity and separation of concerns compared to the previous flat props.
100-104: LGTM: Proper optional handling.The chain and amount extraction correctly uses optional chaining with sensible defaults.
230-242: LGTM: Prefill logic correctly updated.The SwapWidget prefill properly maps the new buy/sell structure to the expected format with appropriate optional handling.
...c/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
Outdated
Show resolved
Hide resolved
.../src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
Show resolved
Hide resolved
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
Outdated
Show resolved
Hide resolved
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: 1
♻️ Duplicate comments (4)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
213-213: Avoid unsafe tokenAddress cast; validate or omit.Casting may pass malformed/native addresses to BuyWidget.
- tokenAddress={props.buy?.tokenAddress as `0x${string}` | undefined} + tokenAddress={ + props.buy?.tokenAddress && props.buy.tokenAddress.startsWith("0x") + ? (props.buy.tokenAddress as `0x${string}`) + : undefined + }Optionally add a small
isHexAddresshelper or reuse a shared validator.
139-145: Deriveis_testnetfrom chainId (don’t hardcode false).Hardcoding corrupts analytics on testnets. Compute once and reuse.
+// near top-level (after imports) +const TESTNET_CHAIN_IDS = new Set<number>([ + 5, // Goerli + 11155111, // Sepolia + 80001, // Polygon Mumbai + 84531, // Base Goerli + 421613, // Arbitrum Goerli + 43113, // Avalanche Fuji + 97, // BSC Testnet +]); + @@ reportAssetBuyFailed({ assetType: "coin", chainId: buyChainId, error: errorMessage, contractType: undefined, - is_testnet: false, + is_testnet: TESTNET_CHAIN_IDS.has(buyChainId), }); @@ reportAssetBuyCancelled({ assetType: "coin", chainId: buyChainId, contractType: undefined, - is_testnet: false, + is_testnet: TESTNET_CHAIN_IDS.has(buyChainId), }); @@ reportAssetBuySuccessful({ assetType: "coin", chainId: buyChainId, contractType: undefined, - is_testnet: false, + is_testnet: TESTNET_CHAIN_IDS.has(buyChainId), });Alternatively, centralize this in a shared util. Based on learnings.
Also applies to: 171-177, 204-209
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)
63-72: Fix buy/sell inversion to match “from → to”.For route “X-to-Y”: sell must be X (origin), buy must be Y (destination). Currently inverted.
<BridgePageUI - buy={{ - tokenAddress: fromToken.address, - chainId: fromToken.chainId, - }} - sell={{ - tokenAddress: toToken.address, - chainId: toToken.chainId, - }} + buy={{ + tokenAddress: toToken.address, + chainId: toToken.chainId, + }} + sell={{ + tokenAddress: fromToken.address, + chainId: fromToken.chainId, + }}
95-101: Fix reversed slug parsing and remove debug log.The bug is confirmed:
getTokenPairDataassigns reversed variable names—const [toSlug, fromSlug]should beconst [fromSlug, toSlug]. Since URL format is{fromSlug}-to-{toSlug}, the current split swaps origin and destination. The code in page.tsx does not compensate for this inversion; swapped data flows directly through, causing incorrect token pair routing.In apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts:
- const [toSlug, fromSlug] = slug.split("-to-"); + const [fromSlug, toSlug] = slug.split("-to-");- console.log("routeSlugs", routeSlugs);
🧹 Nitpick comments (7)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
17-32: Add explicit return type and keep prop shape in sync with BuyAndSwapEmbed.Annotate the component’s return type to satisfy our TS guideline and reduce drift.
Apply:
-export function UniversalBridgeEmbed(props: { +export function UniversalBridgeEmbed(props: { buy: @@ - | undefined; -}) { + | undefined; +}): JSX.Element {Optionally, export a shared
type TokenSide = { chainId: number; tokenAddress: string; amount?: string }from BuyAndSwapEmbed and import it here to avoid duplicate structural types. As per coding guidelines.apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)
14-17: Use correct Next.js params types; avoid Promise-typed params and unnecessary await.Next App Router passes
paramsas a plain object. Clean up typings and removeawait.type PageProps = { - params: Promise<Params>; + params: Params; }; -export async function generateMetadata( - props: PageProps, -): Promise<Metadata | undefined> { - const params = await props.params; +export async function generateMetadata( + { params }: PageProps, +): Promise<Metadata | undefined> { const tokenPair = params["token-pair"];-export default async function Page(props: { params: Promise<Params> }) { - const params = await props.params; +export default async function Page(props: { params: Params }) { + const params = props.params;As per coding guidelines.
Also applies to: 24-31, 53-55
95-101: Don’t call redirect from a shared data helper used by generateMetadata.Let callers decide. Return
undefinedhere; keep the redirect in Page.async function getTokenMetadata(slug: string) { const tokenPairData = getTokenPairData(slug); if (!tokenPairData) { - redirect("/bridge"); + return undefined; } @@ - if (!fromToken || !toToken || !fromChain || !toChain) { - return undefined; - } + if (!fromToken || !toToken || !fromChain || !toChain) return undefined;This avoids swallowing Next’s redirect in generateMetadata.
Also applies to: 120-122
87-93: Add explicit return types to helpers.Small TS hygiene to match our standards.
-function cleanedChainName(chainName: string) { +function cleanedChainName(chainName: string): string { return chainName.replaceAll("mainnet", "").replaceAll("Mainnet", "").trim(); } -function cleanTokenName(tokenName: string) { +function cleanTokenName(tokenName: string): string { return tokenName.replaceAll("Token", "").replaceAll("token", "").trim(); } -function getTitle(data: { +function getTitle(data: { fromToken: { @@ toChain: ChainMetadata; -}) { +}): string {As per coding guidelines.
Also applies to: 132-173
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
35-52: Add explicit return type to component.Matches our TS guideline and improves DX.
-export function BuyAndSwapEmbed(props: { +export function BuyAndSwapEmbed(props: { buy: @@ - wallets?: Wallet[]; -}) { + wallets?: Wallet[]; +}): JSX.Element {As per coding guidelines.
1-1: Remove broad eslint-disable forno-restricted-syntax.No restricted syntax used; keep disables scoped or remove.
-/* eslint-disable no-restricted-syntax */ @@ - // eslint-disable-next-line no-restricted-syntax useEffect(() => {Also applies to: 58-60
236-242: Comment does not match behavior.Code always sets
sellTokenwhenprops.sellis provided; it does not skip for native buy tokens.
- Either update the comment to reflect behavior, or
- Implement the guard:
- // sell the native token by default (but if buytoken is a native token, don't set) - sellToken: props.sell?.chainId + // prefill sell token if provided + sellToken: props.sell?.chainId ? { chainId: props.sell.chainId, tokenAddress: props.sell.tokenAddress } : undefined,If you want the native-token exception, import
NATIVE_TOKEN_ADDRESSand add a check againstprops.buy?.tokenAddress.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.pngis excluded by!**/*.png
📒 Files selected for processing (9)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(8 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/components/bridge-page.tsx(1 hunks)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx(1 hunks)apps/dashboard/src/app/bridge/constants.ts(0 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts(1 hunks)apps/dashboard/src/app/bridge/page.tsx(2 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/dashboard/src/app/bridge/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
- apps/dashboard/src/app/bridge/components/bridge-page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
**/*.{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/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
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/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧠 Learnings (2)
📚 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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (3)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
generateTokenPairSlugs(123-150)getTokenPairData(72-89)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(6-39)apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
serverThirdwebClient(8-11)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbed(35-277)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
reportTokenBuyFailed(264-266)reportTokenBuyCancelled(276-278)reportTokenBuySuccessful(252-254)
⏰ 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). (1)
- GitHub Check: Size
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: 0
♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx (1)
202-210: Fix same-asset prefill: default sell to native token.Setting both buy and sell to the ERC20 yields an invalid swap. Use the chain’s native token for
sell.+import { NATIVE_TOKEN_ADDRESS } from "thirdweb"; ... <BuyAndSwapEmbed - // chain={props.clientContract.chain} - sell={{ - chainId: props.clientContract.chain.id, - tokenAddress: props.clientContract.address, - }} + sell={{ + chainId: props.clientContract.chain.id, + tokenAddress: NATIVE_TOKEN_ADDRESS, + }} buy={{ chainId: props.clientContract.chain.id, tokenAddress: props.clientContract.address, }} pageType="asset" />
🧹 Nitpick comments (11)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
17-31: Extract a shared TradeSide type and add an explicit return type.Define a
TradeSidealias and use optional props to reduce repetition and align with guidelines; also annotate the function’s return type.
[As per coding guidelines]+type TradeSide = { + tokenAddress: `0x${string}`; + chainId: number; + amount?: string; +}; - -export function UniversalBridgeEmbed(props: { - buy: - | { - tokenAddress: string; - chainId: number; - amount?: string; - } - | undefined; - sell: - | { - chainId: number; - tokenAddress: string; - amount?: string; - } - | undefined; -}) { +export function UniversalBridgeEmbed(props: { + buy?: TradeSide; + sell?: TradeSide; +}): JSX.Element {apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
6-20: ExposeclassName, share TradeSide type, and annotate return type.Make the root style-overridable, avoid inline type repetition, and add an explicit return type.
[As per coding guidelines]-export function BridgePageUI(props: { - title: React.ReactNode; - buy: - | { - tokenAddress: string; - chainId: number; - } - | undefined; - sell: - | { - chainId: number; - tokenAddress: string; - } - | undefined; -}) { +type TradeSide = { tokenAddress: `0x${string}`; chainId: number }; +export function BridgePageUI(props: { + title: React.ReactNode; + className?: string; + buy?: TradeSide; + sell?: TradeSide; +}): JSX.Element {
21-38: WireclassNameinto the root container.Enable composition per app guidelines.
[As per coding guidelines]- return ( - <div className="grow flex flex-col"> + return ( + <div className={cn("grow flex flex-col", props.className)}>
1-5: Mark as a server component.Add the directive for clarity and to prevent accidental client-only imports leaking here.
[As per coding guidelines]+import "server-only"; import { cn } from "@workspace/ui/lib/utils";
68-83: Deduplicate Dots background by reusing the shared UI component.Import and use
DotsBackgroundPatternfrom@/components/ui/background-patternsinstead of redefining it.-function DotsBackgroundPattern(props: { className?: string }) { - return ( - <div - className={cn( - "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block", - props.className, - )} - style={{ - backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)", - backgroundSize: "24px 24px", - maskImage: - "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)", - }} - /> - ); -} +import { DotsBackgroundPattern } from "@/components/ui/background-patterns";apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (2)
18-22: Consider curating static params to the SEO target list.Generating all pairs is O(N²). For MNY‑274, statically prebuild only the high‑priority routes; render others on demand.
-export async function generateStaticParams(): Promise<Params[]> { - return generateTokenPairSlugs().map((slug) => ({ - "token-pair": slug, - })); -} +export async function generateStaticParams(): Promise<Params[]> { + // TODO: move to slug-map.ts and keep a single source of truth + const curated = new Set<string>([ + // Examples; fill in exact slugs present in tokens map: + "eth-to-eth-usdt", + "eth-usdc-to-eth-usdt", + "bnb-to-eth", + "bnb-ada-to-eth", + "avax-to-eth", + "eth-shib-to-eth", + "doge-to-eth", + "eth-to-eth-usdc", + "base-to-eth", + "bnb-to-arb", + "pol-to-bnb", + "base-to-pol", + "pol-to-eth", + ]); + return generateTokenPairSlugs() + .filter((slug) => curated.has(slug)) + .map((slug) => ({ "token-pair": slug })); +}I can generate the exact curated slugs from your tokens map to avoid mismatches.
1-9: Mark server file and reuse existing utilities where possible.
- Add
import "server-only";.cleanedChainNameduplicates an existing util; prefer importing a shared helper to avoid drift.+import "server-only"; import type { Metadata } from "next";apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (3)
123-149: Optional: add a curated generator for SEO pages to avoid O(N²) growth.Provide
generatePopularTokenPairSlugs()that returns a vetted allowlist and (optionally) validates viagetTokenPairDatabefore returning.export function generateTokenPairSlugs() { @@ return routeSlugs; } + +// Curated list for SEO-targeted pages; keep in sync with issue MNY‑274. +export function generatePopularTokenPairSlugs() { + const curated: string[] = [ + // fill with slugs that exist in `tokens`; e.g., + // "eth-to-eth-usdt", "eth-usdc-to-eth-usdt", "bnb-to-eth", ... + ]; + return curated.filter((s) => !!getTokenPairData(s)); +}
12-58: Normalize token addresses to EIP‑55 checksum and narrow types.Mixed casing reduces human checks; prefer checksum and the
0x${string}literal type for safety.-const tokens: Tokens = { +const tokens: Tokens = { eth: { chainId: 1, tokens: { - usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - usdt: "0xdAC17F958D2ee523a2206206994597C13D831ec7", - shib: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", + usdc: "0xA0b86991C6218B36C1d19D4a2e9Eb0cE3606eB48", + usdt: "0xdAC17F958D2ee523a2206206994597C13D831ec7", + shib: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", }, }, @@ - usdc: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", - weth: "0x4200000000000000000000000000000000000006", + usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bDA02913", + weth: "0x4200000000000000000000000000000000000006", }, }, @@ - usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", - bnb: "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3", - shib: "0x6f8a06447ff6fcf75d803135a7de15ce88c1d4ec", - weth: "0x7ceb23fd6bc0add59e62ac25578270cff1b9f619", - avax: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b", + usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359", + bnb: "0x3BA4c387f786bFEE076A58914F5Bd38d668B42c3", + shib: "0x6F8A06447Ff6fCF75D803135a7dE15Ce88C1D4eC", + weth: "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619", + avax: "0x2C89bbc92BD86F8075d1DEcc58C7F4E0107f286b", }, }, @@ - usdc: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", + usdc: "0xAf88d065e77c8cC2239327C5EDb3A432268e5831", }, }, };Optionally, enforce
tokenAddress: \0x${string}`inTokenPairDataandTradeSide` for stronger typing.
91-121: Minor robustness: normalize incoming slugs to lowercase.Guard against mixed‑case URLs without relying on routing config.
- const [chainSlug, tokenSlug] = slug.split("-"); + const [chainSlug, tokenSlug] = slug.toLowerCase().split("-");apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
36-49: Excellent refactoring to structured buy/sell objects.The new API with structured
buyandsellobjects is much cleaner and more maintainable than individual flat props. The optional nature and included properties are well-designed.Consider normalizing property order for consistency:
buy: | { - tokenAddress: string; chainId: number; + tokenAddress: string; amount?: string; } | undefined;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.pngis excluded by!**/*.png
📒 Files selected for processing (9)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(8 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/components/bridge-page.tsx(1 hunks)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx(1 hunks)apps/dashboard/src/app/bridge/constants.ts(0 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts(1 hunks)apps/dashboard/src/app/bridge/page.tsx(2 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/dashboard/src/app/bridge/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
**/*.{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/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
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/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx
🧠 Learnings (3)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/app/bridge/components/header.tsx (1)
BridgePageHeader(14-68)apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
DotsBackgroundPattern(4-19)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
UniversalBridgeEmbed(17-41)apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
FaqAccordion(8-23)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
reportTokenBuyFailed(264-266)reportTokenBuyCancelled(276-278)reportTokenBuySuccessful(252-254)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbed(35-277)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (5)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
generateTokenPairSlugs(123-149)getTokenPairData(72-89)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(6-39)packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
cleanedChainName(1-3)apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
serverThirdwebClient(8-11)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
⏰ 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, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Analyze (javascript)
🔇 Additional comments (8)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
34-39: LGTM: Propagation into BuyAndSwapEmbed matches the new API.
buy/sellare forwarded intact;pageType="bridge"andwalletsare correct.apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)
63-72: LGTM: buy = destination, sell = origin.Mapping matches “from → to” semantics and the SwapWidget prefill.
14-16: Fix Next.jsparamstyping (it’s not a Promise).Use
params: Paramsand drop theawaitto align with App Router types.
[As per coding guidelines]-type PageProps = { - params: Promise<Params>; -}; +type PageProps = { params: Params }; @@ -export default async function Page(props: { params: Promise<Params> }) { - const params = await props.params; +export default async function Page(props: { params: Params }) { + const params = props.params;Also applies to: 53-55
⛔ Skipped due to learnings
Learnt from: MananTank PR: thirdweb-dev/js#7152 File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10 Timestamp: 2025-05-26T16:28:10.079Z Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.Learnt from: jnsdls PR: thirdweb-dev/js#6929 File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19 Timestamp: 2025-05-21T05:17:31.283Z Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.
24-31: Also fixgenerateMetadataparam typing and remove unnecessaryawait.
[As per coding guidelines]export async function generateMetadata( - props: PageProps, + props: PageProps, ): Promise<Metadata | undefined> { - const params = await props.params; + const params = props.params;⛔ Skipped due to learnings
Learnt from: MananTank PR: thirdweb-dev/js#7152 File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/accounts/page.tsx:2-10 Timestamp: 2025-05-26T16:28:10.079Z Learning: In Next.js 14+, the `params` object in page components is always a Promise that needs to be awaited, so the correct typing is `params: Promise<ParamsType>` rather than `params: ParamsType`.apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
71-89: LGTM: Correct slug split order and validation.
[fromSlug, toSlug]aligns with<from>-to-<to>; early undefined checks are good.apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
116-125: Well-implemented guard logic prevents undefined chainId.The defensive pattern of deriving
buyChainIdfrom the quote and early-returning when undefined is excellent. This prevents potential runtime errors in the asset reporting calls and handles both "buy" and "onramp" quote types correctly.Also applies to: 149-158, 181-190
101-104: Widget integration properly uses the new buy/sell structure.Both
BuyWidgetandSwapWidgetare correctly updated to consume the new structured props. The use ofdefineChainto convertchainIdto aChainobject is appropriate, and the conditional prefill logic for the swap widget ensures that tokens are only set when the data is available.Also applies to: 230-242
141-144: Asset reporting correctly uses derived buyChainId.The asset reporting calls now properly use the
buyChainIdderived from the quote context, which is more accurate than relying on the original props. The hardcodedis_testnet: falseis correct for this component. Based on learnings.Also applies to: 174-176, 206-208
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: 0
🧹 Nitpick comments (2)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
59-74: Consider reusing shared DotsBackgroundPattern.A similar
DotsBackgroundPatternexists in@/components/ui/background-patterns.tsx(lines 3-18). The shared version accepts aclassNameprop, allowing you to override the default styling.Replace the local implementation with:
+import { DotsBackgroundPattern } from "@/components/ui/background-patterns"; ... -function DotsBackgroundPattern(props: { className?: string }) { - return ( - <div - className={cn( - "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block", - props.className, - )} - style={{ - backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)", - backgroundSize: "24px 24px", - maskImage: - "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)", - }} - /> - ); -}Then use it with:
<DotsBackgroundPattern className="-inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block" />apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
124-126: Consider documenting token address format expectation.The type assertion assumes callers provide valid
0x-prefixed addresses. Consider adding a JSDoc comment on theBuyAndSwapEmbedPropstype to document this requirement.Example:
/** * Props for BuyAndSwapEmbed component * @remarks tokenAddress should be a valid 0x-prefixed address or NATIVE_TOKEN_ADDRESS constant */ export type BuyAndSwapEmbedProps = { // ...
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.pngis excluded by!**/*.png
📒 Files selected for processing (9)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(8 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/components/bridge-page.tsx(1 hunks)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/constants.ts(0 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts(1 hunks)apps/dashboard/src/app/bridge/page.tsx(2 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
- apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsx
**/*.{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/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsx
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/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.
Applied to files:
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx (3)
apps/dashboard/src/@/components/blocks/grid-pattern-embed-container.tsx (1)
GridPatternEmbedContainer(3-23)apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbed(69-286)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
BuyAndSwapEmbedProps(35-67)BuyAndSwapEmbed(69-286)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
Page(53-93)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(7-30)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
generateTokenPairSlugs(123-149)getTokenPairData(72-89)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(7-30)packages/thirdweb/src/react/web/ui/Bridge/swap-widget/utils.ts (1)
cleanedChainName(1-3)apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
serverThirdwebClient(8-11)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
reportTokenBuyFailed(264-266)reportTokenBuyCancelled(276-278)reportTokenBuySuccessful(252-254)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (5)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbedProps(35-67)apps/dashboard/src/app/bridge/components/header.tsx (1)
BridgePageHeader(14-68)apps/dashboard/src/@/components/ui/background-patterns.tsx (1)
DotsBackgroundPattern(4-19)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
UniversalBridgeEmbed(20-32)apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
FaqAccordion(8-23)
⏰ 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). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (10)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
20-31: LGTM! Clean refactor to structured props.The refactor from flat props to the
buyTab/swapTabstructure is well-executed. Type safety is maintained viaBuyAndSwapEmbedProps, and the component remains a clean pass-through wrapper.apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
7-30: LGTM! Well-structured UI composition.The component cleanly composes header, embed, heading, and FAQ sections with proper spacing and type-safe props.
apps/dashboard/src/app/bridge/page.tsx (1)
17-30: LGTM! Clean delegation to BridgePageUI.Passing
undefinedforbuyTabandswapTaballows the bridge widget to start without prefill, which is appropriate for the main bridge landing page.apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
24-51: LGTM! Proper metadata generation with error handling.The function correctly handles missing token pairs by returning
undefinedand constructs appropriate OpenGraph metadata.
53-93: LGTM! Correct buy/sell mapping.The token mapping is correct: for a route "X-to-Y",
swapTab.sellTokenusesfromToken(X) and bothbuyTab.buyTokenandswapTab.buyTokenusetoToken(Y), matching the expected "sell X to buy Y" flow.
103-138: LGTM! Robust metadata fetching with proper error handling.The function correctly uses
Promise.allfor parallel fetching and handles errors gracefully by returningundefined, which triggers the redirect in the Page component.
140-181: LGTM! Comprehensive title generation logic.The function handles multiple edge cases well:
- Native token detection via
NATIVE_TOKEN_ADDRESS- Same-symbol cross-chain swaps
- Cross-chain vs same-chain formatting
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (3)
35-67: LGTM! Well-designed type structure.The nested optional structure for
buyTabandswapTabprovides good flexibility while maintaining type safety.
116-237: LGTM! Proper derivation and error handling.The
buyChainIdderivation with guard clauses correctly handles both"buy"and"onramp"quote types, preventing undefined access in callbacks. Theis_testnet: falseis correct based on learnings.
239-283: LGTM! Clean SwapWidget integration.The prefill structure correctly uses
swapTabdata, and callbacks properly extract intent properties for analytics reporting.
Merge activity
|
) <!-- ## 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 `BuyAndSwapEmbed` component and related functionalities to improve the handling of buy and swap operations across different tokens and chains, enhancing the user experience in the bridge application. ### Detailed summary - Removed `chain` and `tokenAddress` props from `BuyAndSwapEmbed`. - Introduced `buyTab` and `swapTab` props to manage buy/sell token information. - Updated `UniversalBridgeEmbed` to accept new props structure. - Added token pair management in `slug-map.ts`. - Created utility functions for token pair data retrieval. - Refactored `BridgePageUI` to accommodate the new props and structure. - Enhanced error handling and reporting in `BuyAndSwapEmbed`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a Bridge UI and dedicated token-pair pages with static routes, metadata, and token-pair utilities for cross-chain slugs. - Introduced a Bridge page UI with FAQ, data summary, and an embedded universal bridge widget. - **Improvements** - Unified buy/sell input structure for embeds and prefills, simplifying embed wiring and page rendering. - More robust handling of chain/token data and reporting for buy/swap flows; removed legacy testnet flag usage. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
bffc7c3 to
b1a7808
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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
288-292: Add explicit return type to TabButton function.The
TabButtonfunction is missing an explicit return type, which violates the coding guideline requiring explicit return types in TypeScript.As per coding guidelines, apply this diff:
function TabButton(props: { label: string; onClick: () => void; isActive: boolean; -}) { +}): JSX.Element {
♻️ Duplicate comments (3)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
63-81: LGTM: buy/sell mapping now matches “from → to”.
buyTabuses the destination token;swapTab.sellTokenuses the origin token. Correct.apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
71-89: LGTM: Correct<from>-to-<to>parsing.Destructuring order is now correct; resolves prior reversal.
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
124-126: Type assertion may mask invalid addresses.The type assertion
as \0x${string}` | undefinedbypasses TypeScript's type checking. Ifprops.buyTab?.buyToken?.tokenAddress` contains a malformed address, this could cause runtime issues with the BuyWidget.Consider validating the token address format:
- tokenAddress={ - props.buyTab?.buyToken?.tokenAddress as `0x${string}` | undefined - } + tokenAddress={ + props.buyTab?.buyToken?.tokenAddress && + props.buyTab.buyToken.tokenAddress.startsWith('0x') + ? props.buyTab.buyToken.tokenAddress as `0x${string}` + : undefined + }Alternatively, verify that all callers pass properly formatted addresses and document this requirement in JSDoc.
🧹 Nitpick comments (12)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
20-23: Solid API migration; consider a small props type alias for clarity.Inline props are correct. For readability and reuse, define a local alias and use it in the signature.
+type UniversalBridgeEmbedProps = Pick<BuyAndSwapEmbedProps, "buyTab" | "swapTab">; -export function UniversalBridgeEmbed(props: { - buyTab: BuyAndSwapEmbedProps["buyTab"]; - swapTab: BuyAndSwapEmbedProps["swapTab"]; -}) { +export function UniversalBridgeEmbed(props: UniversalBridgeEmbedProps) {apps/dashboard/src/app/bridge/components/bridge-page.tsx (3)
1-6: Mark as a Server Component.Per dashboard guidelines, add the server-only directive at the top.
+import "server-only"; import { cn } from "@workspace/ui/lib/utils"; import type { BuyAndSwapEmbedProps } from "@/components/blocks/BuyAndSwapEmbed"; import { FaqAccordion } from "@/components/blocks/faq-section"; import { UniversalBridgeEmbed } from "./client/UniversalBridgeEmbed"; import { BridgePageHeader } from "./header";Confirm no client-only APIs are used in this file after the change.
7-14: ExposeclassNameand forward to the root; make tab props optional.Expose a
classNameon BridgePageUI’s root and makebuyTab/swapTaboptional so callers don’t passundefined.-export function BridgePageUI(props: { - title: React.ReactNode; - buyTab: BuyAndSwapEmbedProps["buyTab"]; - swapTab: BuyAndSwapEmbedProps["swapTab"]; -}) { - return ( - <div className="grow flex flex-col"> +export function BridgePageUI(props: { + title: React.ReactNode; + buyTab?: BuyAndSwapEmbedProps["buyTab"]; + swapTab?: BuyAndSwapEmbedProps["swapTab"]; + className?: string; +}) { + return ( + <div className={cn("grow flex flex-col", props.className)}> ... - <HeadingSection title={props.title} /> + <HeadingSection title={props.title} />Also applies to: 21-29
32-49: Optional: exposeclassNameon subcomponents for consistency.Add
className?: stringto HeadingSection, DataPill, and BridgeFaqSection and merge viacn().-function HeadingSection(props: { title: React.ReactNode }) { +function HeadingSection(props: { title: React.ReactNode; className?: string }) { return ( - <div className="container"> + <div className={cn("container", props.className)}> ... -function DataPill(props: { children: React.ReactNode }) { +function DataPill(props: { children: React.ReactNode; className?: string }) { return ( - <p className="bg-card flex items-center text-xs lg:text-sm gap-1.5 text-foreground border rounded-full px-8 lg:px-3 py-1.5 hover:text-foreground transition-colors duration-300"> + <p className={cn( + "bg-card flex items-center text-xs lg:text-sm gap-1.5 text-foreground border rounded-full px-8 lg:px-3 py-1.5 hover:text-foreground transition-colors duration-300", + props.className, + )}> {props.children} </p> ); } ... -function BridgeFaqSection() { +function BridgeFaqSection(props: { className?: string }) { return ( - <section className="container max-w-2xl"> + <section className={cn("container max-w-2xl", props.className)}>As per coding guidelines
Also applies to: 51-57, 104-113
apps/dashboard/src/app/bridge/page.tsx (2)
1-3: Add server-only directive.Mark this as a Server Component.
+import "server-only"; import type { Metadata } from "next"; import { BridgePageUI } from "./components/bridge-page";As per coding guidelines
17-27: Avoid passingundefinedexplicitly if props are optional.After making
buyTab/swapTaboptional in BridgePageUI, simplify the call.export default function Page() { return ( - <BridgePageUI - buyTab={undefined} - swapTab={undefined} - title={ + <BridgePageUI + title={ <h1 className="text-3xl md:text-6xl font-semibold tracking-tighter text-balance text-center"> Bridge and Swap tokens <br className="max-sm:hidden" /> across any chain, instantly </h1> } /> ); }apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (3)
1-9: Mark as a Server Component.Add the server-only directive at the top.
+import "server-only"; import type { Metadata } from "next"; import { redirect } from "next/navigation"; import { Bridge, NATIVE_TOKEN_ADDRESS } from "thirdweb"; import type { ChainMetadata } from "thirdweb/chains"; import { serverThirdwebClient } from "@/constants/thirdweb-client.server"; import { fetchChain } from "@/utils/fetchChain"; import { BridgePageUI } from "../../components/bridge-page"; import { generateTokenPairSlugs, getTokenPairData } from "./slug-map";As per coding guidelines
18-22: Limit static params to curated SEO pairs to avoid O(N²) build bloat.Generate only the pairs listed in MNY-274 (e.g., ETH→USDT, USDC→USDT, BNB→ETH, etc.) and let others render dynamically.
-export async function generateStaticParams(): Promise<Params[]> { - return generateTokenPairSlugs().map((slug) => ({ - "token-pair": slug, - })); -} +export async function generateStaticParams(): Promise<Params[]> { + const slugs = generateTokenPairSlugs({ popularOnly: true }); + return slugs.map((slug) => ({ "token-pair": slug })); +}If you prefer not to change the signature, expose
generatePopularTokenPairSlugs()in slug-map and use that here. Based on learningsI can wire the exact slug list derived from the issue text.
24-51: Add explicit return types and cache token metadata to prevent duplicate fetch.
- Add explicit return types for TS helpers and the default export.
- Cache
getTokenMetadatasogenerateMetadataandPageshare results per slug.-export async function generateMetadata( +export async function generateMetadata( props: PageProps, -): Promise<Metadata | undefined> { +): Promise<Metadata | undefined> { ... -export default async function Page(props: { params: Promise<Params> }) { +export default async function Page(props: { params: Promise<Params> }): Promise<JSX.Element> { ... -function cleanedChainName(chainName: string) { +function cleanedChainName(chainName: string): string { return chainName.replaceAll("mainnet", "").replaceAll("Mainnet", "").trim(); } -function cleanTokenName(tokenName: string) { +function cleanTokenName(tokenName: string): string { return tokenName.replaceAll("Token", "").replaceAll("token", "").trim(); } -async function getTokenMetadata(slug: string) { +import { cache } from "react"; +const getTokenMetadata = cache(async function getTokenMetadata(slug: string): Promise<{ + fromToken: { name: string; symbol: string; address: string }; + toToken: { name: string; symbol: string; address: string }; + fromChain: ChainMetadata; + toChain: ChainMetadata; +} | undefined> { const tokenPairData = getTokenPairData(slug); if (!tokenPairData) { redirect("/bridge"); } ... if (!fromToken || !toToken || !fromChain || !toChain) { return undefined; } return { fromToken, toToken, fromChain, toChain, }; -} +}); -function getTitle(data: { +function getTitle(data: { fromToken: { name: string; symbol: string; address: string; }; toToken: { name: string; symbol: string; address: string; }; fromChain: ChainMetadata; toChain: ChainMetadata; -}) { +}): string {As per coding guidelines
Also applies to: 53-93, 95-181
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
123-149: Add a curated popular-slugs generator and stronger typings.Reduce build surface and improve type safety.
-import { NATIVE_TOKEN_ADDRESS } from "thirdweb"; +import { NATIVE_TOKEN_ADDRESS } from "thirdweb"; + +type HexAddress = `0x${string}`; +type ChainSlug = "eth" | "bnb" | "avax" | "doge" | "base" | "pol" | "arb"; +type TokenSlug = + | "usdc" + | "usdt" + | "shib" + | "weth" + | "bnb" + | "avax" + | "ada"; type Tokens = Record< - string, + ChainSlug, | { chainId: number; - tokens: Record<string, string | undefined>; + tokens: Record<string, HexAddress | undefined>; } | undefined >; @@ -export function generateTokenPairSlugs() { +export function generateTokenPairSlugs(opts?: { popularOnly?: boolean }) { const tokenIds = Object.keys(tokens); @@ - const routeSlugs: string[] = []; + const routeSlugs: string[] = []; for (const fromSlug of tokenSlugs) { for (const toSlug of tokenSlugs) { if (fromSlug === toSlug) { continue; } routeSlugs.push(`${fromSlug}-to-${toSlug}`); } } - return routeSlugs; + if (opts?.popularOnly) { + const POPULAR: ReadonlyArray<string> = [ + // From issue MNY-274 (mapped to current slugs) + "eth-to-eth-usdt", + "eth-usdc-to-eth-usdt", + "bnb-to-eth", + "bnb-ada-to-eth", + "avax-to-eth", + "eth-shib-to-eth", + "doge-to-eth", + "eth-to-eth-usdc", + "base-to-eth", + "bnb-to-arb", + "pol-to-bnb", + "base-to-pol", + "pol-to-eth", + ]; + return routeSlugs.filter((s) => POPULAR.includes(s)); + } + return routeSlugs; }If you want, I can validate these slugs against
getTokenPairData()and adjust any that don’t resolve.apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
1-1: Consider scoping the eslint-disable directive.The global
eslint-disableat the file level disablesno-restricted-syntaxfor the entire file, but it appears only theuseEffectat line 76 requires this exception (which already has its own inline disable comment). A file-level disable is overly broad.Remove the global disable and rely on the existing inline directive at line 75:
-/* eslint-disable no-restricted-syntax */ "use client";
35-67: Add JSDoc to document the props structure.The
BuyAndSwapEmbedPropstype has a deeply nested optional structure. Adding JSDoc would help callers understand when to populatebuyTabvsswapTaband the purpose of each nested token object.Add documentation above the type:
/** * Props for BuyAndSwapEmbed component. * @param buyTab - Configuration for the "Buy" tab; populate buyToken to enable buying a specific token * @param swapTab - Configuration for the "Swap" tab; populate sellToken and buyToken to prefill swap pairs * @param pageType - Context for analytics (asset/bridge/chain page) * @param wallets - Optional wallet instances for connection */ export type BuyAndSwapEmbedProps = {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
apps/dashboard/src/app/bridge/exchange/[token-pair]/opengraph-image.pngis excluded by!**/*.png
📒 Files selected for processing (9)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx(8 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx(1 hunks)apps/dashboard/src/app/bridge/components/bridge-page.tsx(1 hunks)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx(2 hunks)apps/dashboard/src/app/bridge/constants.ts(0 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx(1 hunks)apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts(1 hunks)apps/dashboard/src/app/bridge/page.tsx(2 hunks)
💤 Files with no reviewable changes (1)
- apps/dashboard/src/app/bridge/constants.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/components/client/BuyFundsSection.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
**/*.{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/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
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/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.tsapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsxapps/dashboard/src/app/bridge/components/bridge-page.tsxapps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/page.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
🧠 Learnings (4)
📚 Learning: 2025-10-17T22:59:11.851Z
Learnt from: MananTank
PR: thirdweb-dev/js#8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.851Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
PR: thirdweb-dev/js#7933
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/tokens/create/token/distribution/token-sale.tsx:0-0
Timestamp: 2025-08-28T12:24:37.171Z
Learning: In the token creation flow, the tokenAddress field in erc20Asset_poolMode is always initialized with nativeTokenAddress and is never undefined, so conditional checks for undefined tokenAddress are not needed.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsxapps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
PR: thirdweb-dev/js#8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.
Applied to files:
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx
🧬 Code graph analysis (6)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (4)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (2)
generateTokenPairSlugs(123-149)getTokenPairData(72-89)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(7-30)apps/dashboard/src/@/constants/thirdweb-client.server.ts (1)
serverThirdwebClient(8-11)packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/app/bridge/components/bridge-page.tsx (4)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
BuyAndSwapEmbedProps(35-67)apps/dashboard/src/app/bridge/components/header.tsx (1)
BridgePageHeader(14-68)apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
UniversalBridgeEmbed(20-32)apps/dashboard/src/@/components/blocks/faq-section.tsx (1)
FaqAccordion(8-23)
apps/dashboard/src/app/bridge/exchange/[token-pair]/slug-map.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
NATIVE_TOKEN_ADDRESS(31-31)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (1)
apps/dashboard/src/@/analytics/report.ts (3)
reportTokenBuyFailed(264-266)reportTokenBuyCancelled(276-278)reportTokenBuySuccessful(252-254)
apps/dashboard/src/app/bridge/page.tsx (2)
apps/dashboard/src/app/bridge/exchange/[token-pair]/page.tsx (1)
Page(53-93)apps/dashboard/src/app/bridge/components/bridge-page.tsx (1)
BridgePageUI(7-30)
apps/dashboard/src/app/bridge/components/client/UniversalBridgeEmbed.tsx (1)
apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx (2)
BuyAndSwapEmbedProps(35-67)BuyAndSwapEmbed(69-286)
⏰ 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). (6)
- GitHub Check: Unit Tests
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
| }) { | ||
| }; | ||
|
|
||
| export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps) { |
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 | 🟠 Major
Add explicit return type to function declaration.
The function is missing an explicit return type, which violates the coding guideline requiring explicit return types in TypeScript.
As per coding guidelines, apply this diff:
-export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps) {
+export function BuyAndSwapEmbed(props: BuyAndSwapEmbedProps): JSX.Element {🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx around line 69,
the BuyAndSwapEmbed function declaration lacks an explicit return type; update
the function signature to include the correct React return type (e.g.,
React.ReactElement or JSX.Element | null as appropriate) so the declaration
becomes explicitly typed, and import React types if needed.
| const buyChainId = | ||
| quote?.type === "buy" | ||
| ? quote.intent.destinationChainId | ||
| : quote?.type === "onramp" | ||
| ? quote.intent.chainId | ||
| : undefined; | ||
|
|
||
| if (!buyChainId) { | ||
| return; | ||
| } |
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 | 🟠 Major
Extract duplicated buyChainId logic into a helper function.
The buyChainId extraction logic is duplicated across onError, onCancel, and onSuccess callbacks. This violates the DRY principle and increases maintenance burden.
Extract a helper function at the top of the file:
function getBuyChainId(
quote:
| { type: "buy"; intent: { destinationChainId: number } }
| { type: "onramp"; intent: { chainId: number } }
| undefined
): number | undefined {
return quote?.type === "buy"
? quote.intent.destinationChainId
: quote?.type === "onramp"
? quote.intent.chainId
: undefined;
}Then simplify all three callbacks:
onError={(e, quote) => {
const errorMessage = parseError(e);
- const buyChainId =
- quote?.type === "buy"
- ? quote.intent.destinationChainId
- : quote?.type === "onramp"
- ? quote.intent.chainId
- : undefined;
-
- if (!buyChainId) {
- return;
- }
+ const buyChainId = getBuyChainId(quote);
+ if (!buyChainId) return;Apply the same pattern to onCancel and onSuccess.
Also applies to: 171-180, 203-212
🤖 Prompt for AI Agents
In apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx around lines
138-147 (and similarly at 171-180 and 203-212), the logic that derives
buyChainId from the quote object is duplicated in the onError, onCancel, and
onSuccess callbacks; extract that logic into a single helper function
getBuyChainId (as specified in the review) placed near the top of the file,
returning number | undefined, then replace the repeated conditional blocks in
each callback with a call to getBuyChainId(quote) and use the returned value
(early return if undefined) so all three callbacks share the same
implementation.
| function DotsBackgroundPattern(props: { className?: string }) { | ||
| return ( | ||
| <div | ||
| className={cn( | ||
| "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block", | ||
| props.className, | ||
| )} | ||
| style={{ | ||
| backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)", | ||
| backgroundSize: "24px 24px", | ||
| maskImage: | ||
| "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)", | ||
| }} | ||
| /> | ||
| ); | ||
| } |
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 | 🟠 Major
Replace inline styles with Tailwind arbitrary properties.
Inline style violates the Tailwind-only rule. Use arbitrary properties instead.
function DotsBackgroundPattern(props: { className?: string }) {
return (
<div
- className={cn(
- "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
- props.className,
- )}
- style={{
- backgroundImage: "radial-gradient(currentColor 1px, transparent 1px)",
- backgroundSize: "24px 24px",
- maskImage:
- "radial-gradient(ellipse 100% 100% at 50% 50%, black 30%, transparent 50%)",
- }}
+ className={cn(
+ "pointer-events-none absolute -inset-x-36 -inset-y-24 text-foreground/20 dark:text-muted-foreground/20 hidden lg:block",
+ "bg-[radial-gradient(currentColor_1px,transparent_1px)]",
+ "bg-[length:24px_24px]",
+ "[mask-image:radial-gradient(ellipse_100%_100%_at_50%_50%,black_30%,transparent_50%)]",
+ props.className,
+ )}
/>
);
}As per coding guidelines
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/dashboard/src/app/bridge/components/bridge-page.tsx around lines 59 to
74, the component uses an inline style object for backgroundImage,
backgroundSize, and maskImage which violates the Tailwind-only rule; remove the
style prop and move those rules into the className using Tailwind arbitrary
properties (e.g. add classes like bg-[radial-gradient(...)] for
background-image, bg-[length:24px_24px] or equivalent arbitrary background-size,
and mask-image via mask-[radial-gradient(...)]), keeping the existing cn(...)
call and props.className; ensure proper escaping/encoding of parentheses and
commas in the arbitrary values and that class order preserves priority.

PR-Codex overview
This PR focuses on refactoring the
BuyAndSwapEmbedcomponent to improve its structure and functionality. It introduces new props for handling buy and swap operations, enhances type safety, and removes deprecated code, ensuring a more efficient and organized codebase.Detailed summary
constants.tsand an unused image file.BuyAndSwapEmbedto acceptbuyTabandswapTabprops for better token handling.UniversalBridgeEmbedto use the new props structure.generateTokenPairSlugsandgetTokenPairDatafunctions for improved token pair management.BridgePageUIto utilize the newBuyAndSwapEmbedstructure.Summary by CodeRabbit
New Features
Improvements
Refactor
Chores