Skip to content

examples: pay-on-proof (PayPal, Braintree, USDC/x402): an agent pays only against a verified INAM receipt - #169

Merged
hheskihoran merged 6 commits into
mainfrom
examples/pay-on-proof
Nov 11, 2026
Merged

hheskihoran merged 6 commits into
mainfrom
examples/pay-on-proof

Conversation

@hheskihoran

Copy link
Copy Markdown
Member

What

examples/pay-on-proof/: an AI agent may move money only against a verified INAM receipt.

  1. checkTrust(seller). A deny stops the run before any payment call.
  2. The rail holds the payment:
    • PayPal: Orders v2 AUTHORIZE.
    • Braintree: authorizePaymentMethod.
    • USDC: a signed EIP-3009 authorization that is kept, not submitted.
  3. The seller delivers and signs an INAM receipt naming the delivery hash and the hold.
  4. acceptWork with what actually arrived and what is actually held:
    • match: countersign, then capture.
    • MISMATCH / NOT_COMPARED: void. The payer is never charged.

The same receipt and the same reputation come out of every rail. The gates are plain code. The optional AI (Gemini or Claude) writes the seller's work and explains each step; it cannot move money.

Verified

  • Live Braintree sandbox:
    • honest: 12.00 EUR authorized, then captured against a finalized receipt.
    • swap and overclaim: authorized, then voided (MISMATCH).
    • unknown seller: refused before any Braintree call.
    • A currency misconfiguration was voided by the hold check (HOLD_MISMATCH).
  • PayPal and USDC: these rails ran only against stand-ins with the documented response shapes. No PayPal sandbox account was available (PayPal does not serve Turkey), and no x402 testnet settle was run. The README says so.
  • tests/payOnProof.test.ts: 14/14 pass.
    • All four scenarios run on all three rails.
    • One reputation across rails.
    • The EIP-712 domain separator is pinned to Base Sepolia USDC.
  • tsc --noEmit is clean.

Also

.env and .env.* are now gitignored. .env.example lists every key.

🤖 Generated with Claude Code

hheskihoran and others added 6 commits November 10, 2026 22:51
…receipt, void otherwise)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d EIP-3009 payload kept, capture = facilitator verify+settle, void = discard)

A small Rail interface (hold, confirm, capture, void) replaces the PayPal-only
path; PayPalRail adapts the existing client. X402Rail signs the EIP-712
transferWithAuthorization with @noble/curves (no new dependency) for USDC on
Base Sepolia; its domain separator is pinned against the on-chain value.
mockFacilitator() checks signature, recipient, amount, expiry and nonce reuse.
The server takes ?rail=paypal|usdc and goes live on USDC only when
X402_BUYER_PRIVATE_KEY and X402_SELLER_ADDRESS are set. The UI gets a rail
toggle and a Rail ledger column. Tests run all four scenarios on both rails
and check that one seller's reputation counts jobs from both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rse) and .env loading

Braintree is the PayPal-family sandbox open to developers outside PayPal's
markets; fake-paypal-one-time-nonce stands in for a PayPal wallet payment.
.env and .env.* are now gitignored; .env.example lists every key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Node 22.13+, names all three rails

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hheskihoran
hheskihoran merged commit 54aacf7 into main Nov 11, 2026
10 checks passed
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