Docs
Contents

Concepts

Apps and vaults

An app is a Solana program registered with the ledger (register_app). Each app has its own Zcash vault: a shielded address whose spend key is split among the operators (FROST, 2 of 3). Keys for every app's vault come from one key generation, so a new app needs no new ceremony; each app has its own viewing key, so one app's deposits are invisible to another's.

An app starts Pending. The ledger's admin activates it with its vault address and a genesis note (the vault's first "head" note, mined on Zcash), after which it waits an activation delay (1 hour) before taking deposits. A deposit cap bounds what the app can hold.

Session keys

A player is an Ed25519 session key, one per app. It signs the deposit memo and every ledger action that touches the player's balance. It needs no SOL: the app (or a sponsor) pays Solana fees, and rollup transactions are free.

Where the key lives is up to the page. The testnet pages derive it from a passkey (WebAuthn PRF: same passkey, same key, on every device it syncs to) or keep a random session key in the browser, which the player must save. See TypeScript client: session and passkey.

Deposits

  1. The page builds a memo naming the session key, the player's payout address (a Zcash unified address), the vault, the network, an expiry height and flags, signed by the session key.
  2. It registers the intent with every operator (POST /v1/apps/{app}/intents) and gets back a session address: a diversified receiver of the vault, unique to the session.
  3. The player pays a fixed amount (the ledger's denominations: 0.01 or 0.1 TAZ on testnet) to that address from any Zcash wallet, through a ZIP 321 link that carries the memo as text (ZOL1:…). If the wallet drops the memo, the deposit still counts: the session address and the registered intent identify it.
  4. Each operator sees the note in its own scan. Once it has enough confirmations, 2 of 3 operators sign a credit, and a relayer submits it to the ledger, which adds the amount (less a 0.3% entry fee) to the player's balance.

Confirmation depth: testnet credits early, after 1 block (usually 1–2 minutes), up to the float: TAZ the operators keep in the vault to cover early credits. Deposits beyond it wait for full depth (60 blocks, about 25 minutes). A deposit that is never credited is voided and refunded to the payout address.

The payout address is fixed at the first deposit. The ledger stores only a keyed commitment to it; the operators check every payout against it.

Balances

A balance is per app and per session key: an amount, an exiting flag and an auto_exit flag. Balances are not tokens: they cannot be transferred. They move only into pots (through the app, with the player's signature), back from pots (cash-out), and out to Zcash (exit).

Pots, seats and receipts

A pot is where an app holds players' stakes during a session.

The receipt never leaves Solana: it is the authoritative list of who is owed what. Only the pot (an array of seat amounts) goes into the rollup. Whatever happens there, money can only move between that pot's seats, and cash-out pays amounts[i] to receipt.players[i].

Limits on the testnet: up to 16 seats per pot (a ledger setting), a pot open at most 1 hour before it starts, a session of 1 to 120 minutes.

The rollup session

Exits and payouts

Smallest withdrawal: 0.0005 TAZ on testnet (min_exit).

Who pays what

CostPaid by
Zcash deposit feeThe player's wallet
Entry fee (0.3%) and exit fee (0.3%)Deducted from the amounts; kept by the app's fee pool
Zcash payout network feeAn allowance per payout (20,000 zat on testnet)
Solana fees and rent for app actionsThe app or its service (a "house"), as fee payer
Rollup transactionsFree
A return action's Solana feeAn escrow the app funds with MagicBlock's delegation program

Guardians

Each operator also runs a guardian: it reconciles the ledger against the vault and can freeze an app on a mismatch (one guardian freezes; a threshold unfreezes). A frozen app takes no new value in, still returns pots and takes exit requests, and pays out once it's unfrozen. Separately, every operator pins the ledger's code and signs nothing if the deployed program differs.