feat(mpp): implement x402 payment-offer + signed payment-proof core#35
Open
Pattermesh wants to merge 1 commit into
Open
feat(mpp): implement x402 payment-offer + signed payment-proof core#35Pattermesh wants to merge 1 commit into
Pattermesh wants to merge 1 commit into
Conversation
Replaces the all-TODO MPP module with a real, tested HTTP-402 / x402 implementation — arka's machine-payments differentiator. - PaymentOffer + PaymentOfferBuilder (server side): build a 402 offer with amount/currency/recipient/chain, auto-generated nonce, and TTL; OfferEnvelope serializes to the camelCase X-Payment-Required header, wire-compatible with the switchboard Python reference impl. - PaymentProof (client + verifier side): construct a proof bound to an offer and EIP-191-sign it with the agent wallet; verify() recovers the signer, checks it matches the declared payer, and that every offer-bound field (chain/recipient/amount/currency/nonce) and the expiry hold — rejecting tampered amount, forged/wrong signer, expired offer, and nonce mismatch. - MppClient.pay_and_retry(): the full flow — request -> 402 -> pluggable Settle -> sign proof -> retry with X-Payment-Proof. PaymentReceipt for accounting. 12 new unit tests cover offer build, proof construct/verify roundtrip, header roundtrips, and four distinct rejection cases. Also fixes a pre-existing clippy `-D warnings` failure in src/mcp/mod.rs (question_mark lint under rust 1.96) that blocked CI on the branch. cargo fmt/check --all-features/clippy -D warnings/test all green. 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
The MPP / x402 machine-payments module was entirely TODO (
src/mpp/mod.rsonly parsed a 402, withpay()/session()/pay_and_retry()stubbed out). This PR implements the core that arka's pitch depends on: typed payment offers, cryptographically signed payment proofs, and the full HTTP-402 flow — aligned with the x402 pattern and wire-compatible with the switchboard Python reference impl.How
src/mpp/types.rs(new) — the wire types and crypto:PaymentOffer+PaymentOfferBuilder(server side): build a 402 offer foramount/currency/recipient/chain, with an auto-generated 128-bit nonce and optional TTL.OfferEnvelope { accepts: [...] }serializes to the camelCaseX-Payment-Requiredheader.PaymentProof(client + verifier side):sign(wallet, offer, tx_hash)builds a proof bound to the offer (copies recipient/amount/currency/nonce, stamps the payer from the wallet) and EIP-191 (personal_sign) signs a domain-separated canonical message (x402-proof-v1\n…) over every economically meaningful field.verify(offer)/verify_at(offer, now): checks chain/recipient/amount/currency/nonce bind to the offer, the offer hasn't expired, and the signature recovers to exactly the declared payer. Any tampered field diverges the recovered address and is rejected.to_header/from_headerfor theX-Payment-Proofheader.src/mpp/mod.rs— wires it into the flow:MppClient::pay_and_retry(url, wallet, settle): request → on 402, pick the first offer → settle via a pluggableSettleimpl (closure or trait) → sign proof → retry withX-Payment-Proof. Client self-verifies before sending.Settletrait (blanket impl forFn(&PaymentOffer) -> Result<String>) keeps settlement (native/ERC-20/escrow/mock) decoupled from the protocol.PaymentReceipt::from_prooffor verifier-side accounting.Tests (12 new, no network)
Verification — all CI gates green
Note: this branch also carries a one-line fix in
src/mcp/mod.rsfor a pre-existing clippy-D warningsfailure (thequestion_marklint under rust 1.96, introduced by an earlier merge) that was already breaking the CI gate independent of this work. The fix is clippy's own suggested rewrite (let id = id?;) and preserves behavior.🤖 Generated with Claude Code