Docs/Examples/Coin Flipper

CoinFlipper

A provably fair dice game using Full VRF — verifiable randomness on every tick.


Overview

CoinFlipper (RandomGame) is a dice game that rolls a fair 1-6 on every tick using ECVRF proof verification. Every roll is provably fair and tamper-proof.

  • Base: AutoLoopVRFCompatible
  • VRF: Every tick
  • Gas: ~240,000 per tick
  • Use case: Dice games, lotteries, coin flips, any game needing randomness on every tick

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {AutoLoopVRFCompatible} from
    "autoloop/AutoLoopVRFCompatible.sol";

contract RandomGame is AutoLoopVRFCompatible {
    uint256 public lastRoll;
    uint256 public totalRolls;
    uint256 public interval;
    uint256 public lastTimeStamp;
    uint256[10] public rollHistory;
    uint256 private _loopID;

    event DiceRolled(
        uint256 indexed loopID,
        uint256 roll,
        bytes32 randomness,
        uint256 timestamp
    );

    constructor(uint256 _interval) {
        interval = _interval;
        lastTimeStamp = block.timestamp;
    }

    function shouldProgressLoop()
        external view override
        returns (
            bool loopIsReady,
            bytes memory progressWithData
        )
    {
        loopIsReady =
            (block.timestamp - lastTimeStamp) > interval;
        progressWithData = abi.encode(_loopID);
    }

    function progressLoop(
        bytes calldata progressWithData
    ) external override {
        (bytes32 randomness, bytes memory gameData) =
            _verifyAndExtractRandomness(
                progressWithData, tx.origin
            );

        uint256 loopID =
            abi.decode(gameData, (uint256));
        require(loopID == _loopID, "stale");

        lastRoll = (uint256(randomness) % 6) + 1;
        rollHistory[totalRolls % 10] = lastRoll;
        lastTimeStamp = block.timestamp;

        emit DiceRolled(
            _loopID, lastRoll, randomness, block.timestamp
        );

        ++totalRolls;
        ++_loopID;
    }

    function getRecentRolls()
        external view returns (uint256[10] memory)
    {
        return rollHistory;
    }
}

Deploy

forge create examples/CoinFlipper.sol:CoinFlipper \
  --constructor-args 60 \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY

Don't forget to register the controller's VRF public key after deployment:

coinFlipper.registerControllerKey(controllerAddress, pkX, pkY);