---
# System prepended metadata

title: Example Use Cases

---

# Example Use Cases

Band VRF provides deterministic pre-commitments for low entropy inputs, which must resist brute-force pre-image attacks. In addition, the VRF can be used as defense against offline enumeration attacks (such as dictionary attacks) on data stored in hash-based data structures. Therefore, it can be used as a secure source of on-chain randomness. The Band VRF use cases are outlined below.

### Use cases

We separate the use cases into four categories based on the behaviors of the VRF users/consumers.

1. **One-time-use:** Consumers only request random data once in their product lifetime, typically when they initiate their contracts. 
    - NFT minting - in the case where a single random seed is used to generate the entire collection.

2. **Batch-use:** Consumers request random data multiple times but with a countable number of requests for the entire life of their product.
    - NFT minting - in the case where every single ID will be minted one by one. Therefore, whenever the end-user tries to mint an NFT, the VRF request is created to resolve the minting. This process will continue until the entire collection is minted.
    
3. **Interval-use:** Consumers set their specific intervals to request random data from our VRF protocol. This process will continue indefinitely since some parts of their products rely on a trusted source of randomness.
    - Lottery dApps (predetermined start-end, calculatable start-end)
    - NFT minting with a specific minting interval

4. **Continuous-use:** Consumers use randomness as parts of their product with no specific interval. Therefore, they can request random data at any time based on the internal logic of their contracts/system.
    - Lottery dApps (no predetermined interval, unable to calculate future start-end)
    - On-chain games
    - NFT on-demand minting

---


### Lottery Example (Continuous-use)

This on-chain lottery dApp is an example of a continuous-use VRF, and it satisfies the requirements below.

**Requirements:**
- Only the owner can set the minimum price and the round's duration.
- Only the owner can start a new round.
- The owner determined the seed of the 'started' round.
- Anyone can buy lotteries during a 'started' round.
- Anyone can request to resolve the current round if it has ended.
- Only the VRFProvider contract can resolve the 'resolving' round.

```solidity=
pragma solidity ^0.8.17;

interface IVRFConsumer {
    /// @dev The function is called by the VRF provider in order to deliver results to the consumer.
    /// @param seed Any string that used to initialize the randomizer.
    /// @param time Timestamp where the random data was created.
    /// @param result A random bytes for given seed anfd time.
    function consume(
        string calldata seed,
        uint64 time,
        bytes32 result
    ) external;
}

interface IVRFProvider {
    /// @dev The function for consumers who want random data.
    /// Consumers can simply make requests to get random data back later.
    /// @param seed Any string that used to initialize the randomizer.
    function requestRandomData(string calldata seed) external payable;
}

contract SimpleLottery is IVRFConsumer {

    event Buy(address buyer, uint256 buyerIndex, uint256 roundNumber, uint256 buyPrice);
    event StartRound(uint256 roundNumber, string seed);
    event ResolvingRound(uint256 roundNumber, string seed);
    event RoundResolved(uint256 roundNumber, string seed, bytes32 result);

    address public owner;

    uint256 public minLotteryPrice;
    uint256 public roundDuration;
    uint256 public roundCount;
    bool public isResolvingCurrentRound;

    IVRFProvider public provider;
    
    struct Round {
        uint256 startBlock;
        uint256 endBlock;
        string seedOfRound;
        address[] buyers;
    }

    mapping(uint256 => Round) public rounds;

    constructor(IVRFProvider _provider, uint256 _minLotteryPrice, uint256 _roundDuration) {
        provider = _provider;
        minLotteryPrice = _minLotteryPrice;
        roundDuration = _roundDuration;
        owner = msg.sender;
    }

    function isCurrentRoundStart() public view returns(bool) {
        return rounds[roundCount].startBlock > 0;
    }

    function currentRoundBlocksRemaining() public view returns(uint256) {
        Round memory currentRound = rounds[roundCount];
        if (block.number > currentRound.endBlock) {
            return 0;
        }
        return currentRound.endBlock - block.number;
    }

    function setMinLotteryPrice(uint256 _minLotteryPrice) external {
        require(msg.sender == owner, "SimpleLottery: not the owner");
        require(!isCurrentRoundStart(), "SimpleLottery: this round is in progress");

        minLotteryPrice = _minLotteryPrice;
    }

    function setRoundDuration(uint256 _roundDuration) external {
        require(msg.sender == owner, "SimpleLottery: not the owner");
        require(!isCurrentRoundStart(), "SimpleLottery: this round is in progress");

        roundDuration = _roundDuration;
    }

    function startANewRound(string memory roundSeed) external {
        require(msg.sender == owner, "SimpleLottery: not the owner");
        require(!isCurrentRoundStart(), "SimpleLottery: this round is in progress");

        Round memory currentRound = rounds[roundCount];

        currentRound.seedOfRound = roundSeed;
        currentRound.startBlock = block.number;
        currentRound.endBlock = currentRound.startBlock + roundDuration;

        rounds[roundCount] = currentRound;
        emit StartRound(roundCount, roundSeed);
    }

    function buy() external payable {
        require(currentRoundBlocksRemaining() > 0, "SimpleLottery: this round is not in progress");
        require(msg.value >= minLotteryPrice, "SimpleLottery: given price is too low");

        uint256 currentBuyerIndex = rounds[roundCount].buyers.length;
        emit Buy(msg.sender, currentBuyerIndex, roundCount, msg.value);

        rounds[roundCount].buyers.push(msg.sender);
    }

    function resolveCurrentRound() external {
        require(isCurrentRoundStart(), "SimpleLottery: this round is not started yet");
        require(currentRoundBlocksRemaining() == 0, "SimpleLottery: this round has not ended yet");
        require(!isResolvingCurrentRound, "SimpleLottery: round is resolving");

        Round memory currentRound = rounds[roundCount];
        if (currentRound.buyers.length > 0) {
            isResolvingCurrentRound = true;

            provider.requestRandomData{value: 0}(currentRound.seedOfRound);
            emit ResolvingRound(roundCount, currentRound.seedOfRound);
        } else {
            emit RoundResolved(roundCount, currentRound.seedOfRound, bytes32(0));

            roundCount += 1;
            isResolvingCurrentRound = false;
        }
    }

    function consume(string calldata seed, uint64 time, bytes32 result) external override {
        require(msg.sender == address(provider), "Caller is not the provider");
        require(isResolvingCurrentRound, "SimpleLottery: round is not resolving");

        Round memory currentRound = rounds[roundCount];
        address winner = currentRound.buyers[uint256(result) % currentRound.buyers.length];

        emit RoundResolved(roundCount, seed, result);

        roundCount += 1;
        isResolvingCurrentRound = false;

        winner.call{value: address(this).balance}("");
    }
}
```

We have deployed the reference contracts to the [Goerli](https://goerli.etherscan.io) testnet here. 

|Contract         |Address|
|-----------------|------------------------------------------|
|Bridge           |[0xD291A502e3ca4Bb13E09892e57d8Ff0271Bd198A](https://goerli.etherscan.io/address/0xD291A502e3ca4Bb13E09892e57d8Ff0271Bd198A)| 
|VRFProvider      |[0xF1F3554b6f46D8f172c89836FBeD1ea8551eabad](https://goerli.etherscan.io/address/0xF1F3554b6f46D8f172c89836FBeD1ea8551eabad)| 
|VRFLens          |[0x6e876b4Ed458af275Eb049a3f89BF0909618d154](https://goerli.etherscan.io/address/0x6e876b4Ed458af275Eb049a3f89BF0909618d154)| 
|SimpleLottery    |[0xCD3528283aA330003E50350134a48d1920BA70A0](https://goerli.etherscan.io/address/0xCD3528283aA330003E50350134a48d1920BA70A0)| 


---

### NFT Minting Example (Batch-use)

This NFT is an example of a batch-use VRF, and it satisfies the requirements below.

**Requirements:**
- The max supply is set once at the time the contract is deployed.
- Anyone can call `mintWithVRF` to start minting an NFT for themself.
- An actual minting is done when the VRFprovider resolves the token id for the minter/receiver.

```solidity=
pragma solidity ^0.8.17;

import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}

interface IVRFConsumer {
    /// @dev The function is called by the VRF provider in order to deliver results to the consumer.
    /// @param seed Any string that used to initialize the randomizer.
    /// @param time Timestamp where the random data was created.
    /// @param result A random bytes for given seed anfd time.
    function consume(
        string calldata seed,
        uint64 time,
        bytes32 result
    ) external;
}

interface IVRFProvider {
    /// @dev The function for consumers who want random data.
    /// Consumers can simply make requests to get random data back later.
    /// @param seed Any string that used to initialize the randomizer.
    function requestRandomData(string calldata seed) external payable;
}

contract ExampleNFT is ERC721Enumerable, IVRFConsumer {
   using Strings for uint256;

    IVRFProvider public immutable provider;
    uint256 public immutable maxSupply;
    
    uint256 public mintRequestCount = 0;
    uint256 public mintResolveCount = 0;

    mapping(uint256 => uint256) public tokenMintingLogs;
    mapping(string => address) public tokenSeedToMinter;

    constructor(IVRFProvider _provider, uint256 _maxSupply) ERC721("ExampleNFT", "ENFT") {
        provider = _provider;
        maxSupply = _maxSupply;
    }

    function mintWithVRF() external {
        require(mintRequestCount < maxSupply, "Reach max supply");
        string memory clientSeed = string(abi.encodePacked("ExampleNFT-", mintRequestCount.toString()));
        tokenSeedToMinter[clientSeed] = msg.sender;

        mintRequestCount++;

        provider.requestRandomData{value: 0}(clientSeed);
    }

    function consume(string calldata seed, uint64 time, bytes32 result) external override {
        require(msg.sender == address(provider), "Caller is not the provider");

        address _receiver = tokenSeedToMinter[seed];
        uint256 index = uint256(result) % (maxSupply - mintResolveCount);

        uint256 tokenID = tokenMintingLogs[index];
        if (tokenID == 0) {
            tokenID = index;
        }

        mintResolveCount++;
        tokenMintingLogs[index] = maxSupply - mintResolveCount;

        _safeMint(_receiver, tokenID);
    }
}
```

We have deployed the reference contracts to the [Goerli](https://goerli.etherscan.io) testnet here. 

|Contract         |Address|
|-----------------|------------------------------------------|
|Bridge           |[0xD291A502e3ca4Bb13E09892e57d8Ff0271Bd198A](https://goerli.etherscan.io/address/0xD291A502e3ca4Bb13E09892e57d8Ff0271Bd198A)| 
|VRFProvider      |[0xF1F3554b6f46D8f172c89836FBeD1ea8551eabad](https://goerli.etherscan.io/address/0xF1F3554b6f46D8f172c89836FBeD1ea8551eabad)| 
|VRFLens          |[0x6e876b4Ed458af275Eb049a3f89BF0909618d154](https://goerli.etherscan.io/address/0x6e876b4Ed458af275Eb049a3f89BF0909618d154)| 
|NFTBatchMinting    |[0x0b590C537608d121F8e46c2b366f5d22EC942c0f](https://goerli.etherscan.io/address/0x0b590C537608d121F8e46c2b366f5d22EC942c0f#code)| 



