From 2e42884dd768362b17e437190735aaea28843572 Mon Sep 17 00:00:00 2001 From: Julio M Cruz Date: Wed, 29 Jul 2026 04:24:11 +0200 Subject: [PATCH] feat(x402): namespace the deferred scheme and add the v2 Discovery API Implements the actionable findings from STACK-PROTOCOL-RESEARCH-2026-07-29.md. Scheme namespace (research R1) x402 v2 standardizes exactly one scheme, `exact`. `deferred`, `upto` and batch-settlement are proposed, and the namespace is now governed by the x402 Foundation TSC under the Linux Foundation. Stack was advertising a PerkOS-designed voucher scheme as `deferred`, so a future spec release could redefine a string existing clients already negotiate. Stack now advertises `perkos-deferred`. The bare `deferred` name is still accepted on verify/settle and answers with an `X-x402-Deprecation` header, so no client breaks. Scheme handling is centralized in lib/utils/x402-schemes.ts and fails closed on unknown identifiers instead of falling through to a default handler. Transaction filters match the whole scheme family, so rows written before the rename stay visible. Discovery API (research R2) Adds `GET /api/discovery/resources`, the spec-defined listing with limit/offset pagination and type filtering. This is how facilitators index each other; Stack previously had only /.well-known/x402-discovery.json, which is PerkOS metadata about the facilitator rather than a resource listing. Endpoints are read in one batched query per page rather than per vendor. Docs (research R4, R6, R7) - CLAUDE.md documented the v1 request shape the code stopped emitting a major version ago: bare network names instead of CAIP-2, no `accepted` echo. Now v2. - Adds a protocol status table stating plainly that none of x402, ERC-8004, x401 or ERC-8183 is a finalized standard, with the wording to avoid. - Docs/PROTOCOL-PIN-REVIEW.md: monthly re-pin checklist for all four. Unrelated pre-existing fixes, needed to verify any of the above - lib/utils/chains.ts imported `megaeth` from viem/chains, which does not export it (only `megaethTestnet`). package-lock.json is untracked, so any fresh install resolves ^2.44.1 and main does not build. Removed the mainnet entry rather than invent a chain ID; MegaETH mainnet launched 2026-02-09 but its ID is not confirmed in a primary source and its payment token here was the zero-address placeholder. Re-add once viem ships it. - `npm test` ran without --experimental-strip-types, so on Node 23.3 every suite failed with ERR_UNKNOWN_FILE_EXTENSION on the .ts imports. Verified: typecheck clean (first time), npm test 22/22 including 5 new scheme tests, npm run build compiles with /api/discovery/resources registered. --- CLAUDE.md | 121 ++++++++++--- Docs/PROTOCOL-PIN-REVIEW.md | 93 ++++++++++ StackApp/app/(public)/transactions/page.tsx | 4 +- .../.well-known/x402-discovery.json/route.ts | 7 +- .../.well-known/x402-payment.json/route.ts | 3 +- StackApp/app/api/deferred/vouchers/route.ts | 5 +- StackApp/app/api/discovery/resources/route.ts | 162 ++++++++++++++++++ StackApp/app/api/v2/agents/onboard/route.ts | 3 +- StackApp/app/api/v2/x402/config/route.ts | 3 +- StackApp/app/api/v2/x402/health/route.ts | 3 +- StackApp/app/api/v2/x402/settle/route.ts | 13 +- StackApp/app/api/v2/x402/verify/route.ts | 13 +- StackApp/app/api/x402/transactions/route.ts | 6 +- .../lib/services/TransactionLoggingService.ts | 2 +- StackApp/lib/services/X402Service.ts | 38 ++-- StackApp/lib/utils/chains.ts | 5 +- StackApp/lib/utils/x402-payment.ts | 2 +- StackApp/lib/utils/x402-schemes.ts | 85 +++++++++ StackApp/package.json | 2 +- StackApp/tests/x402-schemes.test.cjs | 59 +++++++ 20 files changed, 575 insertions(+), 54 deletions(-) create mode 100644 Docs/PROTOCOL-PIN-REVIEW.md create mode 100644 StackApp/app/api/discovery/resources/route.ts create mode 100644 StackApp/lib/utils/x402-schemes.ts create mode 100644 StackApp/tests/x402-schemes.test.cjs diff --git a/CLAUDE.md b/CLAUDE.md index 0c4bdc1..f6d71f8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,28 @@ **PerkOS Stack** is enterprise-grade agent infrastructure that provides the complete backbone for building agent-powered applications. Built on the x402 protocol, PerkOS Stack delivers production-ready REST APIs, micropayment infrastructure, agent discovery, and ERC-8004 identity management in one unified platform. -Supports both exact (EIP-3009) and deferred (EIP-712) payment schemes across multiple blockchain networks with native multi-chain support. +Supports both exact (EIP-3009) and PerkOS deferred (EIP-712) payment schemes across multiple blockchain networks with native multi-chain support. + +## Protocol status — read before writing copy + +**None of the four protocols Stack builds on is a finalized standard.** Claiming +otherwise in docs, marketing or a pitch is a factual error. Verified 2026-07-29 +against primary sources; full analysis in `STACK-PROTOCOL-RESEARCH-2026-07-29.md` +(workspace root). + +| Protocol | Accurate description | Do **not** say | +|---|---|---| +| **x402** | v2 live, governed by the x402 Foundation under the Linux Foundation since 2026-07-14. Only `exact` is standardized. | "final", "v1.0", "`deferred` is standard" | +| **ERC-8004** | **Draft** EIP (created 2025-08-13). Canonical registries are deployed on 30+ chains; Validation Registry still experimental. | "Final", "ratified" — deployment is not ratification | +| **x401** | **Draft 0.2.0**. No standards body has adopted it; a FIDO Alliance submission is announced, not completed. | "finalized", "FIDO standard", "every credential ecosystem supported" | +| **ERC-8183** | **Draft** EIP (created 2026-02-25). | "Final" | + +The honest framing to reuse, modeled on `Docs/X401-STATUS-2026-07-22.md`: + +> Stack implements a security-hardened verifier profile for x401 Draft 0.2.0, +> using Proof's official Node SDK and OpenID4VP credential verification. + +Re-pin review process: `Docs/PROTOCOL-PIN-REVIEW.md`. ### Key Features @@ -249,20 +270,52 @@ See [DATABASE_TABLES.md](MiddlewareApp/DATABASE_TABLES.md) for complete schema r ## x402 Protocol Implementation +Stack speaks the **x402 v2** envelope. The protocol is governed by the +[x402 Foundation](https://x402.org) under the Linux Foundation since 2026-07-14; +its Technical Steering Committee owns the specification and the scheme +namespace. v2 is live, but it is not a frozen v1.0 — treat it as a moving target. + +**v2 differences that matter when writing a client:** + +- `x402Version` is `2` +- `network` is **CAIP-2** (`eip155:43114`), not a bare name (`avalanche`) +- `paymentPayload.accepted` echoes the requirements and **must match them + field by field** — Stack rejects a mismatch rather than trusting the payload +- `extensions` and `signers` are part of the response surface + +v1 and a pre-standard flat v2 shape are still accepted as a migration bridge +(`lib/utils/x402-normalization.ts`), but new integrations should emit v2. + ### Payment Schemes +**Only `exact` is standardized by x402 v2.** `upto`, `deferred` and +batch-settlement are proposed but not ratified. Stack's aggregated-voucher +settlement therefore advertises the vendor-prefixed name **`perkos-deferred`** +so it does not squat an identifier the TSC may define differently. The bare +`deferred` string is still accepted on input and answers with an +`X-x402-Deprecation` header; it is never advertised. See +`lib/utils/x402-schemes.ts`. + #### 1. Exact Scheme (EIP-3009) Immediate payment execution using EIP-3009 `transferWithAuthorization`. -```typescript -// Example: Exact payment verification -POST /api/v2/x402/verify +```jsonc +// POST /api/v2/x402/verify { - "x402Version": 1, + "x402Version": 2, "paymentPayload": { + "x402Version": 2, "scheme": "exact", - "network": "avalanche", + "network": "eip155:43114", // CAIP-2 + "accepted": { // must equal paymentRequirements + "scheme": "exact", + "network": "eip155:43114", + "amount": "1000000", + "asset": "0x...", + "payTo": "0x...", + "maxTimeoutSeconds": 3600 + }, "payload": { "signature": "0x...", "authorization": { @@ -277,28 +330,43 @@ POST /api/v2/x402/verify }, "paymentRequirements": { "scheme": "exact", - "network": "avalanche", - "maxAmountRequired": "1000000", - "resource": "/api/service", + "network": "eip155:43114", + "amount": "1000000", + "asset": "0x...", "payTo": "0x...", "maxTimeoutSeconds": 3600, - "asset": "0x..." + "resource": "/api/service" } } ``` -#### 2. Deferred Scheme (EIP-712) +#### 2. PerkOS Deferred Scheme (EIP-712) — `perkos-deferred` -Off-chain voucher aggregation with batch settlement. +Off-chain voucher aggregation settled against an escrow contract. **This is a +PerkOS scheme, not an x402 standard one.** Clients still sending `deferred` keep +working and receive `X-x402-Deprecation` on the response. -```typescript -// Example: Deferred payment verification -POST /api/v2/x402/verify +```jsonc +// POST /api/v2/x402/verify { - "x402Version": 1, + "x402Version": 2, "paymentPayload": { - "scheme": "deferred", - "network": "avalanche", + "x402Version": 2, + "scheme": "perkos-deferred", + "network": "eip155:43114", + "accepted": { + "scheme": "perkos-deferred", + "network": "eip155:43114", + "amount": "1000000", + "asset": "0x...", + "payTo": "0x...", + "maxTimeoutSeconds": 3600, + "extra": { + "type": "aggregation", + "escrow": "0x...", + "facilitator": "https://stack.perkos.xyz" + } + }, "payload": { "voucher": { "id": "0x...", @@ -315,13 +383,13 @@ POST /api/v2/x402/verify } }, "paymentRequirements": { - "scheme": "deferred", - "network": "avalanche", - "maxAmountRequired": "1000000", - "resource": "/api/service", + "scheme": "perkos-deferred", + "network": "eip155:43114", + "amount": "1000000", + "asset": "0x...", "payTo": "0x...", "maxTimeoutSeconds": 3600, - "asset": "0x...", + "resource": "/api/service", "extra": { "type": "aggregation", "escrow": "0x...", @@ -331,6 +399,13 @@ POST /api/v2/x402/verify } ``` +### Discovery + +| Endpoint | What it is | +|---|---| +| `GET /api/discovery/resources` | **x402 v2 spec** resource listing (`limit`, `offset`, `type`). How other facilitators index Stack's resources. | +| `GET /.well-known/x402-discovery.json` | PerkOS metadata about the facilitator itself. Not a spec endpoint. | + ### Supported Networks | Network | Chain ID | Type | USDC Address | Status | diff --git a/Docs/PROTOCOL-PIN-REVIEW.md b/Docs/PROTOCOL-PIN-REVIEW.md new file mode 100644 index 0000000..5e8a47b --- /dev/null +++ b/Docs/PROTOCOL-PIN-REVIEW.md @@ -0,0 +1,93 @@ +# Protocol pin review + +Stack builds on four protocols. **All four are moving drafts** — three EIPs in +Draft status and one vendor specification at Draft 0.2.0. A pin that was correct +last month can be a compatibility break this month, and none of these publish a +changelog we get notified about. + +Run this review **monthly**, and always before a release that touches payment, +identity or commerce surfaces. + +Baseline established 2026-07-29 (`STACK-PROTOCOL-RESEARCH-2026-07-29.md`, workspace root). + +--- + +## What to check + +### 1. x402 + +| | | +|---|---| +| Source of truth | [x402 v2 spec](https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md), [x402.org](https://x402.org) | +| Governance | x402 Foundation / Linux Foundation TSC since 2026-07-14 | +| Pinned in Stack | `@x402/core`, `@x402/fetch`, `@x402/stellar` (`^2.19.0`) | +| Baseline | v2 live; **only `exact` standardized** | + +Check: + +- [ ] Has the TSC ratified any new scheme? **Especially `deferred`, `upto` or batch-settlement.** If `deferred` is standardized, compare its semantics against `perkos-deferred` in `lib/utils/x402-schemes.ts` and decide whether to implement the standard one alongside ours. +- [ ] Has a v1.0 been tagged? Backward-compatibility guarantees are expected to start there. +- [ ] Any change to the `PaymentRequirements` required fields, the `accepted` echo rule, or CAIP-2 handling? +- [ ] Does `GET /api/discovery/resources` still match the Discovery extension shape? +- [ ] `npm outdated @x402/core @x402/fetch @x402/stellar` + +### 2. ERC-8004 + +| | | +|---|---| +| Source of truth | [EIP-8004](https://eips.ethereum.org/EIPS/eip-8004), [erc-8004/erc-8004-contracts](https://github.com/erc-8004/erc-8004-contracts) | +| Pinned in Stack | Canonical addresses in `lib/utils/config.ts`; hand-maintained ABIs in `lib/contracts/erc8004/abis.ts` | +| Baseline | EIP **Draft**; Identity + Reputation live on 30+ chains; Validation **experimental** | + +Check: + +- [ ] EIP Status field — still Draft, or moved to Review / Last Call / Final? +- [ ] **Has the Validation Registry been officially deployed?** It was blocked on TEE-community discussion. If it ships, set the address instead of relying on the `NEXT_PUBLIC__VALIDATION_REGISTRY` override. +- [ ] Did the canonical addresses change, or gain new chains? Compare the reference repo against `ERC8004_MAINNET_ADDRESSES` / `ERC8004_TESTNET_ADDRESSES` / `ERC8004_OFFICIAL_NETWORKS`. +- [ ] Any ABI change that invalidates `lib/contracts/erc8004/abis.ts`? +- [ ] Has `@perkos/contracts-erc8004` been republished past `1.0.1`? It still describes pre-v2 contracts, which is why Stack keeps its own ABIs. If it is fixed, drop the local copies. + +### 3. x401 + +| | | +|---|---| +| Source of truth | [x401.proof.com/spec/latest](https://x401.proof.com/spec/latest/) | +| Pinned in Stack | `@proof.com/x401-node` (`^0.3.0`), profile documented in `Docs/X401-STATUS-2026-07-22.md` | +| Baseline | **Draft 0.2.0**, SDK 0.3.0, no standards-body adoption | + +Check: + +- [ ] Spec version — still 0.2.0? **0.2.0 was already a breaking redesign of 0.1.0, so assume a 0.3.0 breaks the wire format.** Diff the header names and the `credential_requirements` shape before bumping. +- [ ] Did the FIDO Alliance agentic authentication workgroup accept the submission? That process may reshape the wire format. +- [ ] Upstream open questions moved? Multi-endpoint proof requests, agent-asserted origins, autonomous delegation, proof/payment binding. +- [ ] `npm outdated @proof.com/x401-node` +- [ ] Does `Docs/X401-STATUS-2026-07-22.md` still describe reality? If not, supersede it with a dated successor rather than editing history. + +### 4. ERC-8183 + +| | | +|---|---| +| Source of truth | [EIP-8183](https://eips.ethereum.org/EIPS/eip-8183), [erc-8183/base-contracts](https://github.com/erc-8183/base-contracts) | +| Pinned in Stack | Submodule at commit `142e669c1fd318486a4628395b629f033654dd06` | +| Baseline | EIP **Draft** (created 2026-02-25); deployed + certified on Robinhood Testnet | + +Check: + +- [ ] EIP Status field, and whether the Job state machine or role model changed. +- [ ] New releases on `erc-8183/base-contracts`. Repin **deliberately** — read the diff, do not follow a branch. +- [ ] **Has `ERC8183WithAuthorization` been slimmed under the EIP-170 limit?** Stack excludes it today, which costs meta-transactions and gasless job actions. If upstream fixes the size, reconsider. +- [ ] Re-run `forge test` and confirm the runtime size margin in `Docs/ROBINHOOD-TESTNET-ERC8183-DEPLOYMENT.md` still holds. + +--- + +## After the review + +1. Note the date and outcome below, even when nothing changed — "checked, no change" is the useful signal. +2. If any status field moved, update the table in `CLAUDE.md` ("Protocol status") in the same PR. +3. If a pin changed, say so in the PR body with the diff you read, not just the version bump. + +## Log + +| Date | Reviewer | Outcome | +|---|---|---| +| 2026-07-29 | Baseline | x402 v2 / LF governance; ERC-8004 Draft, addresses verified, Validation still experimental; x401 Draft 0.2.0 + SDK 0.3.0 current; ERC-8183 Draft, pin current | diff --git a/StackApp/app/(public)/transactions/page.tsx b/StackApp/app/(public)/transactions/page.tsx index a683dd2..deb2276 100644 --- a/StackApp/app/(public)/transactions/page.tsx +++ b/StackApp/app/(public)/transactions/page.tsx @@ -51,7 +51,7 @@ interface ApiResponse { export default function TransactionsPage() { const [timeRange, setTimeRange] = useState<"24h" | "7d" | "30d">("7d"); - const [schemeFilter, setSchemeFilter] = useState<"all" | "exact" | "deferred">("all"); + const [schemeFilter, setSchemeFilter] = useState<"all" | "exact" | "perkos-deferred">("all"); const [chartData, setChartData] = useState>([]); const [transactions, setTransactions] = useState([]); const [stats, setStats] = useState({ @@ -298,7 +298,7 @@ export default function TransactionsPage() {
{/* Scheme Filter */}
- {(["all", "exact", "deferred"] as const).map((scheme) => ( + {(["all", "exact", "perkos-deferred"] as const).map((scheme) => (