agent-pay 0.1.0

L402 + DID-signed invoices: agent-to-agent Lightning payments (Rust port of @p-vbordei/agent-pay)
Documentation
# Architecture

## Goal

Port [`@p-vbordei/agent-pay`](https://github.com/p-vbordei/agent-pay) to idiomatic Rust while staying wire-compatible at the JWS + L402-token layers. The same `C1`–`C4` conformance vectors that pass against the TypeScript reference pass here.

## Module map

| TS source | Rust module | Role |
| --- | --- | --- |
| `src/envelope.ts` | `agent_pay::envelope` | Build + verify `InvoiceEnvelope` and `ReceiptEnvelope`. |
| `src/bolt11.ts` | `agent_pay::bolt11` | Parse + encode BOLT11 invoices. |
| `src/lightning.ts` | `agent_pay::lightning` | `LightningNode` trait + data types. |
| `src/replay.ts` | `agent_pay::replay` | `ReplayCache` keyed by `payment_hash`. |
| `src/lnd-rest.ts` | `agent_pay::lnd_rest` | Real LND adapter (gated). |
| `src/memory-node.ts` | `agent_pay::memory_node` | In-process mock LND for tests + demos. |
| `src/token.ts` | `agent_pay::token` | L402 bearer token (HMAC SHA-256). |
| `src/jws.ts` | `agent_pay::jws` | Compact JWS (EdDSA). |
| `src/jcs.ts` | `agent_pay::jcs` | RFC 8785 JSON Canonicalization Scheme. |
| `src/keys.ts` | `agent_pay::keys` | Ed25519 + `did:key` (multicodec `0xed01`). |
| `src/client.ts` | `agent_pay::client` | `fetch_with_l402` — JWS verify, price/expiry check, pay, retry. |
| `src/server.ts` | `agent_pay::server` | `Paywall::process_request` middleware. |

The Rust port exposes a framework-agnostic `Paywall` struct that any HTTP server (axum, hyper, actix-web) can wrap in a thin adapter. The TS reference is Hono-specific.

## Dependency choices

- **`lightning-invoice`** — the rust-lightning project's BOLT11 codec.
- **`ed25519-dalek`** — Ed25519 sign + verify.
- **`hmac`** + **`sha2`** — HMAC SHA-256 for the L402 token.
- **`serde_jcs`** — RFC 8785 canonicalisation.
- **`bs58`**, **`reqwest`** — DID multibase + the optional LND adapter.

The L402 token we issue is the simple `{base64url(payload)}.{base64url(hmac)}` form the TS reference uses — opaque to the client, validated only by us. A real macaroon implementation is wire-compatible but out of v0.1 scope (same as the TS reference).

## BOLT11 wire-format caveat

BOLT11 invoices with **identical contents** can produce **different signed strings** across libraries. The signature covers the bech32-decoded tagged fields; ordering rules in the spec allow legitimate variations, and library-side defaults (timestamp truncation, optional tags, signature recovery flag) differ. Concretely:

- The TS reference uses the npm `bolt11` package.
- This port uses the `lightning-invoice` crate.

Each port **round-trips its own invoices** (`parse(encode(x)) == x`) and the JWS envelope binds `bolt11_hash = sha256(bolt11_bytes)`, so a tampered invoice fails C4. But you should not expect `rust_encode(parse(ts_bolt11)) == ts_bolt11`.

What **does** match byte-for-byte across ports:

- The JCS-canonical JWS header and payload bytes.
- The `Token` payload + HMAC.
- The DID resolution rules (`did:key` + multicodec `0xed01`).

That is what the conformance vectors lock down.

## `payment_secret` tag

Modern BOLT11 (BOLT-11 amendment, ~2020) requires the `payment_secret` ("s") tag for MPP and to defeat probing attacks. Both ports emit it; both reject invoices without it on the receive path.

## Integration tests

Real-LND tests sit alongside unit tests but are gated behind `AGENT_PAY_INTEGRATION=1`. They drive a `polar`-style regtest network from `docker-compose.polar.yml` (mirrors the TS reference). The default `cargo test` does **not** require Docker.

## Testing strategy

- **`tests/bolt11.rs`** — round-trip equality for a generated invoice.
- **`tests/jcs.rs`** — JCS canonical bytes match a golden vector.
- **`tests/jws.rs`** — sign + verify; tamper detection.
- **`tests/keys.rs`**`did:key` round-trip; multicodec correctness.
- **`tests/token.rs`** — issue + verify; expiry; tampered HMAC.
- **`tests/replay.rs`** — second presentation of the same preimage rejected.
- **`tests/envelope.rs`** — invoice + receipt envelopes against fixtures.
- **`tests/memory_node.rs`**`MemoryNode` invoice lifecycle + ledger book-keeping.
- **`tests/conformance.rs`** — drives every `vectors/c{1..4}-*.json`.
- **`tests/e2e.rs`**`Paywall` + `MemoryNode` full round-trip; receipt verified.

A green `cargo test` runs 30+ tests across binaries in well under a second.