micro / micro/mu

x402: serve before settling, so a stock client gets low latency

Open
#1,457 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Go
Stars
434
Forks
21
Avg merge
18m
Merged PRs (30d)
326

Description

The problem

Every x402 request does verify then settle against the facilitator, and settle is an on-chain transaction. So every single request carries a settlement round trip. An agent making fifty calls pays fifty settlement latencies, which makes sustained use of the tools impractical however cheap each call is.

What x402 actually offers

Checked against the specs rather than assumed — both of my first guesses were wrong.

upto — one authorization per request, single use. From the spec: "Each authorization MUST be settled at most once. After settlement (regardless of amount), the authorization is consumed and cannot be reused." What it gives you is that the settled amount may be less than the authorized ceiling: at verification the amount field is the maximum, at settlement it is "the actual amount to settle".

So upto is the primitive for metered pricing, not for batching. It belongs with the pricing-units work, not here.

batch-settlement — many separate per-request commitments settled together. The client still signs every request. What changes is that the server validates the commitment, stores it, serves immediately, and value moves later through "the network binding's redemption process". That genuinely removes the per-request settlement latency.

But the spec is a framework, not a mechanism: the redemption step is explicitly "network-defined", and the only concrete binding published is Cloudflare's. CDP advertises the scheme on Base; what binding it means there is an open question and should be asked before building anything.

The spec names two backing models — capital-backed (on-chain escrow, a payment channel, delegated spending authority) and credit-backed (a trusted intermediary holds a billing account and settles off-chain).

Rejected: a deposit endpoint

The first design was a deposit endpoint — the agent funds x402:<its address> once, then authenticates per request with Authorization: Wallet and spends credits with no on-chain work. Most of it already exists: the credit ledger is keyed by an arbitrary account id so x402:0xabc… can hold a balance, walletauth proves control of an address without payment, and callerIdentity already collapses signer and payer to the same id.

Rejected because standard clients cannot use it. A stock x402 client knows one thing: hit a URL, get a 402, sign, retry with X-PAYMENT. It will never know to call a deposit endpoint, and it will never send Authorization: Wallet instead of paying. That design makes our own agent fast and leaves everyone else exactly where they were — a Mu feature wearing x402's clothes.

It also makes us custodial, and we are not doing withdrawals, so the balance would be one-way.

Proposed: batch on the server, client unchanged

Keep the stock flow exactly as it is — 402, sign, X-PAYMENT. Change only what happens on receipt:

  1. Verify the signature locally. wallet/recover.go has secp256k1 recovery and SignX402Payment already builds the EIP-712 digest, so the authorization can be checked without a facilitator round trip.
  2. Check the payer can cover it — one RPC balance read, cacheable per address.
  3. Serve immediately.
  4. Settle asynchronously, in batches.

Request-path latency drops to a local signature check. A stock client gets that for free, having changed nothing.

This is batch-settlement's accumulate-then-redeem pattern with the redemption implemented here rather than waiting for a binding.

The cost, stated plainly

We serve before we are paid. A signature can fail to settle afterwards — insufficient balance by redemption time, or a reused nonce.

Mitigations, all ordinary:

  • cache payer balances and refuse when the balance will not cover outstanding commitments
  • cap total unsettled value per payer
  • stop serving an address whose settlements start failing
  • bound how long a commitment may sit unsettled, since authorizations carry a deadline

The real decision is accepting a bounded amount of credit risk in exchange for stock clients getting low latency with no deposit, no custody, and no bespoke protocol.

Before building

  • Ask CDP what batch-settlement on Base actually binds to. If they have defined the redemption path, use theirs rather than inventing one.
  • Decide the outstanding-value cap per payer, and what happens when it is hit.
  • Confirm local verification matches what the facilitator's /verify accepts, so we never serve something it would have rejected.

Not in scope

Metered pricing and the upto scheme. Same conversation originally, genuinely separate problem — tracked separately.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with wallet/recover.go, including secp256k1 recovery and SignX402Payment, then compare local verification with what the facilitator's /verify accepts. Before implementation, resolve the CDP batch-settlement binding, payer caps, and failure behavior. Done means a stock 402/X-PAYMENT client can be served immediately while settlements run asynchronously in bounded batches.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend-api-design, payments
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.