Skip to main content

Quickstart

Here be dragons

The Anyrand codebase has been audited, but its bls-bn254 dependency contains some rather unique cryptography and has not been audited. See our BLS on EVM page for more information.

You request verifiable randomness from your contract, and the anyrand network will deliver you verifiable randomness. Let's get to it!

How to receive randomness

Implement the following interface in your contract that will receive the randomness. The anyrand network will deliver randomness through the function receiveRandomWords. Note that the length of the randomWords array is currently always 1.

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

interface IRandomiserCallbackV3 {
/// @notice Receive random words from a randomiser.
/// @dev Ensure that proper access control is enforced on this function;
/// only the designated randomiser may call this function and the
/// requestId should be as expected from the randomness request.
/// @param requestId The identifier for the original randomness request
/// @param randomWord Uniform random number in the range [0, 2**256)
function receiveRandomness(uint256 requestId, uint256 randomWord) external;
}
Important

Ensure that only the Anyrand contract that you make requests to is allowed to call this function.

How to request randomness

Once we have implemented the IRandomiserCallback interface, we're ready to request randomness from the Anyrand contract. The Anyrand contract implements the IAnyrand interface, a part of which is provided below.

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

interface IAnyrand {
/// @notice State of a request
enum RequestState {
/// @notice The request does not exist
Nonexistent,
/// @notice A request has been made, waiting for fulfilment
Pending,
/// @notice The request has been fulfilled successfully
Fulfilled,
/// @notice The request was fulfilled, but the callback failed
Failed
}

/// @notice Compute the total request price
/// @param callbackGasLimit The callback gas limit that will be used for
/// the randomness request
function getRequestPrice(
uint256 callbackGasLimit
) external view returns (uint256 totalPrice, uint256 effectiveFeePerGas);

/// @notice Request randomness
/// @param deadline Timestamp of when the randomness should be fulfilled. A
/// beacon round closest to this timestamp (rounding up to the nearest
/// future round) will be used as the round from which to derive
/// randomness.
/// @param callbackGasLimit Gas limit for callback
function requestRandomness(
uint256 deadline,
uint256 callbackGasLimit
) external payable returns (uint256);

/// @notice Get the state of a request
/// @param requestId The request identifier
function getRequestState(
uint256 requestId
) external view returns (RequestState);
}

It is necessary to first get a request price using the getRequestPrice function, which will return the price you must pay (in the native currency of the network) when invoking requestRandomness.

tip

requestRandomness returns a uin256 requestId that can be used to correlate your request with the callback.

Example basic consumer

The full request and fulfillment cycle is shown below in an example basic consumer contract. You should be able to use this as a starting point.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IRandomiserCallbackV3} from "../interfaces/IRandomiserCallbackV3.sol";
import {Anyrand} from "../Anyrand.sol";

/// @title AnyrandConsumer
contract AnyrandConsumer is Ownable, IRandomiserCallbackV3 {
/// @notice Anyrand instance
address public immutable anyrand;
/// @notice Recorded randomness. A special value of 1 means the request is
/// inflight
mapping(uint256 requestId => uint256) public randomness;

event RandomnessReceived(uint256 randomness);

constructor(address anyrand_) Ownable(msg.sender) {
anyrand = anyrand_;
}

/// @notice Request a random number, calling back to this contract
function getRandom(
uint256 deadline,
uint256 callbackGasLimit
) external payable {
require(deadline > block.timestamp, "Deadline is in the past");
(uint256 requestPrice, ) = Anyrand(anyrand).getRequestPrice(
callbackGasLimit
);
require(msg.value >= requestPrice, "Insufficient payment");
if (msg.value > requestPrice) {
(bool success, ) = msg.sender.call{value: msg.value - requestPrice}(
""
);
require(success, "Refund failed");
}
uint256 requestId = Anyrand(anyrand).requestRandomness{
value: requestPrice
}(deadline, callbackGasLimit);
randomness[requestId] = 1;
}

/// @notice See {IRandomiserCallbackV3-receiveRandomness}
function receiveRandomness(uint256 requestId, uint256 randomWord) external {
require(msg.sender == anyrand, "Only callable by Anyrand");
require(randomness[requestId] == 1, "Unknown requestId");
randomness[requestId] = randomWord;
emit RandomnessReceived(randomWord);
}
}
warning

The above code snippet is provided as an example only, as a starting point. Always ensure that your contract follows security best practices before deploying.