Skip to content

Conversation

joaquim-verges
Copy link
Member

@joaquim-verges joaquim-verges commented Sep 29, 2025


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

  • Improved token info discovery for x402 payments.
  • Updated chain and token constants in constants.ts.
  • Enhanced error handling in fetchWithPayment.ts.
  • Added new schemas in schemas.ts for supported signature types and assets.
  • Refined X402Playground component with better state management.
  • Updated X402LeftSection and X402RightSection for improved UI interactions.
  • Modified middleware to handle payment parameters more effectively.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • New Features

    • Interactive X402 Playground: configurable chain, token, amount, pay-to, wallet connect, “Pay” flow and multi-tab previews (UI / client / server).
  • Improvements

    • Default network set to Base and USDC defaulted to 6 decimals.
    • Pay-to auto-fills from connected wallet when available.
    • Better token metadata detection and clearer errors when payment requirements aren’t met.
    • Middleware supports simulated wait and computes price from provided inputs.
  • Removals

    • Legacy client preview replaced by consolidated playground.
  • Chores

    • Patch changeset entry added.

Copy link

vercel bot commented Sep 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Sep 29, 2025 9:06am
nebula Ready Ready Preview Comment Sep 29, 2025 9:06am
thirdweb_playground Ready Ready Preview Comment Sep 29, 2025 9:06am
thirdweb-www Ready Ready Preview Comment Sep 29, 2025 9:06am
wallet-ui Ready Ready Preview Comment Sep 29, 2025 9:06am

Copy link

changeset-bot bot commented Sep 29, 2025

🦋 Changeset detected

Latest commit: 1b718f0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
thirdweb Patch
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch

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

Copy link
Contributor

coderabbitai bot commented Sep 29, 2025

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 0307475 and 1b718f0.

📒 Files selected for processing (7)
  • 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/middleware.ts (3 hunks)
  • packages/thirdweb/src/x402/common.ts (6 hunks)

Walkthrough

Adds 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

Cohort / File(s) Summary
Playground UI components
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx, apps/playground-web/src/app/payments/x402/components/X402Playground.tsx, apps/playground-web/src/app/payments/x402/components/X402RightSection.tsx, apps/playground-web/src/app/payments/x402/components/constants.ts, apps/playground-web/src/app/payments/x402/components/types.ts, apps/playground-web/src/app/payments/x402/page.tsx
Adds X402Playground with left/right panels and local state wiring (chain/token/amount/payTo), new X402PlaygroundOptions type, switches default chain to base, hardcodes USDC token metadata, and updates the page to render X402Playground.
Removed playground component
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
Removes legacy X402ClientPreview component.
Middleware
apps/playground-web/src/middleware.ts
Sets facilitator waitUtil to "simulated", uses toUnits and token constants as defaults, and builds a concrete price object (amount → atomic units + asset).
X402 core — common
packages/thirdweb/src/x402/common.ts
Introduces DefaultAsset usage and getOrDetectTokenExtras; processPriceToAtomicAmount now returns `{ maxAmountRequired, asset: DefaultAsset }
X402 core — facilitator
packages/thirdweb/src/x402/facilitator.ts
Adds optional waitUtil to config and includes it in settle payloads; supported() now accepts optional { chainId, tokenAddress? }, returns FacilitatorSupportedResponse, updates URL/query and cache behavior.
X402 core — fetchWithPayment
packages/thirdweb/src/x402/fetchWithPayment.ts
Extends 402 parsing to include optional server error, changes selection guards to surface server errors when no matching payment requirement is found, retains amount validation and retry/payment header flow.
X402 core — schemas
packages/thirdweb/src/x402/schemas.ts
Adds SupportedSignatureTypeSchema, FacilitatorSupportedAssetSchema, and FacilitatorSupportedResponseSchema; exports FacilitatorSupportedResponse type and related schema entities.
X402 core — types
packages/thirdweb/src/x402/types.ts
Adds DefaultAsset type, derives SupportedSignatureType from schema, and makes ERC20TokenAmount.asset.decimals and asset.eip712 optional.
Changeset
.changeset/dirty-experts-kiss.md
Adds a patch changeset for the thirdweb package noting improved token info discovery for x402 payments.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jnsdls

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description leaves the template comments in place and does not provide any of the required sections such as “## Notes for the reviewer” or “## How to test,” so it lacks the structured context and testing instructions mandated by the repository’s template. Please remove the placeholder template comments and populate the description with a concise title reference, a “## Notes for the reviewer” section detailing important context, and a “## How to test” section with concrete validation steps, including the issue tag if available.
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title “[SDK] Improve token info discovery for x402 payments” concisely describes the primary change by indicating both the subsystem (SDK) and the specific enhancement (token info discovery for x402 payments), making it clear to reviewers and maintainers.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added Playground Changes involving the Playground codebase. packages SDK Involves changes to the thirdweb SDK labels Sep 29, 2025
@joaquim-verges joaquim-verges changed the title Improve token info discovery for x402 payments [SDK] Improve token info discovery for x402 payments Sep 29, 2025
@joaquim-verges joaquim-verges marked this pull request as ready for review September 29, 2025 02:32
@joaquim-verges joaquim-verges requested review from a team as code owners September 29, 2025 02:32
Copy link
Member Author


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

Copy link
Contributor

github-actions bot commented Sep 29, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.69 KB (0%) 1.3 s (0%) 206 ms (+289.3% 🔺) 1.5 s
thirdweb (cjs) 361.52 KB (0%) 7.3 s (0%) 590 ms (+12.03% 🔺) 7.9 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 97 ms (+3094.25% 🔺) 211 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 28 ms (+1033.52% 🔺) 38 ms
thirdweb/react (minimal + tree-shaking) 19.14 KB (0%) 383 ms (0%) 81 ms (+2979.65% 🔺) 464 ms

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 X402Playground

Line 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 X402LeftSection

Line 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.

📥 Commits

Reviewing files that changed from the base of the PR and between e2931df and 3c6fdd0.

📒 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-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 in packages/* 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)

Copy link

codecov bot commented Sep 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.29%. Comparing base (e2931df) to head (1b718f0).
⚠️ Report is 1 commits behind head on main.

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     
Flag Coverage Δ
packages 56.29% <ø> (+<0.01%) ⬆️
see 3 files with indirect coverage changes
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 available

Also 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 3c6fdd0 and 640f12a.

📒 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-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 and SupportedSignatureTypeSchema 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 and eip712 optional in ERC20TokenAmount.asset aligns well with the enhanced token metadata detection logic in common.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 from FacilitatorSupportedAssetSchema 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 in schemas.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 and tokenAddress filters to the supported() 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 updated processPriceToAtomicAmount 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 the FacilitatorSupportedAssetSchema.


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 extended FacilitatorSupportedResponseSchema.


60-63: LGTM: Well-defined signature type schema.

The SupportedSignatureTypeSchema correctly defines the two supported EIP-712 signature methods for token operations. Using z.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 addresses
  • decimals as number for proper amount calculations
  • eip712 object with all required fields for signature generation
  • Uses SupportedSignatureTypeSchema for primaryType 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 and supportedAssets 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}",
+      },
+    },

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 type

Add 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 IDs

The 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 casting

The 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 concern

The 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 valid SupportedSignatureType, 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 discovery

The 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 640f12a and d57ae09.

📒 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-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 the type keyword appropriately.


161-236: Well-structured UI with proper state management

Good 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 components

TabButtons 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 conversion

Rendering the snippet as-is drops the quotes around payTo/address, so the preview outputs payTo: 0xabc... which is invalid JavaScript and will throw immediately when copied. Additionally, coercing amount with Number(...) * 10 ** ... will emit scientific notation (e.g., 1e+24) for larger values, which breaks settlePayment.

-    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 setup

The 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 interface

The 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 setup

The 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 state

The 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 handler

The code uses selectedChain! on line 59 without null checking. While the TokenSelector is only rendered when selectedChain 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 correct

Both 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 rendering

The 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 extensibility

The 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 support

The 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 discovery

The 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 handling

Extracting 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 check

Good 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 inference

Using 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 definitions

Making decimals and eip712 optional in ERC20TokenAmount allows for progressive enhancement of asset metadata, while DefaultAsset provides a complete type when all information is available.

packages/thirdweb/src/x402/common.ts (1)

198-257: Excellent improvement to token metadata handling

The refactored processPriceToAtomicAmount now properly discovers and validates token metadata, with clear error messages when information is missing. The use of DefaultAsset ensures consistent asset representation.

packages/thirdweb/src/x402/facilitator.ts (2)

12-46: LGTM! Well-designed API extensions

The 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 parameter

The conditional inclusion of waitUtil in the settle request maintains backward compatibility while enabling transaction finality control.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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/examples

Per repo guidelines, public symbols need TSDoc with a compiling @example and a custom tag (@beta, @internal, etc.). Please add for decodePaymentRequest (and also getSupportedSignatureType).

As per coding guidelines

🧹 Nitpick comments (5)
packages/thirdweb/src/x402/common.ts (5)

120-123: Expose decimals in payment extra for clients

You merge EIP‑712 extras but omit decimals. Many clients need it to display/convert correctly without refetching. Add it alongside facilitatorAddress.

     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 expects AbiFunction. 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: Harden getDefaultAsset: pass filter and handle errors

Call supported with chainId 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 via getSupportedSignatureType (already available in this file). This may require threading a ThirdwebClient 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 issue

There’s a TODO to rename outputSchema to requestStructure. 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.

📥 Commits

Reviewing files that changed from the base of the PR and between d57ae09 and 0307475.

📒 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-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: Validate decimals before building the price payload.

We still parse the decimals query param with parseInt and pass the result straight into toUnits/price construction. Any malformed value (e.g. ?decimals=abc or an out-of-range integer) turns into NaN, which makes toUnits 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 a 400 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 cap wrapFetchWithPayment.
Hard-coding BigInt(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 with toUnits to avoid scientific notation.
The template still emits Number(...)*10 ** ..., which turns larger payments into scientific notation (e.g., 1e+24). That breaks settlePayment and contradicts the recommended usage. Pull toUnits 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: Confirm payTo is always provided; otherwise return 402 early

getAddress(payTo) will throw if payTo 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(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

packages Playground Changes involving the Playground codebase. SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant