Skip to content

feat: migrate x402-proxy-template to x402 v2 with Solana support - #1087

Open
notorious-d-e-v wants to merge 3 commits into
cloudflare:mainfrom
notorious-d-e-v:feat/x402-v2-solana
Open

feat: migrate x402-proxy-template to x402 v2 with Solana support#1087
notorious-d-e-v wants to merge 3 commits into
cloudflare:mainfrom
notorious-d-e-v:feat/x402-v2-solana

Conversation

@notorious-d-e-v

@notorious-d-e-v notorious-d-e-v commented Jul 31, 2026

Copy link
Copy Markdown

Summary

Upgrades x402-proxy-template from x402 v1 to the current v2 protocol (@x402/* 2.19.0) and adds Solana support alongside Base. The legacy x402-* v1 packages haven't shipped since April 2026, and the template was hard-coded to a single EVM network.

Out of the box the template now advertises Base Sepolia and Solana devnet payment options on every protected route. NETWORK takes CAIP-2 identifiers (single or comma-separated) — the v1-era friendly names are gone entirely; a config still using one gets an explicit error naming the CAIP-2 format to switch to.

What changed

  • Middleware: legacy x402-hono@x402/hono with EVM + Solana schemes registered per configured network.
  • New PAY_TO_SOLANA var for Solana recipients (defaults to the well-known incinerator, mirroring the existing 0x…dEaD testing default).
  • Test client (test-client.ts) rewritten on @x402/fetch — works with an EVM key, a Solana key, or both.
  • Playwright spec and all docs (README/AGENTS/TESTING/wrangler comments) updated to the v2 wire format.
  • Removed the unused @coinbase/x402 dependency and the legacy x402 dev dependency.

Verification

Settled real USDC end-to-end (402 → pay → verify → settle → JWT cookie → cookie-only re-access) on all four networks, each confirmed on-chain:

Checks: npm run lint clean, Playwright 5/5, pnpm run check green.

Notes for AI Agent Reviewers

Implementation and verification detail

Implementation

  • Middleware construction (src/auth.ts): an x402ResourceServer registers ExactEvmScheme for eip155:* and ExactSvmScheme for solana:* networks, wrapped by @x402/hono's paymentMiddleware. The middleware is memoized at module scope keyed by a fingerprint of (facilitator URL, networks, recipients, route config), so the facilitator /supported sync runs once per isolate instead of per request. Measured: first protected request ~620 ms (sync), subsequent ~8 ms.
  • Route matching: the template's /*-suffix patterns are converted to x402 v2 route patterns whose compiled regexes are a strict superset of the template's startsWith semantics; index.ts remains the outer gate, and both matchers are first-match-in-insertion-order, so pricing selection is consistent.
  • Network resolution: CAIP-2 identifiers only (eip155:*, solana:*). Non-CAIP-2 entries (including pre-v2 names like base-sepolia) and missing per-family recipients return a JSON 500 config error with guidance (matching the existing JWT_SECRET error pattern) rather than crashing.
  • Recipients: PAY_TO covers eip155:*; PAY_TO_SOLANA covers solana:* and defaults to 1nc1nerator11111111111111111111111111111111, whose devnet USDC token account already exists — necessary because the v2 exact SVM scheme (unlike v1) does not create the recipient's associated token account, so a fresh address fails verification with a simulation error until it has received the token once. This constraint is documented in the README and wrangler comments.
  • Runtime: nodejs_compat compatibility flag added — the v2 middleware uses Buffer in its settlement path.
  • Test client: wrapFetchWithPayment + x402Client with optional EVM (PRIVATE_KEY) and Solana (SOLANA_PRIVATE_KEY, SOLANA_RPC_URL) signers; the client pre-filters the server's accepts to registered schemes, so either key works alone. Added TARGET_PATH override (defaults to /premium; the built-in /__x402/protected works without configuring an origin), prints the decoded PAYMENT-RESPONSE settlement receipt (network + tx hash), surfaces decoded rejection reasons on failed payments, and consumes response bodies so the process exits cleanly.
  • E2E spec: v2 assertions — requirements in the base64 PAYMENT-REQUIRED header, x402Version: 2, both default accepts (including the incinerator payTo and facilitator-injected extra.feePayer), and the SDK's static HTML fallback for browser requests when @x402/paywall isn't installed.

Compatibility

  • The 402 challenge is now v2-only (header-carried requirements). Custom API clients written against the v1 body format need a v2 client such as @x402/fetchtest-client.ts shows the pattern.
  • The default facilitator (https://x402.org/facilitator) verifies both shipped testnets, including the Solana devnet fee-payer sponsorship (extra.feePayer) the SVM scheme requires. Payers need no ETH/SOL: EVM payments are signed offline (EIP-3009) and Solana fees are sponsored via extra.feePayer; the facilitator submits transactions.

Additional manual verification (wrangler dev)

  • GET /__x402/health → 200; GET /__x402/config → resolved networks + masked per-family recipients.
  • GET /__x402/protected (default config) → 402 whose decoded PAYMENT-REQUIRED carries both accepts — eip155:84532 (USDC, amount 10000) and solana:EtWT… (devnet USDC mint 4zMMC9…, extra.feePayer injected).
  • NETWORK="base-sepolia" → explicit 500 config error: unknown NETWORK entry "base-sepolia"; use CAIP-2 identifiers such as eip155:84532.
  • Solana network enabled without PAY_TO_SOLANA → JSON 500 config error.
  • Browser UA + Accept: text/html → 402 HTML fallback page.
  • Each settlement above was independently confirmed on-chain (receipt status / transaction meta + recipient balance deltas).

🤖 Generated with Claude Code

Comment thread x402-proxy-template/wrangler.jsonc Outdated
@notorious-d-e-v

notorious-d-e-v commented Aug 1, 2026

Copy link
Copy Markdown
Author

Pushed a follow-up based on private feedback from @phdargen -- the feedback was that the template still has a lot of x402 v1 artifacts.

Now the v1-era network aliases are removed entirely. NETWORK now accepts CAIP-2 identifiers only (eip155:*, solana:*), and a config still using an old name gets an explicit error pointing at the CAIP-2 format (e.g. unknown NETWORK entry "base-sepolia"; use CAIP-2 identifiers such as eip155:84532).

All alias/legacy mentions are gone from the docs as well.

notorious-d-e-v and others added 3 commits August 12, 2026 22:49
Replace legacy x402-hono v1 middleware with @x402/hono 2.19.0. NETWORK now
accepts CAIP-2 identifiers (legacy aliases still resolve), one or many via
comma-separated list; each protected route advertises one payment option per
configured network. Adds PAY_TO_SOLANA for solana:* networks, memoizes the
payment middleware so facilitator sync runs once per isolate, migrates the
test client to @x402/fetch with optional EVM/Solana signers, and updates the
Playwright spec to the v2 wire format (PAYMENT-REQUIRED header).
Co-authored-by: Ethan Oroshiba <ethan.oroshiba@gmail.com>
Remove the v1-era network aliases per review feedback. NETWORK now takes
CAIP-2 identifiers exclusively; configs using an old name get an explicit
error pointing at the CAIP-2 format.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants