Skip to content

Feat/add cardano exact implementation - #2

Merged
Kammerlo merged 6 commits into
mainfrom
feat/add-cardano-exact-implementation
May 4, 2026
Merged

Feat/add cardano exact implementation#2
Kammerlo merged 6 commits into
mainfrom
feat/add-cardano-exact-implementation

Conversation

@Kammerlo

Copy link
Copy Markdown
Member

Description

Adds the exact scheme for Cardano to multiple x402 SDKs:

  • TypeScript: full client/server/facilitator (typescript/packages/mechanisms/cardano)
  • Python: full client/server/facilitator (python/x402/mechanisms/cardano)
  • Go: server-role only (go/mechanisms/cardano)
  • Java: server filter + facilitator HTTP client (java/src/main/java/org/x402/cardano)

Implements the spec at specs/schemes/exact/scheme_exact_cardano.md, including
the six facilitator verification rules (network, recipient, amount, asset,
nonce/UTXO replay prevention, TTL) plus structural unsigned-tx rejection,
atomic duplicate-settlement guard, and fail-safe rejection of script-mode
payments by default.

Also adds an optional extensions field to the generic Python SettleResponse
so the Cardano facilitator can surface the spec's extensions.status.

Tests

  • TypeScript: pnpm test from typescript/packages/mechanisms/cardano → 41 passing.
  • Python: uv run pytest tests/unit/mechanisms/cardano → 39 passing.
  • Go: go test ./mechanisms/cardano/... → all passing.
  • Java: mvn -f java/pom.xml test → all passing.
  • Real-CBOR end-to-end smoke check per specs/schemes/exact/scheme_exact_cardano_TESTING.md §4.

Disclosure

Substantial portions of this implementation were drafted & written with Claude Code;
all logic was reviewed against the spec and verified to pass tests by the
author.

Checklist

  • Formatted and linted
  • Tests pass
  • Commits signed
  • Changelog fragments added (TS Changeset, Python Towncrier, Go Changie)

Kammerlo and others added 4 commits April 29, 2026 08:15
Resolved conflicts:
- python/x402/schemas/responses.py: kept both extensions (Cardano) and amount (main) fields
- python/x402/uv.lock, typescript/pnpm-lock.yaml: accepted main's lock files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@fabianbormann fabianbormann left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think my comment on the Java dto is probably the same for all languages. Could you check against the schema?

Comment thread java/src/main/java/org/x402/cardano/PaymentResponseHeader.java Outdated
Comment thread java/src/main/java/org/x402/cardano/PaymentResponseHeader.java
@Kammerlo
Kammerlo requested a review from fabianbormann April 30, 2026 04:34
@Kammerlo
Kammerlo merged commit 5a8d85b into main May 4, 2026
16 checks passed
@Kammerlo
Kammerlo deleted the feat/add-cardano-exact-implementation branch August 20, 2026 13:35
Kammerlo pushed a commit that referenced this pull request Aug 24, 2026
…dation#2698)

* docs(svm): add `batch-settlement` SVM scheme specification

SVM profile of the network-agnostic `batch-settlement` scheme: high-throughput
channel payments where a client deposits once, signs cumulative Ed25519 vouchers
verified off-chain, and the operator redeems the latest voucher per channel
on-chain in batches. The multi-voucher generalization of `upto`.

* docs(svm/batch): cascade upto role-model + cleanups to batch-settlement

Mirrors the upto spec revision, adapted for batch's client-signed cumulative
vouchers:

- Role model: the operator is the channel `payee` (the program requires the
  `settle_and_finalize` merchant == `channel.payee`), as well as fee payer and
  `rentPayer`; `authorizedSigner` stays the payer (client signs vouchers). `payTo`
  is realized as the payee (self-facilitating, `operator == payTo`) or a
  `distributionSplits` entry (separate facilitator). Added the self-facilitating
  reference-status note and set `payee = operator` / `rentPayer = operator` at open.
- Cleanups (match upto): dropped the `pay-kit`-controlled / `CHNLxY` program-id /
  "program we control" references.
- Clarified that `expiresAt` is a genuine *client* commitment here (the client
  signs each voucher), unlike upto's operator-attested field.

Deliberately NOT cascaded: `deposit == maxAmount` — batch's deposit is a
multi-request escrow, so the ceiling is `cumulativeAmount ≤ deposit`, not equality.

* docs(svm/batch): address review feedback (security, conformance, clarity)

Resolves @notorious-d-e-v's review on PR x402-foundation#2698 (verified against the
payment-channels program where relevant):

- Voucher replay (#8): the cumulativeAmount is the per-request nonce — a new
  request needs a strict increment (watermark + amount); an equal voucher is only
  an idempotent retry that replays the response cached at that cumulative, never a
  fresh serve.
- Async expiry (#9): expires_at is re-checked on-chain at settle (not just
  settleAndFinalize), so vouchers must use expiresAt == 0 or a TTL outlasting the
  redemption window (grace + buffer).
- Fee-payer guard (#7): validate the full compiled open tx (ALT resolution,
  allowed-instruction-set only, fee payer never an authority/source/writable
  except fees), per the exact SVM scheme.
- State ownership (#3): the watermark/ChannelStore is the resource server's state;
  a separate facilitator stays stateless.
- Response shape (#6): nest chargedAmount/channelState under extra, amount
  optional (core SettleResponse + EVM batch companion).
- asset is the concrete mint, not a symbol (#5); dropped SDK function names (#1);
  added a grace buffer SHOULD (#2); genericized the per-tx settle cap (#10).

* docs(svm): align batch-settlement spec with channels

* docs(svm): align batch settlement wire contract

* docs(svm): refine batch settlement lifecycle

* docs(svm): add batch refund authorization

* docs(svm): define batch refund fallback

Make payer-signed request_close the portable refund path, with facilitator-funded initiation and asynchronous finalization after a bounded grace period. Keep authenticated cooperative close as an optional fast path and align setup validation with the current SVM upto profile.

Co-authored-by: Ludo Galabru <ludo.galabru@solana.org>
Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>

* docs(svm): drop block height hint

Co-authored-by: Ludo Galabru <ludo.galabru@solana.org>
Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>

* docs(svm): batch-settlement review follow-ups

- switch the scheme to the protocol-default authorization payment flow:
  read-only verify before the handler, voucher commit and deposit
  broadcast in the post-handler settle
- clarify that the 900-2592000 withdrawDelay range is an x402
  conformance bound enforced by facilitators, not a program constraint
- quantify the voucher-expiry settlement buffer via an advertised
  extra.settlementBufferSeconds (default 60) so clients can compute a
  passing expiresAt from the 402 alone
- require clients to verify the corrective 402 voucherState signature
  before adopting chargedCumulativeAmount

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(svm): add settlement-buffer error code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(svm): make non-expiring vouchers normative

Voucher expiry added a second clock the server had to beat on top of the
forced-close grace period, and a nonzero expiresAt could make an accepted
voucher unredeemable while the channel was still open. The client MUST now
sign expiresAt = 0, the server and facilitator MUST reject nonzero values,
and extra.settlementBufferSeconds is dropped along with the expiry-window
bound.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: Ludo Galabru <ludo.galabru@solana.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants