Skip to content

Tutorial: a fair raffle ​

Source: verity-examples/contracts/src/Raffle.sol (with tests).

Players buy tickets with PLS. When sales close, anyone starts the draw. One verifiable random word picks the winning ticket, and the winner withdraws the pot.

The parts that matter ​

Lock entries when the draw starts. Once draw() runs, the state is Drawing and buyTickets reverts, so nobody can join after the randomness is requested.

solidity
function draw() external inState(State.Open) returns (uint256 requestId) {
    if (block.timestamp < closesAt) revert TooEarly();
    state = State.Drawing;                         // lock first
    requestId = s_coordinator.requestRandomWords(keyHash, subId, confirmations, CALLBACK_GAS_LIMIT, 1);
    drawRequestId = requestId;
    drawRequestedAt = block.number;
}

One draw only. draw() requires state Open, which is gone after the first call. There is no way to draw twice.

If the oracle never answers: refunds, not a re-draw. After refundAfterBlocks, anyone can switch the raffle to Refunding and every player reclaims their tickets. A re-draw would let someone who saw an unfavourable result in the mempool block it and try again.

solidity
function enableRefunds() external inState(State.Drawing) {
    if (block.number <= drawRequestedAt + refundAfterBlocks) revert TooEarly();
    state = State.Refunding;
}

A late answer is ignored, not reverted. The callback returns early unless the raffle is still Drawing and the id matches.

Pull payments. The callback only records the winner; claimPrize() sends the money.

Picking the winner ​

solidity
uint256 index = words[0] % tickets.length;
winner = tickets[index];

Each ticket has an equal chance. Buying more tickets buys proportionally more chance. The tests fuzz the word to check the winner is always a ticket holder and matches the formula.

Choosing refundAfterBlocks ​

Set it longer than the coordinator's request timeout, so the oracle and its backups have every chance to answer first.

Testnet: PulseChain testnet v4. Unaudited software; do not use on mainnet yet.