Rand Protocol
Documentation
Guides

Mint and burn

How RAND enters the pool - genesis deposits and the testnet faucet - and how it leaves it - fees and the burn words of a bundle - and what each movement publishes.

Use this page to run a faucet against a test chain, to understand what a Mint transaction is on the wire, and to see exactly how a bond or a bridge burn takes value out of the pool. Every entry and every exit is public; everything in between is a note.

The faucet mint

A Mint is the only way RAND is created after genesis on chain 21, as on chain 20, and it exists only on chains whose genesis says "faucet": true. It is a validator-signed, bundle-less transaction:

Action::Mint { cm: Word8, pk: Word8, time: u32, r: Word8, envelope: Envelope, amount: u64,
               minter: PublicKey, signature: Signature }

rand_mint(address[, amount]) on a validator node builds a note of amount to the given rand1… address, seals its envelope under a throwaway sender key, signs the mint with the node’s own Dilithium2 key, and submits it through the normal mempool — so the mint goes through consensus and every node applies it. The cap is 100000000000 units, 100 RAND, per call, and the default is the cap. Since chain 14 the mint carries the note’s opening — pk, time and r — and the signature covers it: admission recomputes the commitment of (pk, no sender, amount, asset 0, time, r) and refuses a cm that does not match with the mint's commitment does not open to its published note and amount, and it holds time to the bundle window. rand_mint’s parameters are unchanged. The signed message is blake3("rand-mint-2" ‖ bincode(chain_id, cm, pk, time, r, envelope, amount)) on chains 14 to 19; on chain 20, whose genesis sets binding_domain: 1, it is rand-mint-3 over the genesis hash followed by the same fields, so a mint signed for one chain is refused on any other, even one sharing the chain id and the validator keys. An observer has no validator key and answers faucet mints are signed by validators; ask a validator node; a chain without the flag answers faucet is disabled on this chain.

Chain 21’s faucet is on but bounded by its genesis staking section, with the same values as chain 20’s:

rulechain 21 (as chain 20)refusal
recipientsan allowlist of 16 wallets (staking.faucet_recipients); the mint’s published pk must be on itthe faucet may not mint to this recipient (not in staking.faucet_recipients), permanent
budget10,000 RAND per 1,000-block epoch (staking.faucet_budget_per_epoch), across every validatorthe faucet budget of … for this epoch is exhausted (… minted); the next epoch admits it
minters18 of the 26 validators (staking.faucet_minters, listed since chain 16); the mint must be signed by one of themminter … is not a faucet minter on this chain

So rand faucet works on chain 21 only for a wallet on the list, asked of a validator node whose key is a listed minter; any other address has to be paid by someone who holds RAND.

rand faucet                          # 100 RAND to this wallet's address, waits for the commit
rand faucet rand1… --amount 25       # to another address, less than the cap
→ {"method":"rand_mint","params":["rand1…", "100000000000"]}
← "9ab1c0…4f"

What is public: the new note’s commitment, its envelope, the amount in the clear, and the minting validator’s public key (shown as its address) and signature. The opening also publishes the note’s owner key pk, so a faucet note’s owner is public, as a withdraw’s payout is; what stays hidden is when and where that note is later spent. The one-hop link from “100 RAND was minted” to “a note worth 100 RAND exists” is the same visibility a transparent-to-shielded deposit has anywhere. Admission checks that the faucet is enabled, the amount is under the cap, the epoch’s budget has room, the recipient is on the allowlist where the genesis has one, the commitment opens to the published note, the minter is a validator, and on the minter list where the genesis has one, and the signature verifies; a mint pays no fee.

rand_getTransaction renders one as { "kind": "mint", "cm": "…", "amount": "100000000000", "minter": "<validator base58>" } with "bundle": null — the amount is a decimal string, like every u64 amount the RPC serves since chain 14; the explorer lists them under kind=mint, one of the few kinds with a public amount.

Genesis deposits

The other way value enters is the genesis file: each --alloc rand1<address>=<RAND> to rand-node genesis becomes one deposit note { cm, envelope, amount, opening } with fresh commitment randomness, the first leaves of the tree. Chain 21 (fullnode v0.8.0, live since 2026-10-12) has ten genesis notes: seven RAND notes, 3,938.879078887 RAND in all (genesis_deposited), the operator balances found by a scan of chain 20’s pool at heights 822,056 to 822,229, and three zUSD notes of 10, 89.002999 and 0.999 zUSD, the 100.001999 zUSD of bridge custody carried from chain 20’s state at height 814,702 (Bridge), which are not RAND and not counted in genesis_deposited. RAND held on chain 20 by wallets the operator does not hold, about 36,025 RAND (35,040 of it faucet mints to the allowlisted recipients), and 2.606 RAND of unwithdrawn validator fees were not carried. One more genesis entry is not a note at all: the foundation treasury, 100,000 RAND of new issuance in a multisig account under 2 of 3 Dilithium2 signers, a public balance in the multisig register (multisig_issued), which reaches the pool only as the chain-computed notes a MultisigPay creates. History: chain 20 had nine, seven RAND notes of 5,184.243719258 RAND and two zUSD notes of 10 and 89, carried from chain 19; chain 19 had eight, seven RAND notes of 5,294.644359629 RAND and one of 10 zUSD; chain 18 had six RAND notes, five of 1,000 RAND and one of 300 RAND; chains 14 and 15 had five of 1,000 RAND. The amount is public so everyone can add up the initial supply, and since chain 14 the note carries its opening too, so a genesis note’s owner is public by design. Re-cutting the same allocations yields different notes and a different genesis hash, on purpose.

Burns

Every transaction carries one four-slot hidden-asset bundle, and it has two burn words: burn_r is RAND leaving the pool into a public place, and burn_a is an amount of the token named by burn_asset. The bundle guest balances both groups in one proof, and admission requires all three to be zero except on these actions:

burnrulewhere the value goes
a Bond’s bundleburn_r == amountthe validator’s public stake in the register
a BridgeBurn’s bundleburn_asset == asset, burn_a == amount, burn_r == 0, asset != 0destroyed on Rand; the source-chain contract releases amount of the named coin against the guardian-signed burn message. Since chain 20 the chain keeps a 10 bps fee as a zUSD note to the treasury and the release is amount − fee
a TokenBurn’s bundlethe same shape as a bridge burn’sdestroyed; the RPL token’s public total_supply drops by exactly that
an Invoke’s bundle (RPL-2, since chain 20)burn_r, and burn_a of burn_asset, as the program’s transition declaresRAND and tokens deposited into the program’s public vault, or the program’s own token destroyed; a vault pays out again only as chain-computed notes (Programs)
a CreateMultisig’s or MultisigDeposit’s bundle (chain 21)burn_r is the RAND paid inmoved into the multisig account’s public balance (multisig_rand_in); it comes back to the pool only as the chain-computed notes a MultisigPay creates (Transactions)
a PerpDeposit’s bundle (RPL-3, chain 21)burn_a of the market’s collateral asset, zUSD on chain 21credited to a trading account in the perps engine; a withdrawal pays out as a note the chain computes

(A register_aggregator’s bundle also burns its genesis bond through burn_r; aggregation is off on chain 21.)

Burns are not fees. A bond’s burn is RAND moving from the pool to the register and is counted in the supply audit’s burned (and reappears in register_total). A bridge burn is one bundle since chain 14 (it was two before): slots 0–1 burn the bridged asset and slots 2–3 pay the fee, so it touches RAND supply only through that fee, BRIDGE_BURN_FEE, 0.01 RAND. It must name a coin that backs the asset, release a whole number of that coin’s units, and fit what that backing has locked (Bridge). On chain 20 its genesis bridge.fees also takes 10 bps of every bridged mint and burn in zUSD: a deposit credits the gross less the fee and a burn releases amount − fee, each fee a shielded zUSD note to the treasury. The fee note stays issued and backed, so zUSD’s total_supply == Σ locked still holds; it is not a RAND movement and does not enter the RAND supply audit. A TokenBurn pays the 0.001 RAND bundle base; a bridged token is refused there and leaves through bridge-burn.

One fee is also a burn on every chain since 15, chain 21 included: the genesis sets tokens.burn_registration_fee, so the 1 RAND registration_fee of a RegisterToken or RegisterBridgedToken is destroyed instead of paid to the proposer, who keeps only the bundle base. It is counted in burned and, separately, in registration_fees_burned (RPL tokens). On chain 21 every bundle’s floor is burned the same way: the genesis fees section (burn_base, burn_floor) destroys the ledger’s own floor for the bundle — the 0.001 RAND base, a deploy’s per-word term, a call’s gas and byte terms, a bridge burn’s 0.01 RAND — and the proposer keeps fee − floor; the burn is counted in burned and in base_fees_burned (Fees).

rand bond <validator> 1000 [--registration <hex>]     # burns 1000 RAND out of this wallet's notes
rand bridge-burn <ASSET> <AMOUNT> <TO_CHAIN> <TOKEN> <TO>   # burns AMOUNT of a bridged asset, released as TOKEN on TO_CHAIN
rand token burn <ASSET> <AMOUNT>                      # destroys AMOUNT of an RPL token this wallet holds

Fees are the other exit

Every bundle’s fee leaves the pool into the block proposer’s rewards, a public register field, and comes back into the pool only when the validator withdraws it as a note (Staking). A Withdraw pays the 0.001 RAND base out of the amount withdrawn to the proposer of the block that applies it; that base never leaves the register, so it is not a crossing.

How supply moves

in:   genesis_deposited, faucet_minted, withdraw_deposited, program_rand_out
out:  fees_paid, burned
pool_value     = in − out
total_supply   = pool_value + Σ register (stake + pending + rewards) + program_rand_held
               ==  genesis_deposited + genesis_staked + faucet_minted − slashed − registration_fees_burned

program_rand_held and program_rand_out are there since chain 20 (RPL-2): RAND an Invoke burns into a program vault through burn_r is counted in burned on the pool side and held in the vault, and what a vault pays out as notes comes back into the pool. rand_getSupply serves both, with invariant_holds. Chain 21 adds the same pair for the perps engine (perps_rand_held, perps_rand_out, both 0 while its one market is collateralised in zUSD) and five multisig_* counters: multisig_issued (the treasury’s 100,000 RAND), multisig_rand_in and multisig_rand_out (what creations and deposits burned in and what payments paid out as notes), multisig_base_out (the 0.001 RAND bases payments paid proposers out of the accounts) and multisig_rand_held, their net (Supply).

Only a faucet mint adds to what the chain has issued after genesis (chain 21’s genesis itself issued 26,000 RAND of stake, 3,938.879078887 RAND of notes and the treasury’s 100,000 RAND), and on chain 21 a burned registration fee and every burned fee floor take from it: slashed would count a slashed aggregator bond or, under a genesis staking.slashing section, a slashed validator stake, and chain 21 has neither (aggregation is off and slashing is null). A bond, a withdraw, a vault deposit, a multisig deposit or payment and a perp deposit move value between the pool and the public registers, and create nothing; a tip moves from the pool to the proposer’s row, and the floor under it is gone. Supply has the counters and a worked example. The block-aggregation subsidy — new RAND per sealed block on a halving schedule, paid to an aggregator as a deposit note — would be the first scheduled issuance, and it is not active on chain 21.

Last verified against fullnode commit c0878c3f (chain 21) on 2026-10-12. Where the code and this page disagree, the code is right; tell us.