Skip to content

wozos/lez-agentic-payments-prototype

Repository files navigation

LEZ Agentic Payments Prototype

A Rust-first, Docker-only prototype for agentic payments on the Logos Execution Zone (LEZ). The prototype is a hybrid of three real-world designs:

  1. Stripe Link Wallet for Agents — owner-approved per-transaction spend requests, explicit approval flow, scoped one-time payment credentials, auditability. The owner reviews a meaningful free-text reason; the credential is signed, scoped, and time-bound.
  2. x402 v2 — HTTP 402 Payment Required challenge-response transport with PAYMENT-REQUIRED, PAYMENT-SIGNATURE, and PAYMENT-RESPONSE headers; replay protection via nonce.
  3. Logos LEZ — CAIP-2-style network identifier logos:lez-testnet, exact payment scheme, build-and-sign-without-broadcast wallet split (today: mocked; upstream change required).

The two research documents that shaped this design — Stripe Link and x402-on-LEZ — are committed verbatim under spec/research/. Read those first for the wider context.

Status

Architecture (one-paragraph version)

An agent composes a PaymentRequest (≥32-character reason). The owner reviews it and produces a signed PaymentPayload. The agent retries an HTTP GET to the merchant with the payload in the PAYMENT-SIGNATURE header. The merchant calls into a facilitator which verifies the payload against a PaymentBackend (the MockLezBackend today, the real LEZ sequencer in a future life) and settles. Replay fails with a stable nonce_replayed error code.

See spec/architecture.md for the sequence diagram and crate-level dependency graph. See spec/protocol.md for the wire-level field-by-field spec.

Quickstart

Everything runs inside Docker. The host needs only docker and docker compose.

# Build the dev image (multi-arch: linux/amd64, linux/arm64).
docker compose build

# Run the full test suite.
docker compose run --rm demo just test

# Run the CLI demo (in-process, no HTTP).
docker compose run --rm demo just demo-cli

# Run the HTTP demo end-to-end (boots an axum merchant + facilitator
# on an ephemeral port, drives the 402 -> retry -> 200 -> replay-fail
# flow over real TCP).
docker compose run --rm demo just demo-http

CLI surface

The lez-agent-pay binary supports:

# 1. Owner / agent keypairs.
lez-agent-pay owner create --out owner.json
lez-agent-pay agent create --out agent.json

# 2. Compose a spend request.
lez-agent-pay request create \
  --merchant-name "Mock Merchant" \
  --merchant-url "http://merchant:8080/premium" \
  --pay-to merchant_demo_account \
  --amount 10000 \
  --asset native \
  --reason "Fetching the premium dataset for the user's research task." \
  --agent-file agent.json \
  --out request.json

# 3. Owner approves (or declines).
lez-agent-pay owner approve --request-file request.json \
                            --owner-file owner.json \
                            --out payment-payload.json
lez-agent-pay owner decline --request-file request.json

# 4. Drive an HTTP request manually.
lez-agent-pay http get --url http://merchant:8080/premium                # 402
lez-agent-pay http get --url http://merchant:8080/premium \
                       --payload payment-payload.json                    # 200

# 5. End-to-end demos.
lez-agent-pay demo cli
lez-agent-pay demo http

Crate layout

crates/
  core/             PaymentRequest, PaymentPayload, WalletSigner, MockLezBackend
  cli/              lez-agent-pay binary + subcommands + demos
  merchant-server/  axum HTTP merchant (lib + bin)
  facilitator/      verify/settle wrapper around PaymentBackend (lib + bin)
  lez-adapter/      PaymentBackend trait choice: MockLezBackend vs RealLezBackend stub
tests/              CLI + HTTP integration tests (root-level by design)
spec/               Architecture, protocol, lez-integration notes, follow-ups
spec/research/      Original Stripe Link + x402-on-LEZ research docs (committed verbatim)
reports/            Final run report, test results, LEZ integration attempt log
examples/           Sample payment-request.json, payment-payload.json, payment-required.json

What is real and what is mocked

Real:

  • The HTTP transport (axum + reqwest, real TCP, two integration tests exercise it).
  • The x402 v2 header dance (PAYMENT-REQUIRED, PAYMENT-SIGNATURE, PAYMENT-RESPONSE) carrying base64(JSON) bodies.
  • The 12-entry stable error-code list, surfaced both in JSON bodies and in the x-payment-error response header.
  • ed25519 signatures over a domain-separated SHA-256 digest; tamper testing covers signature, amount, recipient, network.
  • Nonce replay protection enforced inside the mock backend's settlement step.

Mocked:

  • Balances and consumed nonces live in an in-memory Mutex<HashMap>, not on a LEZ sequencer.
  • PaymentPayload.payload.signed_tx is None. Real LEZ will populate it with the base64-borsh of a buyer-signed NSSATransaction::Public.
  • The signature path uses ed25519-dalek+SHA-256 rather than nssa::WitnessSet::for_message(...) over an LEZ public transaction.

The WalletSigner and PaymentBackend traits are sized to receive the real implementation. See spec/lez-integration-notes.md for the upstream wallet API gap (build_signed_transfer_transaction doesn't exist yet) and the circuits-repo blocker that prevented us from cargo check'ing the LEZ tree on this Pi.

How this relates to the prior art

Where it comes from Where it lives in this repo
Owner-approved spend-request UX, ≥100-char reason Stripe Link Wallet for Agents crates/core/src/flow.rs (with a 32-char threshold for tests; raise to 100 per follow-up)
HTTP 402 + PAYMENT-REQUIRED / PAYMENT-SIGNATURE / PAYMENT-RESPONSE x402 v2 crates/merchant-server/src/lib.rs
exact scheme, logos:lez-testnet network x402_research_lez.md §3-4 crates/core/src/lib.rs constants + crates/core/src/mock_backend.rs
Build-and-sign-without-broadcast wallet split x402_research_lez.md §6.1 upstream gap; tracked in spec/follow-up-tasks.md
Stable error-code list x402_research_lez.md §4.6 crates/core/src/errors.rs

Limitations

This is a prototype. It does not solve, attempt, or block on:

  • Production wallet security (mock signer uses an unprotected seed in a JSON file)
  • Real Stripe Link integration (only the semantics are mirrored)
  • Real card payments
  • Full x402 conformance suite (field names use snake_case rather than the upstream camelCase; see follow-ups)
  • Private LEZ payments / exact-private (Phase 2 of x402_research_lez.md §5)
  • Mobile push approval UX (the owner step is a CLI today)
  • MCP server / browser extension / polished UI

These belong in spec/follow-up-tasks.md.

License

Apache-2.0.

About

Prototype for agentic payments on Logos Execution Zone

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors