Units
| Value | |
|---|---|
| 1 unit of collateral | 0.01 ZEC = 1,000,000 zats |
| 1 unit | 200 half-ticks (balances and costs are in half-ticks) |
| 1 half-tick | 5,000 zats |
| One matched YES/NO contract | locks 1 unit, pays 1 unit to the winner |
The escrow
Collateral sits at one Ironwood-only unified address whose spend authority is a FROST 2-of-3 group key from a distributed key generation. No relayer holds the whole key: any two must sign to move funds, and one alone cannot. The testnet escrow from the key ceremony (2026-10-23, deploy/README.md):
utest18yg3cneyjgxxknjm0j9020hmx5jp2wm67qn2p3rfmflct9hwlt363gzl50qeu3ms2u044hq8jzuzkl2tq8xa4m0ukzvlpqgtvu96ffyyIts group key a0cff44d86411e03d1ae3a76982d38bf0aac73db9568a2496324167486dbc534 is served by all three relayers at GET /group-key; it also signs outcomes.
Deposits
- Fixed denominations only: 1, 5 or 25 units (
DENOMINATIONS). Any other amount, or a note without a readable memo slot, is flagged and never credited. - The memo (ZIP 302
0xFF, 512 bytes):0xFF | 0x02 | epk | slot₀ | slot₁ | slot₂. Slotiis ChaCha20-Poly1305 ofid ‖ sᵢunder a key from X25519 with relayeri's memo key and a fresh ephemeral key. Each relayer can open only its own slot, so none ever reads your tag, and no order data or amount is in the memo. The app hands your wallet a ZIP 321 payment request (depositUri). - Crediting: after 10 confirmations, and only when all three relayers' own escrow scans found the deposit. The credit enters the circuit as a public per-row input. No single relayer can credit money the chain does not show.
Withdrawals
- You send all three relayers
POST /withdrawalswith the amount, a fresh shielded address, and a fresh XOR share of your tag each. - In the next batch, the circuit takes the amount from the row whose key the shares rebuild, only if it covers it, before orders reserve funds. A public bit per slot (two slots per batch) says whether it went through; it does not say whose it was.
- Debited withdrawals are paid in one v6 transaction with an Ironwood output per payee and change back to the escrow, ZIP 317 fee, wallet-default padding. Each withdrawal keeps 2 half-ticks (10,000 zats) toward the fee: you receive
(amount − 2) × 5,000zats. - Status:
pending → debited → paying → paid(with the txid), orrefused. A payout the escrow cannot cover, or one a node misses, showspayout: "retrying"and is retried with backoff; it never stops clearing.
Relayers do see each withdrawal's amount, address and time (they need them to pay), so amount and timing can link a deposit to a payout at the relayers (#91). Withdraw round amounts at unremarkable times if that matters to you.
Judge credits are not money
Judge mode (testnet only) opens an account with mock credit: 25 units, no deposit. Because a judge claim shows every relayer the new account's id, each relayer flags that row as mock, feeds its flags into the circuit as private input, and the circuit refuses any withdrawal from a flagged row if any relayer flagged it (#104, test mock_rows_never_withdraw). The refusal looks like any uncovered withdrawal. A judge account that later receives a real deposit stays mock: deposit with a fresh tag. Mainnet builds refuse judge mode.
Limits on the demo
- The balance table has 48 rows on the hosted demo (one per funded account); when it is full, Judge mode answers "table full". Rows are not reclaimed yet (#64).
- Mock and real accounts trade in the same markets, so a real account can win mock credit, and the escrow can hold less than real accounts are owed. A payout it can't cover is retried. That is acceptable on testnet only.