Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

joaquim-verges
Copy link
Member

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


PR-Codex overview

This PR introduces support for ERC-2612 permit functionality in the thirdweb library, enhancing payment capabilities for x402 transactions. It updates various components, adds new types, and modifies existing functions to accommodate the new feature.

Detailed summary

  • Added support for ERC-2612 permit for x402 payments.
  • Updated message in apps/playground-web/src/app/api/paywall/route.ts to reflect payment success.
  • Introduced transferWithAuthorization function in packages/thirdweb/scripts/generate/abis/erc20/USDC.json.
  • Modified wrapFetchWithPayment to accept a client parameter.
  • Updated payment handling in packages/thirdweb/src/x402/sign.ts to include ERC-2612 permit logic.
  • Enhanced ThirdwebX402Facilitator type with new methods for payment processing.
  • Updated createPaymentHeader to include client parameter.
  • Introduced new utility functions for signature handling related to permits.
  • Adjusted UI components to reflect changes in payment messaging and token handling.

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

Summary by CodeRabbit

  • New Features

    • ERC-2612 Permit support for x402 payments with automatic detection between Permit and TransferWithAuthorization; USDC authorized-transfer flow supported.
    • Facilitator now exposes its address for easier configuration.
    • New ERC20 token amount type to standardize payment payloads.
  • UI

    • Playgrounds: dynamic chain/token preview, token amount badge, button relabeled "Access Premium Content", paywall message updated, testnet faucet guidance added.
    • Pagination links updated to main transactions route.
  • Refactor

    • Payment signing/header flow is client-aware and API updated; fetch-with-payment wrapper adjusted.
  • Chores

    • Patch release changeset added.

@joaquim-verges joaquim-verges requested review from jnsdls and a team as code owners September 25, 2025 12:28
Copy link

changeset-bot bot commented Sep 25, 2025

🦋 Changeset detected

Latest commit: 536f520

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

vercel bot commented Sep 25, 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 26, 2025 1:28am
nebula Ready Ready Preview Comment Sep 26, 2025 1:28am
thirdweb_playground Canceled Canceled Sep 26, 2025 1:28am
thirdweb-www Ready Ready Preview Comment Sep 26, 2025 1:28am
wallet-ui Canceled Canceled Sep 26, 2025 1:28am

Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Walkthrough

Adds a changeset and ABI updates, removes several MinimalAccount ABI hooks, and extends x402 payment flow with client-aware detection and dual signing (EIP‑2612 permit vs transferWithAuthorization). Exposes facilitator address, adjusts header/nonce handling, updates playground UI/constants and middleware, and fixes dashboard pagination links.

Changes

Cohort / File(s) Summary
Release metadata
.changeset/giant-suns-drive.md
Adds a changeset entry marking a patch: "Support ERC-2612 permit for x402 payments".
ERC20 ABI — USDC
packages/thirdweb/scripts/generate/abis/erc20/USDC.json
Adds transferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce,bytes signature) ABI entry.
MinimalAccount ABI (reduced)
packages/thirdweb/scripts/generate/abis/erc7702/MinimalAccount.json
Removes ERC‑receiver callbacks (onERC1155BatchReceived, onERC1155Received, onERC721Received), supportsInterface, and receive() entries.
x402: detection & extras
packages/thirdweb/src/x402/common.ts
Adds getSupportedSignatureType(...) to determine EIP‑712 signature method; includes facilitatorAddress in decoded extras and adds ABI/selector fallback checks.
x402: types
packages/thirdweb/src/x402/types.ts
Adds local exported ERC20TokenAmount type (amount + asset with address, decimals, eip712 {name, version, primaryType}).
x402: signing, header & nonce flow
packages/thirdweb/src/x402/sign.ts
Makes signing client-aware: createPaymentHeader now takes client; adds signERC2612Permit (permit path) and signERC3009Authorization (transferWithAuthorization path); nonce creation moved async and passed into header prep; several helper signatures updated.
x402: facilitator & fetch wrapper
packages/thirdweb/src/x402/facilitator.ts, packages/thirdweb/src/x402/fetchWithPayment.ts
Exposes address on facilitator return (ThirdwebX402Facilitator); renames wrapFetchWithPayment param _clientclient and forwards client into payment header creation.
x402 exports
packages/thirdweb/src/exports/x402.ts
Re-exports new type ThirdwebX402Facilitator.
Playground — constants & UI
apps/playground-web/src/app/payments/x402/components/constants.ts, apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
Adds chain/token constants; replaces hard-coded chain/token usage; builds dynamic paywall URL; renders badge; passes BigInt amount and token.address to payment wrapper; updates labels and faucet text.
Playground — API & middleware
apps/playground-web/src/app/api/paywall/route.ts, apps/playground-web/src/middleware.ts
Changes paywall GET message to "Payment successful..."; middleware now requires chainId and payTo query params, uses defineChain(Number(chainId)), validates params, and forwards them to settlePayment.
Dashboard — routing fix
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
Updates pagination/link targets from /transactions/server-wallets to /transactions (query param based).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as Application
  participant Wrap as wrapFetchWithPayment
  participant Net as fetch()
  participant Header as createPaymentHeader
  participant Detect as getSupportedSignatureType
  participant Permit as signERC2612Permit
  participant Auth as signERC3009Authorization

  App->>Wrap: fetch(url, init)
  Wrap->>Net: fetch(url, init)
  Net-->>Wrap: Response (402)
  alt 402 Payment Required
    Wrap->>Header: createPaymentHeader(client, account, requirements)
    Header->>Detect: getSupportedSignatureType(client, asset, chainId, eip712Extras)
    Detect-->>Header: { usePermit?, useTransferWithAuthorization? }
    alt usePermit
      Header->>Permit: signERC2612Permit(...)
      Permit-->>Header: signed permit + nonce
    else useTransferWithAuthorization
      Header->>Auth: signERC3009Authorization(...) (createNonce())
      Auth-->>Header: signed auth + nonce
    end
    Header-->>Wrap: x402 header (includes nonce)
    Wrap->>Net: fetch(url, init + x402 header)
    Net-->>Wrap: Response (success/error)
  else non-402
    Wrap-->>App: original response
  end
  Wrap-->>App: Response
Loading
sequenceDiagram
  autonumber
  participant Client as ThirdwebClient
  participant Detect as getSupportedSignatureType
  participant ABI as resolveContractAbi/getContract
  participant Sel as toFunctionSelector

  Client->>Detect: asset, chainId, eip712Extras
  Detect->>ABI: resolveContractAbi/getContract(asset, chain)
  ABI-->>Detect: ABI (or none)
  Detect->>Sel: compute/check function selectors (permit / transferWithAuthorization)
  Sel-->>Detect: support flags
  Detect-->>Client: supported signature type
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ⚠️ Warning The pull request description retains the commented‐out template placeholders without replacing them with actual content for the PR title, reviewer notes, or testing instructions, so it does not adhere to the repository’s required description structure. Please update the PR description by filling in the HTML comment template: provide a concise title in the prescribed “[SDK/Dashboard/Portal] Feature/Fix: …” format, add Notes for the reviewer detailing any important context or considerations, and include clear “How to test” instructions for verifying the changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly highlights the primary change—adding ERC-2612 permit support for x402 payments—and follows the concise bracketed tag convention without extraneous detail, making it clear to reviewers at a glance.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch joaquim/x402-permit

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

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

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

Copy link
Contributor

graphite-app bot commented Sep 25, 2025

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.

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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/thirdweb/src/x402/fetchWithPayment.ts (2)

117-124: Do not send Access-Control-Expose-Headers in requests.

This is a response header; setting it on the request has no effect. Remove it to avoid confusion.

Apply this diff:

   const newInit = {
     ...initParams,
     headers: {
       ...(initParams.headers || {}),
       "X-PAYMENT": paymentHeader,
-      "Access-Control-Expose-Headers": "X-PAYMENT-RESPONSE",
     },
     __is402Retry: true,
   };

12-50: Add required TSDoc custom tag (e.g., @beta) for public API.

Repo guideline requires a custom tag on public symbols.

Apply this diff:

 /**
  * Enables the payment of APIs using the x402 payment protocol.
  *
@@
  * @bridge x402
+ * @beta
  */
packages/thirdweb/src/x402/sign.ts (3)

133-148: Update TSDoc to match new signature and add required tag.

Docs still reference x402Version param. Add a custom tag per repo guideline.

Apply this diff:

 /**
  * Creates and encodes a payment header for the given client and payment requirements.
  *
- * @param client - The signer wallet instance used to create the payment header
- * @param x402Version - The version of the X402 protocol to use
+ * @param client - The thirdweb client used for chain/ABI resolution
  * @param paymentRequirements - The payment requirements containing scheme and network information
  * @returns A promise that resolves to the encoded payment header string
  */
 export async function createPaymentHeader(
   client: ThirdwebClient,
   account: Account,
   paymentRequirements: RequestedPaymentRequirements,
 ): Promise<string> {
   const payment = await signPaymentHeader(client, account, paymentRequirements);
   return encodePayment(payment);
 }
+/**
+ * @beta
+ */

167-214: Validate domain info (name/version) before signing EIP‑3009; fetch or fail clearly.

If extra.name/version are missing, signTypedData may fail or produce invalid payloads. Add validation.

Apply this diff:

 async function signERC3009Authorization(
@@
-  const name = extra?.name;
-  const version = extra?.version;
+  const name = extra?.name;
+  const version = extra?.version;
+  if (!name || !version) {
+    throw new Error(
+      "Missing contract domain: extra.name and extra.version are required for EIP-3009 signing",
+    );
+  }
@@
-  const signature = await account.signTypedData({
+  const signature = await account.signTypedData({
     types: {

216-262: Validate domain info (name/version) before signing EIP‑2612 permit.

Same concern as above; also good to keep error messages explicit.

Apply this diff:

 async function signERC2612Permit(
   account: Account,
   { from, value, validBefore, nonce }: ExactEvmPayloadAuthorization,
   { asset, network, extra }: RequestedPaymentRequirements,
 ): Promise<{ signature: Hex }> {
   const chainId = networkToChainId(network);
-  const name = extra?.name;
-  const version = extra?.version;
+  const name = extra?.name;
+  const version = extra?.version;
+  if (!name || !version) {
+    throw new Error(
+      "Missing contract domain: extra.name and extra.version are required for EIP-2612 signing",
+    );
+  }
 
   const facilitatorAddress = extra?.facilitatorAddress;
   if (!facilitatorAddress) {
     throw new Error(
       "facilitatorAddress is required in PaymentRequirements extra to pay with permit-based assets",
     );
   }
🧹 Nitpick comments (2)
packages/thirdweb/src/x402/sign.ts (2)

59-74: Correct param docs for signPaymentHeader (client is not a wallet).

Minor doc fix to avoid confusion.

Apply this diff:

 /**
  * Signs a payment header using the provided client and payment requirements.
  *
- * @param client - The signer wallet instance used to sign the payment header
+ * @param client - ThirdwebClient used for chain/ABI resolution
  * @param paymentRequirements - The payment requirements containing scheme and network information
  * @param unsignedPaymentHeader - The unsigned payment payload to be signed
  * @returns A promise that resolves to the signed payment payload
  */

269-277: Safer Node fallback without require; avoid CJS in ESM bundles.

Use dynamic import of node:crypto to stay bundler/ESM-friendly.

Apply this diff:

-async function createNonce(): Promise<Hex> {
-  const cryptoObj =
-    typeof globalThis.crypto !== "undefined" &&
-    typeof globalThis.crypto.getRandomValues === "function"
-      ? globalThis.crypto
-      : // Dynamic require is needed to support node.js
-        // eslint-disable-next-line @typescript-eslint/no-require-imports
-        require("crypto").webcrypto;
-  return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
-}
+async function createNonce(): Promise<Hex> {
+  const hasWebCrypto =
+    typeof globalThis.crypto !== "undefined" &&
+    typeof globalThis.crypto.getRandomValues === "function";
+  const cryptoObj = hasWebCrypto
+    ? globalThis.crypto
+    : (await import("node:crypto")).webcrypto;
+  return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
+}
📜 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 7bc513c and 2461aa4.

⛔ Files ignored due to path filters (1)
  • packages/thirdweb/src/extensions/erc20/__generated__/USDC/write/transferWithAuthorization.ts is excluded by !**/__generated__/**
📒 Files selected for processing (7)
  • .changeset/giant-suns-drive.md (1 hunks)
  • packages/thirdweb/scripts/generate/abis/erc20/USDC.json (1 hunks)
  • packages/thirdweb/scripts/generate/abis/erc7702/MinimalAccount.json (0 hunks)
  • packages/thirdweb/src/x402/common.ts (3 hunks)
  • packages/thirdweb/src/x402/facilitator.ts (1 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (2 hunks)
  • packages/thirdweb/src/x402/sign.ts (9 hunks)
💤 Files with no reviewable changes (1)
  • packages/thirdweb/scripts/generate/abis/erc7702/MinimalAccount.json
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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/facilitator.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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/facilitator.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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/facilitator.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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/giant-suns-drive.md
🧠 Learnings (3)
📚 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
  • .changeset/giant-suns-drive.md
📚 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 src/extensions/** : Auto-generated contracts from ABI definitions in extensions

Applied to files:

  • packages/thirdweb/src/x402/common.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 .changeset/*.md : Version bump rules: patch for non‑API changes; minor for new/modified public API

Applied to files:

  • .changeset/giant-suns-drive.md
🧬 Code graph analysis (3)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • ThirdwebClient (25-25)
packages/thirdweb/src/x402/sign.ts (4)
packages/thirdweb/src/x402/schemas.ts (1)
  • networkToChainId (59-80)
packages/thirdweb/src/x402/common.ts (1)
  • detectSupportedAuthorizationMethods (254-280)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/x402/types.ts (1)
  • x402Version (17-17)
packages/thirdweb/src/x402/common.ts (3)
packages/thirdweb/src/x402/facilitator.ts (1)
  • facilitator (59-197)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/extensions/erc20/__generated__/USDC/write/transferWithAuthorization.ts (1)
  • isTransferWithAuthorizationSupported (75-82)
⏰ 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: Size
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Build Packages
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)

105-109: LGTM: updated createPaymentHeader call matches new signature.

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx (1)

217-259: Restore server-wallet pagination route

Pagination links now drop the /server-wallets segment, so clicking “next” sends users to the generic transactions page instead of page N of the server-wallet table. That breaks pagination for this view. Please restore the original route segment (or ensure an equivalent route exists that still renders this table).

-                    href={`/team/${teamSlug}/${project.slug}/transactions?page=${
+                    href={`/team/${teamSlug}/${project.slug}/transactions/server-wallets?page=${
                       currentPage > 1 ? currentPage - 1 : 1
                     }`}
...
-                        href={`/team/${teamSlug}/${project.slug}/transactions?page=${pageNumber}`}
+                        href={`/team/${teamSlug}/${project.slug}/transactions/server-wallets?page=${pageNumber}`}
...
-                    href(`/team/${teamSlug}/${project.slug}/transactions?page=${
+                    href(`/team/${teamSlug}/${project.slug}/transactions/server-wallets?page=${
                       currentPage < totalPages ? currentPage + 1 : totalPages
                     }`}
📜 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 2461aa4 and b3603fa.

📒 Files selected for processing (9)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx (3 hunks)
  • apps/playground-web/src/app/api/paywall/route.ts (1 hunks)
  • apps/playground-web/src/app/payments/x402/components/constants.ts (1 hunks)
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (4 hunks)
  • apps/playground-web/src/middleware.ts (2 hunks)
  • packages/thirdweb/src/x402/common.ts (4 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (2 hunks)
  • packages/thirdweb/src/x402/sign.ts (9 hunks)
  • packages/thirdweb/src/x402/types.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
  • apps/playground-web/src/middleware.ts
  • packages/thirdweb/src/x402/types.ts
  • apps/playground-web/src/app/api/paywall/route.ts
  • apps/playground-web/src/app/payments/x402/components/constants.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
  • apps/playground-web/src/middleware.ts
  • packages/thirdweb/src/x402/types.ts
  • apps/playground-web/src/app/api/paywall/route.ts
  • apps/playground-web/src/app/payments/x402/components/constants.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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/types.ts
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
  • apps/playground-web/src/middleware.ts
  • apps/playground-web/src/app/api/paywall/route.ts
  • apps/playground-web/src/app/payments/x402/components/constants.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.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
🧠 Learnings (13)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.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} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
📚 Learning: 2025-06-06T23:46:08.795Z
Learnt from: MananTank
PR: thirdweb-dev/js#7298
File: apps/dashboard/src/app/nebula-app/move-funds/move-funds.tsx:424-424
Timestamp: 2025-06-06T23:46:08.795Z
Learning: The thirdweb project has an ESLint rule that restricts direct usage of `defineChain`. When it's necessary to use `defineChain` directly, it's acceptable to disable the rule with `// eslint-disable-next-line no-restricted-syntax`.

Applied to files:

  • apps/playground-web/src/middleware.ts
  • apps/playground-web/src/app/payments/x402/components/constants.ts
📚 Learning: 2025-06-06T23:47:55.122Z
Learnt from: MananTank
PR: thirdweb-dev/js#7298
File: apps/dashboard/src/app/nebula-app/move-funds/move-funds.tsx:255-277
Timestamp: 2025-06-06T23:47:55.122Z
Learning: The `transfer` function from `thirdweb/extensions/erc20` accepts human-readable amounts via the `amount` property and automatically handles conversion to base units (wei) by fetching the token decimals internally. Manual conversion using `toWei()` is not required when using the `amount` property.

Applied to files:

  • packages/thirdweb/src/x402/types.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-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/x402-client-preview.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/x402-client-preview.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 : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.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/common.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:

  • packages/thirdweb/src/x402/common.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/exports/** : Every public symbol must have comprehensive TSDoc with at least one `example` block that compiles and custom annotation tags (`beta`, `internal`, `experimental`)

Applied to files:

  • packages/thirdweb/src/x402/common.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 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.)

Applied to files:

  • packages/thirdweb/src/x402/common.ts
🧬 Code graph analysis (6)
packages/thirdweb/src/x402/fetchWithPayment.ts (2)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • ThirdwebClient (25-25)
packages/thirdweb/src/x402/types.ts (1)
  • x402Version (13-13)
apps/playground-web/src/middleware.ts (1)
packages/thirdweb/src/x402/settle-payment.ts (1)
  • settlePayment (126-187)
apps/playground-web/src/app/payments/x402/components/constants.ts (1)
packages/thirdweb/src/exports/chains.ts (1)
  • arbitrumSepolia (12-12)
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
apps/playground-web/src/app/payments/x402/components/constants.ts (2)
  • chain (6-6)
  • token (7-7)
packages/thirdweb/src/x402/sign.ts (4)
packages/thirdweb/src/x402/schemas.ts (2)
  • RequestedPaymentRequirements (48-50)
  • RequestedPaymentPayload (33-35)
packages/thirdweb/src/x402/types.ts (1)
  • ERC20TokenAmount (89-100)
packages/thirdweb/src/x402/common.ts (1)
  • detectSupportedAuthorizationMethods (255-299)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/x402/common.ts (4)
packages/thirdweb/src/x402/facilitator.ts (1)
  • facilitator (59-197)
packages/thirdweb/src/x402/types.ts (1)
  • ERC20TokenAmount (89-100)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/extensions/erc20/__generated__/USDC/write/transferWithAuthorization.ts (1)
  • isTransferWithAuthorizationSupported (75-82)
⏰ 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: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (5)
packages/thirdweb/src/x402/common.ts (2)

118-121: Guard extra spread from undefined

Line 118 spreads (asset as ERC20TokenAmount["asset"]).eip712 directly. When the facilitator (or caller) omits EIP‑712 metadata—which is still the default for most supported assets—eip712 is undefined, and spreading it throws TypeError: Cannot convert undefined or null to object, breaking every payment request on runtime. Please guard with a nullish fallback before spreading.

-    extra: {
-      facilitatorAddress: facilitator.address,
-      ...(asset as ERC20TokenAmount["asset"]).eip712,
-    },
+    extra: {
+      facilitatorAddress: facilitator.address,
+      ...(((asset as ERC20TokenAmount["asset"]).eip712) ?? {}),
+    },

250-299: Add required TSDoc for the new public API

SupportedAuthorizationMethods and detectSupportedAuthorizationMethods are part of the published surface under packages/thirdweb, so per our SDK guidelines every public symbol must ship with TSDoc that includes a stability tag (e.g. @beta) and at least one compiling @example. Please add the missing documentation blocks.

+/**
+ * Describes which authorization flows an ERC-20 contract supports.
+ * @beta
+ * @example
+ * ```ts
+ * const support: SupportedAuthorizationMethods = {
+ *   hasPermit: true,
+ *   hasTransferWithAuthorization: false,
+ * };
+ * ```
+ */
 export type SupportedAuthorizationMethods = {
   hasPermit: boolean;
   hasTransferWithAuthorization: boolean;
 };
 
+/**
+ * Detects whether an ERC-20 asset supports ERC-2612 permit or ERC-3009 transferWithAuthorization.
+ * @beta
+ * @example
+ * ```ts
+ * import { detectSupportedAuthorizationMethods } from "thirdweb/x402";
+ * const result = await detectSupportedAuthorizationMethods({
+ *   client,
+ *   asset: "0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
+ *   chainId: 1,
+ *   eip712Extras: undefined,
+ * });
+ * console.log(result.hasPermit, result.hasTransferWithAuthorization);
+ * ```
+ */
 export async function detectSupportedAuthorizationMethods(args: {
packages/thirdweb/src/x402/sign.ts (1)

85-134: Don’t default to transferWithAuthorization when unsupported

When both hasPermit and hasTransferWithAuthorization are false, the current else branch still builds an EIP‑3009 payload. This produces invalid signatures (or throws once the signer hits missing domain fields) and breaks payments for tokens that support neither flow. We must only use transferWithAuthorization when hasTransferWithAuthorization is true, otherwise fall back to permit when available, and fail fast if neither is supported.

-  // only use permit if no transfer with authorization is supported
-  if (hasPermit && !hasTransferWithAuthorization) {
+  if (hasTransferWithAuthorization) {
+    const nonce = await createNonce();
+    const unsignedPaymentHeader = preparePaymentHeader(
+      from,
+      x402Version,
+      paymentRequirements,
+      nonce, // random nonce
+    );
+    const { signature } = await signERC3009Authorization(
+      account,
+      unsignedPaymentHeader.payload.authorization,
+      paymentRequirements,
+    );
+    return {
+      ...unsignedPaymentHeader,
+      payload: {
+        ...unsignedPaymentHeader.payload,
+        signature,
+      },
+    };
+  } else if (hasPermit) {
     const nonce = await nonces({
       contract: getContract({
         address: paymentRequirements.asset,
         chain: getCachedChain(chainId),
         client: client,
       }),
       owner: from,
     });
@@
-  } else {
-    // default to transfer with authorization
-    const nonce = await createNonce();
-    const unsignedPaymentHeader = preparePaymentHeader(
-      from,
-      x402Version,
-      paymentRequirements,
-      nonce, // random nonce
-    );
-    const { signature } = await signERC3009Authorization(
-      account,
-      unsignedPaymentHeader.payload.authorization,
-      paymentRequirements,
-    );
-    return {
-      ...unsignedPaymentHeader,
-      payload: {
-        ...unsignedPaymentHeader.payload,
-        signature,
-      },
-    };
-  }
+  }
+  throw new Error(
+    "Asset does not support permit or transferWithAuthorization on this chain",
+  );
packages/thirdweb/src/x402/fetchWithPayment.ts (1)

105-110: Good call on threading the client through

Routing the ThirdwebClient into createPaymentHeader lines up with the new permit/authorization detection path and keeps the retry flow self-contained. Looks solid.

apps/playground-web/src/app/api/paywall/route.ts (1)

6-9: Updated success copy reads well

The revised message matches the new payment flow and keeps the handler unchanged otherwise.

Copy link
Contributor

github-actions bot commented Sep 26, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.09 KB (0%) 1.3 s (0%) 606 ms (+277.93% 🔺) 1.9 s
thirdweb (cjs) 361.63 KB (0%) 7.3 s (0%) 1.9 s (+22.56% 🔺) 9.1 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 258 ms (+2127.39% 🔺) 372 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 138 ms (+3815.35% 🔺) 149 ms
thirdweb/react (minimal + tree-shaking) 19.14 KB (0%) 383 ms (0%) 197 ms (+2319.66% 🔺) 580 ms

Copy link

codecov bot commented Sep 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.28%. Comparing base (9069351) to head (536f520).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8128      +/-   ##
==========================================
+ Coverage   56.26%   56.28%   +0.01%     
==========================================
  Files         906      906              
  Lines       59193    59193              
  Branches     4173     4172       -1     
==========================================
+ Hits        33305    33316      +11     
+ Misses      25783    25772      -11     
  Partials      105      105              
Flag Coverage Δ
packages 56.28% <ø> (+0.01%) ⬆️
see 4 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
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

@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 (3)
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)

26-45: Payment amount is off by 12 orders of magnitude for USDC

BigInt(1 * 10 ** 18) assumes an 18‑decimals token and ends up charging 1e12 USDC (and even for 18‑decimals tokens it bills 1 whole token while the UI promises 0.1). This will either overflow the allowance path or silently overcharge the shopper. Derive the base-unit amount from token.decimals and align it with the displayed 0.1 token price.

-      const fetchWithPay = wrapFetchWithPayment(
-        fetch,
-        THIRDWEB_CLIENT,
-        activeWallet,
-        BigInt(1 * 10 ** 18),
-      );
+      const paymentAmount =
+        (10n ** BigInt(token.decimals)) / 10n; // 0.1 token in base units
+      const fetchWithPay = wrapFetchWithPayment(
+        fetch,
+        THIRDWEB_CLIENT,
+        activeWallet,
+        paymentAmount,
+      );
packages/thirdweb/src/x402/common.ts (1)

196-229: Avoid floating‑point math when computing atomic amounts

Using JS floating arithmetic for USD->atomic conversion can introduce precision errors. Prefer integer math via parseUnits.

Apply this diff:

@@
-import { toFunctionSelector } from "viem/utils";
+import { parseUnits } from "viem";
+import { toFunctionSelector } from "viem/utils";
@@
-    maxAmountRequired = (parsedUsdAmount * 10 ** asset.decimals).toString();
+    maxAmountRequired = parseUnits(
+      parsedUsdAmount.toString(),
+      asset.decimals,
+    ).toString();
packages/thirdweb/src/x402/sign.ts (1)

285-294: Replace require with dynamic import for Node crypto in ESM

require is not defined in ESM builds; use a dynamic import of node:crypto instead.

Apply this diff:

-  const cryptoObj =
-    typeof globalThis.crypto !== "undefined" &&
-    typeof globalThis.crypto.getRandomValues === "function"
-      ? globalThis.crypto
-      : // Dynamic require is needed to support node.js
-        // eslint-disable-next-line @typescript-eslint/no-require-imports
-        require("crypto").webcrypto;
+  const cryptoObj =
+    typeof globalThis.crypto !== "undefined" &&
+    typeof globalThis.crypto.getRandomValues === "function"
+      ? globalThis.crypto
+      : (await import("node:crypto")).webcrypto;
🧹 Nitpick comments (1)
packages/thirdweb/src/x402/facilitator.ts (1)

79-82: Explicit return type on facilitator — LGTM; align @returns text

Return type annotation looks good. Please update the function TSDoc’s @returns line to reference ThirdwebX402Facilitator (and mention the address field) instead of “FacilitatorConfig”.

As per coding guidelines

📜 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 b3603fa and a1e06b2.

📒 Files selected for processing (11)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx (3 hunks)
  • apps/playground-web/src/app/api/paywall/route.ts (1 hunks)
  • apps/playground-web/src/app/payments/x402/components/constants.ts (1 hunks)
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (4 hunks)
  • apps/playground-web/src/middleware.ts (2 hunks)
  • packages/thirdweb/src/exports/x402.ts (1 hunks)
  • packages/thirdweb/src/x402/common.ts (4 hunks)
  • packages/thirdweb/src/x402/facilitator.ts (3 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (2 hunks)
  • packages/thirdweb/src/x402/sign.ts (9 hunks)
  • packages/thirdweb/src/x402/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/playground-web/src/middleware.ts
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • apps/playground-web/src/app/payments/x402/components/constants.ts
  • packages/thirdweb/src/x402/types.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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/api/paywall/route.ts
  • packages/thirdweb/src/exports/x402.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/sign.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
  • packages/thirdweb/src/x402/common.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.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/api/paywall/route.ts
  • packages/thirdweb/src/exports/x402.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/sign.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
  • packages/thirdweb/src/x402/common.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.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/api/paywall/route.ts
  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
packages/thirdweb/src/exports/**

📄 CodeRabbit inference engine (CLAUDE.md)

packages/thirdweb/src/exports/**: Export everything via exports/ directory, grouped by feature in the SDK public API
Every public symbol must have comprehensive TSDoc with at least one @example block that compiles and custom annotation tags (@beta, @internal, @experimental)

Files:

  • packages/thirdweb/src/exports/x402.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/exports/x402.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/sign.ts
  • packages/thirdweb/src/x402/common.ts
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
🧠 Learnings (13)
📓 Common learnings
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
📚 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 packages/thirdweb/exports/** : Export all public API via `packages/thirdweb/exports/`, grouped by feature

Applied to files:

  • packages/thirdweb/src/exports/x402.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/exports/** : Export everything via `exports/` directory, grouped by feature in the SDK public API

Applied to files:

  • packages/thirdweb/src/exports/x402.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 : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.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/x402-client-preview.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 : Use React Query (`tanstack/react-query`) for all client data fetching.

Applied to files:

  • apps/playground-web/src/app/payments/x402/components/x402-client-preview.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/common.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:

  • packages/thirdweb/src/x402/common.ts
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to packages/thirdweb/src/exports/** : Every public symbol must have comprehensive TSDoc with at least one `example` block that compiles and custom annotation tags (`beta`, `internal`, `experimental`)

Applied to files:

  • packages/thirdweb/src/x402/common.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 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.)

Applied to files:

  • packages/thirdweb/src/x402/common.ts
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.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} : Use `NavLink` for internal navigation with automatic active states in dashboard and playground apps

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx
🧬 Code graph analysis (4)
packages/thirdweb/src/x402/facilitator.ts (1)
packages/thirdweb/src/x402/schemas.ts (3)
  • RequestedPaymentPayload (33-35)
  • RequestedPaymentRequirements (48-50)
  • FacilitatorSettleResponse (55-57)
packages/thirdweb/src/x402/sign.ts (4)
packages/thirdweb/src/x402/schemas.ts (2)
  • RequestedPaymentRequirements (48-50)
  • RequestedPaymentPayload (33-35)
packages/thirdweb/src/x402/types.ts (1)
  • ERC20TokenAmount (89-100)
packages/thirdweb/src/x402/common.ts (1)
  • detectSupportedAuthorizationMethods (255-299)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)
apps/playground-web/src/app/payments/x402/components/constants.ts (2)
  • chain (6-6)
  • token (7-7)
packages/thirdweb/src/x402/common.ts (4)
packages/thirdweb/src/x402/facilitator.ts (1)
  • facilitator (79-219)
packages/thirdweb/src/x402/types.ts (1)
  • ERC20TokenAmount (89-100)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/extensions/erc20/__generated__/USDC/write/transferWithAuthorization.ts (1)
  • isTransferWithAuthorizationSupported (75-82)
⏰ 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). (2)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
🔇 Additional comments (12)
apps/playground-web/src/app/api/paywall/route.ts (1)

6-9: Updated success copy looks good

The revised message communicates the payment completion clearly and stays aligned with the updated x402 flow.

apps/playground-web/src/app/payments/x402/components/x402-client-preview.tsx (1)

32-44: Stop sending payTo as the shopper’s wallet

We’re still populating payTo with activeWallet.getAccount()?.address, so the backend will try to settle funds back to the caller, breaking the payment flow. Drop this param (or send the fixed merchant address once the middleware exposes it) so settlement stays server-controlled.

       const searchParams = new URLSearchParams();
       searchParams.set("chainId", chain.id.toString());
-      searchParams.set("payTo", activeWallet.getAccount()?.address || "");
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/wallet-table/wallet-table-ui.client.tsx (1)

218-221: Verify the new /transactions route supports these query params

The hrefs now target /transactions. Confirm that:

  • page is handled by the unified transactions page, and
  • testTxWithWallet preserves the server‑wallets context (no regression from the former /transactions/server-wallets path).

Also applies to: 235-236, 247-250

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

94-94: Exposing facilitator.address — LGTM

Address is correctly wired to serverWalletAddress.

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

4-6: Publicly re‑exporting ThirdwebX402Facilitator — LGTM

This aligns the exports surface with the new type.

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

118-121: Good fix: guard spreading eip712 extras

Using the nullish fallback prevents runtime TypeError when eip712 is undefined.


250-299: Document new public authorization‑detection API

SupportedAuthorizationMethods and detectSupportedAuthorizationMethods are public; add TSDoc with stability tags and compiling examples.

Apply this diff:

@@
-export type SupportedAuthorizationMethods = {
+/**
+ * Describes which authorization flows an ERC‑20 contract supports.
+ * @beta
+ * @example
+ * ```ts
+ * const methods: SupportedAuthorizationMethods = {
+ *   usePermit: true,
+ *   useTransferWithAuthorization: false,
+ * };
+ * ```
+ */
+export type SupportedAuthorizationMethods = {
   usePermit: boolean;
   useTransferWithAuthorization: boolean;
 };
@@
-export async function detectSupportedAuthorizationMethods(args: {
+/**
+ * Detects whether an ERC‑20 asset supports ERC‑2612 Permit or EIP‑3009 TransferWithAuthorization.
+ * Prefers TransferWithAuthorization when both are present.
+ * @beta
+ * @example
+ * ```ts
+ * const support = await detectSupportedAuthorizationMethods({
+ *   client,
+ *   asset: "0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
+ *   chainId: 1,
+ *   eip712Extras: { name: "USD Coin", version: "2", primaryType: "Permit" },
+ * });
+ * console.log(support.usePermit, support.useTransferWithAuthorization);
+ * ```
+ */
+export async function detectSupportedAuthorizationMethods(args: {
   client: ThirdwebClient;
   asset: string;
   chainId: number;
   eip712Extras: ERC20TokenAmount["asset"]["eip712"] | undefined;
 }): Promise<SupportedAuthorizationMethods> {

As per coding guidelines

packages/thirdweb/src/x402/sign.ts (5)

67-84: Authorization method selection — LGTM

Prefers TWA, falls back to Permit, else throws. This addresses the prior default‑to‑3009 issue.


85-113: Permit path with nonces() — LGTM

Correctly derives nonce from ERC20Permit and uses it in the header.


112-133: TransferWithAuthorization path — LGTM

Random 32‑byte nonce and signing flow look correct.


195-222: Typed‑data payload BigInt conversions — LGTM

Converting value and time bounds to BigInt matches EIP‑3009 types.


228-278: Permit signing checks — LGTM

Validates facilitatorAddress/name/version and uses uint256 nonce/deadline correctly.

Comment on lines +18 to +36
export type ThirdwebX402Facilitator = {
url: `${string}://${string}`;
address: string;
createAuthHeaders: () => Promise<{
verify: Record<string, string>;
settle: Record<string, string>;
supported: Record<string, string>;
list: Record<string, string>;
}>;
verify: (
payload: RequestedPaymentPayload,
paymentRequirements: RequestedPaymentRequirements,
) => Promise<VerifyResponse>;
settle: (
payload: RequestedPaymentPayload,
paymentRequirements: RequestedPaymentRequirements,
) => Promise<FacilitatorSettleResponse>;
supported: () => Promise<SupportedPaymentKindsResponse>;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Add TSDoc for new public type ThirdwebX402Facilitator

This is part of the public API; per SDK guidelines, it needs TSDoc with stability tag and a compiling example. Add a brief doc and show the address field in the example.

As per coding guidelines

🤖 Prompt for AI Agents
In packages/thirdweb/src/x402/facilitator.ts around lines 18 to 36, the new
public type ThirdwebX402Facilitator lacks TSDoc; add a TSDoc block immediately
above the type that marks stability (e.g., @stability stable or the appropriate
tag), provides a short description of the type, documents each field (url,
address, createAuthHeaders, verify, settle, supported), and includes a minimal
compiling example showing instantiation/usage that explicitly shows the address
field; keep the doc concise and follow existing SDK doc style and tags.

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

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/sign.ts (1)

142-151: Add required TSDoc tags and example for public API

packages/thirdweb public exports require comprehensive TSDoc with a compiling @example and a custom tag.

As per coding guidelines

 /**
  * Creates and encodes a payment header for the given client and payment requirements.
  *
  * @param client - The signer wallet instance used to create the payment header
  * @param x402Version - The version of the X402 protocol to use
  * @param paymentRequirements - The payment requirements containing scheme and network information
  * @returns A promise that resolves to the encoded payment header string
+ * @example
+ * ```ts
+ * import { createPaymentHeader } from "thirdweb/x402/sign";
+ * const header = await createPaymentHeader(client, account, {
+ *   scheme: "evm",
+ *   network: "eip155:1",
+ *   asset: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
+ *   maxAmountRequired: "1000000",
+ *   maxTimeoutSeconds: 600,
+ *   payTo: "0xYourFacilitator",
+ *   extra: { name: "USD Coin", version: "2", primaryType: "TransferWithAuthorization" }
+ * }, 1);
+ * ```
+ * @beta
  */
🧹 Nitpick comments (5)
packages/thirdweb/src/x402/sign.ts (5)

114-121: Update outdated inline comment

This path isn’t a “default” anymore. Tweak the comment to avoid confusion.

-      // default to transfer with authorization
+      // TransferWithAuthorization path (EIP-3009)

168-181: Doc param name mismatch (“walletClient” vs “account”)

JSDoc references walletClient but the function param is account. Fix the annotation to prevent confusion.

- * @param walletClient - The wallet client that will sign the authorization
+ * @param account - The account that will sign the authorization

231-249: Strengthen typing for extra based on selected method

At runtime you validate facilitatorAddress, name, and version. Prefer a discriminated union for RequestedPaymentRequirements.extra keyed by eip712.primaryType so TypeScript enforces required fields per method (Permit requires facilitatorAddress, name, version).

As per coding guidelines

Also applies to: 269-276


288-297: Avoid require in ESM; use dynamic import("node:crypto")

Using require in ESM can break in Node/browser builds without CJS shim. Dynamic import is safer and tree-shakeable.

 async function createNonce(): Promise<Hex> {
   const cryptoObj =
     typeof globalThis.crypto !== "undefined" &&
     typeof globalThis.crypto.getRandomValues === "function"
       ? globalThis.crypto
-      : // Dynamic require is needed to support node.js
-        // eslint-disable-next-line @typescript-eslint/no-require-imports
-        require("crypto").webcrypto;
-  return toHex(cryptoObj.getRandomValues(new Uint8Array(32)));
+      : (await import("node:crypto")).webcrypto;
+  const bytes = new Uint8Array(32);
+  cryptoObj.getRandomValues(bytes);
+  return toHex(bytes);
 }

34-39: Tiny cleanup: avoid string→string toString()

validAfter/validBefore are already strings; calling .toString() again is redundant. Keep as bigint locally and stringify once at assignment.

-  const validAfter = BigInt(
-    Math.floor(Date.now() / 1000) - 600, // 10 minutes before
-  ).toString();
-  const validBefore = BigInt(
-    Math.floor(Date.now() / 1000 + paymentRequirements.maxTimeoutSeconds),
-  ).toString();
+  const validAfter = BigInt(Math.floor(Date.now() / 1000) - 600); // 10 minutes before
+  const validBefore = BigInt(
+    Math.floor(Date.now() / 1000 + paymentRequirements.maxTimeoutSeconds),
+  );
 ...
-        validAfter: validAfter.toString(),
-        validBefore: validBefore.toString(),
+        validAfter: validAfter.toString(),
+        validBefore: validBefore.toString(),

Also applies to: 51-54

📜 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 a1e06b2 and da2b065.

📒 Files selected for processing (3)
  • packages/thirdweb/src/x402/common.ts (4 hunks)
  • packages/thirdweb/src/x402/sign.ts (9 hunks)
  • packages/thirdweb/src/x402/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/thirdweb/src/x402/common.ts
  • packages/thirdweb/src/x402/types.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/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/sign.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/sign.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/sign.ts
🧠 Learnings (1)
📓 Common learnings
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
🧬 Code graph analysis (1)
packages/thirdweb/src/x402/sign.ts (5)
packages/thirdweb/src/exports/thirdweb.ts (3)
  • Hex (230-230)
  • ThirdwebClient (25-25)
  • getContract (43-43)
packages/thirdweb/src/x402/schemas.ts (3)
  • RequestedPaymentRequirements (48-50)
  • RequestedPaymentPayload (33-35)
  • networkToChainId (59-80)
packages/thirdweb/src/x402/types.ts (1)
  • ERC20TokenAmount (91-102)
packages/thirdweb/src/x402/common.ts (1)
  • getSupportedSignatureType (251-289)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
⏰ 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: Lint Packages
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Build Packages
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Unit Tests
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
packages/thirdweb/src/x402/sign.ts (1)

84-139: Authorization method selection fixed — LGTM

Switching on the detected signature type and throwing when none are supported resolves the prior critical default-to-3009 bug. Prefer TWA, else Permit, else fail — correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Dashboard Involves changes to the Dashboard. 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