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.
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.valuesent: 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
| Parameter | Limits | Notes |
|---|---|---|
keyHash | A registered proving key | Identifies which operator key answers |
confirmations | 0–200 | Blocks to wait before fulfilling. On Elysium these are parent-chain blocks |
callbackGasLimit | up to 2,500,000 | Gas for your fulfillRandomWords. It must not revert |
numWords | 1–500 | Independent words expanded from one VRF output |
Fees
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
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
fulfillRandomWordsrevert. 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.