Skip to content

Conversation

@joaquim-verges
Copy link
Member

@joaquim-verges joaquim-verges commented Nov 24, 2025


PR-Codex overview

This PR introduces the x402 payment protocol across the codebase, enhancing payment handling by integrating new functionalities and updating existing methods to support this protocol, including UI improvements for error handling and wallet connection.

Detailed summary

  • Updated documentation tags from @bridge x402 to @x402 in multiple files.
  • Introduced useFetchWithPayment React hook for handling payments with automatic UI for errors and wallet connections.
  • Added SignInRequiredModal for prompting user sign-in.
  • Implemented PaymentErrorModal for displaying payment errors and options to fund wallets.
  • Enhanced wrapFetchWithPayment to accept customizable options for payment handling.
  • Updated sidebar and documentation references to include @x402.
  • Adjusted UI components to improve layout and spacing, particularly in basic.tsx.
  • Added new examples and documentation for using the useFetchWithPayment hook and wrapFetchWithPayment.

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

Summary by CodeRabbit

  • New Features

    • Cross-platform useFetchWithPayment hook and UI modals (payment error & sign-in) for automatic 402 handling, retry, and wallet top‑up flows; customizable theming and behaviors.
  • Documentation

    • Docs updated with TypeScript and React tabs, examples, and guidance for the new hook and options.
  • Chores

    • Public exports and docs tags updated to surface the new React/Native APIs.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 24, 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 Nov 24, 2025 10:35pm
nebula Ready Ready Preview Comment Nov 24, 2025 10:35pm
thirdweb_playground Ready Ready Preview Comment Nov 24, 2025 10:35pm
thirdweb-www Ready Ready Preview Comment Nov 24, 2025 10:35pm
wallet-ui Ready Ready Preview Comment Nov 24, 2025 10:35pm

@changeset-bot
Copy link

changeset-bot bot commented Nov 24, 2025

🦋 Changeset detected

Latest commit: 32a243c

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

This PR includes changesets to release 4 packages
Name Type
thirdweb Minor
@thirdweb-dev/nebula Patch
@thirdweb-dev/wagmi-adapter Patch
wagmi-inapp 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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 24, 2025

Walkthrough

Adds a platform-agnostic fetch-with-payment feature: core hook (useFetchWithPaymentCore), web/native hooks (useFetchWithPayment), web UI modals (PaymentErrorModal, SignInRequiredModal), updated wrapFetchWithPayment options signature, export barrel updates, documentation/examples, and small UI/tsdoc tweaks.

Changes

Cohort / File(s) Summary
Core hook & runtime
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts, packages/thirdweb/src/x402/fetchWithPayment.ts, packages/thirdweb/src/x402/facilitator.ts, packages/thirdweb/src/x402/settle-payment.ts, packages/thirdweb/src/x402/verify-payment.ts
Adds useFetchWithPaymentCore (wallet-aware, retryable fetch wrapper with 402 handling, parseAs option, connect/error callbacks). Changes wrapFetchWithPayment to accept options?: { maxValue?: bigint; paymentRequirementsSelector?: (...) }. JSDoc tags updated (@bridge x402@x402).
Platform hooks (web & native)
packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx, packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
Adds useFetchWithPayment: web variant wires UI modals around core; native variant delegates to core. Re-exports UseFetchWithPaymentOptions type.
Web UI components
packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx, packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx
New PaymentErrorModal with insufficient-funds → BuyWidget flow, retry/cancel behavior, theming. New SignInRequiredModal prompting sign-in before retry.
Export barrels
packages/thirdweb/src/exports/react.ts, packages/thirdweb/src/exports/react.native.ts
Adds re-exports for useFetchWithPayment and UseFetchWithPaymentOptions to web and native export files.
Example / playground
apps/playground-web/src/app/x402/components/X402RightSection.tsx
Replaces previous mutation/wallet-driven example with useFetchWithPayment usage; UI now driven by isPending, isError, and data, removing wallet preconditions.
Documentation & changelog
apps/portal/src/app/x402/page.mdx, apps/portal/src/app/x402/client/page.mdx, .changeset/wet-maps-play.md
Adds React tab and examples for useFetchWithPayment, updates examples to new wrapFetchWithPayment options shape, and adds changelog doc describing hook and UI flows.
Portal/site adjustments
apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts, apps/portal/src/app/wallets/server/send-transactions/page.mdx
Adds @x402 tag mapping/order; adjusts an OpenAPI example path; integrates React docs into client page.
TSDoc / tooling
packages/thirdweb/tsdoc.json
Adds support and tag definition for @x402 in TSDoc configuration.
Minor UI tweak
packages/thirdweb/src/react/web/ui/components/basic.tsx
Adjusts ScreenBottomContainer gap from spacing.lg to spacing.md.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant App as React App
    participant Hook as useFetchWithPayment (web)
    participant Core as useFetchWithPaymentCore
    participant Wrap as wrapFetchWithPayment
    participant Wallet as ConnectFlow
    participant API as Server
    participant Modal as PaymentErrorModal

    User->>App: trigger fetchWithPayment(url)
    App->>Hook: fetchWithPayment(url)
    Hook->>Core: delegate to core
    Core->>Wrap: perform fetch(url)
    Wrap->>API: HTTP request
    API-->>Wrap: 402 Payment Required

    alt wallet not connected
        Core->>Hook: request showConnectModal
        Hook->>Wallet: show SignInRequiredModal -> ConnectWallet
        User->>Wallet: connect wallet
        Wallet-->>Core: wallet available
    end

    Core->>Hook: showErrorModal with errorData
    Hook->>Modal: show PaymentErrorModal
    alt insufficient funds
        User->>Modal: Top up (BuyWidget)
        Modal-->>Core: onRetry
    else Try again
        User->>Modal: Try again
        Modal-->>Core: onRetry
    end

    Core->>Wrap: retry with payment headers
    Wrap->>API: retry request
    API-->>Wrap: 200 OK + data
    Wrap-->>Core: return parsed response
    Core-->>Hook: return data/state
    Hook-->>App: update UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas to focus:
    • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx — modal orchestration, connect/error callback wiring, defaults.
    • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts — recursive retry, parseAs behavior, error contracts.
    • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx — paymentRequirements selection, chain/token resolution, BuyWidget integration.
    • packages/thirdweb/src/x402/fetchWithPayment.ts — signature change and selector fallback.
    • Export barrels and docs to ensure public API and examples match implementations.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The PR description is largely auto-generated by PR-Codex and lacks required sections from the template (reviewer notes, testing instructions, Linear issue tag). Add explicit sections for Notes for the reviewer, How to test, and Linear issue tag (TEAM-XXXX format) to follow the repository template.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: introducing a new useFetchWithPayment React hook for x402 payment handling.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch _SDK_Add_useFetchWithPayment_React_hook_for_x402_payment_handling

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.

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

🧹 Nitpick comments (9)
.changeset/wet-maps-play.md (1)

20-43: Clarify whether fetchWithPayment returns a Response or parsed data.

The basic usage example treats fetchWithPayment as returning a Response (await response.json()), but the core hook exposes a parseAs option and the playground uses the data field as already‑parsed content. Please confirm the intended contract and update this snippet (and optionally mention parseAs) so docs and behavior stay in sync.

apps/playground-web/src/app/x402/components/X402RightSection.tsx (1)

55-74: Align client code sample with actual fetchWithPayment contract.

In this snippet you treat fetchWithPayment as returning a Response (await response.json()), while the UI below relies on the hook’s data field for parsed content. Once you confirm whether fetchWithPayment returns a Response or parsed body, it’d be good to update this sample (and the changeset docs) to use the same pattern.

packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1)

34-67: Verify native fetchWithPayment return type and update examples accordingly.

The examples here also assume fetchWithPayment returns a Response that you then .json(). If the core hook instead returns parsed data based on parseAs, the examples should show const data = await fetchWithPayment(...) (or just rely on the data field) rather than chaining response.json().

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

23-27: Update JSDoc to match the new options param and max-value behavior.

The documentation still refers to a positional maxValue argument with a default of 1 USDC, but the implementation now takes an options object and only enforces options.maxValue when provided. Please:

  • Update the @param docs to describe options.maxValue and options.paymentRequirementsSelector.
  • Decide explicitly whether a default max should still exist and, if so, enforce it either here or in the core hook.

Also applies to: 55-60, 101-107

packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (2)

22-49: Consider exporting the full config type for consumers.

UseFetchWithPaymentConfig adds UI-focused options (theme, fundWalletOptions, connectOptions, showErrorModal) on top of UseFetchWithPaymentOptions, but only the latter is exported. If you expect callers to share this shape (e.g. typed config objects), exporting UseFetchWithPaymentConfig (or a similarly named public type) would avoid local redefinitions.


142-216: Confirm modal-toggle semantics and harden the connect flow.

Two small points:

  • showErrorModal currently gates both the error modal and the sign‑in/connect modal. If the intent is “no UI at all when false,” that’s fine but worth making explicit in docs; otherwise consider a separate flag for the connect modal.
  • If useConnectModal().connect can resolve without a wallet (e.g. null), data.onConnect(connectedWallet) would get an invalid value. A quick guard (if (!connectedWallet) { data.onCancel(); return; }) would make this more robust.
packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (2)

67-107: Validate assettokenAddress assumptions for BuyWidget

tokenAddress is derived via selectedRequirement.asset as \0x${string}` without any runtime check. This is fine if RequestedPaymentRequirements["asset"] is guaranteed to always be an EVM 0x token address for the supported "exact" scheme, but will break if:

  • asset can be "native" or another sentinel, or
  • non‑EVM networks / other asset formats are later introduced.

If those cases are possible now or in the near future, consider guarding here (e.g. only returning a config when asset matches an EVM address pattern and the chain is EVM, otherwise return null and fall back to the plain error UI).


228-257: Avoid duplicating payment requirement selection logic

defaultPaymentRequirementsSelector intentionally mirrors the logic in fetchWithPayment.ts. Keeping two copies in sync is easy to forget and could cause inconsistent behavior between the core payment flow and the UI flow if one side evolves (e.g. supporting additional schemes or selection heuristics).

Consider extracting this selector into a shared helper in the x402 module (or exporting the existing implementation) so both wrapFetchWithPayment and PaymentErrorModal reuse the same function.

packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

133-159: Consider tightening parseAs typing for better DX

Currently parseResponse returns unknown | string | Response while the hook’s mutation result is typed as unknown, which forces callers to manually narrow the type even when parseAs is known at call‑site.

In a follow‑up, you could:

  • Make useFetchWithPaymentCore generic on the response type (e.g. <T = unknown> when parseAs: "json"), and/or
  • Use a discriminated union on parseAs so fetchWithPayment can infer Promise<any> | Promise<string> | Promise<Response> accordingly.

Not urgent, but it would make the hook more ergonomic for downstream consumers.

📜 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 a3c76d5 and 8403241.

📒 Files selected for processing (10)
  • .changeset/wet-maps-play.md (1 hunks)
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx (4 hunks)
  • packages/thirdweb/src/exports/react.native.ts (1 hunks)
  • packages/thirdweb/src/exports/react.ts (1 hunks)
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1 hunks)
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1 hunks)
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • packages/thirdweb/src/exports/react.native.ts
  • packages/thirdweb/src/exports/react.ts
  • .changeset/wet-maps-play.md
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/exports/react.native.ts
  • packages/thirdweb/src/exports/react.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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:

  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts
📚 Learning: 2025-09-17T11:02:13.528Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts:15-17
Timestamp: 2025-09-17T11:02:13.528Z
Learning: The thirdweb `client` object is serializable and can safely be used in React Query keys, similar to the `contract` object.

Applied to files:

  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-05-27T19:54:55.885Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx:15-17
Timestamp: 2025-05-27T19:54:55.885Z
Learning: The `fetchDashboardContractMetadata` function from "3rdweb-sdk/react/hooks/useDashboardContractMetadata" has internal error handlers for all promises and cannot throw errors, so external error handling is not needed when calling this function.

Applied to files:

  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • .changeset/wet-maps-play.md
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-09-23T19:56:43.668Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx:482-485
Timestamp: 2025-09-23T19:56:43.668Z
Learning: In packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx, the EmbedContainer uses width: "100vw" intentionally rather than "100%" - this is by design for the bridge widget embedding use case.

Applied to files:

  • packages/thirdweb/src/exports/react.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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/playground-web/src/app/x402/components/X402RightSection.tsx
  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-09-17T11:14:35.659Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx:919-930
Timestamp: 2025-09-17T11:14:35.659Z
Learning: In the thirdweb codebase, useCustomTheme() hook can be used inside styled-components callbacks, contrary to the general React Rules of Hooks. This is a valid pattern in their implementation.

Applied to files:

  • .changeset/wet-maps-play.md
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
🧬 Code graph analysis (4)
packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (4)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)
  • Modal (32-173)
packages/thirdweb/src/react/web/ui/components/basic.tsx (2)
  • Container (80-193)
  • ScreenBottomContainer (14-23)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • spacing (142-154)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
packages/thirdweb/src/x402/schemas.ts (1)
  • RequestedPaymentRequirements (37-39)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
  • wrapFetchWithPayment (51-156)
packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (4)
packages/thirdweb/src/exports/react.ts (3)
  • BuyWidgetProps (144-144)
  • UseConnectModalOptions (179-179)
  • useFetchWithPayment (137-137)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)
  • useFetchWithPaymentCore (35-148)
packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1)
  • PaymentErrorModal (53-226)
packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1)
  • SignInRequiredModal (23-75)
⏰ 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: Unit Tests
  • 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: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (3)
packages/thirdweb/src/exports/react.native.ts (1)

117-121: RN x402 exports look consistent and correct.

Re-exporting useFetchWithPayment and UseFetchWithPaymentOptions from the native hook matches the web pattern and cleanly surfaces the API on thirdweb/react.native.

packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1)

14-75: Sign-in modal wiring and behavior look solid.

Theme handling, header/title, and close behavior (including overlay/close icon via setOpenonCancel) all look correct; actions cleanly delegate to onSignIn/onCancel.

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

134-138: Web x402 exports are wired correctly.

The new export block cleanly surfaces useFetchWithPayment and its options type from the web hook and aligns with the existing export structure.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 24, 2025

size-limit report 📦

Path Size
@thirdweb-dev/nexus (esm) 104.88 KB (0%)
@thirdweb-dev/nexus (cjs) 316.6 KB (0%)

@joaquim-verges joaquim-verges force-pushed the _SDK_Add_useFetchWithPayment_React_hook_for_x402_payment_handling branch from 8403241 to 3038bb7 Compare November 24, 2025 21:04
@github-actions github-actions bot added the Portal Involves changes to the Portal (docs) codebase. label Nov 24, 2025
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: 5

Caution

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

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

23-32: Default maxValue is no longer enforced and docs are now misleading

The implementation now only enforces a limit when options?.maxValue is explicitly provided:

  • The previous maxValue parameter (documented as “defaults to 1 USDC”) is gone.
  • options?.maxValue is optional and, if omitted, the if (options?.maxValue && …) guard simply never runs, so there’s effectively no client-side cap.
  • The JSDoc still documents @param maxValue and a default of 1 USDC, but the function no longer has such a parameter nor a default.

This is both a behavioral change (potentially allowing much larger payments than before) and a doc/contract drift.

I’d strongly recommend either:

  1. Restoring an actual default cap in code, e.g. by computing an effectiveMaxValue (const maxValue = options?.maxValue ?? DEFAULT_MAX_VALUE;) and checking against that, or
  2. Explicitly deciding that “no cap by default” is the new behavior and updating the JSDoc (and any higher‑level docs like the React hooks) to remove references to a default 1 USDC limit and describe options.maxValue instead of a standalone maxValue parameter.

Right now, callers relying on the documented default safeguard may be surprised by the new behavior.

Also applies to: 49-49, 55-60, 101-107

apps/portal/src/app/wallets/server/send-transactions/page.mdx (1)

77-83: Endpoint reference text and example path are inconsistent

The narrative text still links to:

  • /reference#tag/contracts/post/v1/contracts/{chainId}/{address}/write

But the OpenApiEndpoint directly below now uses:

  • path="/v1/contracts/write"

These should describe the same endpoint. Please update the text link (or the example path if that’s the one that’s wrong) so they match and avoid confusing readers about the correct HTTP path.

apps/playground-web/src/app/x402/components/X402RightSection.tsx (1)

67-111: Probable typo in server code sample: waitUtil vs waitUntil

In the serverCode template you have:

const thirdwebFacilitator = facilitator({
  client,
  serverWalletAddress: "0xYourServerWalletAddress",
  waitUtil: "${props.options.waitUntil}",
});

Everywhere else in this file (e.g. search params) the field is named waitUntil, so this is likely a typo in the example and could confuse users copying the snippet.

Consider updating the sample:

-  waitUtil: "${props.options.waitUntil}",
+  waitUntil: "${props.options.waitUntil}",
♻️ Duplicate comments (1)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

89-123: 402 error handling still downgrades detailed errors to a generic message

Because the try { ... } catch (_parseError) around the 402 branch currently wraps both response.json() and the subsequent “no modal” throw new Error(...), any thrown error gets caught and replaced with the generic "Payment failed with status 402":

  • In the no‑modal path, the detailed error (errorBody.errorMessage || \Payment failed: ${errorBody.error}``) is never surfaced.
  • Any synchronous error thrown while preparing the modal data would also be masked.

Refactor to only catch JSON‑parse failures, and let the detailed error propagate, e.g.:

-        if (response.status === 402) {
-          try {
-            const errorBody =
-              (await response.json()) as PaymentRequiredResult["responseBody"];
-
-            // If a modal handler is provided, show the modal and handle retry/cancel
-            if (showErrorModal) {
-              return new Promise<unknown>((resolve, reject) => {
-                showErrorModal({
-                  errorData: errorBody,
-                  onRetry: async () => {
-                    // Retry the entire fetch+error handling logic recursively
-                    try {
-                      const result = await executeFetch();
-                      resolve(result);
-                    } catch (error) {
-                      reject(error);
-                    }
-                  },
-                  onCancel: () => {
-                    reject(new Error("Payment cancelled by user"));
-                  },
-                });
-              });
-            }
-
-            // If no modal handler, throw the error with details
-            throw new Error(
-              errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
-            );
-          } catch (_parseError) {
-            // If we can't parse the error body, throw a generic error
-            throw new Error("Payment failed with status 402");
-          }
-        }
+        if (response.status === 402) {
+          let errorBody: PaymentRequiredResult["responseBody"];
+          try {
+            errorBody = (await response.json()) as PaymentRequiredResult["responseBody"];
+          } catch {
+            // If we can't parse the error body, throw a generic error
+            throw new Error("Payment failed with status 402");
+          }
+
+          // If a modal handler is provided, show the modal and handle retry/cancel
+          if (showErrorModal) {
+            return new Promise<unknown>((resolve, reject) => {
+              showErrorModal({
+                errorData: errorBody,
+                onRetry: async () => {
+                  // Retry the entire fetch+error handling logic recursively
+                  try {
+                    const result = await executeFetch();
+                    resolve(result);
+                  } catch (error) {
+                    reject(error);
+                  }
+                },
+                onCancel: () => {
+                  reject(new Error("Payment cancelled by user"));
+                },
+              });
+            });
+          }
+
+          // If no modal handler, throw the error with details
+          throw new Error(
+            errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
+          );
+        }

This preserves informative server feedback while still handling malformed JSON responses gracefully.

🧹 Nitpick comments (3)
packages/thirdweb/tsdoc.json (1)

8-8: Move "@x402" to maintain alphabetical ordering in supportForTags.

The "@x402" tag is inserted after "@bridge" but should be placed near the end of the supportForTags list (after "@walletUtils") to maintain alphabetical order, since tags starting with 'x' come after those starting with 'w'.

Apply this diff to reorder the supportForTags:

  "supportForTags": {
    "@account": true,
    "@auth": true,
    "@beta": true,
    "@bridge": true,
-   "@x402": true,
    "@chain": true,
    "@client": true,
    "@component": true,
    "@connectWallet": true,
    "@contract": true,
    "@engine": true,
    "@extension": true,
    "@insight": true,
    "@locale": true,
    "@modules": true,
    "@nebula": true,
    "@nft": true,
    "@rpc": true,
    "@social": true,
    "@storage": true,
    "@theme": true,
    "@transaction": true,
    "@utils": true,
    "@wallet": true,
    "@walletConfig": true,
    "@walletConnection": true,
    "@walletUtils": true,
+   "@x402": true
  },
.changeset/wet-maps-play.md (1)

1-111: Examples match the hook API; consider minor clarity tweaks

The option names and usage in these snippets (parseAs, maxValue, paymentRequirementsSelector, fundWalletOptions, connectOptions, showErrorModal) line up with the useFetchWithPayment config type. To make the snippets more copy‑paste friendly, you could optionally add the missing imports in the customized connect example (e.g. inAppWallet, createWallet) or a brief note that they’re assumed to be imported elsewhere.

packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1)

81-88: Consider removing unused error parameter.

The errorData.error value is passed to defaultPaymentRequirementsSelector (line 87), but the function parameter is prefixed with _ indicating it's unused (line 233). If there's no plan to use this parameter, consider removing it to simplify the function signature.

     const selectedRequirement = paymentRequirementsSelector
       ? paymentRequirementsSelector(parsedPaymentRequirements)
       : defaultPaymentRequirementsSelector(
           parsedPaymentRequirements,
           currentChainId,
           "exact",
-          errorData.error,
         );
 function defaultPaymentRequirementsSelector(
   paymentRequirements: RequestedPaymentRequirements[],
   chainId: number | undefined,
   scheme: "exact",
-  _error?: string,
 ): RequestedPaymentRequirements | undefined {

Also applies to: 228-234

📜 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 8403241 and 3038bb7.

📒 Files selected for processing (18)
  • .changeset/wet-maps-play.md (1 hunks)
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx (4 hunks)
  • apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts (2 hunks)
  • apps/portal/src/app/wallets/server/send-transactions/page.mdx (1 hunks)
  • apps/portal/src/app/x402/client/page.mdx (3 hunks)
  • apps/portal/src/app/x402/page.mdx (2 hunks)
  • packages/thirdweb/src/exports/react.native.ts (1 hunks)
  • packages/thirdweb/src/exports/react.ts (1 hunks)
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1 hunks)
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1 hunks)
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1 hunks)
  • packages/thirdweb/src/x402/facilitator.ts (1 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (3 hunks)
  • packages/thirdweb/src/x402/settle-payment.ts (1 hunks)
  • packages/thirdweb/src/x402/verify-payment.ts (1 hunks)
  • packages/thirdweb/tsdoc.json (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/x402/settle-payment.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/thirdweb/src/exports/react.ts
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
📚 Learning: 2025-10-01T22:32:18.080Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8169
File: packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx:95-107
Timestamp: 2025-10-01T22:32:18.080Z
Learning: In the thirdweb-dev/js codebase, specifically for React components in packages/thirdweb/src/react/**/*.{ts,tsx} files, do not suggest adding TSDoc blocks to function components. The project maintainer MananTank has explicitly declined these suggestions.

Applied to files:

  • packages/thirdweb/tsdoc.json
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • packages/thirdweb/src/exports/react.native.ts
  • .changeset/wet-maps-play.md
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/page.mdx
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/exports/react.native.ts
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-09-17T11:14:35.659Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx:919-930
Timestamp: 2025-09-17T11:14:35.659Z
Learning: In the thirdweb codebase, useCustomTheme() hook can be used inside styled-components callbacks, contrary to the general React Rules of Hooks. This is a valid pattern in their implementation.

Applied to files:

  • .changeset/wet-maps-play.md
📚 Learning: 2025-05-27T19:54:55.885Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx:15-17
Timestamp: 2025-05-27T19:54:55.885Z
Learning: The `fetchDashboardContractMetadata` function from "3rdweb-sdk/react/hooks/useDashboardContractMetadata" has internal error handlers for all promises and cannot throw errors, so external error handling is not needed when calling this function.

Applied to files:

  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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:

  • .changeset/wet-maps-play.md
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts
  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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:

  • .changeset/wet-maps-play.md
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts
  • apps/portal/src/app/x402/page.mdx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-09-17T11:02:13.528Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts:15-17
Timestamp: 2025-09-17T11:02:13.528Z
Learning: The thirdweb `client` object is serializable and can safely be used in React Query keys, similar to the `contract` object.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/page.mdx
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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/x402/components/X402RightSection.tsx
📚 Learning: 2025-09-23T19:56:43.668Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx:482-485
Timestamp: 2025-09-23T19:56:43.668Z
Learning: In packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx, the EmbedContainer uses width: "100vw" intentionally rather than "100%" - this is by design for the bridge widget embedding use case.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-08-07T17:24:31.965Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.

Applied to files:

  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
Repo: thirdweb-dev/js PR: 7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.

Applied to files:

  • apps/portal/src/app/x402/client/page.mdx
🧬 Code graph analysis (3)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (2)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • ThirdwebClient (25-25)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
  • wrapFetchWithPayment (51-156)
packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (7)
packages/thirdweb/src/exports/react.native.ts (1)
  • Theme (6-6)
packages/thirdweb/src/exports/react.ts (2)
  • Theme (6-6)
  • BuyWidget (143-143)
packages/thirdweb/src/x402/schemas.ts (2)
  • networkToCaip2ChainId (183-188)
  • extractEvmChainId (104-111)
packages/thirdweb/src/chains/utils.ts (1)
  • getCachedChain (79-89)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)
  • Modal (32-173)
packages/thirdweb/src/react/web/ui/components/basic.tsx (3)
  • Container (80-193)
  • ModalHeader (36-68)
  • ScreenBottomContainer (14-23)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (5)
packages/thirdweb/src/exports/react.native.ts (2)
  • useFetchWithPayment (120-120)
  • UseFetchWithPaymentOptions (119-119)
packages/thirdweb/src/exports/react.ts (2)
  • useFetchWithPayment (137-137)
  • UseFetchWithPaymentOptions (136-136)
packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (2)
  • useFetchWithPayment (163-238)
  • UseFetchWithPaymentOptions (20-20)
packages/thirdweb/src/exports/thirdweb.ts (1)
  • ThirdwebClient (25-25)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (2)
  • UseFetchWithPaymentOptions (11-17)
  • useFetchWithPaymentCore (35-148)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (12)
packages/thirdweb/src/x402/verify-payment.ts (1)

73-73: LGTM! Documentation tag updated for consistency across all x402 APIs.

The JSDoc tag change from @bridge x402 to @x402 is part of a complete standardization effort. Verification confirms all x402-related files use the consistent @x402 tag, with no remaining old tags.

packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

35-87: Core hook structure and mutation wiring look solid

The recursive executeFetch flow, connect‑modal integration, delegation to wrapFetchWithPayment, and parseAs‑based response handling are coherent and align well with React Query’s mutation API. Aside from the 402 error‑handling concern above, the rest of the hook reads clean and maintainable.

Also applies to: 126-160

packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1)

90-96: Native wrapper correctly delegates to the core hook

The hook signature and return shape are thin, accurate wrappers over useFetchWithPaymentCore, which is exactly what you want on the native side (no modal wiring here, errors bubble up). This looks good.

apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts (1)

10-17: @x402 tag wiring into tagsToGroup + sidebarGroupOrder looks correct

You’ve added @x402 to both tagsToGroup and sidebarGroupOrder, so x402 docs will group correctly and won’t trip the safety check that throws when a tag lacks an ordering. Placement before @bridge also makes sense for discoverability.

Also applies to: 53-69

packages/thirdweb/src/exports/react.native.ts (1)

117-121: Native x402 hook export matches the new web surface

The new useFetchWithPayment + UseFetchWithPaymentOptions export looks consistent with the rest of the barrel and keeps native in sync with web. No issues from an API-surface perspective.

apps/portal/src/app/x402/page.mdx (1)

1-98: Tabbed client-side docs align with the new hook API

The new Tabs-based split between TypeScript (wrapFetchWithPayment) and React (useFetchWithPayment) reads clearly and matches the exported hook signature (useFetchWithPayment(client)). The examples are coherent and consistent with the server-side section below.

apps/playground-web/src/app/x402/components/X402RightSection.tsx (1)

28-45: Hook wiring and playground UI state handling look solid

useFetchWithPayment(THIRDWEB_CLIENT) is integrated cleanly: handlePayClick builds the paywall URL, the main CTA is disabled via isPending, and the response card shows loading, error, and pretty‑printed JSON from data. This is a good end‑to‑end playground for the new flow.

Also applies to: 184-208

apps/portal/src/app/x402/client/page.mdx (2)

2-2: LGTM!

The React tab integration follows the established pattern for multi-language documentation.

Also applies to: 30-33


71-73: Documentation accurately matches implementation—no changes needed.

The wrapFetchWithPayment function signature correctly implements the documented options object structure with maxValue and paymentRequirementsSelector as optional properties. Verification confirms the implementation at packages/thirdweb/src/x402/fetchWithPayment.ts:51-60 aligns with the documentation.

packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (3)

1-46: LGTM!

The type definitions are well-structured. The fundWalletOptions type properly excludes the props that will be controlled by the component while allowing customization of other BuyWidget options.


109-153: LGTM!

The buy-widget modal flow is well-implemented with proper guards (isInsufficientFunds && buyWidgetConfig), clear user messaging, and appropriate callback handling for success and cancel actions.


156-226: LGTM!

The error screen provides clear user feedback with contextual messaging for insufficient funds vs. generic payment errors, and appropriate action buttons for each scenario.

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

♻️ Duplicate comments (4)
packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (2)

232-261: defaultPaymentRequirementsSelector comment overstates equivalence with core selector.

This helper claims “same logic as in fetchWithPayment.ts”, but it:

  • Accepts chainId: number | undefined instead of required number
  • Returns undefined on empty paymentRequirements instead of throwing
  • Skips chain matching entirely and falls back to the first matching scheme when chainId is undefined

Either:

  • Update the comment to describe these UI‑specific, more defensive differences, or
  • Share a single implementation with the core selector (same signature and behavior) and reuse it here.
#!/bin/bash
# Compare selector behavior between core and UI implementations
rg -n "defaultPaymentRequirementsSelector" packages/thirdweb/src/x402/fetchWithPayment.ts packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx -A10 -B5

67-105: Validate selectedRequirement.asset before casting to an EVM address.

selectedRequirement.asset is blindly asserted to 0x${string} and passed to BuyWidget. If the asset is a non‑EVM identifier, native token marker, or malformed string, this can surface as a runtime issue in the buy flow.

Add a small validator before the cast and bail out when the asset is not a proper 20‑byte hex address so the BuyWidget isn't misconfigured:

-    const chain = getCachedChain(chainId);
-    const tokenAddress = selectedRequirement.asset as `0x${string}`;
-
-    return {
-      chain,
-      tokenAddress,
-      amount: undefined,
-    };
+    const chain = getCachedChain(chainId);
+
+    const asset = selectedRequirement.asset;
+    if (
+      typeof asset !== "string" ||
+      !/^0x[a-fA-F0-9]{40}$/.test(asset)
+    ) {
+      // Non-EVM or invalid asset; skip BuyWidget config
+      return null;
+    }
+
+    const tokenAddress = asset as `0x${string}`;
+
+    return {
+      chain,
+      tokenAddress,
+      amount: undefined,
+    };
#!/bin/bash
# Inspect the RequestedPaymentRequirements schema to confirm asset typing
rg -n "asset" packages/thirdweb/src/x402/schemas.ts -A3 -B3

# Check BuyWidgetProps tokenAddress expectations
rg -n "tokenAddress" packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx -A3 -B3
apps/portal/src/app/x402/client/page.mdx (1)

71-74: maxValue docs still claim a default that the implementation does not apply.

The React useFetchWithPayment parameters still say:

maxValue - Maximum allowed payment amount in base units (defaults to 1 USDC = 1,000,000)

but wrapFetchWithPayment and the core options only gate on options?.maxValue and never set a default value. This will mislead users into assuming a cap exists when it does not.

Please update the description to state that maxValue is optional and has no default (just an upper bound when explicitly provided). The rest of the React section (example, features, other options, reference link) looks consistent with the hook behavior.

#!/bin/bash
# Confirm that maxValue is only honored when explicitly provided
rg -n "maxValue" packages/thirdweb/src/x402/fetchWithPayment.ts packages/thirdweb/src/react -A3 -B3

# Check that the reference page for useFetchWithPayment exists in the portal
fd -t f "useFetchWithPayment" apps/portal/src/app/references || echo "No reference file found"

Also applies to: 81-133

packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

90-123: 402 handling still downgrades detailed errors to a generic message.

Because the detailed throw new Error(errorBody.errorMessage || \Payment failed: ${errorBody.error}`)is inside the sametryasresponse.json(), it is immediately caught by the catch (_parseError)and replaced with"Payment failed with status 402". This means callers never see server‑provided details when showErrorModal` is not used.

Refactor so the try/catch only wraps JSON parsing, and keep the detailed throw outside:

-        if (response.status === 402) {
-          try {
-            const errorBody =
-              (await response.json()) as PaymentRequiredResult["responseBody"];
-
-            // If a modal handler is provided, show the modal and handle retry/cancel
-            if (showErrorModal) {
-              return new Promise<unknown>((resolve, reject) => {
-                showErrorModal({
-                  errorData: errorBody,
-                  onRetry: async () => {
-                    // Retry the entire fetch+error handling logic recursively
-                    try {
-                      const result = await executeFetch();
-                      resolve(result);
-                    } catch (error) {
-                      reject(error);
-                    }
-                  },
-                  onCancel: () => {
-                    reject(new Error("Payment cancelled by user"));
-                  },
-                });
-              });
-            }
-
-            // If no modal handler, throw the error with details
-            throw new Error(
-              errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
-            );
-          } catch (_parseError) {
-            // If we can't parse the error body, throw a generic error
-            throw new Error("Payment failed with status 402");
-          }
-        }
+        if (response.status === 402) {
+          let errorBody: PaymentRequiredResult["responseBody"];
+          try {
+            errorBody =
+              (await response.json()) as PaymentRequiredResult["responseBody"];
+          } catch {
+            // If we can't parse the error body, throw a generic error
+            throw new Error("Payment failed with status 402");
+          }
+
+          // If a modal handler is provided, show the modal and handle retry/cancel
+          if (showErrorModal) {
+            return new Promise<unknown>((resolve, reject) => {
+              showErrorModal({
+                errorData: errorBody,
+                onRetry: async () => {
+                  // Retry the entire fetch+error handling logic recursively
+                  try {
+                    const result = await executeFetch();
+                    resolve(result);
+                  } catch (error) {
+                    reject(error);
+                  }
+                },
+                onCancel: () => {
+                  reject(new Error("Payment cancelled by user"));
+                },
+              });
+            });
+          }
+
+          // If no modal handler, throw the error with details
+          throw new Error(
+            errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
+          );
+        }
In JavaScript/TypeScript, does a `throw` inside a `try` block always route to the corresponding `catch` (unless rethrown), thereby preventing that error from escaping past the `catch`?
🧹 Nitpick comments (2)
packages/thirdweb/tsdoc.json (1)

8-8: Move @x402 to maintain alphabetical order in supportForTags.

The new "@x402" tag is inserted after "@bridge" (line 8), but based on the alphabetical ordering of other tags in this array, it should be placed at the end (after "@walletUtils") to maintain consistency.

Apply this change:

  "supportForTags": {
    "@account": true,
    "@auth": true,
    "@beta": true,
    "@bridge": true,
-   "@x402": true,
    "@chain": true,
    "@client": true,
    "@component": true,
    "@connectWallet": true,
    "@contract": true,
    "@engine": true,
    "@extension": true,
    "@insight": true,
    "@locale": true,
    "@modules": true,
    "@nebula": true,
    "@nft": true,
    "@rpc": true,
    "@social": true,
    "@storage": true,
    "@theme": true,
    "@transaction": true,
    "@utils": true,
    "@wallet": true,
    "@walletConfig": true,
    "@walletConnection": true,
    "@walletUtils": true,
+   "@x402": true
  },
packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1)

23-74: Well-scoped, theme-aware sign-in modal; consider future-proofing copy

The component is wired cleanly: theme is correctly scoped via CustomThemeProvider, callbacks (onSignIn, onCancel, overlay/escape via setOpen) behave as expected, and layout matches existing modal patterns.

If you expect reuse or localization later, consider accepting the title/body copy as props (or at least hoisting "Sign in required" into a shared constant) to avoid duplicated, hard-coded strings in the UI surface.

📜 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 3038bb7 and c5c1789.

📒 Files selected for processing (19)
  • .changeset/wet-maps-play.md (1 hunks)
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx (4 hunks)
  • apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts (2 hunks)
  • apps/portal/src/app/wallets/server/send-transactions/page.mdx (1 hunks)
  • apps/portal/src/app/x402/client/page.mdx (3 hunks)
  • apps/portal/src/app/x402/page.mdx (2 hunks)
  • packages/thirdweb/src/exports/react.native.ts (1 hunks)
  • packages/thirdweb/src/exports/react.ts (1 hunks)
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1 hunks)
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1 hunks)
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/basic.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1 hunks)
  • packages/thirdweb/src/x402/facilitator.ts (1 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (3 hunks)
  • packages/thirdweb/src/x402/settle-payment.ts (1 hunks)
  • packages/thirdweb/src/x402/verify-payment.ts (1 hunks)
  • packages/thirdweb/tsdoc.json (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/thirdweb/src/x402/settle-payment.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • apps/portal/src/app/wallets/server/send-transactions/page.mdx
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/exports/react.native.ts
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • packages/thirdweb/src/x402/verify-payment.ts
  • apps/portal/src/app/x402/page.mdx
🧰 Additional context used
🧠 Learnings (19)
📓 Common learnings
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • packages/thirdweb/src/exports/react.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-10-03T23:36:00.631Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8181
File: packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx:27-27
Timestamp: 2025-10-03T23:36:00.631Z
Learning: In packages/thirdweb/src/react/web/ui/Bridge/BuyWidget.tsx, the component intentionally uses a hardcoded English locale (connectLocaleEn) rather than reading from the provider, as BuyWidget is designed to be English-only and does not require internationalization support.

Applied to files:

  • packages/thirdweb/src/exports/react.ts
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-09-23T19:56:43.668Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx:482-485
Timestamp: 2025-09-23T19:56:43.668Z
Learning: In packages/thirdweb/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx, the EmbedContainer uses width: "100vw" intentionally rather than "100%" - this is by design for the bridge widget embedding use case.

Applied to files:

  • packages/thirdweb/src/exports/react.ts
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
  • packages/thirdweb/src/react/web/ui/components/basic.tsx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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/react/web/ui/x402/SignInRequiredModal.tsx
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-09-17T11:02:13.528Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts:15-17
Timestamp: 2025-09-17T11:02:13.528Z
Learning: The thirdweb `client` object is serializable and can safely be used in React Query keys, similar to the `contract` object.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-09-24T11:08:43.783Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8106
File: packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx:34-41
Timestamp: 2025-09-24T11:08:43.783Z
Learning: In BridgeWidgetProps for packages/thirdweb/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx, the Swap onError callback signature requires a non-undefined SwapPreparedQuote parameter (unlike Buy's onError which allows undefined quote). This is intentional - SwapWidget's onError is only called when a quote is available.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-07-10T10:18:33.238Z
Learnt from: arcoraven
Repo: thirdweb-dev/js PR: 7505
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx:186-204
Timestamp: 2025-07-10T10:18:33.238Z
Learning: The ThirdwebBarChart component in apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/analytics/components/WebhookAnalyticsCharts.tsx does not accept standard accessibility props like `aria-label` and `role` in its TypeScript interface, causing compilation errors when added.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-08-28T12:24:37.171Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-05-27T19:55:25.056Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-10-17T22:59:11.867Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8278
File: apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx:144-144
Timestamp: 2025-10-17T22:59:11.867Z
Learning: The BuyAndSwapEmbed component in apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx cannot be used in testnets, so the hardcoded `is_testnet: false` in asset reporting calls is intentional and correct.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-10-16T19:00:34.707Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 8267
File: packages/thirdweb/src/extensions/erc20/read/getCurrencyMetadata.ts:47-52
Timestamp: 2025-10-16T19:00:34.707Z
Learning: In the thirdweb SDK's getCurrencyMetadata function (packages/thirdweb/src/extensions/erc20/read/getCurrencyMetadata.ts), zero decimals is not a valid value for native currency. If `options.contract.chain.nativeCurrency.decimals` is 0, it should be treated as missing/invalid data and trigger an API fetch to get the correct native currency metadata.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
  • apps/portal/src/app/x402/client/page.mdx
📚 Learning: 2025-06-10T00:50:20.795Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7315
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx:153-226
Timestamp: 2025-06-10T00:50:20.795Z
Learning: In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/launch-nft.tsx, the updateStatus function correctly expects a complete MultiStepState["status"] object. For pending states, { type: "pending" } is the entire status object. For error states, { type: "error", message: React.ReactNode } is the entire status object. The current code incorrectly spreads the entire step object instead of passing just the status object.

Applied to files:

  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
📚 Learning: 2025-08-29T23:44:47.512Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7951
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx:38-38
Timestamp: 2025-08-29T23:44:47.512Z
Learning: The ContractPageLayout component in apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/_layout/contract-page-layout.tsx is not the root layout - it's nested within the dashboard layout which already handles footer positioning with min-h-dvh and AppFooter placement. The ContractPageLayout needs flex flex-col grow to properly participate in the parent's flex layout.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/basic.tsx
📚 Learning: 2025-10-01T22:32:18.080Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8169
File: packages/thirdweb/src/react/web/ui/Bridge/FundWallet.tsx:95-107
Timestamp: 2025-10-01T22:32:18.080Z
Learning: In the thirdweb-dev/js codebase, specifically for React components in packages/thirdweb/src/react/**/*.{ts,tsx} files, do not suggest adding TSDoc blocks to function components. The project maintainer MananTank has explicitly declined these suggestions.

Applied to files:

  • packages/thirdweb/src/react/web/ui/components/basic.tsx
  • packages/thirdweb/tsdoc.json
📚 Learning: 2025-07-07T21:21:47.488Z
Learnt from: saminacodes
Repo: thirdweb-dev/js PR: 7543
File: apps/portal/src/app/pay/page.mdx:4-4
Timestamp: 2025-07-07T21:21:47.488Z
Learning: In the thirdweb-dev/js repository, lucide-react icons must be imported with the "Icon" suffix (e.g., ExternalLinkIcon, RocketIcon) as required by the new linting rule, contrary to the typical lucide-react convention of importing without the suffix.

Applied to files:

  • apps/portal/src/app/x402/client/page.mdx
🧬 Code graph analysis (3)
packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (4)
packages/thirdweb/src/react/web/ui/components/Modal.tsx (1)
  • Modal (32-173)
packages/thirdweb/src/react/web/ui/components/basic.tsx (2)
  • Container (80-193)
  • ModalHeader (36-68)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • spacing (142-154)
packages/thirdweb/src/react/web/ui/components/text.tsx (1)
  • Text (18-34)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
  • wrapFetchWithPayment (51-156)
packages/thirdweb/src/react/web/ui/components/basic.tsx (1)
packages/thirdweb/src/react/core/design-system/index.ts (1)
  • spacing (142-154)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: Unit Tests
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Build Packages
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (11)
packages/thirdweb/tsdoc.json (1)

137-140: Tag definition structure is correct.

The new "@x402" tag definition follows the proper structure and is appropriately placed at the end of the tagDefinitions array.

packages/thirdweb/src/react/web/ui/components/basic.tsx (1)

14-23: Verify visual impact on existing wallet connection flows.

The spacing reduction from spacing.lg (24px) to spacing.md (16px) affects existing components beyond the new x402 UI. While the new x402 modals (PaymentErrorModal, SignInRequiredModal) are designed for this spacing, two existing wallet connection flows will be visually impacted:

  • ScanScreen.tsx (line 158): Optional "Get Started" button section
  • WalletSelector.tsx (lines 293, 478): Guest option and "new to wallets" sections

Manually verify these components in the development environment to ensure the 8px spacing reduction doesn't negatively impact the wallet connection UX.

apps/playground-web/src/app/x402/components/X402RightSection.tsx (6)

8-8: LGTM! Clean migration to the new payment hook.

The import change correctly reflects the new useFetchWithPayment API, replacing the previous wrapFetchWithPayment approach.


28-29: Well-structured hook usage.

The useFetchWithPayment hook initialization correctly provides both the fetch function and state management, streamlining the payment flow.


47-65: Excellent documentation example.

The client code example demonstrates the dual usage pattern effectively: capturing the return value directly from fetchWithPayment (lines 56-57) while also showing proper loading state management with isPending. This flexibility gives developers options for different use cases.


188-188: Proper loading state handling.

Disabling the button during payment processing prevents duplicate submissions and provides good user feedback.


202-208: Comprehensive response state handling.

The rendering logic properly covers all states (loading, error, success) and provides clear feedback for each, enhancing the user experience.


31-45: Verified: /api/paywall endpoint correctly handles all payment parameters.

The endpoint exists and properly extracts, validates, and uses all six query parameters being sent from the component: chainId, payTo, amount, tokenAddress, decimals, and waitUntil. Parameter types and defaults align with the implementation.

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

134-138: Expose x402 React hook from the main React barrel (LGTM).

Re-exporting UseFetchWithPaymentOptions and useFetchWithPayment here is consistent with other web hooks and matches the documented "thirdweb/react" import path.

apps/portal/src/app/x402/client/page.mdx (1)

2-2: React tab wiring and icons look consistent.

The new React tab trigger and ReactIcon import integrate cleanly with the existing Tabs setup; no changes needed.

Also applies to: 30-33

packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

11-18: Core hook structure and response parsing look solid.

The core hook cleanly composes wrapFetchWithPayment, wallet connection flow, and response parsing (parseAs + parseResponse), and the mutation API surface (fetchWithPayment plus spread mutation) matches typical React Query patterns.

Also applies to: 43-88, 126-160

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

♻️ Duplicate comments (1)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)

90-124: 402 error handling still swallows detailed error messages.

The throw new Error(...) at lines 117-119 is inside the same try block as response.json(), so the catch at line 120 catches both JSON parse failures and the intentional throw, replacing the detailed message with a generic "Payment failed with status 402".

Refactor to isolate the JSON parse from the error throw:

 if (response.status === 402) {
+  let errorBody: PaymentRequiredResult["responseBody"];
   try {
-    const errorBody =
-      (await response.json()) as PaymentRequiredResult["responseBody"];
-
-    // If a modal handler is provided, show the modal and handle retry/cancel
-    if (showErrorModal) {
-      return new Promise<unknown>((resolve, reject) => {
-        showErrorModal({
-          errorData: errorBody,
-          onRetry: async () => {
-            // Retry the entire fetch+error handling logic recursively
-            try {
-              const result = await executeFetch();
-              resolve(result);
-            } catch (error) {
-              reject(error);
-            }
-          },
-          onCancel: () => {
-            reject(new Error("Payment cancelled by user"));
-          },
-        });
-      });
-    }
-
-    // If no modal handler, throw the error with details
-    throw new Error(
-      errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
-    );
-  } catch (_parseError) {
-    // If we can't parse the error body, throw a generic error
+    errorBody = (await response.json()) as PaymentRequiredResult["responseBody"];
+  } catch {
     throw new Error("Payment failed with status 402");
   }
+
+  if (showErrorModal) {
+    return new Promise<unknown>((resolve, reject) => {
+      showErrorModal({
+        errorData: errorBody,
+        onRetry: async () => {
+          try {
+            const result = await executeFetch();
+            resolve(result);
+          } catch (error) {
+            reject(error);
+          }
+        },
+        onCancel: () => {
+          reject(new Error("Payment cancelled by user"));
+        },
+      });
+    });
+  }
+
+  throw new Error(
+    errorBody.errorMessage || `Payment failed: ${errorBody.error}`,
+  );
 }
📜 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 c5c1789 and 32a243c.

📒 Files selected for processing (19)
  • .changeset/wet-maps-play.md (1 hunks)
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx (4 hunks)
  • apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts (2 hunks)
  • apps/portal/src/app/wallets/server/send-transactions/page.mdx (1 hunks)
  • apps/portal/src/app/x402/client/page.mdx (3 hunks)
  • apps/portal/src/app/x402/page.mdx (2 hunks)
  • packages/thirdweb/src/exports/react.native.ts (1 hunks)
  • packages/thirdweb/src/exports/react.ts (1 hunks)
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1 hunks)
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (1 hunks)
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/components/basic.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx (1 hunks)
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx (1 hunks)
  • packages/thirdweb/src/x402/facilitator.ts (1 hunks)
  • packages/thirdweb/src/x402/fetchWithPayment.ts (4 hunks)
  • packages/thirdweb/src/x402/settle-payment.ts (1 hunks)
  • packages/thirdweb/src/x402/verify-payment.ts (1 hunks)
  • packages/thirdweb/tsdoc.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (12)
  • packages/thirdweb/tsdoc.json
  • apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts
  • packages/thirdweb/src/x402/verify-payment.ts
  • packages/thirdweb/src/x402/facilitator.ts
  • packages/thirdweb/src/exports/react.ts
  • packages/thirdweb/src/react/web/ui/x402/PaymentErrorModal.tsx
  • packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx
  • packages/thirdweb/src/x402/fetchWithPayment.ts
  • packages/thirdweb/src/react/web/ui/x402/SignInRequiredModal.tsx
  • apps/portal/src/app/x402/client/page.mdx
  • packages/thirdweb/src/react/web/ui/components/basic.tsx
  • packages/thirdweb/src/exports/react.native.ts
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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.
📚 Learning: 2025-09-17T11:14:35.659Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx:919-930
Timestamp: 2025-09-17T11:14:35.659Z
Learning: In the thirdweb codebase, useCustomTheme() hook can be used inside styled-components callbacks, contrary to the general React Rules of Hooks. This is a valid pattern in their implementation.

Applied to files:

  • .changeset/wet-maps-play.md
📚 Learning: 2025-05-27T19:54:55.885Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/erc20.tsx:15-17
Timestamp: 2025-05-27T19:54:55.885Z
Learning: The `fetchDashboardContractMetadata` function from "3rdweb-sdk/react/hooks/useDashboardContractMetadata" has internal error handlers for all promises and cannot throw errors, so external error handling is not needed when calling this function.

Applied to files:

  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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:

  • .changeset/wet-maps-play.md
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 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:

  • .changeset/wet-maps-play.md
  • packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-06-17T18:30:52.976Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7356
File: apps/nebula/src/app/not-found.tsx:1-1
Timestamp: 2025-06-17T18:30:52.976Z
Learning: In the thirdweb/js project, the React namespace is available for type annotations (like React.FC) without needing to explicitly import React. This is project-specific configuration that differs from typical TypeScript/React setups.

Applied to files:

  • .changeset/wet-maps-play.md
  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-07-31T16:17:42.753Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7768
File: apps/playground-web/src/app/navLinks.ts:1-1
Timestamp: 2025-07-31T16:17:42.753Z
Learning: Configuration files that import and reference React components (like icon components from lucide-react) need the "use client" directive, even if they primarily export static data, because the referenced components need to be executed in a client context when used by other client components.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
📚 Learning: 2025-09-17T11:02:13.528Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 8044
File: packages/thirdweb/src/react/web/ui/Bridge/swap-widget/use-tokens.ts:15-17
Timestamp: 2025-09-17T11:02:13.528Z
Learning: The thirdweb `client` object is serializable and can safely be used in React Query keys, similar to the `contract` object.

Applied to files:

  • apps/playground-web/src/app/x402/components/X402RightSection.tsx
  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
  • apps/portal/src/app/x402/page.mdx
📚 Learning: 2025-05-30T17:14:25.332Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 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/x402/components/X402RightSection.tsx
📚 Learning: 2025-10-16T19:00:34.707Z
Learnt from: jnsdls
Repo: thirdweb-dev/js PR: 8267
File: packages/thirdweb/src/extensions/erc20/read/getCurrencyMetadata.ts:47-52
Timestamp: 2025-10-16T19:00:34.707Z
Learning: In the thirdweb SDK's getCurrencyMetadata function (packages/thirdweb/src/extensions/erc20/read/getCurrencyMetadata.ts), zero decimals is not a valid value for native currency. If `options.contract.chain.nativeCurrency.decimals` is 0, it should be treated as missing/invalid data and trigger an API fetch to get the correct native currency metadata.

Applied to files:

  • packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts
📚 Learning: 2025-08-07T17:24:31.965Z
Learnt from: MananTank
Repo: thirdweb-dev/js PR: 7812
File: apps/dashboard/src/app/(app)/team/~/~project/[[...paths]]/page.tsx:1-11
Timestamp: 2025-08-07T17:24:31.965Z
Learning: In Next.js App Router, page components (page.tsx files) are server components by default and do not require the "server-only" import directive. The "server-only" directive is primarily used for utility functions, API helpers, and data access modules that should never be included in the client bundle.

Applied to files:

  • apps/portal/src/app/x402/page.mdx
🧬 Code graph analysis (2)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (1)
packages/thirdweb/src/x402/fetchWithPayment.ts (1)
  • wrapFetchWithPayment (51-156)
packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (3)
packages/thirdweb/src/exports/react.native.ts (2)
  • useFetchWithPayment (120-120)
  • UseFetchWithPaymentOptions (119-119)
packages/thirdweb/src/react/web/hooks/x402/useFetchWithPayment.tsx (2)
  • useFetchWithPayment (163-238)
  • UseFetchWithPaymentOptions (20-20)
packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (2)
  • UseFetchWithPaymentOptions (11-17)
  • useFetchWithPaymentCore (35-148)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, webpack)
  • GitHub Check: E2E Tests (pnpm, vite)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (13)
packages/thirdweb/src/x402/settle-payment.ts (1)

125-125: LGTM!

The JSDoc tag update from @bridge x402 to @x402 aligns with the broader documentation standardization in this PR.

packages/thirdweb/src/react/core/hooks/x402/useFetchWithPaymentCore.ts (4)

11-17: LGTM!

The UseFetchWithPaymentOptions type is well-structured with appropriate optional fields for payment configuration and response parsing flexibility.


52-78: LGTM!

The wallet connection flow is well-designed: it gracefully handles the missing wallet case by either prompting via modal callback or throwing a descriptive error, maintaining platform-agnostic core logic.


126-135: LGTM!

Good error handling for non-402 failures with detailed status information, and proper delegation to the parseResponse helper.


150-160: LGTM!

Clean helper function with appropriate handling for all documented parseAs options.

packages/thirdweb/src/react/native/hooks/x402/useFetchWithPayment.ts (2)

27-37: LGTM!

The documentation correctly describes maxValue as optional without claiming a non-existent default value. The past review concern has been addressed.


90-96: LGTM!

Clean delegation to the core hook with appropriate documentation noting that React Native doesn't include modal UI and errors should be handled by the application.

apps/portal/src/app/x402/page.mdx (2)

1-1: LGTM!

Appropriate imports added to support the new tabbed documentation UI.


36-98: LGTM!

The tabbed documentation structure provides clear separation between TypeScript and React usage patterns. The examples accurately demonstrate the new useFetchWithPayment hook API and wrapFetchWithPayment function.

.changeset/wet-maps-play.md (1)

1-111: LGTM!

Comprehensive changeset documentation covering all features and customization options of the new useFetchWithPayment hook. The examples are clear and consistent with the implementation.

apps/playground-web/src/app/x402/components/X402RightSection.tsx (3)

28-45: LGTM!

Clean refactor to use the new useFetchWithPayment hook. The handlePayClick function is simplified and demonstrates the intended usage pattern well.


47-65: LGTM!

The client code example accurately demonstrates the useFetchWithPayment hook usage pattern for playground visitors.


202-208: LGTM!

The UI properly handles all states from the useFetchWithPayment hook: loading, error, and success with data display.

- For user wallets in TypeScript applications, you can get it by calling `wallet.getAuthToken()` on a connected [`inAppWallet()`](/references/typescript/v5/inAppWallet) or [`ecosystemWallet()`](/references/typescript/v5/ecosystemWallet).

<OpenApiEndpoint path="/v1/contracts/{chainId}/{address}/write" method="POST" />
<OpenApiEndpoint path="/v1/contracts/write" method="POST" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify the API endpoint path change.

The endpoint path changed from /v1/contracts/{chainId}/{address}/write to /v1/contracts/write, removing the path parameters. Please confirm this reflects the actual API structure, as it's a significant change to the documented endpoint.


🏁 Script executed:

#!/bin/bash
# Search for other references to this endpoint path in the codebase
rg -n "v1/contracts.*write" --type=md --type=ts --type=tsx -g '!node_modules'

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for endpoint references - fix file type flag
rg -n "v1/contracts.*write" --type=md --type=ts -g '!node_modules'

Length of output: 1042


🏁 Script executed:

#!/bin/bash
# Also search for the old endpoint pattern with path parameters
rg -n "chainId.*address.*write" -g '!node_modules'

Length of output: 414


🏁 Script executed:

#!/bin/bash
# Search for the new endpoint pattern
rg -n "/v1/contracts/write" -g '!node_modules'

Length of output: 1611


@codecov
Copy link

codecov bot commented Nov 24, 2025

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 54.83%. Comparing base (82ba2b2) to head (32a243c).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
...ges/thirdweb/src/react/web/ui/components/basic.tsx 0.00% 1 Missing ⚠️

❌ Your patch status has failed because the patch coverage (0.00%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8444      +/-   ##
==========================================
- Coverage   54.83%   54.83%   -0.01%     
==========================================
  Files         919      919              
  Lines       60868    60868              
  Branches     4141     4140       -1     
==========================================
- Hits        33375    33374       -1     
- Misses      27391    27392       +1     
  Partials      102      102              
Flag Coverage Δ
packages 54.83% <0.00%> (-0.01%) ⬇️
Files with missing lines Coverage Δ
...ges/thirdweb/src/react/web/ui/components/basic.tsx 84.07% <0.00%> (ø)

... and 1 file 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.

@joaquim-verges joaquim-verges merged commit 9809d5c into main Nov 24, 2025
23 of 24 checks passed
@joaquim-verges joaquim-verges deleted the _SDK_Add_useFetchWithPayment_React_hook_for_x402_payment_handling branch November 24, 2025 22:42
@joaquim-verges joaquim-verges mentioned this pull request Nov 24, 2025
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. Portal Involves changes to the Portal (docs) codebase. SDK Involves changes to the thirdweb SDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants