Skip to main content
Each raffle runs for four weeks. At the end of every week, the rewards you claimed that week and the tier they earned you are turned into raffle entries. When the fourth week closes, your entries from all four weeks are added together, frozen in a public snapshot, and a public random number picks the winners. Entries are counted per wallet. If you have linked more than one wallet, each wallet earns entries from its own claims and appears in the snapshot on its own. The raffle and the weekly USDC reward pool are separate. Both use the same weekly tier, but they calculate rewards differently.

Prizes

Rabbithole awards three fixed prizes every month: The three prizes total 5,000 USDC. The public snapshot commits the wallets, entry counts, and three winners. It does not include the prize amounts; those follow the fixed schedule above.

How Entries Are Calculated

At the end of each week, Rabbithole determines your tier from the USD value of rewards you claimed during that week, before any campaign multiplier. See Tiers and Leaderboard for the thresholds and cutoff. Every campaign has a campaign multiplier. The default is 1×, and selected campaigns carry 2× or 5×. The multiplier weights the USD you claimed from that campaign before your tier multiplier is applied. It does not change your tier.

Worked Example

Suppose you claim $10.25 from a 1× campaign and $1.50 from a 5× campaign during one week.
  1. Your claimed value before multipliers is $11.75, which puts you in Gold for that week.
  2. Your weighted claimed value is $10.25 × 1 + $1.50 × 5 = $17.75.
  3. Gold has a 2× tier multiplier, so the result is $17.75 × 2 = 35.5.
  4. The result is rounded down, giving you 35 entries for the week.
The campaign multiplier changes how much a particular campaign contributes. The tier multiplier applies once to the weighted total. Your four finalized weekly entry totals are added together when the raffle closes. When you are signed in, the app shows the weekly and monthly cutoffs. Open the raffle page from the ticket button to see your entries.

The Public Snapshot

When the fourth week closes, the entry pool is frozen in a public snapshot:
The endpoint returns compact JSON with no whitespace. Pretty-printed, it has this shape:
raffleId identifies the draw, numberOfWinners fixes the number of draws, rows lists every eligible wallet with its entry count, and totalTickets is the sum of those counts. Entry counts are strings so large integers stay exact. Wallet addresses are lowercase and sorted lexicographically. canonicalIndex is the wallet’s zero-based position in that order. The order matters when reproducing the winners.

On-Chain Commitment

Before requesting randomness, Rabbithole hashes the snapshot with keccak256. The hash covers the exact UTF-8 bytes the endpoint returns, so hashing the raw response body reproduces it. If you rebuild the object yourself, serialize it with no whitespace and preserve this property order:
  1. version
  2. raffleId
  3. numberOfWinners
  4. rows
  5. totalTickets
Each row must use canonicalIndex, walletAddress, then ticketCount. Rows stay in ascending canonicalIndex order with no extra properties. The production RaffleManager is deployed on Base mainnet (chain ID 8453) at 0xbd4452ca27e71c9bd00fac9da50460d617d5d3ff. Read getRaffle(raffleId).snapshotHash and compare it case-insensitively with your computed hash. A match proves that the published wallets, entry counts, and winner count are the inputs committed before the draw.

Pyth Randomness

RaffleManager requests randomness from Pyth Entropy V2. Pyth fulfills the request in a later transaction, and RaffleManager records the final randomNumber on-chain in the RaffleFulfilled event and the raffle record. You can inspect RaffleManager events on BaseScan. For example, this fulfillment transaction recorded the random number for raffle 2.

Reproducing the Winners

For each draw index i, starting at 0, calculate:
Walk the wallets in ascending canonicalIndex, adding their entry counts until the target falls inside a wallet’s range. Record that wallet, remove it and all of its entries, and then calculate the next draw against the new remainingEntries total. Because a winning wallet leaves the pool, each wallet can win at most once per raffle. Draw 0 is prize rank 1, draw 1 is prize rank 2, and so on.

TypeScript Verifier

Save this as verify-raffle.mts, install viem and tsx, and run it with a snapshot URL, the RaffleManager address, and a Base RPC endpoint:
For the historical raffle 2, the verifier reports a single winner, 0x822e04f2050e146f824a908c5dd1bfd34935df8a. Anyone running it against the public snapshot and the on-chain random number gets the same result.
The verifier needs only the public snapshot, the RaffleManager address, and an RPC endpoint. Use a trusted Base RPC provider for independent verification.

Claiming Prizes

Winners are shown on the raffle page after Pyth fulfills the randomness request and Rabbithole runs the draw. If you won, the raffle page shows your prize and a Claim button once the prize is ready to be paid. Prize rank 1 receives 3,000 USDC, rank 2 receives 1,500 USDC, and rank 3 receives 500 USDC.