Skip to content

Conversation

@joaquim-verges
Copy link
Member

@joaquim-verges joaquim-verges commented Oct 9, 2025


PR-Codex overview

This PR adds a new input field for a "Pay To Address" in the X402LeftSection component and updates the API route to handle the payTo parameter in the payment request.

Detailed summary

  • Added payToId using useId() in X402LeftSection.
  • Introduced handlePayToChange function to update the payTo option.
  • Created a new input field for "Pay To Address" in the UI.
  • Updated the API route to retrieve payTo from query parameters.

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

Summary by CodeRabbit

  • New Features
    • Added a “Pay To Address” field in the payment form, allowing users to direct payments to a specific address.
    • The payments API now accepts an optional payTo parameter and includes it in successful payment responses for end-to-end recipient control.
  • Improvements
    • Streamlined request handling to improve reliability and responsiveness during payment initialization.

@vercel vercel bot temporarily deployed to Preview – wallet-ui October 9, 2025 21:13 Inactive
@vercel
Copy link

vercel bot commented Oct 9, 2025

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

Project Deployment Preview Comments Updated (UTC)
thirdweb_playground Error Error Oct 9, 2025 9:38pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
docs-v2 Skipped Skipped Oct 9, 2025 9:38pm
nebula Skipped Skipped Oct 9, 2025 9:38pm
thirdweb-www Skipped Skipped Oct 9, 2025 9:38pm
wallet-ui Skipped Skipped Oct 9, 2025 9:38pm

@changeset-bot
Copy link

changeset-bot bot commented Oct 9, 2025

⚠️ No Changeset found

Latest commit: 2e8fca4

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel vercel bot temporarily deployed to Preview – thirdweb-www October 9, 2025 21:13 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 9, 2025 21:13 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 9, 2025 21:13 Inactive
@github-actions github-actions bot added the Playground Changes involving the Playground codebase. label Oct 9, 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

Walkthrough

Moved thirdweb client and x402 facilitator initialization to module scope in the paywall API route, added an optional payTo query parameter threaded through settlePayment and response, and temporarily hardcoded the API base URL to localhost. Added a corresponding “Pay To Address” input and state handling in the X402 left section UI.

Changes

Cohort / File(s) Summary
Paywall API route updates
apps/playground-web/src/app/api/paywall/route.ts
- Initialize thirdweb client and x402 facilitator at module scope
- Switch API base URL to http://localhost:3030 (previous env-based code commented)
- Add optional payTo query param; include in settlePayment payload and success response
- Minor refactor to export GET after initializations
X402 UI: Pay To input
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
- Add “Pay To Address” input and helper text
- Add local payToId, handlePayToChange, and bind to options.payTo typed as 0x\${string}
- No changes to external API of component

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant UI as X402LeftSection (UI)
  participant API as /api/paywall (GET)
  participant X4 as x402 Facilitator
  participant NW as Network/Settle

  U->>UI: Enter amount, payer, payTo
  UI->>API: GET /api/paywall?amount=...&payer=...&payTo=...
  Note over API: thirdweb client & facilitator initialized at module scope
  API->>X4: prepare settlement params (incl. payTo)
  X4->>NW: settlePayment({ ..., payTo })
  alt Success
    NW-->>X4: settlement result
    X4-->>API: payment details (incl. payTo)
    API-->>UI: 200 OK { ..., payTo }
  else Failure
    NW-->>X4: error
    X4-->>API: error
    API-->>UI: 4xx/5xx error
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description includes an embedded PR‐Codex overview but does not complete the required template sections: the initial template remains commented out and the mandatory headings “## Notes for the reviewer” and “## How to test” are left empty. Please uncomment and fill in the template by adding a concise PR title, detailed notes for reviewers, and clear “How to test” instructions with specific steps so the description aligns with the repository’s required structure.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly summarizes the main change by stating the key addition—introducing a payTo parameter to the X402 payment API—using concise phrasing and the appropriate [Playground] prefix to indicate its context.
✨ 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 _Playground_Add_payTo_parameter_to_X402_payment_API

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.

@codecov
Copy link

codecov bot commented Oct 9, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.02%. Comparing base (0082e99) to head (2e8fca4).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8231   +/-   ##
=======================================
  Coverage   55.02%   55.02%           
=======================================
  Files         919      919           
  Lines       60583    60583           
  Branches     4124     4124           
=======================================
  Hits        33333    33333           
  Misses      27146    27146           
  Partials      104      104           
Flag Coverage Δ
packages 55.02% <ø> (ø)
🚀 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 marked this pull request as ready for review October 9, 2025 21:15
@joaquim-verges joaquim-verges requested review from a team as code owners October 9, 2025 21:16
@joaquim-verges joaquim-verges merged commit 9086cdb into main Oct 9, 2025
24 of 26 checks passed
@joaquim-verges joaquim-verges deleted the _Playground_Add_payTo_parameter_to_X402_payment_API branch October 9, 2025 21:19
@github-actions
Copy link
Contributor

github-actions bot commented Oct 9, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.51 KB (0%) 1.3 s (0%) 281 ms (+230.03% 🔺) 1.6 s
thirdweb (cjs) 365.79 KB (0%) 7.4 s (0%) 874 ms (+18.77% 🔺) 8.2 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 178 ms (+5444.07% 🔺) 292 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 65 ms (+2246.36% 🔺) 75 ms
thirdweb/react (minimal + tree-shaking) 19.13 KB (0%) 383 ms (0%) 144 ms (+3855.53% 🔺) 526 ms

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)

151-165: Consider adding validation feedback.

The input field implementation is consistent with existing patterns and includes helpful placeholder and helper text. However, users would benefit from visual feedback when they enter an invalid address format.

Consider adding validation state and error messaging:

  <div className="flex flex-col gap-2">
    <Label htmlFor={payToId}>Pay To Address</Label>
    <Input
      id={payToId}
      type="text"
      placeholder="0x..."
      value={options.payTo}
      onChange={handlePayToChange}
      className="bg-card"
+     aria-describedby={`${payToId}-description`}
    />
-   <p className="text-sm text-muted-foreground">
+   <p id={`${payToId}-description`} className="text-sm text-muted-foreground">
      The wallet address that will receive the payment
    </p>
+   {options.payTo && !/^0x[a-fA-F0-9]{40}$/.test(options.payTo) && (
+     <p className="text-sm text-destructive">
+       Please enter a valid Ethereum address
+     </p>
+   )}
  </div>
apps/playground-web/src/app/api/paywall/route.ts (2)

42-42: Consider validating the payTo address format.

The payTo parameter extraction is correct and properly handles the optional case. However, consider adding validation to ensure it's a valid Ethereum address format before passing it to settlePayment.

Add validation after extraction:

  const payTo = queryParams.get("payTo") ?? undefined;
+ if (payTo && !/^0x[a-fA-F0-9]{40}$/i.test(payTo)) {
+   return NextResponse.json(
+     { error: "Invalid payTo address format" },
+     { status: 400 },
+   );
+ }

This prevents invalid addresses from reaching the payment settlement logic and provides clear error messages to clients.


75-78: Include payTo in the success response for consistency.

The success response includes amount and tokenAddress but omits the payTo parameter. For consistency and to help clients verify the payment destination, consider including payTo in the response.

Apply this diff to include payTo:

  payment: {
    amount,
    tokenAddress,
+   ...(payTo && { payTo }),
  },

This maintains backward compatibility by only including payTo when it's present.

📜 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 0082e99 and 2e8fca4.

📒 Files selected for processing (2)
  • apps/playground-web/src/app/api/paywall/route.ts (3 hunks)
  • apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from @/types or local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial, Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose

**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from @/types where applicable
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size

Files:

  • apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
  • apps/playground-web/src/app/api/paywall/route.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
  • apps/playground-web/src/app/api/paywall/route.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/* (Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() from @/lib/utils for conditional class logic
Use design system tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components (Node edge): Start files with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
  • apps/playground-web/src/app/api/paywall/route.ts
🧬 Code graph analysis (2)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)
packages/thirdweb/src/react/web/ui/components/formElements.tsx (1)
  • Label (20-28)
apps/playground-web/src/app/api/paywall/route.ts (2)
apps/playground-web/src/app/ai/api/types.ts (1)
  • API_URL (1-1)
packages/thirdweb/src/x402/facilitator.ts (1)
  • facilitator (107-262)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Size
🔇 Additional comments (1)
apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx (1)

48-48: LGTM!

The payToId declaration follows the established pattern and correctly uses the useId() hook for generating a unique ID.

Comment on lines +10 to +26
const client = createThirdwebClient({
secretKey: process.env.THIRDWEB_SECRET_KEY as string,
});

const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
// const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_SMART_WALLET as string;
const ENGINE_VAULT_ACCESS_TOKEN = process.env
.ENGINE_VAULT_ACCESS_TOKEN as string;
const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
// const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_SMART_WALLET as string;
const ENGINE_VAULT_ACCESS_TOKEN = process.env
.ENGINE_VAULT_ACCESS_TOKEN as string;
// const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
const API_URL = "http://localhost:3030";

const twFacilitator = facilitator({
baseUrl: `${API_URL}/v1/payments/x402`,
client,
serverWalletAddress: BACKEND_WALLET_ADDRESS,
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
});
const twFacilitator = facilitator({
baseUrl: `${API_URL}/v1/payments/x402`,
client,
serverWalletAddress: BACKEND_WALLET_ADDRESS,
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify error handling for module-scope initialization.

Moving the client and facilitator initialization to module scope is an appropriate optimization that reduces per-request overhead. However, ensure that initialization failures are handled gracefully.

Run the following script to verify error handling when environment variables are missing:

Consider adding validation at module scope to fail fast with clear error messages:

if (!process.env.THIRDWEB_SECRET_KEY) {
  throw new Error("THIRDWEB_SECRET_KEY environment variable is required");
}
if (!process.env.ENGINE_BACKEND_WALLET) {
  throw new Error("ENGINE_BACKEND_WALLET environment variable is required");
}

🏁 Script executed:

#!/bin/bash
# Description: Check if there's error handling for missing environment variables

# Search for error handling around these environment variables
rg -nP -A5 -B5 'THIRDWEB_SECRET_KEY|ENGINE_BACKEND_WALLET|ENGINE_VAULT_ACCESS_TOKEN' apps/playground-web/src/app/api/paywall/route.ts

# Search for any try-catch or error boundaries in API routes
rg -nP -A3 'export.*async.*function.*(GET|POST)' apps/playground-web/src/app/api/ --type ts

Length of output: 2016


Add validation for required environment variables

Validate and throw clear errors if THIRDWEB_SECRET_KEY, ENGINE_BACKEND_WALLET, or ENGINE_VAULT_ACCESS_TOKEN is undefined before module-scope initialization. For example:

if (!process.env.THIRDWEB_SECRET_KEY) {
  throw new Error("THIRDWEB_SECRET_KEY environment variable is required");
}
// …repeat for ENGINE_BACKEND_WALLET and ENGINE_VAULT_ACCESS_TOKEN
🤖 Prompt for AI Agents
In apps/playground-web/src/app/api/paywall/route.ts around lines 10 to 26, the
module currently reads process.env values at module scope without validating
them; add explicit checks at the top of the module to validate
THIRDWEB_SECRET_KEY, ENGINE_BACKEND_WALLET (or ENGINE_BACKEND_SMART_WALLET if
intended), and ENGINE_VAULT_ACCESS_TOKEN and throw clear, descriptive errors if
any are missing before creating the thirdweb client or facilitator; after
validation proceed to initialize createThirdwebClient and twFacilitator as
before so runtime failures are replaced by immediate, clear startup errors.

Comment on lines +18 to +19
// const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
const API_URL = "http://localhost:3030";
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 | 🔴 Critical

Critical: Hardcoded localhost URL will break in production.

The API URL is hardcoded to http://localhost:3030, which will fail in any non-local environment. This appears to be temporary test code based on the commented production URL.

Apply this diff to restore the production URL:

- // const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
- const API_URL = "http://localhost:3030";
+ const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;

Alternatively, if localhost testing is needed, use an environment variable to switch between environments:

const API_URL = process.env.X402_API_URL || `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
🤖 Prompt for AI Agents
In apps/playground-web/src/app/api/paywall/route.ts around lines 18 to 19, the
API_URL is hardcoded to "http://localhost:3030", which will break in production;
revert to using the production-safe environment-based value by restoring the
original production URL construction or use an environment-switching fallback
(e.g., read a dedicated X402_API_URL first, then fall back to
NEXT_PUBLIC_API_URL or "api.thirdweb.com") so the app uses the correct API
endpoint in non-local environments.

Comment on lines +85 to +90
const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setOptions((v) => ({
...v,
payTo: e.target.value as `0x${string}`,
}));
};
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 | 🟠 Major

Unsafe type assertion without validation.

The type assertion as 0x${string}`` does not validate that the user input is actually a valid Ethereum address. Users can enter any string, including empty values or malformed addresses, which could lead to payment failures or incorrect routing.

Consider adding validation to ensure the address:

  • Starts with "0x"
  • Contains only valid hexadecimal characters
  • Has the correct length (42 characters for Ethereum addresses)

Apply this diff to add basic validation:

  const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+   const value = e.target.value;
+   // Only update if empty or valid hex address format
+   if (value === '' || /^0x[a-fA-F0-9]{0,40}$/.test(value)) {
      setOptions((v) => ({
        ...v,
-       payTo: e.target.value as `0x${string}`,
+       payTo: value as `0x${string}`,
      }));
+   }
  };

Alternatively, use a proper address validation library like viem's isAddress() function for comprehensive validation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setOptions((v) => ({
...v,
payTo: e.target.value as `0x${string}`,
}));
};
const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// Only update if empty or valid hex address format
if (value === '' || /^0x[a-fA-F0-9]{0,40}$/.test(value)) {
setOptions((v) => ({
...v,
payTo: value as `0x${string}`,
}));
}
};
🤖 Prompt for AI Agents
In apps/playground-web/src/app/payments/x402/components/X402LeftSection.tsx
around lines 85 to 90, the handler unsafely casts user input to the template
type `0x${string}`; replace that with proper validation before updating state:
validate the input starts with "0x", is 42 characters long, and contains only
hex characters (or call a library helper like viem.isAddress), and only call
setOptions with the validated value (or set an error/validation state when
invalid) so malformed addresses are never stored via the type assertion.

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

Labels

Playground Changes involving the Playground codebase.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants