feat(rust/x402): add the batch-settlement scheme on Solana#177
Draft
lgalabru wants to merge 2 commits into
Draft
feat(rust/x402): add the batch-settlement scheme on Solana#177lgalabru wants to merge 2 commits into
lgalabru wants to merge 2 commits into
Conversation
Move the channel store, voucher signature verification, and the
voucher-accept state machine out of `solana-mpp` and into
`solana-pay-core`, so both mpp and x402 build on one tested
implementation (mirrors the earlier `payment_channels` / `parse_units`
extractions). `solana-x402` deliberately does not depend on `solana-mpp`,
so this is the prerequisite for the x402 `batch-settlement` scheme.
- core::store <- mpp/src/store.rs (ChannelStore/ChannelState/
MemoryChannelStore, ...); mpp::store re-exports it
- core::voucher <- verify_voucher_signature (Ed25519, ed25519-dalek)
- core::session <- accept_voucher (monotonic + deposit cap +
idempotent replay + atomic compare-and-set advance)
mpp::server::session now delegates to these helpers, keeping the MPP-wire
mapping and metering in mpp. Guardrail: mpp's full suite stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
High-throughput channel payments: the client deposits once into an escrow channel, signs a cumulative Ed25519 voucher per request (verified off-chain and served immediately), and the operator redeems the latest voucher per channel on-chain later, in batches. On SVM this is the MPP `session` model over the x402 wire, backed by the same payment-channels program + 48-byte voucher already used by `upto`. v1 ships a fixed per-request price; settlement is operator-driven (out of the request path). SVM spec at specs/schemes/batch-settlement/. - protocol::schemes::batch_settlement — wire types (deposit/voucher/refund payload union, requirements, settlement response) + pure verify - server::batch_settlement::X402BatchSettlement — challenge, verify_payment (deposit broadcasts+binds the open reusing upto's SOL-drain guard; voucher accepts via core::session; refund settle-and-finalizes), and the operator primitives settle_batch (packs <=3 channels/tx, chunked) + distribute - client::batch_settlement — build_deposit, a BatchChannel cumulative tracker, encode/parse - kit: paid_batch_get/post + batch_gate_middleware (verify voucher -> serve; settlement deferred), pay.x402_batch() for out-of-band settle_batch/ distribute; example axum_batch - README: batch-settlement -> supported Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the x402
batch-settlementscheme to the Rust SDK — the high-throughput sibling ofupto(#174). A client deposits once into an escrow channel, signs a cumulative Ed25519 voucher per request (verified off-chain and served immediately, no on-chain tx in the request path), and the operator redeems the latest voucher per channel later, in batches. Per-request cost and latency approach zero.On SVM this is the MPP
sessionmodel surfaced over the x402 wire, backed by the same payment-channels program + 48-byte voucher already used byupto.SVM spec:
specs/schemes/batch-settlement/scheme_batch_settlement_svm.md.Commits (review in order)
refactor(rust/core): hoist wire-agnostic session/channel logic into core—solana-x402deliberately doesn't depend onsolana-mpp, so the shared channel/voucher/session logic moves intosolana-pay-core(mirrors the earlierpayment_channels/parse_unitsextractions).mppre-exports the moved paths and delegates to the new helpers; its full suite stays green, which is the guardrail that the extraction is behavior-preserving.core::store← channel store + state +MemoryChannelStorecore::voucher::verify_voucher_signature(Ed25519)core::session::accept_voucher(monotonic + deposit cap + idempotent replay + atomic CAS advance)feat(rust/x402): add the batch-settlement scheme on Solana— the scheme, self-contained in x402 (reuses core, not mpp):protocol::schemes::batch_settlement— wire types (deposit/voucher/refundpayload union, requirements, settlement response) + pure verifyserver::batch_settlement::X402BatchSettlement—challenge,verify_payment(deposit broadcasts+binds the open, reusing upto's SOL-drain guard; voucher accepts viacore::session; refund settle-and-finalizes), and the operator primitivessettle_batch(packs ≤3 channels/tx, chunked) +distributeclient::batch_settlement—build_deposit, aBatchChannelcumulative tracker, encode/parsepaid_batch_get/paid_batch_post+batch_gate_middleware(verify voucher → serve; settlement deferred),pay.x402_batch()for out-of-bandsettle_batch/distribute;examples/axum_batch.rsbatch-settlement→ ✅Design notes
settleinstruction draws the voucher's exact cumulative (not EVM's "claim up to a ceiling"). So vouchers commit the actual cumulative; EVM'sclaim/settlemaps to oursettle(watermark) /distribute(sweep). Consequently v1 = fixed per-request price; dynamic pricing below the advertised amount needs a commit round-trip — deferred.authorizedSigner(client-voucher /sessionmodel), unlikeuptowhere the operator signs. The operator only ever submits on-chainsettle/distribute/finalize— it can't exceed the on-chaindepositor redirect funds away from the fixedpayee.ChannelStorewiring, and metered/dynamic pricing are documented follow-ups.Testing
* the one
large_enum_variantwarning is pre-existing inmpp::session.rs, pulled in transitively — not from this change.No on-chain E2E in CI (needs Surfnet); the off-chain logic is unit-tested and the on-chain builders are the same ones
uptoexercises.🤖 Generated with Claude Code