Skip to content

Quickstart

Randoo is pay-per-request on Ronin. Inherit RandooConsumerRonin (shipped with the sample below), quote the fee on-chain, and send it with the request.

  1. Deploy your consumer with the Randoo coordinator 0xC66eB2e7EE91145875000Ad46B55600000000001 (same CREATE3 address on Ronin mainnet and Saigon).
  2. Call estimateRequestRandomFee(callbackGasLimit, gasPrice).
  3. Call requestRandomSeed with msg.value >= estimate and a non-zero refund address (not the consumer if it is not payable).
  4. The oracle fulfills. Your rawFulfillRandomSeed runs with the seed.

Consumer

TemplateConsumer is the canonical consumer sample. Its base RandooConsumerRonin ships with the sample and is inlined first; together with contracts/src/interfaces/IRoninVRFCoordinatorForConsumers.sol they compile as shown in a fresh Foundry project.

RandooConsumerRonin.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IRoninVRFCoordinatorForConsumers} from "./interfaces/IRoninVRFCoordinatorForConsumers.sol";

/// @notice Ronin VRFConsumer-shaped base. Swap coordinator address to migrate.
abstract contract RandooConsumerRonin {
    error OnlyCoordinatorCanFulfill();

    address public vrfCoordinator;

    constructor(address vrfCoordinator_) {
        vrfCoordinator = vrfCoordinator_;
    }

    function rawFulfillRandomSeed(bytes32 reqHash, uint256 randomSeed) external {
        if (msg.sender != vrfCoordinator) revert OnlyCoordinatorCanFulfill();
        _fulfillRandomSeed(reqHash, randomSeed);
    }

    function _fulfillRandomSeed(bytes32 reqHash, uint256 randomSeed) internal virtual;

    function _requestRandomness(
        uint256 value,
        uint256 callbackGasLimit,
        uint256 gasPriceToFulfill,
        address refundAddr
    ) internal returns (bytes32 reqHash) {
        reqHash = IRoninVRFCoordinatorForConsumers(vrfCoordinator).requestRandomSeed{value: value}(
            callbackGasLimit, gasPriceToFulfill, address(this), refundAddr
        );
    }
}
TemplateConsumer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// ---------------------------------------------------------------------------
// Randoo consumer template: copy-pasteable as a unit with
// RandooConsumerTemplate.t.sol and MockRandooCoordinator.sol (this folder), plus
// src/RandooConsumerRonin.sol and src/interfaces/IRoninVRFCoordinatorForConsumers.sol.
// Imports resolve in a fresh `forge init` with only forge-std installed.
// ---------------------------------------------------------------------------

import {RandooConsumerRonin} from "../../src/RandooConsumerRonin.sol";

/// @notice The canonical Randoo consumer. Copy it, rename it, put your game
///         logic in `_fulfillRandomSeed`.
///
/// Flow: a caller pays `estimateRequestRandomFee(callbackGasLimit, gasPrice)`
/// into `roll`, which forwards the request to the coordinator and returns the
/// `reqHash`. Later the coordinator calls `rawFulfillRandomSeed` (inherited,
/// coordinator-only) which lands in `_fulfillRandomSeed` with the seed.
contract TemplateConsumer is RandooConsumerRonin {
    /// @notice Last seed delivered by the coordinator.
    uint256 public lastSeed;
    /// @notice Request hash of the most recent `roll`, then of the most recent fulfil.
    bytes32 public lastReqHash;

    constructor(address vrfCoordinator_) RandooConsumerRonin(vrfCoordinator_) {}

    /// @param callbackGasLimit Gas the coordinator will give `_fulfillRandomSeed` (50k..2.5M).
    /// @param gasPrice Gas price the fulfiller may spend; must be >= the coordinator floor.
    /// @param refundAddr Receives unspent fulfilment gas; must be non-zero.
    function roll(uint256 callbackGasLimit, uint256 gasPrice, address refundAddr)
        external
        payable
        returns (bytes32 reqHash)
    {
        reqHash = _requestRandomness(msg.value, callbackGasLimit, gasPrice, refundAddr);
        lastReqHash = reqHash;
    }

    /// @dev Your randomness lands here. Keep it within `callbackGasLimit`.
    function _fulfillRandomSeed(bytes32 reqHash, uint256 randomSeed) internal override {
        lastReqHash = reqHash;
        lastSeed = randomSeed;
    }
}

Last verified 2026-08-25.