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 purpose hint (Payment | Settlement | Fee | Refund | Reach | Custom(String)) and a metadata: 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 DomainTagKind trait parameterizes the signing helpers over the tag enum. The generic primitives sign with the rail-agnostic DomainTag set; 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 identical sign / open discipline — the protocol never enumerates application object kinds.
  • Deterministic archived wire. Bodies are rkyv-archived; equal inputs always yield equal bytes. There are no HashMap/HashSet in 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), the payee_fingerprint, an idempotency key the eventual payment references, and an optional accepts_referee fingerprint when the action may be mediated — plus purpose / metadata and 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 idempotency back-reference, payer/payee fingerprints, amount_raw + asset, and a PaymentProof — either a Rail proof (an evidence_hash committing to the rail's proof of payment, plus an optional ZK proof) or a Bearer(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, and at_unix, plus purpose / metadata and 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-form reason.
  • 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 a Custom escape hatch), the recipient_fingerprint and a recipient_pubkey_commitment (tying the ciphertext to the exact key it was sealed to), the public_token_hash, the amount_raw + asset, the ciphertext and its ciphertext_hash (SHA-256), and an optional zkp (primitive 8).
  • Security binding. The verifier recomputes sha256(ciphertext) and checks it against ciphertext_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, the asset, a generic amount_raw, a generic locked_ref (a VTXO id, a UTXO, a contract output — the protocol does not interpret it), the signing parties and the referee fingerprint, the nonce_commitment, an optional zkp attesting the gate, and the outcome.
  • Outcomes are mutually exclusive by construction. The outcome is an enum of N mutually exclusive variants — Release, Refund, or Custom(label) — each carrying only its own tx_hash, the counterparty's encrypted_counterparty_partial_sig, and an optional referee_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, MediatedConditional has 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 + asset and the shares: Vec<Share>, each Share naming a recipient fingerprint, its amount_raw, and a per-share rail (AssetRef), plus purpose / metadata and 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 named Custom), the circuit_id + circuit_version, a verifying_key_commitment, a transcript_hash, the proof_bytes, and ProofPublicInputs — 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_version stops 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 generic original_ref (the failed action, not an order-specific id), the asset, the public_token_hash, the holder_fingerprint (who must rotate), a closed-set FailReason, and a retry_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.

ScenarioPrimitives in playWhat lives in the application
Marketplace / shoppingPaymentRequest, Payment, Receipt, Refund; MediatedConditional for held settlementCart, listings, return policy
In-game economyPaymentRequest, Payment, MediatedConditional (a Custom 2-of-2 game asset)Item catalogue, trade rules
Banking / transfersPayment, Receipt, RefundAccount model, statements, reversals
Multi-party payoutsSplit (commissions, royalties, payroll, revenue-share)Who gets what share, and when
API / inbound reachPaymentRequest (purpose: Reach), Payment, ReceiptReach pricing, rate policy
ExchangePaymentRequest as an order request; EncryptedBearerDelivery + MediatedConditional swap legs; Split for the seeder fee; ProofAttachment for exact-fill proofs; FailToDeliver to recover a stuck legOrder 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.

extro

A decentralised social & economic network. Reach has a price.