Skip to content

VRF ​

Request random numbers from a contract. Each answer comes with an ECVRF proof. The coordinator verifies it before calling you back, so neither the operator nor anyone else can choose the result.

Use it in a contract ​

Inherit GenesisVRFConsumerBase, request with _requestRandomWords, and receive the result in fulfillRandomWords.

solidity
import {GenesisVRFConsumerBase} from "./vrf/GenesisVRFConsumerBase.sol";

contract Lottery is GenesisVRFConsumerBase {
    bytes32 public immutable keyHash;
    mapping(uint256 => address) public players;

    constructor(address coordinator, bytes32 keyHash_) GenesisVRFConsumerBase(coordinator) {
        keyHash = keyHash_;
    }

    /// Send the HYPE fee as msg.value, or approve GENESIS to this contract and send nothing.
    function play() external payable returns (uint256 requestId) {
        requestId = _requestRandomWords(msg.sender, keyHash, 3, 100_000, 1);
        players[requestId] = msg.sender;
    }

    function fulfillRandomWords(uint256 requestId, uint256[] memory words) internal override {
        bool won = words[0] % 10 == 0;
        // ... pay out players[requestId] if they won
    }
}

_requestRandomWords(payer, keyHash, confirmations, callbackGasLimit, numWords) handles payment for you:

  • msg.value sent: the fee is paid in HYPE.
  • No value sent: the GENESIS fee is pulled from payer, who must approve your contract first. GENESIS is the cheaper option.

Don't want users to pay per request?

Use a subscription: prepay credit once, and your contract requests with _requestRandomWordsWithSubscription(subId, …), sending no fee.

Parameters ​

ParameterLimitsNotes
keyHashA registered proving keyIdentifies which operator key answers
confirmations0–200Blocks to wait before fulfilling. On Elysium these are parent-chain blocks
callbackGasLimitup to 2,500,000Gas for your fulfillRandomWords. It must not revert
numWords1–500Independent words expanded from one VRF output

Fees ​

solidity
uint256 hypeFee = coordinator.quoteFee(account, address(0));
uint256 genFee  = coordinator.quoteFee(account, coordinator.genesisToken());

First-party consumers that the coordinator marks as trusted price the fee for the end user, so holder discounts reach them. Other consumers are priced for the consumer contract itself. See Staking & discounts.

Verifying a result yourself ​

ts
const client = new GenesisClient(deployment, provider);
const { requestId, valid, output } = await client.verifyFulfillment(fulfillTxHash);

This decodes the proof from the fulfillment transaction and re-runs the full ECVRF verification locally.

Good practice ​

  • Don't let fulfillRandomWords revert. A failed callback still consumes the request.
  • Never let users act on a result before it arrives, for example by allowing a bet to be cancelled after the request.
  • Keep the callback cheap. Store the words, then process them in a separate transaction if needed.

GENESIS · verifiable infrastructure for Elysium