THE RAFFLE FAIRNESS · DRAW #2049

Commit. Reveal. Recompute.

The operator cannot bias which holder wins. The server seed is committed before the window closes; the roll is HMAC-SHA-256 of the resolved slot hash keyed by that seed, walked over the weighted holder snapshot. Recompute it here and check the winner yourself — we never ask you to trust our outcome flag.

Drawn  Pot 0 cards · $0Outcome VOID
FOUR STEPS · ONE VIEWPORT
Commit > Snapshot > Reveal > Roll
  1. Commit
    SHA-256 of the server seed lands before the window closes
    A 256-bit server seed is generated and its SHA-256 hash is committed before the target slot resolves. The operator cannot swap the seed once the slot is known.
    serverSeedHash = SHA-256(serverSeed)
  2. Snapshot
    Every holder balance is recorded at the close slot
    When the window closes we record a Merkle root of every eligible $GACHA balance at that exact Solana slot. Nobody touches your balance — we just take a tamper-evident snapshot the weighted pick runs over.
    snapshotMerkleRoot = MerkleRoot(holders[closeSlot])
  3. Reveal
    We publish the seed + the resolved slot hash
    Once the target slot lands we reveal the serverSeed and the resolved slot hash. Anyone hashes the seed to confirm it matches the commit, then feeds the slot hash into the roll.
    reveal: serverSeed ‖ slotHash
  4. Roll
    HMAC-SHA-256 picks the weighted winner
    roll = HMAC(seed, slotHash ‖ utf8(drawId)), mapped into [0,1). We walk the prefix-sum of weights — first holder whose slice covers the offset wins the whole pot.
    roll = HMAC(seed, slotHash ‖ drawId)
SECTION 02

Recompute the roll. Right here. In your browser.

The widget re-runs the same HMAC-SHA-256 the worker ran, confirms the revealed seed hashes to the pre-window commit, and compares the published roll. If our published roll diverges from what your browser computes, the badge turns red. The reveal has not landed for this draw yet, so the verifier reports the seed as missing — that is the honest current state, not an error.

RECOMPUTED IN BROWSER
Commit-reveal · HMAC-SHA-256
● AWAITING REVEAL
DRAW #2049
AUTO-RUN · NO FETCH
Seed commit
089cdc37b889c9c23c440499e7393ff770111e25f8604207dde210fad8c1f280

The roll lands once the target slot resolves on-chain: the operator reveals the committed server seed and the resolved slot hash. This verifier then re-checks everything in your browser.

The potnothing opened

An operational error voided this draw — no winner was named. The opened cards rolled forward to draw #938.

No packs were opened during this window

No winner

An operational failure (e.g. a reveal-block abort) aborted this draw — an error state, shown unedited, not a fair no-winner result. The opened cards rolled forward to draw #938.

REFERENCE IMPLEMENTATION

Copy-paste. Run it locally. Same answer.

raffle-roll.tsTypeScript
import { createHmac } from 'node:crypto';

// Mirrors the draw-runner's roll derivation.
export function raffleRoll(
  serverSeedHex: string,
  slotHashHex: string,
  drawId: number,
): string {
  const mac = createHmac('sha256', Buffer.from(serverSeedHex, 'hex'));
  mac.update(Buffer.from(slotHashHex, 'hex'));
  mac.update(Buffer.from(String(drawId), 'utf8'));
  return '0x' + mac.digest('hex');
}

// Map the roll into [0,1), then walk the holder snapshot's weight
// prefix-sum (sorted by address, Merkle-committed) — the first holder
// whose cumulative slice covers the offset wins the whole pot.

Node ≥ 20 · no dependencies · same output as the browser widget.

Missing rows land once the draw reveals. Very early draws predate parts of this record — what exists is shown, nothing is backfilled.This draw in historyHow the mechanism works
COMMIT PHASE

Partial state for Draw #2049

serverSeedHash
089cdc37b889c9c23c440499e7393ff770111e25f8604207dde210fad8c1f280
holders snapshotted
(awaiting close)
slot
(awaiting reveal)
serverSeed
(awaiting reveal)