Appearance
Security rules for consumers
The VRF guarantees the result cannot be chosen. Your contract still has to avoid giving anyone a second chance. Most exploits of "random" games come from these mistakes.
1. Lock state when you request, not when you receive
Everything that the result affects (entries, bets, the participant list, a player's position) must be fixed before requestRandomWords. If a player can still change their bet after the request, they can wait until the result is visible in the mempool and react.
solidity
state = State.Drawing; // lock first
requestId = s_coordinator.requestRandomWords(...);2. Never re-request because of the outcome
No function should let anyone ask for new randomness for the same draw after seeing a result, including "retry" buttons, admin functions, or a new request when the callback "failed".
3. A cancelled request is a refund, never a reroll
A request can be cancelled after the timeout. The requester may already have seen the fulfilment transaction in the mempool before cancelling. If cancelling led to a fresh draw, they could keep cancelling until they liked the result. On timeout: refund (see Raffle) or keep the item locked. Never draw again.
4. Don't use the result in the same transaction it arrives
Do the heavy work in the callback or later, but don't let a third party trigger an action that reads the result and can revert depending on its value (they would revert on outcomes they dislike).
5. Callback failures are final
A reverting callback still consumes the request. Make the callback unable to revert (see Handling the callback).
6. Choose confirmations for the value at stake
A deep chain reorganisation could replace the request's block and therefore the seed. The oracle waits minimumRequestConfirmations before proving, and re-checks that the block is still canonical. Use more confirmations for higher stakes.
7. Bias from %
word % n is unbiased for practical purposes when n is small compared with 2²⁵⁶ (the bias is about n / 2²⁵⁶). For huge n, use rejection sampling.
8. Test the ugly paths
Use the mock coordinator to simulate: no answer (refund path), every possible outcome (fuzz the word), a reverting callback, and a late answer after a refund.