HOW IT WORKS · HOW TO VERIFY

Don’t trust us.
Verify the draw.

Every round is a public paper trail: who entered, how the winner was picked, where the SOL went. Here’s how it works, and how to check it yourself.

Pre-mainnet preview · real devnet rounds, verifiable on-chain and recomputable in your browser.

01 · THE MECHANISM

Six steps. Every ten minutes.

  1. 01

    Hold $BALL

    Every 10,000 $BALL in your wallet is one ticket. Nothing to sign.

  2. 02

    Snapshot

    At a fixed slot, every eligible wallet and its ticket range is recorded.

  3. 03

    Lock the list

    A Merkle root fingerprints the list before any randomness exists.

  4. 04

    Outside randomness

    ORAO VRF supplies a random number nobody on the team can choose.

  5. 05

    Anyone settles

    The program checks the winning proof. Anyone can trigger it.

  6. 06

    Paid in SOL

    90% to the winner. 10% buys and burns $BALL. No team cut.

PROVABLY FAIR

What gets published.

Before every draw we publish two files anyone can download and audit: the eligible-holder snapshot and the ticket-range matrix. Pair them with the on-chain Merkle root and ORAO randomness and the whole draw is checkable end to end. No trust required.

snapshot.jsonWHO WAS ELIGIBLE
TOP OF FILE
mint, slot, ticketUnit (10,000 $BALL), totalTickets
BODY
Every eligible wallet with its balance and ticket count, sorted by wallet address.
HASH
SHA-256 of the canonical JSON = the snapshotHash committed on-chain. It locks the participant set before any randomness exists.
tickets.jsonWHICH TICKET BELONGS TO WHOM
BODY
An array of { owner, from, to }: each holder owns one contiguous ticket range.
MERKLE LEAF
sha256(owner ‖ from · u64le ‖ to · u64le), hashed sorted-pair up to the root stored in the round.
ORDER
Sorted by owner. Any order gives the same root: the proof is position-independent.

How to verify a draw

  1. Download both files for the round from the snapshot and tickets links (or the round record).
  2. Rebuild the Merkle root from the ticket ranges. It must equal the merkleRoot stored in the on-chain round.
  3. SHA-256 the canonical snapshot. It must equal the committed snapshotHash.
  4. Compute winningIndex = bigEndian(sha256(oraoRandomness64)) % totalTickets from the ORAO VRF account for that round.
  5. Walk the ranges to the one containing winningIndex. Its owner must equal the recorded winner and the settle transaction.

VRF randomness

The winning index comes from ORAO VRF on Solana: unpredictable before it is drawn, verifiable after. Nobody on the team can choose it.

Frozen participant set

The snapshot is committed at a fixed Solana slot, before randomness. Anyone fetching that slot later sees the exact same holders.

Equal odds per ticket

Every ticket has exactly 1 / totalTickets chance. More $BALL just means more tickets, never better tickets.

Independent re-runs

Pull the same files, run the same hash and modulo, walk the same ranges. The result reproduces for anyone, every time.

02 · FIND A DRAW

Your round. Its receipts.

Settled devnet rounds 1-3.

ROUND #2DEVNET
0.00 SOL
Winner
53aYSeEeQ3DCmuzuGch8LXfaudsgXZqZ95AsPUhcW2iH
Winning ticket
#1 of 6
Snapshot slot
521264935
03 · PUBLIC VERIFIER

Run the check yourself.

One open-source script. It reads the chain and the published files, then recomputes every step. No trust required.

# 1. Get the public verifier
curl -O /proofs/verify_draw.mjs
npm i @solana/web3.js

# 2. Check any round against the chain
node verify_draw.mjs \
  --rpc https://api.devnet.solana.com \
  --program CBGRwadBhjMwswqYBe6788DFnHYTj1rCU4J994epwEZP \
  --round 1 \
  --data ./proofs/devnet
Example output · round 1 (not run here)✓ Merkle root matches on-chain round✓ Snapshot SHA-256 matches committed hash✓ Seed = sha256(roundId ‖ root ‖ slot)✓ Winning index 4 → AaqP…WoV○ ORAO account closed: source check skipped✓ Settle tx pays 0.09 SOL to winner✓ DRAW VERIFIED: 5 passed, 0 failed
04 · THE DETAILS

All the nuts & bolts.

The exact winning calculation

seed = sha256(roundId ‖ merkleRoot ‖ slot)winningIndex = bigEndian(sha256(randomness64)) % totalTickets

The seed is committed before ORAO is asked. The ticket range that contains the index is the winning wallet.

Where the pot comes from

5% Meteora feeVault PDA
90% winner 10%

The 10% is swapped to $BALL via Jupiter and burned. No team cut, no rollover.

Every ten minutes

Draws run on 10-minute boundaries in America/New_York. Fulfillment and settlement can take a moment longer.

Guaranteed by the program*

  • Immutable program, no upgrade authority
  • Root locked before randomness
  • Deterministic winning index from VRF
  • Settlement rules & recorded payout

Operator-published, but checkable

  • Which wallets are excluded
  • Snapshot accuracy & ticket ranges
  • Snapshot timing & draw liveness
  • Files match the committed set

*Program-level guarantees apply once the upgrade authority is revoked at mainnet launch. The addresses below are the real deployed devnet instance, which stays upgradeable while we iterate. Open them on the explorer and check for yourself.

Seen enough?

Check the latest winners, each one with its own receipts.

See results