agent-pay (Rust)
Idiomatic Rust port of
@p-vbordei/agent-pay. L402 + DID-signed invoices for agent-to-agent Lightning payments. Wire-compatible with the TS reference; ships an in-memory mock LND so tests and demos run without a real node.
What's in the box
Paywall::process_request(path, headers, inner)— L402 challenge/response middleware, framework-agnostic.Token— L402 macaroon-style bearer token (HMAC SHA-256{payload}.{hmac}).BOLT11— parse + encode Lightning invoices via thelightning-invoicecrate (with the modernpayment_secrettag).JWS— DID-bound envelope (Ed25519 + JCS-canonical headers/payloads).MemoryNode— mock LND for tests and offline demos (sharedMemoryLedgerbetween server and client wallets).LndRest— real LND adapter (optional, skipped unlessAGENT_PAY_INTEGRATION=1).ReplayCache— preimage-based replay protection keyed bypayment_hash.
Install
[]
= "0.1"
Quickstart
use Arc;
use ;
async
Run the full demo:
server DID: did:key:z6Mk…
status: 200
payload: {"insight":"agents charging agents works."}
receipt: eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa…
How it relates
| Language | Package | Source of truth |
|---|---|---|
| TypeScript | @p-vbordei/agent-pay |
reference |
| Python | agent-pay-py |
port |
| Rust | agent-pay (this) |
port |
Conformance
This port passes the same C1–C4 clauses as the TS reference and adds a full e2e round-trip:
- C1-missing — client rejects 402 missing
X-Did-Invoice. - C1-bad-sig — client rejects 402 with a tampered
X-Did-InvoiceJWS. - C2 — happy-path: valid invoice paid → 200 with verified
X-Payment-Receipt. - C3 — server rejects a replayed preimage with 401.
- C4 — client rejects when
invoice_hashmismatches BOLT11. - e2e —
Paywall+MemoryNoderound-trip end to end (tests/e2e.rs).
Vectors live in vectors/ and are byte-identical to the TS suite's conformance/vectors/ for the JWS + token layers. BOLT11 wire bytes differ across libraries even with identical contents — see docs/architecture.md for why.
Architecture
See docs/architecture.md.
Development
License
Apache-2.0 — see LICENSE.