Skip to content

feat: settle in requirePayment + x402 v2 upgrade + unit/identity fixes#151

Merged
badjer merged 3 commits intomainfrom
fix/settle-in-requirepayment
Apr 7, 2026
Merged

feat: settle in requirePayment + x402 v2 upgrade + unit/identity fixes#151
badjer merged 3 commits intomainfrom
fix/settle-in-requirepayment

Conversation

@badjer
Copy link
Copy Markdown
Contributor

@badjer badjer commented Apr 7, 2026

Summary

Moves settlement from Express middleware to requirePayment() (stateless design), upgrades x402 to v2 packages, and fixes unit/identity mismatches.

Architecture: settle in requirePayment

  • Middleware detects credential → stores in ATXP context
  • requirePayment() settles with full pricing context (regenerates X402 requirements from server config)
  • Standard X402 pattern: server is stateless, no stored challenge data needed

x402 v2 upgrade

  • @x402/core + @x402/evm replace x402 v1 package
  • v2 types: amount (not maxAmountRequired), CAIP-2 networks, x402Version 2
  • PAYMENT-SIGNATURE header (v2) detected alongside X-PAYMENT (v1 fallback)
  • EIP-712 domain params included in X402 accepts for facilitator validation

Unit/identity fixes

  • X402/MPP settle: convert micro-units → USDC (÷1e6) before ledger credit
  • X402 identity: falls back to OAuth sub (matches charge sourceAccountId)
  • Settlement errors throw McpError(-32000) instead of silent fallback

E2E Verified

Full X402 payment on Base mainnet via CDP facilitator:

  • 0x23f9260e913ca98d04c4496aaf4f2eff65dce2ef8446bbc5216e4e281b79b169
  • Tool result returned to client ✅

Test plan

  • ATXP pull mode: challenge → authorize → settle → charge → Result
  • X402 via ATXPAccount: challenge → authorize x402 → Permit2 → settle on-chain → charge → Result
  • Legacy mode (flag OFF): unchanged behavior
  • Unit conversion: micro-USDC settled → USDC credited to ledger
  • Identity: OAuth sub used for both settle credit and charge debit
  • 159 server tests, 200 client tests, 17 express tests pass

🤖 Generated with Claude Code

badjer and others added 3 commits April 7, 2026 11:54
…sign)

Settlement now happens inside requirePayment() instead of the Express
middleware. This is the correct design because:

1. requirePayment has the pricing context (amount, options, destination)
   needed to regenerate protocol-specific settlement data
2. For X402, the server regenerates paymentRequirements from its own config
   (standard X402 pattern — no state from previous request needed)
3. The middleware's only job is detection + context storage

Flow:
- Middleware: detectProtocol() → setDetectedCredential() in ATXP context
- requirePayment: getDetectedCredential() → settle with pricing context → charge from credited ledger

Changes:
- atxpContext: DetectedCredential type, get/setDetectedCredential helpers
- requirePayment: settleDetectedCredential() with full pricing context
  - X402: fetches destination sources, builds requirements, passes to settle
  - ATXP: passes sourceAccountToken + options
  - MPP: passes credential (self-contained)
- atxpExpress: simplified — detect + store credential, no settlement logic
- protocol.ts: X402PaymentOption adds asset field, buildRequestBody extracts
  first accept from X402PaymentRequirements for auth schema compatibility
- omniChallenge: includes asset + mimeType in X402 accepts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Settlement failure throws McpError(-32000) instead of swallowing error
  and falling through to confusing insufficient_balance + new challenge
- 3 new tests: settlement success, settlement failure (McpError), no credential
- Removed unused X402PaymentRequirements import
- Documented: testnet asset/network mismatch, per-request ProtocolSettlement,
  first-accept extraction rationale

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…r cleanup

- Express middleware tests updated: verify credential stored in context,
  handler proceeds (no settle/402 from middleware)
- Fix payeeName null handling inconsistency
- Remove temp cli-base-temp.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@badjer badjer merged commit 791e5d4 into main Apr 7, 2026
1 check passed
@badjer badjer deleted the fix/settle-in-requirepayment branch April 7, 2026 20:48
@badjer badjer changed the title feat: move settlement from middleware to requirePayment (stateless X402) feat: settle in requirePayment + x402 v2 upgrade + unit/identity fixes Apr 7, 2026
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.

1 participant