x402 on Nano: a payment that cannot run in parallel
Every x402 scheme so far asks the buyer to sign an authorization the facilitator can submit. A proposed scheme for Nano asks for something different: a complete, already-valid ledger block. That one choice removes fees and parallelism in the same stroke. We read PR #3432 at head 2c5607a, recomputed a real mainnet block from its fields, and measured what the proof-of-work costs.
Nano is a native-coin network (ticker XNO) with a block-lattice ledger: each account has its own chain of blocks, and a payment is a "send" block appended to the payer's chain. There are no fees. The PR adds one file, specs/schemes/exact/scheme_exact_nano.md, 445 lines. It was opened on 2026-09-09 by kilkelly, who says in the PR body they are a volunteer with the Nano Foundation and that the spec was shared internally with it. As of 2026-10-22 it is open and unmerged, last updated 2026-10-16. A reference TypeScript implementation is promised in a separate PR after approval.
We care for two reasons. It is the second native-coin scheme in the repo after Bitcoin Lightning (scheme_exact_lnbtc.md, commit 6fe0d4bf, 2026-09-23, from #2861). And its design makes three properties of x402 payments visible that EIP-3009 hides: the signed object has no expiry, it can be invalidated by the payer's own next action, and it serializes the payer.
What the scheme asks for
The requirement is plain. asset is always XNO, amount is in raw units (1 XNO = 10^30 raw, so the spec's example 10000000000000000000000000000 is 0.01 XNO), payTo is a nano_ account, and maxTimeoutSeconds bounds how long the facilitator polls, not how long anything is valid.
The payload is a full state block:
"payload": { "block": {
"type": "state",
"account": "nano_3qgmh1...", // payer
"previous": "F47B2310...", // hash of payer's current frontier
"representative": "nano_1hza3f...",
"balance": "20000000000000000000000000000", // balance AFTER the send
"link": "19D3D919...", // payee public key
"link_as_account": "nano_3ah94b...", // must equal payTo
"signature": "3BFBA64A...",
"work": "ffffffd2e1234567"
} }
Note what is not there: no amount field. A Nano send block states the new balance. The amount is the difference between the payer's previous balance and that number. The facilitator has to fetch the previous balance from the network to learn what the buyer is paying. That is why the spec needs a balance-delta check, and it is the first place this scheme differs from EIP-3009, where the signed message carries the value.
The flow is verify, then settle. Verify runs 14 ordered checks. Settle re-runs all of them, calls the node RPC process with subtype: send, waits half a second, then polls block_info once per second until confirmed is true or maxTimeoutSeconds runs out. The spec defines 18 error codes shared by both stages, from error_previous_not_frontier to error_block_awaiting_confirmation.
Check 1: we rebuilt a real block
A spec like this is only useful if an independent implementer can reproduce its numbers. A commenter on the PR, pursekeeper (an autonomous agent that runs a public Nano facilitator), contributed test vectors from a real mainnet payment, block 1D60903E…D0BEB. We did not take that on trust. We asked a public node for the block and rebuilt the hash ourselves: Blake2b with a 32-byte output over a 32-byte preamble ending in 0x06, then the account public key, previous, the representative key, the balance as 16 big-endian bytes, and link.
node block_info: 1D60903EFD920FA78746E18F08C021EE7B8155205709DF5A4125BBDCF96D0BEB
our recompute: 1D60903EFD920FA78746E18F08C021EE7B8155205709DF5A4125BBDCF96D0BEB
subtype send, confirmed true, height 99, amount 1000000000000000000000000000 raw (0.001 XNO)
Identical. Checks 7 and 8 of the spec are implementable from the text. We did not verify the Ed25519-Blake2b signature itself, so we make no claim about check 7 beyond the hash.
Check 2: the work is over previous, not over the block
The payload section says the work "MUST be generated using previous as input". Pursekeeper's review noted that a reviewer they paid assumed the block hash instead. We tested both on the same block, whose work value is 3f6ff9e7b7ba27a7 and whose network send threshold is fffffff800000000 (confirmed live from the node's active_difficulty: send fffffff800000000, receive fffffe0000000000).
work value over previous: fffffffb24be3db3 (>= fffffff800000000: valid)
work value over block hash: 06827dd571ecd105 (below threshold: invalid)
So the spec is right, and the distinction matters for a practical reason. The work depends only on the previous hash. It can be computed as soon as the payer knows what the next block's parent is, before there is any payment to make. We will come back to what that buys and what breaks it.
One gap in the text: check 14, "Work Difficulty Check", says the work must meet "the Nano network's current minimum difficulty threshold for a send transaction" and does not name the value, the input, or the RPC. A facilitator that cannot get this right has no recourse to the spec. The values above are from a live node, and the facilitator we probed advertises the same threshold in its /supported response.
What the work costs
Nano replaces fees with proof-of-work as anti-spam. The expected number of Blake2b-8 trials is 2^64 divided by (2^64 minus the threshold). For send, that is 2^29 = 536,870,912 trials. For receive, the threshold is 64 times easier: 2^23 = 8,388,608.
We measured. A single core of this machine runs Python's hashlib.blake2b(digest_size=8) at 912,834 hashes per second, so one core needs about 9.8 minutes on average for a send and about 9 seconds for a receive. We then ran the search across 72 processes, five trials each:
send (fffffff800000000) 0.8 s, 4.6 s, 22.9 s, 33.8 s, 39.1 s median 22.9 s
receive (fffffe0000000000) 0.2 s, 0.3 s, 0.4 s, 0.4 s, 0.9 s median 0.39 s
The spread is the point. Proof-of-work is a geometric search, so the time to a valid nonce varies by an order of magnitude from run to run. Our code is unoptimized Python on CPU. Wallets use GPUs and work servers, and an agent would too. We read these numbers as an order of magnitude only: a send is a heavy computation that can take seconds to minutes on commodity hardware, and a receive is nearly free.
Compare the buyer-side cost of the other schemes. An EIP-3009 authorization is one signature, microseconds. Here the buyer either precomputes work or pays the latency on the 402 round trip, which is on the critical path of a per-call purchase.
The frontier rule: one payment in flight
Check 12, "Frontier Hash Check", requires the block's previous to equal the account's confirmed_frontier, fetched with include_confirmed: true. Read that twice. It is not the account's frontier, it is the confirmed one.
Follow it through. The first payment is signed with previous = H0, producing a block with hash H1. Until H1 is confirmed, the confirmed frontier is still H0. A second payment built on top of H1 fails check 12. A second payment built on H0 is a fork of the first and, per the spec's own appendix, only one of the two can ever confirm. So one Nano account can have exactly one x402 payment in flight, and the next one cannot be verified until the last has been cemented.
The facilitator we probed reports /verify at 85 ms and /settle at 649 ms end to end on a real block (its operator's measurement, from the PR thread; we did not time it). If that holds, a single account tops out near 1.5 payments per second before counting work generation. EIP-3009 payments from one address are unconstrained, because each authorization carries its own random 32-byte nonce and they commute.
The spec's own settlement section names the failure mode: if the payer's account gains a block between verify and settle, "like an auto-receive block or another concurrent payment", the send block no longer matches the frontier, and the facilitator MUST return error_previous_not_frontier. The client must build a new block. The same event also invalidates any work precomputed over the old previous. It follows (our inference, not stated in the spec) that an agent account that auto-receives incoming funds keeps moving its own frontier and keeps wasting its precomputed work. Separate inbound and outbound accounts are the natural design.
The block never expires
EIP-3009 has validBefore. A Nano block has no such field. The spec's appendix is explicit: valid blocks "do not expire", and maxTimeoutSeconds "bounds the Facilitator's polling period ... not expiration". The block stays valid until the payer's frontier changes.
Two consequences.
First, the buyer's only way to withdraw an unsettled payment is to publish a different block on the same account, which makes the signed one unprocessable. The spec does not say this in so many words. Pursekeeper proposed it as an optional nit in the thread, and the current text (445 lines, commit above) still leaves it out. A buyer library that wants a cancel operation has to implement it.
Second, a signed block can be broadcast by anyone who holds it, to any node, with no facilitator. The block commits to payTo through link, so a leaked block can only pay the intended payee. The harm is not theft. It is double delivery: the seller settles through the facilitator, the block confirms, and a second party also presents it. The spec handles this with the "Scenario 2" rule: when a settle returns error_block_already_confirmed, the seller delivers only if its own records say the resource was not delivered, keyed by block hash. That is the same delivery-ledger idea our recovery audit arrived at from the other direction.
The spec uses a three-way settlement outcome, not a boolean: confirmed, already confirmed, awaiting confirmation. For the third case it says do not deliver, resettle, and after a bound of the seller's choosing answer 402 again, with a rule for the block that confirms late. Our finality audit asked what settle success means per chain; this is one chain's written answer to what "not yet" means.
Forks, and who protects the seller
Between verify and settle, a malicious payer can publish a conflicting block with the same previous. Whichever reaches representative quorum first wins; the other is rejected forever. If the seller delivered at verify, it would be robbed. The flow in the spec delivers after settle returns confirmed, so a lost fork race means no delivery.
The appendix adds a "fork protection" recommendation: the seller should remember the previous value of every in-flight attempt and reject a second payload with the same previous. That is a SHOULD, with the state living in the seller. The chain enforces safety; the seller's memory only saves wasted work.
Quorum is concrete on the live network. The node we queried reports a 67% online-weight quorum, with 8.54 x 10^37 raw (about 85.4 million XNO) of online stake, and 225,586,751 cemented blocks, 432 unchecked at the moment we asked. Confirmation in this model is quorum of representatives voting, which the spec equates with irreversible finality. We did not test the claim; it is the protocol's.
Review history: who has run it
This PR has had unusual hands-on review. Pursekeeper ran their own facilitator against successive drafts and sent four suggestions, all taken: distinct reason when the frontier moves, an explicit no-expiry section, copy the representative from account_info to avoid silently re-delegating the payer's voting weight, and the work input. When the author added an error vocabulary and an extra scheme, network and account check, the commenter supplied test vectors as a PR to the author's branch (kilkelly/x402-nano-exact-scheme-proposal#1, which was still open when we looked).
According to the same commenter, three independent facilitators implement the text: their own, the x402nano reference, and gosuda/x402-facilitator. We confirmed that the gosuda repository has a scheme/nano directory and that facilitator.pursekeeper.dev/supported answers for exact on nano:mainnet with work: required and the send threshold. We did not run those facilitators. We also did not verify the claims about live sellers, which are theirs.
The honest summary: the scheme is further along in implementation than in review. The PR carries the specs label and 18 comments, and no formal review has been submitted on it. The same commenter says the lnbtc spec drew 22 comments before it merged; that number is theirs, we did not count.
What we would change
Four edits would close the remaining gaps.
First, name the threshold in check 14 and say it is computed over previous. The values are public and the mistake is easy.
Second, add the cancel recipe to "Blocks have no expiry": publish any block on the same account, such as a change block with the same representative and balance.
Third, state the concurrency limit in the Summary. Right now it is derivable only by reading check 12 against the settlement section. A seller that issues many 402s to the same payer, such as one agent fanning out parallel calls, needs to know that the second call will not verify.
Fourth, simplify the check list. Checks 7 and 8 both verify the signature, and 8 describes the hash computation that 7 depends on. The order is also unusual: the existence check on the block is at position 10, before the account check at 11. These are cosmetic, but a spec that other languages implement should have one canonical order of operations.
What it means for LLM4Agents
Our billing rails are Solana and Polygon stablecoins. Nano is a native coin with a floating price, so a 402 quote in USD would need an exchange rate frozen at quote time and a short window. That is the same quote-risk shape as our dated-price audit, in a new place. The scheme is not a fit for our stable-price model today and we are not proposing to add it.
It is still worth reading as design input, because it forces three questions our own stack should answer whatever the rail. Does our settlement state have a third value for "broadcast, not confirmed", or only success and failure? Does our delivery ledger key on the settlement id so that a replayed payment cannot be delivered twice? And can one buyer account make parallel purchases from us, or does some rail serialize it? The parallelism point is the one with teeth. A fleet of agents sharing one funded account is a normal setup for an operator. On an EIP-3009 rail that works. On a Nano-style rail it collapses to one purchase at a time, and the fix is one funded account per concurrent worker. Any buyer guidance we publish should say which rails commute.
Staying on the frontier
In order:
First, do not build Nano support. Watch #3432. The trigger to reconsider is a maintainer review plus the reference implementation landing, not the number of facilitators.
Second, make our facilitator interface three-valued for settlement (confirmed, pending, failed) and key delivery on the settlement id, as Scenario 2 does. This is rail-independent and pays off for the preconfirmation cases we already measured on Base.
Third, write a rail table for buyers: for each supported scheme, whether signed payments from one account commute, whether a signed payment expires, and how a buyer cancels. Nano is the first row where the answers are no, no, and "publish another block".
Fourth, add a parallel-purchase test to our buyer harness: N concurrent paid calls from one account, assert N successes. It costs nothing on current rails and is the regression test for any future serialized one.
Fifth, keep the 402-quote FX question on the list of things to solve before any volatile-asset rail. A quote in USD with an amount in a floating asset needs an explicit rate and expiry in the response, not an implicit one.
Sixth, track the neighbours: the Canton, BSV and Bitcoin Cash scheme PRs are all open. Each native-coin rail brings its own answers to the same three questions. Our Sui audit found that the dedup state ends up in whichever layer nobody reviews. The first native-coin rail to merge will set the precedent for how the others write theirs.
Pay per call, in stablecoins, over an OpenAI-compatible API
One 402, one signature, 345+ models. No subscription, no minimum.
Register your agent