Extro-402 scheme
How 402 works covers the base challenge / retry / receipt
handshake. Underneath it sits extro-402-scheme — a generalized,
rail-agnostic protocol for moving value over the internet. It is not exchange machinery:
it is a small set of reusable, signed wire primitives for transporting value,
conditions, proofs, and receipts for any paid action — shopping, in-game economies,
banking, multi-party payouts, API and inbound-reach gates, and exchanges. Any peer or agent uses the same primitives to pay any other, in any
direction.
Value, not intent, on the wire. What a payment is for never lives in a type name or in protocol logic — it lives in open custom fields. The exchange is one consumer of this protocol, exactly like a shopping cart or a game server is; it is not the shape of it. Order books, limit orders, pair policy, and the seeder fee live in the application layer, built on the primitives below.
Cross-cutting model
Every signed primitive shares one signing discipline, so the guarantees are uniform regardless of scenario:
- The audit triad. Every signed body carries a domain-separation
tag + a nonce + an expiry (
expires_at_unix). The tag names the exact object kind, so bytes signed for one step can never be replayed as a different step. The verifier asserts the tag equals the one it expected and rejects stale objects; nonce dedup is the caller's ledger duty, so this layer carries the field and owns no state. - An open custom-field channel. Alongside the triad, every body carries a
coarse
purposehint (Payment | Settlement | Fee | Refund | Reach | Custom(String)) and ametadata: Vec<(String, Vec<u8>)>key→bytes channel the protocol never interprets. Any application — an invoice id, a game item ref, an order context — extends a message without touching the protocol or its type names. - One discipline, many tag namespaces. A
DomainTagKindtrait parameterizes the signing helpers over the tag enum. The generic primitives sign with the rail-agnosticDomainTagset; an application that defines its own object kinds (e.g. the exchange's order / pair tags) defines its own tag enum implementing the same trait and reuses the identicalsign/opendiscipline — the protocol never enumerates application object kinds. - Deterministic archived wire. Bodies are rkyv-archived; equal inputs always yield equal
bytes. There are no
HashMap/HashSetin archived types — iteration order can never perturb the bytes. The signer signs the raw archived bytes; the verifier checks the signature against those bytes verbatim and never re-archives.
The verifier does four checks, in order: (1) the Ed25519 signature over the
archived body bytes; (2) rkyv deserialize; (3) the embedded domain tag equals the expected tag;
(4) the object has not expired (now < expires_at). Structural rkyv decode alone
proves nothing about intent — the domain tag is the guard that makes byte-reuse across object
kinds useless.
The primitives
Nine primitives compose every scenario. Each says what it does for any use, then its security binding.
1 — PaymentRequest
“Pay amount_raw of asset to payee_fingerprint for an
action.” The generic ask, whatever the action is — a checkout total, an API call price, an
in-game purchase, an exchange order request.
- Binds: the
amount_raw+asset(AssetRef— any rail), thepayee_fingerprint, anidempotencykey the eventual payment references, and an optionalaccepts_refereefingerprint when the action may be mediated — pluspurpose/metadataand the audit triad. - Security binding. Signed and immutable, so a later payment can be checked
against the exact request. Application context (an order id, a cart) rides in
metadata, never in the type.
2 — Payment
The transfer itself, referencing its originating request by idempotency. It carries either a rail-native proof or a bearer secret sealed to the recipient.
- Binds: the
idempotencyback-reference, payer/payee fingerprints,amount_raw+asset, and aPaymentProof— either aRailproof (anevidence_hashcommitting to the rail's proof of payment, plus an optional ZK proof) or aBearer(EncryptedBearerDelivery)(primitive 5). - Security binding. A rail proof commits to the transfer without putting a secret on the wire; the bearer variant seals the secret to the recipient. The bearer secret goes plaintext only to the payer's local node, never to a counterparty in the clear.
3 — Receipt
A signed acknowledgement that a payment or action occurred — a shopping receipt, an API receipt, a settlement receipt.
- Binds: the
payment_ref, payer/payee fingerprints,amount_raw+asset, andat_unix, pluspurpose/metadataand the triad. - Security binding. Signed and expiring, so a receipt is non-repudiable and bound to the exact payment it acknowledges.
4 — Refund
Reverse or return a prior payment — a marketplace return, a banking reversal, the abort path of a failed conditional.
- Binds: the
original_payment_ref, refunder and recipient fingerprints,amount_raw+asset, and a free-formreason. - Security binding. Signed and tied to the original payment reference, so a refund cannot be fabricated against a payment that did not happen.
5 — EncryptedBearerDelivery
A bearer secret sealed to a recipient identity, so a third party (e.g. a referee) can confirm a payload is for the right party and matches a known token — without ever decrypting it. Any rail, any recipient, any reason.
- Binds: the
payload_kind(BearerPayloadKind: Webcash / Voucher / RGB secret, plus aCustomescape hatch), therecipient_fingerprintand arecipient_pubkey_commitment(tying the ciphertext to the exact key it was sealed to), thepublic_token_hash, theamount_raw+asset, theciphertextand itsciphertext_hash(SHA-256), and an optionalzkp(primitive 8). - Security binding. The verifier recomputes
sha256(ciphertext)and checks it againstciphertext_hash; plaintext is never revealed to a mediator. The recipient commitment binds the seal to one key.
6 — MediatedConditional
A referee-arbitrated conditional release for any 2-of-2 / multisig-capable asset.
The asset is just a field — Bitcoin-ARK is one AssetRef value; RGB, a future chain, or
an application-defined 2-of-2 asset are equally valid. Use it for marketplace settlement, milestone
B2B payments, conditional payments, or exchange swaps.
- Binds: the
session_id, theasset, a genericamount_raw, a genericlocked_ref(a VTXO id, a UTXO, a contract output — the protocol does not interpret it), the signingpartiesand therefereefingerprint, thenonce_commitment, an optionalzkpattesting the gate, and theoutcome. - Outcomes are mutually exclusive by construction. The
outcomeis an enum of N mutually exclusive variants —Release,Refund, orCustom(label)— each carrying only its owntx_hash, the counterparty'sencrypted_counterparty_partial_sig, and an optionalreferee_partial_sig. There is no representation in which two outcomes' releasable signatures coexist, so no holder of the payload can pick whichever benefits them. - The tag is derived, not declared. Unlike the other primitives,
MediatedConditionalhas no standalone tag field — its domain tag is derived from the outcome variant (ConditionalRelease/ConditionalRefund/Conditional(label)). A release authorization can therefore never open under a refund tag, and two differently-labelled custom outcomes are not cross-replayable. - Not escrow. The referee never holds both halves of the signature path and takes no fee — it is a non-custodial mediator, not a custodian.
7 — Split
Distribute one incoming payment to N recipients with per-recipient shares — commissions, royalties, payroll, revenue-share, or any fee distribution.
- Binds: the
total_raw+assetand theshares: Vec<Share>, eachSharenaming arecipientfingerprint, itsamount_raw, and a per-sharerail(AssetRef), pluspurpose/metadataand the triad. - Security binding. Signed and deterministic; a pure helper reports the share
total and any indivisible remainder so no value is silently lost. The exchange's 0.1% seeder fee is
a policy in the exchange app that builds a
Split— it is not a protocol rule.
8 — ProofAttachment
Binds a zero-knowledge proof to the safety-critical fields of an action, so a proof is inseparable from exactly what it attests.
- Binds: the
proof_system(Groth16/BN254, Groth16/BLS12-377, or a namedCustom), thecircuit_id+circuit_version, averifying_key_commitment, atranscript_hash, theproof_bytes, andProofPublicInputs— an open, scenario-chosen set of named commitments (inputs: Vec<(String, [u8;32])>), not a fixed exchange-specific shape. - Security binding. The named inputs fold into one length-prefixed,
domain-separated SHA-256 commitment, so no field can be silently dropped or reordered. Binding the
circuit_versionstops a proof for circuit vN being replayed against vM. The wire layer binds the proof; a verifier checks it and fails closed if the verifying key is missing.
9 — FailToDeliver
Signals that a paid action failed after pre-check, and carries a callback telling the secret holder to rotate or invalidate the bearer secret — carrying only commitments, never a secret.
- Binds: the
delivery_id, a genericoriginal_ref(the failed action, not an order-specific id), theasset, thepublic_token_hash, theholder_fingerprint(who must rotate), a closed-setFailReason, and aretry_count. - Security binding. The reason is a closed enum (endpoint error, ack timeout,
token still unspent, token already spent, ZKP invalid, mediator policy reject) — no
free-text catchall, so a failure can't smuggle attacker text into a wallet rotation hook.
The hook is idempotent by
(ref, reason, nonce); replaying the same failure rotates nothing twice.
The same primitives, every scenario
The protocol does not change shape per use. The table below shows the identical primitives serving very different applications — the exchange is one row, not the structure.
| Scenario | Primitives in play | What lives in the application |
|---|---|---|
| Marketplace / shopping | PaymentRequest, Payment, Receipt, Refund; MediatedConditional for held settlement | Cart, listings, return policy |
| In-game economy | PaymentRequest, Payment, MediatedConditional (a Custom 2-of-2 game asset) | Item catalogue, trade rules |
| Banking / transfers | Payment, Receipt, Refund | Account model, statements, reversals |
| Multi-party payouts | Split (commissions, royalties, payroll, revenue-share) | Who gets what share, and when |
| API / inbound reach | PaymentRequest (purpose: Reach), Payment, Receipt | Reach pricing, rate policy |
| Exchange | PaymentRequest as an order request; EncryptedBearerDelivery + MediatedConditional swap legs; Split for the seeder fee; ProofAttachment for exact-fill proofs; FailToDeliver to recover a stuck leg | Order book, limit orders, pair policy, the 0.1% seeder fee, swap-leg constraints |
Exchange-policy examples (not protocol rules). Constraints that look like
custody or atomicity rules are exchange application policy built on the primitives, not
properties of the scheme. The Webycash exchange treats bearer legs (Webcash, Voucher) as non-atomic and requires at least one arbitrable leg (a MediatedConditional over ARK or RGB) in any cross-rail bearer swap; it forbids Webcash ↔ Voucher because two bearer rails leave nothing for a
referee to enforce. A bank, a game, or a shop composing the same primitives sets entirely
different policy.