Browse
Help us improveSign In

Every Winner Is Verifiable

You don't have to trust us. The proof is public.

How a winner is picked

  1. 1

    Tickets are sealed

    Like locking a sealed envelope in a public vault.

    When the raffle ends, every ticket is uploaded to IPFS and its fingerprint is recorded on Arbitrum. From this moment on, no one — including us — can add, remove, or edit tickets.

  2. 2

    Randomness arrives

    An independent referee rolls the dice.

    A random number is delivered by Chainlink VRF, together with a cryptographic proof the number wasn't tampered with. We can't predict it, retry it, or influence the outcome.

  3. 3

    Math picks the winner

    Open the envelope, apply the dice roll, read the name.

    The formula is public: (random % totalTickets) + 1. Given the same random number and the same frozen ticket list, anyone re-runs the formula and gets the same winner.

Public proof, private identity

A public ledger makes the draw verifiable. A public ledger must never carry personal data. Here's how we split them.

Never on IPFS

  • — Your name
  • — Your email
  • — Payment info
  • — Your account ID

Public on IPFS

  • — Ticket number
  • — Ticket code
  • — Identity commitment (one-way hash)
  • — Timestamp

The identity commitmentis a one-way SHA-256 hash of your account combined with the raffle ID. Nobody can reverse it to find you, but you can recompute it yourself to prove the ticket is yours. Because the hash is raffle-scoped, your activity also can't be linked across raffles.

Verify your ticket

Enter your raffle and ticket code. Here's what you'll see.

Found

Your ticket inside the frozen IPFS dataset.

Proved

Cryptographic proof it was committed before the draw.

Computed

The random number and formula that picked the winner.

Found in the raffle's URL

Protocol details▸

The full verification pipeline is open for inspection. After any completed raffle, you can independently reconstruct the result:

  1. Read the on-chain Commitment struct to get the manifest hash, ticket count, and winner count
  2. Convert the manifest hash to an IPFS CID and fetch the manifest JSON
  3. Download ticket chunks from IPFS and verify the Merkle root matches
  4. Read the RandomWordsFulfilled event to get the VRF random numbers
  5. Run the winner formula for each position and compare against the announced results

Commit-reveal protocol

// Commit-Reveal Protocol
// Step 1: Before random number exists
const ticketManifest = buildManifest(allTickets);
const commitHash = sha256(ticketManifest);
await blockchain.commit(commitHash); // Locked forever

// Step 2: Random number generated (can't be influenced)
const randomNumber = await chainlinkVRF.getRandomNumber();

// Step 3: Apply random to committed data
const winner = selectWinner(ticketManifest, randomNumber);
// Manipulation impossible: data locked before randomness

Winner selection formula

// Winner Selection Formula
const randomNumber = BigInt("0x7a3b9c2d...4f2c1e8a");
const totalTickets = 12_847n;

// Simple modulo operation
const winningIndex = Number(randomNumber % totalTickets);
const winningTicket = winningIndex + 1;

// Result: Ticket #8432 wins
// Anyone can verify: (random % 12847) + 1 = 8432
Verification tools →Arbiscan →

Every winner on Rafli can be independently verified.

Browse Raffles