Fairness

Every draw is committed on-chain before its randomness exists, and every result is recomputable from published data. Cheating would be publicly provable.

The draw protocol

  1. Freeze. The ticket snapshot for the draw is frozen: every eligible wallet and its exact ticket weight (fees paid, in wei), derived from chain history.
  2. Publish. The snapshot is published in full, and its hash is computed. Anyone can rebuild the same snapshot from chain data and check the hash.
  3. Commit. A commitment transaction is sent on-chain, binding the snapshot hash, the draw id, the algorithm version, and a future drand round at least 10 minutes ahead. At commit time, nobody on earth knows what that round's randomness will be.
  4. Reveal. drand publishes the round: BLS-signed randomness from the League of Entropy network, verifiable against the beacon's public key.
  5. Select. Winners are computed by a deterministic weighted-without-replacement algorithm over (snapshot, randomness). Same inputs, same winners, every time, on anyone's machine.
  6. Pay. Winners claim on the site; claimed prizes pay out in ETH. The full fairness bundle is published when the draw settles, before any claim.

The order is the point: the ticket set is fixed and publicly hashed before the randomness exists, and the randomness comes from a public beacon nobody here controls. There is no moment at which winners could be steered.

The commitment

The commitment is carried as calldata in a zero-value transaction from the published announcer address; the commitment id is the transaction hash. Its payload commits to everything that determines the outcome:

commitment = keccak256(
  snapshot_hash        // 32 raw bytes
  || u64le(drand_round)
  || u32le(len(algorithm_version))
  || algorithm_version // utf8
  || u64le(draw_id)
)

The bound drand round must be at least 600 seconds in the future at commit time. Randomness source: drand quicknet (League of Entropy mainnet; 3-second rounds; unchained BLS signatures), chain hash:

52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971

Any round is independently fetchable and BLS-verifiable at https://api.drand.sh/<chain-hash>/public/<round>.

Verify a draw yourself

Everything needed is in the draw bundle at /v1/draws/:id: snapshot URL and hash, commitment bytes and transaction, drand round and randomness, algorithm version, winners, and payout transactions. The verification is:

  1. Fetch the snapshot; hash it; compare with the published snapshot hash.
  2. Recompute the commitment from the bundle fields using the encoding above; fetch the commitment transaction from the chain and confirm the calldata matches.
  3. Confirm the commitment transaction landed before the bound drand round's time. That proves the ticket set was fixed pre-randomness.
  4. Fetch the drand round and verify its BLS signature against the quicknet public key.
  5. Run the winner-selection algorithm over (snapshot, randomness) and compare winners and amounts with the published result.

The repository ships this as a one-command check, pnpm verify-draw <drawId>, which performs exactly the steps above. But the point of the design is that you do not need our tooling: the encoding, the snapshot, and the beacon are all public, and any independent implementation must reach the same winners.

Claims never expire

A won prize stays claimable forever. There is no claim window, no sweep, and no forfeiture; claiming only accelerates the payment of money that is already yours. (The claim signature you sign on the site is fresh for 10 minutes as replay protection: if it expires you simply sign a new one. The prize itself never expires.)