Under the sand
Tech & math
Every round is a verifiable draw derived from a single 256-bit seed. No Math.random touches the outcome — one seeded PRNG drives everything, and the same (seed, snapshot) always yields the same field of 16 and the same winner, in the browser, in Node, and on-chain. The logic is a small core engine in TypeScript, mirrored 1:1 in Rust for the program, and a parity test holds the two byte-for-byte identical across 128 vectors.
01 Eligibility & weight
Any address above a minimum balance is eligible. Each holder's sampling weight is the integer square root of its balance (in base units):
Square-root weighting gives whales more presence with diminishing returns — quadrupling your balance only doubles your weight. We use integer sqrt (not floating point) so the result is bit-identical between JavaScript and Rust; a floating sqrt could differ in its last bits across languages and break determinism.
02 The PRNG & the seed
The engine uses mulberry32, a tiny 32-bit generator (the exact one already in the animation), advanced by the constant 0x6D2B79F5. The production seed is a 256-bit on-chain VRF value; we fold it into a 32-bit base with FNV-1a (offset 0x811C9DC5, prime 0x01000193) and spin up three independent streams by XOR-ing a salt:
select = mulberry32(base)
winner = mulberry32(base ⊕ 0x85EBCA6B)
cosmetic = mulberry32(base ⊕ 0x9E3779B9)
Integers in [0, n) come from a 64-bit fixed-point map — no modulo bias, and trivially reproducible in Rust as ((u32 as u64 · n) >> 32):
03 Building the field of 16
The 16 bulls are drawn by weighted sampling without replacement, with an anti-whale cap, using the select stream. Candidates are sorted by address (a stable, caller-independent order). For each of the 16 slots:
- Sum the weights of every candidate still under the cap:
W = Σ wᵢ. - Draw a target
t = ⌊ (u32 × W) / 2³² ⌋in[0, W). - Walk candidates accumulating weight; pick the first whose running sum exceeds
t. - Increment that address's count; once it reaches 3 it drops out of the pool.
So a whale can field up to 3 bulls (pay-to-advantage) but never a fourth, no matter how large. Expected appearances grow with √balanceand saturate at the cap:
04 The winner — uniform 1/16
Once on the sand, weight stops mattering. The winning slot is one draw from the independent winner stream:
Each of the 16 bulls has probability exactly 1/16. Combining the two stages, an address's chance of winning a round is its share of the field — bounded by the cap:
That's the whole philosophy in one inequality: pay-to-advantage, not pay-to-win. You buy more frequent presence (up to 3 of 16), never a better-than-1/16 bull once the gates open.
05 The elimination order is theater
The order in which bulls fall is a Fisher–Yates shuffle of the 15 losers from the cosmetic stream, with the winner appended last. It runs on a separate stream, so however dramatic the faena, it can never change who wins — the winner was fixed in step 04.
06 Field commitment
The fielded roster is committed to a root over its canonical serialization. Today that's an FNV-1a-64 digest (integrity + the verify page); on-chain it becomes a sha-256 Merkle root so the program can verify a (slot, address) proof before paying. The winning slot is derived from the seed alone — the address is bound afterward against the committed root.
07 The pot — 2% trading fee
$CORRIDA trades on Meteora with a 2% fee, and the protocol controls that fee stream. Every fee lands in the pot wallet:
A keeper sweeps the accumulated fees and the winner of each round takes the whole pot. No minting, no inflation — the pot is the trading volume made spectacle. (Holding $CORRIDA also weights you into the field; also holding $ansem multiplies your presence.)
08 Why you can trust it
The seed comes from an on-chain VRF; from it, anyone can recompute the field and the winner and get the identical result. The same logic runs in three places, held in lock-step: the site, the on-chain program (a 1:1 Rust mirror, verified by a parity test over 128 vectors), and the keeper. Replay the seed yourself:
Constants and algorithm reflect the current implementation. The FNV-commitment → sha-256 Merkle upgrade and the optional on-chain VRF/payout land with the program deployment.