Every Winner Is Verifiable
You don't have to trust us. The proof is public.
How a winner is picked
- 1
Entries are sealed
Like locking a sealed envelope in a public vault.
When the sweepstakes ends, every entry is uploaded to IPFS and its fingerprint is recorded on Arbitrum. From this moment on, no one, including us, can add, remove, or edit entries.
- 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
Math picks the winner
Open the envelope, apply the dice roll, read the name.
The formula is public:
(random % totalEntries) + 1. Given the same random number and the same frozen entry 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
- Entry number
- Entry code
- Identity commitment (one-way hash)
- Timestamp
The identity commitmentis a one-way SHA-256 hash of your account combined with the sweepstakes ID. Nobody can reverse it to find you, but you can recompute it yourself to prove the entry is yours. Because the hash is sweepstakes-scoped, your activity also can't be linked across sweepstakes.
Verify your entry
Enter your sweepstakes ID and entry code. Here's what you'll see.
Your entry inside the frozen IPFS dataset.
Cryptographic proof it was committed before the draw.
The random number and formula that picked the winner.
Protocol details
The full verification pipeline is open for inspection. After any completed sweepstakes, you can independently reconstruct the result:
- Read the on-chain
Commitmentstruct to get the manifest hash, entry count, and winner count - Convert the manifest hash to an IPFS CID and fetch the manifest JSON
- Download entry chunks from IPFS and verify the Merkle root matches
- Read the
RandomWordsFulfilledevent to get the VRF random numbers - 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 randomnessWinner 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 = 8432Every winner on Rafli can be independently verified.
Browse Sweepstakes