Docs/Examples/Lottery Sweepstakes

LotterySweepstakes (Weekly VRF Draw)

A ticket-based weekly lottery where VRF picks one winner from a weighted pool — nobody should control when the draw runs.


Overview

LotterySweepstakes is a recurring lottery with proportional-ticket weighting. Players buy tickets at ticketPrice ETH each; more tickets = higher draw weight. On schedule, AutoLoop uses ECVRF to pick one winner proportionally, transfers the prize pool (minus fees), and resets for the next round.

PropertyValue
Base contractAutoLoopVRFCompatible
VRF usageWinner selection
Gas per tick~75k + 8k per entrant
Sourceautoloop/src/agents/LotterySweepstakes.sol
Tests22 passing (unit + fuzz)

Why AutoLoop + VRF Are Structurally Required

Inverted interest — identical to CrumbleCore but financial. Two structural failures stack:

  1. Timing manipulation: with a deterministic draw, the trigger holder can compute who wins before calling and time the trigger to a favorable state, or hold it until they've bought a winning position.
  2. Free-rider failure: if the prize pool is large enough, nobody wants to trigger the draw for free — every player reasons "let someone else pay gas." Everyone reasons identically, so the loop self-stalls. A neutral keeper with a fee incentive is the only structural fix.

Keeper Trust Model

What AutoLoop guarantees: Ticket holders cannot predict the winner or manipulate the draw timing. The keeper's private key is required to produce the VRF proof, so outcomes are unguessable to participants.

What the keeper knows: Each keeper generates its VRF proof off-chain before submitting, so it knows its own output — but the keeper holds no tickets, so it has no stake in who wins.

How collusion resistance works: AutoLoop registers multiple independent controllers per VRF contract. Each controller's VRF output is unique (derived from their individual private key applied to the same seed). They race to submit:

  • Any one controller can withhold their output if they dislike it
  • Another controller immediately submits with a completely different, independent winner
  • The colluding controller cannot prevent this or predict what the alternative outcome will be
  • Determining a specific winner requires ALL registered controllers to withhold simultaneously

This is the same trust model as Chainlink VRF: shift trust from participants (who have conflicts of interest) to a decentralized set of keepers (who don't hold tickets). Additional controllers can self-register via registerControllerKey() to raise the collusion bar for high-value rounds.

Mechanics

  • Enter: buyTickets(count) at ticketPrice × count ETH. Calling again adds more tickets to the same address
  • shouldProgressLoop: returns true when entrantCount > 0 and roundInterval has elapsed since last draw
  • Winner selection: VRF-seeded linear scan through cumulative ticket weights picks one winner
  • Settlement: 3% protocol fee; prize = pool - fee transferred to winner. Round recorded in rounds[roundId]
  • Reset: all ticket counts and the entrants list are cleared after each draw — fresh start every round

Revenue Model

  • 3% protocol fee on each prize pool
  • AutoLoop gas fee per draw tick

Deploy

forge create src/agents/LotterySweepstakes.sol:LotterySweepstakes \
  --constructor-args 10000000000000000 604800 \
  --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast

Args: ticketPrice (wei), roundInterval (seconds). A 0.01 ETH ticket price and 7-day interval (604800) is typical.

VRF Key Registration

Register each controller worker's ECVRF public key before the first draw:

lotterySweepstakes.registerControllerKey(controllerAddress, pkX, pkY);

The caller must be either the controller address itself or a contract admin. Use register-vrf-keys.js to automate all workers:

NETWORK=sepolia VRF_CONTRACTS=<lotterySweepstakesAddress> node scripts/register-vrf-keys.js

Dashboard

View LotterySweepstakes on the AutoLoop Dashboard.