-
Notifications
You must be signed in to change notification settings - Fork 604
[SDK] Improve token info discovery for x402 payments #8142
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
[SDK] Improve token info discovery for x402 payments #8142
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 1b718f0 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Warning Rate limit exceeded@joaquim-verges has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 14 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (7)
WalkthroughAdds a new X402 playground UI and page, updates middleware defaults and price construction, and enhances x402 core logic: facilitator supported API/filtering, default asset detection/token metadata inference, improved 402 parsing/error propagation, types/schemas updates, and a changeset entry. (50 words) Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant L as X402LeftSection
participant R as X402RightSection
participant WF as wrapFetchWithPayment
participant F as Facilitator (ThirdwebX402Facilitator)
participant S as Paywalled API (middleware)
participant W as Wallet
participant C as Chain
U->>L: configure chain/token/amount/payTo
L->>R: setOptions(...) (update options state)
U->>R: click "Pay"
R->>WF: perform wrapped fetch (initial request)
WF->>S: request -> 402 response (requirements ± error)
S-->>WF: 402 + requirements (and optional error)
WF->>F: supported({ chainId, tokenAddress? })
F-->>WF: supported kinds + default/supported assets
WF->>W: request on-chain action (tx/signature)
W->>C: submit tx / signature (wait per waitUtil)
C-->>W: confirmation/result
WF->>S: retry original request with X-402 payment headers
S-->>WF: 200 OK + resource
WF-->>R: return response
R-->>U: display result or error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
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. |
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: 3
🧹 Nitpick comments (2)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (1)
19-44
: Add explicit return type for X402PlaygroundLine 19 currently declares
export function X402Playground()
without a return type, but our TypeScript guideline calls for explicit return types. Please annotate the component accordingly.Apply this diff:
-export function X402Playground() { +export function X402Playground(): React.JSX.Element {apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)
14-153
: Add explicit return type for X402LeftSectionLine 14 defines
export function X402LeftSection(...)
without a return type. To stay consistent with our TypeScript rules, please specify the component’s return type.Use this update:
-export function X402LeftSection(props: { +export function X402LeftSection(props: { options: X402PlaygroundOptions; setOptions: React.Dispatch<React.SetStateAction<X402PlaygroundOptions>>; -}) { +}): React.JSX.Element {
📜 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 selected for processing (13)
.changeset/dirty-experts-kiss.md
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/constants.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/types.ts
(1 hunks)apps/playground-web/src/app/payments/x402/page.tsx
(2 hunks)apps/playground-web/src/middleware.ts
(3 hunks)packages/thirdweb/src/x402/common.ts
(5 hunks)packages/thirdweb/src/x402/facilitator.ts
(7 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts
(2 hunks)packages/thirdweb/src/x402/schemas.ts
(2 hunks)packages/thirdweb/src/x402/types.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless 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@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless 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/playground-web/src/app/payments/x402/components/X402Playground.tsx
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/src/x402/types.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/src/x402/types.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}
: Import UI primitives from@/components/ui/*
(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
from@/lib/utils
for 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: Bearer
header – 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, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-js
in server components
Files:
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/types.ts
**/types.ts
📄 CodeRabbit inference engine (AGENTS.md)
Provide and re‑use local type barrels in a
types.ts
file
Files:
apps/playground-web/src/app/payments/x402/components/types.ts
packages/thirdweb/src/x402/types.ts
.changeset/*.md
📄 CodeRabbit inference engine (AGENTS.md)
.changeset/*.md
: Each change inpackages/*
must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API
Files:
.changeset/dirty-experts-kiss.md
🧠 Learnings (7)
📚 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/playground-web/src/app/payments/x402/components/X402Playground.tsx
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Applied to files:
packages/thirdweb/src/x402/facilitator.ts
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/_` (e.g., Button, Input, Tabs, Card)
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Applied to files:
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/types.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to .changeset/*.md : Version bump rules: patch for non‑API changes; minor for new/modified public API
Applied to files:
.changeset/dirty-experts-kiss.md
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.
Applied to files:
packages/thirdweb/src/x402/types.ts
🧬 Code graph analysis (8)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (4)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)apps/playground-web/src/app/payments/x402/components/constants.ts (2)
chain
(6-6)token
(7-10)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)
X402LeftSection
(14-153)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (1)
X402RightSection
(24-268)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
FacilitatorSupportedResponse
(94-96)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)apps/playground-web/src/app/payments/components/LeftSection.tsx (1)
LeftSection
(21-492)
apps/playground-web/src/app/payments/x402/page.tsx (1)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (1)
X402Playground
(19-44)
apps/playground-web/src/middleware.ts (2)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
token
(7-10)packages/thirdweb/src/x402/settle-payment.ts (1)
settlePayment
(126-187)
packages/thirdweb/src/x402/common.ts (2)
packages/thirdweb/src/x402/types.ts (3)
DefaultAsset
(109-109)ERC20TokenAmount
(96-107)SupportedSignatureType
(92-94)packages/thirdweb/src/x402/facilitator.ts (3)
facilitator
(89-244)supported
(204-240)ThirdwebX402Facilitator
(24-46)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)packages/thirdweb/src/x402/fetchWithPayment.ts (1)
wrapFetchWithPayment
(51-138)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)
packages/thirdweb/src/x402/types.ts (1)
packages/thirdweb/src/x402/schemas.ts (2)
SupportedSignatureTypeSchema
(60-63)FacilitatorSupportedAssetSchema
(65-73)
⏰ 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: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
Show resolved
Hide resolved
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
Outdated
Show resolved
Hide resolved
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8142 +/- ##
=======================================
Coverage 56.28% 56.29%
=======================================
Files 906 906
Lines 59208 59208
Branches 4180 4177 -3
=======================================
+ Hits 33324 33329 +5
+ Misses 25780 25774 -6
- Partials 104 105 +1
🚀 New features to boost your workflow:
|
3c6fdd0
to
640f12a
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
🧹 Nitpick comments (5)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
1-1
: Trim commented-out alternatives and centralize ZERO_ADDRESS.Large commented blocks and hardcoded zero-addresses appear across components; export a shared ZERO_ADDRESS here and remove stale comments to reduce noise.
+export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" as const; - -// export const chain = base; -// export const token = { ... } -// (remove long commented presets)Also applies to: 11-35
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (1)
19-44
: Add explicit return type and reuse a shared ZERO_ADDRESS.
- Per repo TS guidelines, annotate component return type.
- Import and use a shared ZERO_ADDRESS (from constants.ts) instead of duplicating the literal.
-import { chain, token } from "./constants"; +import { chain, token } from "./constants"; +// import { ZERO_ADDRESS } from "./constants"; // if exported -export function X402Playground() { +export function X402Playground(): JSX.Element { const [options, setOptions] = useState<X402PlaygroundOptions>(defaultOptions); const activeAccount = useActiveAccount(); // Update payTo address when wallet connects, but only if it's still the default React.useEffect(() => { - if ( - activeAccount?.address && - options.payTo === "0x0000000000000000000000000000000000000000" - ) { + if (activeAccount?.address && options.payTo === "0x0000000000000000000000000000000000000000" /* or ZERO_ADDRESS */) { setOptions((prev) => ({ ...prev, payTo: activeAccount.address as `0x${string}`, })); } }, [activeAccount?.address, options.payTo]);apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (3)
24-33
: Add explicit return types for components.Follow the repo guideline to annotate TSX component return types.
-export function X402RightSection(props: { options: X402PlaygroundOptions }) { +export function X402RightSection(props: { options: X402PlaygroundOptions }): JSX.Element { @@ -function BackgroundPattern() { +function BackgroundPattern(): JSX.Element { @@ -function TabButtons(props: { +function TabButtons(props: { tabs: Array<{ name: string; isActive: boolean; onClick: () => void; }>; -}) { +}): JSX.Element {Also applies to: 270-314
56-61
: Be resilient if the response isn’t JSON.Some non-402 responses may not include JSON. Guard parsing to avoid throwing and surface useful errors.
- const response = await fetchWithPay(url.toString()); - return response.json(); + const response = await fetchWithPay(url.toString()); + const text = await response.text(); + try { + return JSON.parse(text); + } catch { + return { ok: response.ok, status: response.status, body: text }; + }
169-197
: Minor: centralize ZERO_ADDRESS and tighten supportedTokens shape.Use a shared ZERO_ADDRESS constant, and consider passing the real token name if available instead of reusing the symbol twice.
- "0x0000000000000000000000000000000000000000" + /* ZERO_ADDRESS */ + "0x0000000000000000000000000000000000000000" @@ - symbol: props.options.tokenSymbol, - name: props.options.tokenSymbol, + symbol: props.options.tokenSymbol, + name: props.options.tokenSymbol, // prefer actual token name if availableAlso applies to: 210-221
📜 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 selected for processing (14)
.changeset/dirty-experts-kiss.md
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/constants.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/types.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
(0 hunks)apps/playground-web/src/app/payments/x402/page.tsx
(2 hunks)apps/playground-web/src/middleware.ts
(3 hunks)packages/thirdweb/src/x402/common.ts
(5 hunks)packages/thirdweb/src/x402/facilitator.ts
(7 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts
(2 hunks)packages/thirdweb/src/x402/schemas.ts
(2 hunks)packages/thirdweb/src/x402/types.ts
(2 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
✅ Files skipped from review due to trivial changes (1)
- .changeset/dirty-experts-kiss.md
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/thirdweb/src/x402/fetchWithPayment.ts
- apps/playground-web/src/middleware.ts
- apps/playground-web/src/app/payments/x402/components/types.ts
- apps/playground-web/src/app/payments/x402/components/X402LeftSection.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@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless 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@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless 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/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/page.tsx
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/page.tsx
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.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
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
from@/lib/utils
for 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: Bearer
header – 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, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-js
in server components
Files:
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
**/types.ts
📄 CodeRabbit inference engine (AGENTS.md)
Provide and re‑use local type barrels in a
types.ts
file
Files:
packages/thirdweb/src/x402/types.ts
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/facilitator.ts
🧠 Learnings (7)
📚 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/playground-web/src/app/payments/x402/components/X402Playground.tsx
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Applied to files:
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/schemas.ts
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.
Applied to files:
packages/thirdweb/src/x402/types.ts
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/_` (e.g., Button, Input, Tabs, Card)
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-05-20T18:54:15.781Z
Learnt from: MananTank
PR: thirdweb-dev/js#7081
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/assets/create/create-token-page-impl.tsx:110-118
Timestamp: 2025-05-20T18:54:15.781Z
Learning: In the thirdweb dashboard's token asset creation flow, the `transferBatch` function from `thirdweb/extensions/erc20` accepts the raw quantity values from the form without requiring explicit conversion to wei using `toUnits()`. The function appears to handle this conversion internally or is designed to work with the values in the format they're already provided.
Applied to files:
packages/thirdweb/src/x402/common.ts
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Applied to files:
packages/thirdweb/src/x402/facilitator.ts
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
🧬 Code graph analysis (7)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
packages/thirdweb/src/exports/chains.ts (1)
base
(17-17)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (4)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)apps/playground-web/src/app/payments/x402/components/constants.ts (2)
chain
(6-6)token
(7-10)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)
X402LeftSection
(14-153)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (1)
X402RightSection
(24-268)
packages/thirdweb/src/x402/types.ts (1)
packages/thirdweb/src/x402/schemas.ts (2)
SupportedSignatureTypeSchema
(60-63)FacilitatorSupportedAssetSchema
(65-73)
apps/playground-web/src/app/payments/x402/page.tsx (1)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (1)
X402Playground
(19-44)
packages/thirdweb/src/x402/common.ts (2)
packages/thirdweb/src/x402/types.ts (3)
DefaultAsset
(109-109)ERC20TokenAmount
(96-107)SupportedSignatureType
(92-94)packages/thirdweb/src/x402/facilitator.ts (3)
facilitator
(89-244)supported
(204-240)ThirdwebX402Facilitator
(24-46)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
FacilitatorSupportedResponse
(94-96)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)packages/thirdweb/src/x402/fetchWithPayment.ts (1)
wrapFetchWithPayment
(51-138)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)
⏰ 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: Build Packages
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Lint Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (30)
packages/thirdweb/src/x402/types.ts (5)
2-2
: LGTM: Adding zod for type inference.Good practice to import zod types when using
z.infer<>
for schema-based type generation.
10-10
: LGTM: Schema-based imports improve type safety.Adding
FacilitatorSupportedAssetSchema
andSupportedSignatureTypeSchema
imports enables deriving types from schemas, which ensures consistency between runtime validation and TypeScript types.Also applies to: 13-13
92-94
: LGTM: Migrating to schema-derived types.Replacing the hardcoded string union with
z.infer<typeof SupportedSignatureTypeSchema>
ensures the TypeScript type stays synchronized with the runtime schema validation.
100-100
: LGTM: Optional properties enable better error handling.Making
decimals
andeip712
optional inERC20TokenAmount.asset
aligns well with the enhanced token metadata detection logic incommon.ts
where these values can be derived from the facilitator when not provided.Also applies to: 101-105
109-109
: LGTM: New DefaultAsset type for facilitator integration.The
DefaultAsset
type derived fromFacilitatorSupportedAssetSchema
provides a consistent interface for assets returned by the facilitator's supported endpoints.packages/thirdweb/src/x402/facilitator.ts (10)
1-1
: LGTM: Updated import for new response type.Import change from previous response type to
FacilitatorSupportedResponse
aligns with the schema updates inschemas.ts
.
15-15
: LGTM: Adding waitUtil configuration option.The optional
waitUtil
config provides flexibility in transaction settlement behavior, supporting different confirmation levels as per common blockchain patterns.
27-27
: LGTM: Exposing client field for downstream usage.Making the
client
field public enables downstream code to access the ThirdwebClient, which is useful for additional operations that may need the client instance.
42-45
: LGTM: Enhanced supported() method with filtering.Adding optional
chainId
andtokenAddress
filters to thesupported()
method enables more targeted queries to the facilitator, improving efficiency and reducing data transfer.
105-105
: LGTM: Client field implementation.Correctly assigns the client from config to the facilitator object, making it accessible as specified in the type definition.
186-186
: LGTM: Conditional waitUtil inclusion in settle payload.The conditional spreading of
waitUtil
into the settle request body follows good practices for optional parameters and enables the facilitator to respect different settlement preferences.
204-207
: LGTM: Updated supported() method signature.The method signature correctly implements the filtering capability defined in the type interface.
214-224
: LGTM: URL construction with query parameters.Properly constructs the supported API URL with optional query parameters using the URL constructor and searchParams, following web standards for URL building.
233-233
: LGTM: Updated return type.Return type correctly matches the new
FacilitatorSupportedResponse
schema.
236-237
: Reasonable cache adjustments.The cache key now includes filter parameters to ensure proper cache isolation, and reducing cache time from 24 hours to 1 hour is reasonable for more dynamic facilitator data.
packages/thirdweb/src/x402/common.ts (8)
19-19
: LGTM: Adding DefaultAsset type import.Import of
DefaultAsset
type enables the enhanced asset handling in the updatedprocessPriceToAtomicAmount
function.
203-203
: LGTM: Enhanced function signature with better error handling.The updated return type
Promise<{ maxAmountRequired: string; asset: DefaultAsset } | { error: string }>
provides better error handling compared to throwing exceptions, making error cases explicit and easier to handle.
207-207
: LGTM: Consistent variable typing.Using
DefaultAsset
type for the asset variable ensures consistency with the new schema-based approach.
225-228
: LGTM: Improved USDC amount calculation.Using
defaultAsset.decimals
from the facilitator-provided asset information ensures correct decimal scaling for different tokens, not just hardcoded assumptions.
232-251
: LGTM: Robust token metadata detection.The new
getOrDetectTokenExtras
approach is well-designed:
- First checks for embedded
eip712
data in the asset- Falls back to facilitator-provided metadata
- Constructs a complete
DefaultAsset
with all required fields- Provides clear error messaging when token info cannot be resolved
262-262
: LGTM: Updated getDefaultAsset return type.Changing to
Promise<DefaultAsset | undefined>
aligns with the schema-based approach and makes the undefined case explicit.
267-267
: LGTM: Type casting for defaultAsset.The cast to
DefaultAsset
is appropriate here since the facilitator response should conform to theFacilitatorSupportedAssetSchema
.
311-367
: LGTM: Comprehensive token metadata detection helper.The
getOrDetectTokenExtras
function is well-implemented:
- Prioritizes embedded metadata when available
- Uses facilitator's supported assets as fallback
- Handles API errors gracefully with try-catch
- Performs case-insensitive address matching
- Returns all required metadata fields
The logic flow is sound and provides good fallback behavior.
packages/thirdweb/src/x402/schemas.ts (5)
8-8
: LGTM: Adding required import.Import of
SupportedPaymentKindsResponseSchema
is needed for the extendedFacilitatorSupportedResponseSchema
.
60-63
: LGTM: Well-defined signature type schema.The
SupportedSignatureTypeSchema
correctly defines the two supported EIP-712 signature methods for token operations. Usingz.enum()
provides both runtime validation and precise TypeScript typing.
65-73
: LGTM: Comprehensive asset schema definition.
FacilitatorSupportedAssetSchema
is well-structured:
address
as string for token contract addressesdecimals
as number for proper amount calculationseip712
object with all required fields for signature generation- Uses
SupportedSignatureTypeSchema
forprimaryType
to ensure consistency
75-92
: LGTM: Comprehensive facilitator response schema.The
FacilitatorSupportedResponseSchema
is well-designed:
- Extends existing
SupportedPaymentKindsResponseSchema
for consistency- Defines structured
kinds
array with required fields- Makes
extra
object optional with proper nesting- Includes both
defaultAsset
andsupportedAssets
for flexibility- Good use of
.describe()
for documentation
94-96
: LGTM: Proper type inference from schema.Correctly exports the TypeScript type inferred from the schema, maintaining the schema-first approach for consistency between runtime validation and compile-time types.
apps/playground-web/src/app/payments/x402/page.tsx (1)
1-1
: LGTM — page integrates the new playground cleanly.Also applies to: 5-5, 31-31
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (1)
87-115
: Server snippet: use toUnits for exact base units; avoid Number(...) and scientific notation.The template converts amount with Number(...) * 10 ** ..., which can lose precision and emit 1e+N strings, breaking settlePayment.
- price: { - amount: "${Number(props.options.amount) * 10 ** props.options.tokenDecimals}", - asset: { - address: "${props.options.tokenAddress}", - }, - }, + price: { + amount: toUnits("${props.options.amount}", ${props.options.tokenDecimals}).toString(), + asset: { + address: "${props.options.tokenAddress}", + }, + },
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
Show resolved
Hide resolved
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
Outdated
Show resolved
Hide resolved
640f12a
to
e20f68f
Compare
e20f68f
to
d57ae09
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: 0
🧹 Nitpick comments (5)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (1)
23-23
: Consider adding explicit return typeAdd an explicit return type for better TypeScript practices and IDE support.
-export function X402RightSection(props: { options: X402PlaygroundOptions }) { +export function X402RightSection(props: { options: X402PlaygroundOptions }): JSX.Element {packages/thirdweb/src/x402/schemas.ts (1)
114-117
: Consider adding constants for Solana chain IDsThe hardcoded chain IDs (101, 103) for Solana networks would be more maintainable as named constants. This would make the code more readable and easier to update when Solana support is added.
+const SOLANA_MAINNET_CHAIN_ID = 101; +const SOLANA_DEVNET_CHAIN_ID = 103; + export function networkToChainId(network: string | Chain): number { // ... existing code ... // TODO (402): support solana networks - if (mappedChainId === 101 || mappedChainId === 103) { + if (mappedChainId === SOLANA_MAINNET_CHAIN_ID || mappedChainId === SOLANA_DEVNET_CHAIN_ID) { throw new Error("Solana networks not supported yet."); }packages/thirdweb/src/x402/common.ts (2)
259-269
: Consider type validation instead of castingThe type cast
as DefaultAsset
on line 267 bypasses TypeScript's type checking. Consider validating the structure or using a type guard to ensure type safety.- const assetConfig = matchingAsset?.extra?.defaultAsset as DefaultAsset; + const assetConfig = matchingAsset?.extra?.defaultAsset; + if (assetConfig && !isValidDefaultAsset(assetConfig)) { + return undefined; + } return assetConfig;You could add a type guard function or use zod parsing for validation.
311-367
: Well-designed token metadata discovery with minor type safety concernThe
getOrDetectTokenExtras
function provides excellent progressive enhancement for token metadata discovery. However, the type cast on line 365 should be validated.- primaryType: supportedAsset.eip712.primaryType as SupportedSignatureType, + primaryType: supportedAsset.eip712.primaryType,The schema already ensures
primaryType
is a validSupportedSignatureType
, so the cast may be unnecessary if the types are properly aligned.packages/thirdweb/src/x402/facilitator.ts (1)
204-240
: Good implementation of filtered asset discoveryThe enhanced
supported()
function properly handles optional filters and caching. The reduced cache time (1 hour) is appropriate for potentially dynamic asset data.Note: The cache key has a '2' suffix on line 236, which appears to be a versioning mechanism. Consider using a constant or documenting this versioning approach for maintainability.
- cacheKey: `supported-payment-kinds-${url}-${filters?.chainId}-${filters?.tokenAddress}2`, + cacheKey: `supported-payment-kinds-${url}-${filters?.chainId}-${filters?.tokenAddress}-v2`,
📜 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 selected for processing (14)
.changeset/dirty-experts-kiss.md
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/constants.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/types.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
(0 hunks)apps/playground-web/src/app/payments/x402/page.tsx
(2 hunks)apps/playground-web/src/middleware.ts
(3 hunks)packages/thirdweb/src/x402/common.ts
(5 hunks)packages/thirdweb/src/x402/facilitator.ts
(7 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts
(2 hunks)packages/thirdweb/src/x402/schemas.ts
(2 hunks)packages/thirdweb/src/x402/types.ts
(2 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
✅ Files skipped from review due to trivial changes (1)
- .changeset/dirty-experts-kiss.md
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/playground-web/src/app/payments/x402/components/types.ts
- apps/playground-web/src/middleware.ts
- apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
- apps/playground-web/src/app/payments/x402/page.tsx
- apps/playground-web/src/app/payments/x402/components/constants.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@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless 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@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless 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:
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/src/x402/schemas.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/schemas.ts
**/types.ts
📄 CodeRabbit inference engine (AGENTS.md)
Provide and re‑use local type barrels in a
types.ts
file
Files:
packages/thirdweb/src/x402/types.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}
: Import UI primitives from@/components/ui/*
(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
from@/lib/utils
for 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: Bearer
header – 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, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-js
in server components
Files:
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
🧠 Learnings (16)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Applied to files:
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/types.ts
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Applied to files:
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.
Applied to files:
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-05-27T19:55:25.056Z
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_hooks/useTokenPriceData.ts:49-49
Timestamp: 2025-05-27T19:55:25.056Z
Learning: In the ERC20 public pages token price data hook (`useTokenPriceData.ts`), direct array access on `json.data[0]` without optional chaining is intentionally correct and should not be changed to use safety checks.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402LeftSection.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/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-05-20T18:54:15.781Z
Learnt from: MananTank
PR: thirdweb-dev/js#7081
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/assets/create/create-token-page-impl.tsx:110-118
Timestamp: 2025-05-20T18:54:15.781Z
Learning: In the thirdweb dashboard's token asset creation flow, the `transferBatch` function from `thirdweb/extensions/erc20` accepts the raw quantity values from the form without requiring explicit conversion to wei using `toUnits()`. The function appears to handle this conversion internally or is designed to work with the values in the format they're already provided.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Server Components must start with `import "server-only"`; use `next/headers`, server‑only env, heavy data fetching, and `redirect()` where appropriate
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Do not import `posthog-js` in server components (client-side only)
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Client Components must start with `'use client'`; handle interactivity with hooks and browser APIs
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/**/*.{ts,tsx} : Client-side only: never import `posthog-js` in server components.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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 : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
🧬 Code graph analysis (6)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
chain
(5-5)
packages/thirdweb/src/x402/common.ts (2)
packages/thirdweb/src/x402/types.ts (3)
DefaultAsset
(109-109)ERC20TokenAmount
(96-107)SupportedSignatureType
(92-94)packages/thirdweb/src/x402/facilitator.ts (3)
facilitator
(89-244)supported
(204-240)ThirdwebX402Facilitator
(24-46)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
FacilitatorSupportedResponse
(94-96)
packages/thirdweb/src/x402/types.ts (1)
packages/thirdweb/src/x402/schemas.ts (2)
SupportedSignatureTypeSchema
(60-63)FacilitatorSupportedAssetSchema
(65-73)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)apps/playground-web/src/app/payments/components/LeftSection.tsx (1)
LeftSection
(21-492)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)packages/thirdweb/src/x402/fetchWithPayment.ts (1)
wrapFetchWithPayment
(51-138)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)
⏰ 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
🔇 Additional comments (22)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (5)
1-19
: LGTM! Proper client component setup with appropriate imports.The file correctly starts with
"use client"
directive and imports are well-organized following the coding guidelines. Type imports use thetype
keyword appropriately.
161-236
: Well-structured UI with proper state managementGood implementation with:
- Proper conditional token configuration for non-zero addresses
- Correct disabled state logic for the pay button
- Comprehensive loading/error/success states for the mutation
- Clean use of design system components
277-305
: Clean implementation of internal UI componentsTabButtons component properly manages active states with appropriate styling using the design system tokens and
cn()
utility.
42-47
: Cap the payment to the selected amount/decimals — hardcoded 1e18 defeats the guard.Passing
BigInt(1 * 10 ** 18)
as maxValue allows astronomically large charges on 6-decimals tokens. Compute the cap from the user-entered amount and token decimals.-import { wrapFetchWithPayment } from "thirdweb/x402"; +import { wrapFetchWithPayment } from "thirdweb/x402"; +import { toUnits } from "thirdweb/utils"; ... const fetchWithPay = wrapFetchWithPayment( fetch, THIRDWEB_CLIENT, activeWallet, - BigInt(1 * 10 ** 18), + toUnits(props.options.amount || "0", props.options.tokenDecimals), );
108-115
: Fix server code interpolation and amount conversionRendering the snippet as-is drops the quotes around
payTo
/address
, so the preview outputspayTo: 0xabc...
which is invalid JavaScript and will throw immediately when copied. Additionally, coercingamount
withNumber(...) * 10 ** ...
will emit scientific notation (e.g.,1e+24
) for larger values, which breakssettlePayment
.- payTo: ${props.options.payTo}, + payTo: "${props.options.payTo}", network: defineChain(${props.options.chain.id}), price: { - amount: "${Number(props.options.amount) * 10 ** props.options.tokenDecimals}", + amount: "${Number(props.options.amount) * 10 ** props.options.tokenDecimals}", asset: { - address: ${props.options.tokenAddress}, + address: "${props.options.tokenAddress}", },However, for the amount field, consider importing
toUnits
in the server code example and using it properly:+import { toUnits } from "thirdweb/utils"; ... - amount: "${Number(props.options.amount) * 10 ** props.options.tokenDecimals}", + amount: toUnits("${props.options.amount}", ${props.options.tokenDecimals}).toString(),apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (7)
1-12
: LGTM: Clean imports and client component setupThe imports are well-organized and appropriate for the component's functionality. The "use client" directive correctly marks this as a client-side component that uses React hooks and state management.
14-18
: LGTM: Well-typed component interfaceThe component props are properly typed using the X402PlaygroundOptions interface and React's built-in types. The destructuring pattern is clean and follows React best practices.
20-41
: LGTM: Proper state initialization and accessibility setupThe local state setup correctly initializes from the options prop with fallback logic. The useId() calls for form accessibility are appropriate and follow coding guidelines for UI components.
42-54
: LGTM: Chain change handler properly resets dependent stateThe handler correctly clears token selection when the chain changes and resets related options to safe defaults. The use of defineChain follows the thirdweb SDK patterns.
56-68
: Verify null assertion safety in token handlerThe code uses
selectedChain!
on line 59 without null checking. While the TokenSelector is only rendered whenselectedChain
exists, this could be fragile if the component structure changes.Consider adding a guard clause for safety:
const handleTokenChange = (token: TokenMetadata) => { + if (!selectedChain) return; + setSelectedToken({ address: token.address, - chainId: selectedChain!, + chainId: selectedChain, });
70-82
: LGTM: Input change handlers are straightforward and correctBoth amount and payTo handlers properly update the options state. The address casting is appropriate for the Address type requirement.
84-153
: LGTM: Well-structured UI with proper conditional renderingThe render logic correctly:
- Uses conditional rendering to show TokenSelector only when chain is selected
- Applies proper Tailwind classes following the coding guidelines
- Includes helpful hint text for user guidance
- Maintains good accessibility with labeled inputs
The component structure follows the established patterns from the existing LeftSection component while being specific to x402 use cases.
packages/thirdweb/src/x402/schemas.ts (3)
1-28
: LGTM! Well-structured network schema with good extensibilityThe FacilitatorNetworkSchema properly supports both known networks and custom EIP-155 chains, providing flexibility for future network additions.
60-73
: LGTM! Comprehensive asset schema with EIP-712 supportThe schemas properly model supported signature types and asset metadata required for token operations. The structure aligns well with EIP-712 signing requirements.
75-96
: LGTM! Well-designed response schema for payment discoveryThe schema extends the base response appropriately and provides a flexible structure for asset discovery with optional default and supported assets.
packages/thirdweb/src/x402/fetchWithPayment.ts (2)
64-68
: Good enhancement to error handlingExtracting the optional error message from the server response improves debugging by providing more context when payment requirements don't match.
87-91
: Critical fix: Added missing null checkGood addition of the null check for
selectedPaymentRequirements
. The error message now provides helpful context including the chain ID and any server-provided error message.packages/thirdweb/src/x402/types.ts (2)
92-94
: Good type consolidation using zod inferenceUsing
z.infer
to derive the type from the schema ensures consistency and maintains a single source of truth for the signature types.
96-109
: LGTM! Flexible asset type definitionsMaking
decimals
andeip712
optional inERC20TokenAmount
allows for progressive enhancement of asset metadata, whileDefaultAsset
provides a complete type when all information is available.packages/thirdweb/src/x402/common.ts (1)
198-257
: Excellent improvement to token metadata handlingThe refactored
processPriceToAtomicAmount
now properly discovers and validates token metadata, with clear error messages when information is missing. The use ofDefaultAsset
ensures consistent asset representation.packages/thirdweb/src/x402/facilitator.ts (2)
12-46
: LGTM! Well-designed API extensionsThe additions enhance the facilitator's capabilities:
waitUtil
provides control over transaction finality- Exposing
client
enables direct client access when needed- Filter support in
supported()
allows targeted asset discovery
186-186
: Clean implementation of optional waitUtil parameterThe conditional inclusion of
waitUtil
in the settle request maintains backward compatibility while enabling transaction finality control.
d57ae09
to
0307475
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: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/thirdweb/src/x402/common.ts (1)
34-41
: Public API TSDoc is missing required tags/examplesPer repo guidelines, public symbols need TSDoc with a compiling
@example
and a custom tag (@beta
,@internal
, etc.). Please add fordecodePaymentRequest
(and alsogetSupportedSignatureType
).As per coding guidelines
🧹 Nitpick comments (5)
packages/thirdweb/src/x402/common.ts (5)
120-123
: Expose decimals in paymentextra
for clientsYou merge EIP‑712 extras but omit
decimals
. Many clients need it to display/convert correctly without refetching. Add it alongsidefacilitatorAddress
.extra: { facilitatorAddress: facilitator.address, - ...((asset as ERC20TokenAmount["asset"]).eip712 ?? {}), + decimals: asset.decimals, + ...((asset as ERC20TokenAmount["asset"]).eip712 ?? {}), },
295-297
: Strengthen type‑narrowing for ABI functions
toFunctionSelector
expectsAbiFunction
. Add a typed predicate to avoid implicit any/unsafe narrowing.-import { type Abi } from "abitype"; +import { type Abi, type AbiFunction } from "abitype"; @@ - const selectors = abi - .filter((f) => f.type === "function") - .map((f) => toFunctionSelector(f)); + const selectors = abi + .filter((f): f is AbiFunction => f.type === "function") + .map((f) => toFunctionSelector(f));
262-269
: HardengetDefaultAsset
: pass filter and handle errorsCall
supported
withchainId
to reduce payload and add a catch to avoid unhandled rejections. Also avoid unsafe cast.- const supportedAssets = await facilitator.supported(); + const supportedAssets = await facilitator + .supported({ chainId }) + .catch(() => ({ kinds: [] as Array<{ network: string; extra?: unknown }> })); @@ - const assetConfig = matchingAsset?.extra?.defaultAsset as DefaultAsset; - return assetConfig; + const assetConfig = (matchingAsset as any)?.extra?.defaultAsset; + return assetConfig as DefaultAsset | undefined;Optionally validate with your zod
FacilitatorSupportedAssetSchema
before returning.
311-367
: Improve token extras detection resilience
- If facilitator response lacks the token, consider falling back to on‑chain detection for
primaryType
viagetSupportedSignatureType
(already available in this file). This may require threading aThirdwebClient
into this helper.- Validate
supportedAsset.eip712.primaryType
against your union before returning; don’t cast blindly.If you can thread
client
, minimal fallback:-async function getOrDetectTokenExtras(args: { - facilitator: ThirdwebX402Facilitator; - partialAsset: ERC20TokenAmount["asset"]; - chainId: number; -}): Promise< { name: string; version: string; decimals: number; primaryType: SupportedSignatureType; } | undefined> { +async function getOrDetectTokenExtras(args: { + facilitator: ThirdwebX402Facilitator; + partialAsset: ERC20TokenAmount["asset"]; + chainId: number; + client?: ThirdwebClient; +}): Promise<{ name: string; version: string; decimals: number; primaryType: SupportedSignatureType; } | undefined> { @@ - return { - name: supportedAsset.eip712.name, - version: supportedAsset.eip712.version, - decimals: supportedAsset.decimals, - primaryType: supportedAsset.eip712.primaryType as SupportedSignatureType, - }; + let primaryType = supportedAsset.eip712?.primaryType; + if (!primaryType && args.client) { + primaryType = await getSupportedSignatureType({ + client: args.client, + asset: partialAsset.address, + chainId, + eip712Extras: undefined, + }); + } + if (primaryType !== "Permit" && primaryType !== "TransferWithAuthorization") return undefined; + return { + name: supportedAsset.eip712.name, + version: supportedAsset.eip712.version, + decimals: supportedAsset.decimals, + primaryType, + };
110-111
: Track TODO rename with issueThere’s a TODO to rename
outputSchema
torequestStructure
. Open an issue so it doesn’t get lost; happy to create it with context.
📜 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 selected for processing (14)
.changeset/dirty-experts-kiss.md
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
(1 hunks)apps/playground-web/src/app/payments/x402/components/constants.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/types.ts
(1 hunks)apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
(0 hunks)apps/playground-web/src/app/payments/x402/page.tsx
(2 hunks)apps/playground-web/src/middleware.ts
(3 hunks)packages/thirdweb/src/x402/common.ts
(5 hunks)packages/thirdweb/src/x402/facilitator.ts
(5 hunks)packages/thirdweb/src/x402/fetchWithPayment.ts
(2 hunks)packages/thirdweb/src/x402/schemas.ts
(2 hunks)packages/thirdweb/src/x402/types.ts
(2 hunks)
💤 Files with no reviewable changes (1)
- apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/playground-web/src/app/payments/x402/components/X402Playground.tsx
- apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
- .changeset/dirty-experts-kiss.md
🧰 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@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless 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@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless 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:
packages/thirdweb/src/x402/fetchWithPayment.ts
apps/playground-web/src/middleware.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/schemas.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/page.tsx
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
apps/playground-web/src/middleware.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/schemas.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/page.tsx
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/x402/fetchWithPayment.ts
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/schemas.ts
packages/thirdweb/src/x402/facilitator.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}
: Import UI primitives from@/components/ui/*
(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
from@/lib/utils
for 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: Bearer
header – 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, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-js
in server components
Files:
apps/playground-web/src/middleware.ts
apps/playground-web/src/app/payments/x402/components/types.ts
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/app/payments/x402/components/constants.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
**/types.ts
📄 CodeRabbit inference engine (AGENTS.md)
Provide and re‑use local type barrels in a
types.ts
file
Files:
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/components/types.ts
🧠 Learnings (18)
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/wallets/** : EIP-1193, EIP-5792, EIP-7702 standard support in wallet modules
Applied to files:
packages/thirdweb/src/x402/common.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/schemas.ts
📚 Learning: 2025-06-26T19:46:04.024Z
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.
Applied to files:
packages/thirdweb/src/x402/types.ts
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Import UI primitives from `@/components/ui/_` (e.g., Button, Input, Tabs, Card)
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
📚 Learning: 2025-05-27T19:55:25.056Z
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_hooks/useTokenPriceData.ts:49-49
Timestamp: 2025-05-27T19:55:25.056Z
Learning: In the ERC20 public pages token price data hook (`useTokenPriceData.ts`), direct array access on `json.data[0]` without optional chaining is intentionally correct and should not be changed to use safety checks.
Applied to files:
apps/playground-web/src/app/payments/x402/components/constants.ts
📚 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/playground-web/src/app/payments/x402/components/constants.ts
📚 Learning: 2025-05-20T18:54:15.781Z
Learnt from: MananTank
PR: thirdweb-dev/js#7081
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/assets/create/create-token-page-impl.tsx:110-118
Timestamp: 2025-05-20T18:54:15.781Z
Learning: In the thirdweb dashboard's token asset creation flow, the `transferBatch` function from `thirdweb/extensions/erc20` accepts the raw quantity values from the form without requiring explicit conversion to wei using `toUnits()`. The function appears to handle this conversion internally or is designed to work with the values in the format they're already provided.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Server Components (Node edge): Start files with `import "server-only";`
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Server Components must start with `import "server-only"`; use `next/headers`, server‑only env, heavy data fetching, and `redirect()` where appropriate
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/api/**/*.{ts,tsx} : Prefix files with `import "server-only";` so they never end up in the client bundle.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Client Components (browser): Begin files with `'use client';`
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/**/components/*.client.tsx : Client components must start with `'use client';` before imports.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Do not import `posthog-js` in server components (client-side only)
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.{ts,tsx} : Client Components must start with `'use client'`; handle interactivity with hooks and browser APIs
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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/**/*.{ts,tsx} : Client-side only: never import `posthog-js` in server components.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.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 : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
PR: thirdweb-dev/js#7227
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/OpenEditionMetadata.tsx:26-26
Timestamp: 2025-05-30T17:14:25.332Z
Learning: The ModuleCardUIProps interface already includes a client prop of type ThirdwebClient, so when components use `Omit<ModuleCardUIProps, "children" | "updateButton">`, they inherit the client prop without needing to add it explicitly.
Applied to files:
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx
🧬 Code graph analysis (7)
apps/playground-web/src/middleware.ts (2)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
token
(6-11)packages/thirdweb/src/x402/settle-payment.ts (1)
settlePayment
(126-187)
packages/thirdweb/src/x402/common.ts (2)
packages/thirdweb/src/x402/types.ts (3)
DefaultAsset
(109-109)ERC20TokenAmount
(96-107)SupportedSignatureType
(92-94)packages/thirdweb/src/x402/facilitator.ts (3)
facilitator
(88-242)supported
(202-238)ThirdwebX402Facilitator
(24-45)
packages/thirdweb/src/x402/types.ts (1)
packages/thirdweb/src/x402/schemas.ts (2)
SupportedSignatureTypeSchema
(60-63)FacilitatorSupportedAssetSchema
(65-73)
apps/playground-web/src/app/payments/x402/page.tsx (1)
apps/playground-web/src/app/payments/x402/components/X402Playground.tsx (1)
X402Playground
(19-44)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
FacilitatorSupportedResponse
(94-96)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
packages/thirdweb/src/exports/chains.ts (1)
base
(17-17)
apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (3)
apps/playground-web/src/app/payments/x402/components/types.ts (1)
X402PlaygroundOptions
(4-11)packages/thirdweb/src/x402/fetchWithPayment.ts (1)
wrapFetchWithPayment
(51-138)apps/playground-web/src/lib/client.ts (1)
THIRDWEB_CLIENT
(20-43)
⏰ 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, vite)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (4)
apps/playground-web/src/middleware.ts (1)
41-57
: Validatedecimals
before building the price payload.We still parse the
decimals
query param withparseInt
and pass the result straight intotoUnits
/price construction. Any malformed value (e.g.?decimals=abc
or an out-of-range integer) turns intoNaN
, which makestoUnits
throw and the middleware return a 500 instead of a controlled 400. Please parse once, ensure it’s a finite non-negative integer (within the token-decimals range), and short-circuit with a400
if it isn’t valid, reusing the safe parsed value afterwards.- const tokenAddress = queryParams.get("tokenAddress") || token.address; - const decimals = queryParams.get("decimals") || token.decimals.toString(); + const tokenAddress = queryParams.get("tokenAddress") || token.address; + const decimalsParam = queryParams.get("decimals"); + const decimals = + decimalsParam === null + ? token.decimals + : Number.parseInt(decimalsParam, 10); + + if (!Number.isInteger(decimals) || decimals < 0 || decimals > 36) { + return NextResponse.json( + { error: "Invalid token decimals parameter" }, + { status: 400 }, + ); + } @@ - price: { - amount: toUnits(amount, parseInt(decimals)).toString(), - asset: { - address: tokenAddress as `0x${string}`, - decimals: decimals ? parseInt(decimals) : token.decimals, - }, - }, + price: { + amount: toUnits(amount, decimals).toString(), + asset: { + address: tokenAddress as `0x${string}`, + decimals, + }, + },apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx (2)
42-47
: Use the selected token amount to capwrapFetchWithPayment
.
Hard-codingBigInt(1 * 10 ** 18)
ignores the user’s configured amount/decimals, so the guard happily allows vastly larger settlements (e.g., 1e18 units on a 6‑decimals token). Compute the ceiling from the current form state before calling the wrapper.-import { wrapFetchWithPayment } from "thirdweb/x402"; +import { wrapFetchWithPayment } from "thirdweb/x402"; +import { toUnits } from "thirdweb/utils"; @@ - activeWallet, - BigInt(1 * 10 ** 18), + activeWallet, + toUnits(props.options.amount || "0", props.options.tokenDecimals), );
86-115
: Render the server snippet withtoUnits
to avoid scientific notation.
The template still emitsNumber(...)*10 ** ...
, which turns larger payments into scientific notation (e.g.,1e+24
). That breakssettlePayment
and contradicts the recommended usage. PulltoUnits
into the snippet and stringify the bigint so readers copy valid code.-const serverCode = `// Usage in a Next.js API route -import { settlePayment, facilitator } from "thirdweb/x402"; -import { createThirdwebClient } from "thirdweb"; +const serverCode = `// Usage in a Next.js API route +import { settlePayment, facilitator } from "thirdweb/x402"; +import { createThirdwebClient } from "thirdweb"; +import { toUnits } from "thirdweb/utils"; @@ - price: { - amount: "${Number(props.options.amount) * 10 ** props.options.tokenDecimals}", - asset: { - address: "${props.options.tokenAddress}", - }, - }, + price: { + amount: toUnits("${props.options.amount}", ${props.options.tokenDecimals}).toString(), + asset: { + address: "${props.options.tokenAddress}", + }, + },packages/thirdweb/src/x402/common.ts (1)
100-109
: ConfirmpayTo
is always provided; otherwise return 402 early
getAddress(payTo)
will throw ifpayTo
is undefined/invalid. If upstream types don’t guarantee it, guard and surface a 402 with a clear message.Suggested guard:
@@ - const atomicAmountForAsset = await processPriceToAtomicAmount( + if (!payTo) { + return { + status: 402, + responseHeaders: { "Content-Type": "application/json" }, + responseBody: { x402Version, error: "Missing payTo address", accepts: [] }, + }; + } + const atomicAmountForAsset = await processPriceToAtomicAmount(
0d4a8d3
to
1b718f0
Compare
PR-Codex overview
This PR focuses on enhancing the
x402
payments functionality by improving token information discovery, updating payment processing, and refining the user interface for better usability.Detailed summary
x402
payments.chain
andtoken
constants inconstants.ts
.fetchWithPayment.ts
.schemas.ts
for supported signature types and assets.X402Playground
component with better state management.X402LeftSection
andX402RightSection
for improved UI interactions.Summary by CodeRabbit
New Features
Improvements
Removals
Chores