open-standards/jcp/jcp-rs/crates/jcp-x402/Cargo.toml
Transaction Science f5e5ee7c20
All checks were successful
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 4m35s
jcp-x402: upto is the dual ceiling's own scheme, so settle down and seal what was measured
The crate refused `upto`, for a stated reason: nothing downstream read the
scheme, so an accepted `upto` would be gated as `exact` — its per-request
*maximum* charged as the price, with no reconciliation afterwards, exhausting a
session's money ceiling many times too fast. The refusal named what was
missing: "honouring `upto` needs a settle-down reconciliation that does not
exist". This is that reconciliation.

`upto` is the scheme a joule-budgeted profile was always shaped for. The buyer
authorizes a maximum and the server charges what the work consumed, by sending
a different `amount` at settlement than the one it verified. Authorization
still debits the maximum, and that is correct rather than conservative: before
the work runs the maximum is the only upper bound in existence, and a ceiling
that admits on an estimate is not a ceiling. `settle_upto` then enforces the
scheme's one hard bound (settled <= authorized, 0 legal) before anything is
sealed — a facilitator re-verifies the signature against the signed maximum, so
an over-authorized settle does not buy a larger payment, it loses the
settlement after the work is already done.

What the scheme leaves out is the point. `upto` defines **no metering or
usage-reporting fields**: the server measures, names one number, and nothing in
the protocol says the measurement happened. The sealed receipt commits to that
number, the maximum it was settled against, the transaction, and the metered
joules at their meter's grade — so a server that later reports different usage
for the same transaction contradicts a signature rather than an invoice line.
An `exact` settlement omits both money figures and keeps its content id
byte-identical to one computed before the field existed.

The unused reservation is reported, not silently absorbed: `over_reserved_minor`
is what the session held and never spent. It is not credited back, because the
runtime's money counter is monotonic by design — that is what makes a ceiling
enforceable across concurrent holders with no consensus — so a release is a
change to the enforcement model, not to this profile. Until there is one, an
`upto` session sizes its ceiling to the sum of its maxima.

Ingest also reads v2: the charge is `amount` there and `maxAmountRequired` in
v1, both live, and the declared version is recorded because a caller
reconciling against a server's logs needs to know which it read. An
x402Version this crate has never seen is refused rather than read as v1.
Networks stay unparsed and compared for equality — two spellings of one chain
are two grant audiences, which is the safe direction to fail.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-10 12:32:13 -05:00

24 lines
1.2 KiB
TOML

[package]
name = "jcp-x402"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "x402 profile of JCP — ingest an x402 PaymentRequirements from either live wire version (v2 `amount`, v1 `maxAmountRequired`): its stablecoin charge becomes the grant's money ceiling, SPEC §4.8, paired with an operator-set joule ceiling, and every payment is gated against both outside the model and sealed in a JCR-1 receipt. A charge past the money cap, in a foreign asset, or to the wrong merchant is denied before the agent pays, never converted. v2's `upto` scheme settles down to measured usage and defines no metering fields; settle_upto enforces its bound and seals the settled figure beside the transaction and the metered joules at their grade. Ingest, not compete."
[dependencies]
jcp-schema = { workspace = true }
jcp-grant = { workspace = true }
jcp-runtime = { workspace = true }
jcp-receipt = { workspace = true }
jcp-bridge = { workspace = true }
ed25519-dalek = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
# The pay example meters its paid compute with this host's meter.
[dev-dependencies]
jcp-energy = { workspace = true }
[lints]
workspace = true