Skip to main content
Use this page when you want the fastest path to a working consumer contract on Abstract. Choose the path that matches your starting point:
  • New project: scaffold a Foundry starter that already includes an example consumer contract.
  • Existing project: wire the hosted roll.codes coordinator into your current Solidity app.

New projects

The starter CLI generates a Foundry project with:
  • src/DiceDuelConsumer.sol
  • test/DiceDuelConsumer.t.sol
  • script/DeployDiceDuelConsumer.s.sol
  • remappings and Foundry config for Abstract
The generated consumer already requests randomness with requestRandomNumberWithTraceId(...) and receives it in randomNumberCallback(...).
1

Build the starter CLI

The CLI source currently lives in this repository.
git clone https://github.com/jarrodwatts/roll.codes.git
cd roll.codes/packages/create-roll-codes
npm ci
npm run build
2

Scaffold a starter project

Run the generator from the CLI package directory:
node dist/index.js contract my-game
This creates ./my-game with the example consumer already wired to the public IVRFSystem interface.
3

Build and test the generated project

cd my-game
forge build --zksync
forge test --zksync -vvv
4

Configure the hosted coordinator and deploy

cast wallet import deployer --interactive
export ROLL_OWNER=$(cast wallet address --account deployer)
export ABSTRACT_RPC_URL=https://api.testnet.abs.xyz
export ROLL_VRF_SYSTEM=0x5ab0e04147A2A1BCa1D06da3c1cB48ea04294B5E

forge script script/DeployDiceDuelConsumer.s.sol:DeployDiceDuelConsumer \
  --account deployer \
  --rpc-url "$ABSTRACT_RPC_URL" \
  --zksync \
  --broadcast
See Deployed addresses for the current network-specific coordinator status and addresses.
If you want the full CLI surface, including --dir, --force, and --skip-install, see CLI reference.

Integrating into an existing project

Use this path if you already have a Foundry project and only need to add roll.codes support.
1

Install the dependency

forge install roll.codes=jarrodwatts/roll.codes@main --no-git
forge install forge-std=foundry-rs/forge-std --no-git
2

Add remappings

Your project should include:
@rollcodes/=lib/roll.codes/src/
forge-std/=lib/forge-std/src/
3

Request a random number

Import the public interfaces, store the hosted coordinator address, then request randomness by paying requestFee().
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {IVRFSystem} from "@rollcodes/interfaces/IVRFSystem.sol";
import {IVRFSystemCallback} from "@rollcodes/interfaces/IVRFSystemCallback.sol";

contract ExampleConsumer is IVRFSystemCallback {
    IVRFSystem public immutable vrfSystem;

    constructor(address coordinatorAddress) {
        vrfSystem = IVRFSystem(coordinatorAddress);
    }

    function play() external payable returns (uint256 requestId) {
        uint256 fee = vrfSystem.requestFee();
        require(msg.value == fee, "fee mismatch");

        uint256 traceId = 0;
        requestId = vrfSystem.requestRandomNumberWithTraceId{ value: fee }(traceId);
    }

    function randomNumberCallback(uint256 requestId, uint256 randomNumber) external override {}
}
4

Handle the callback safely

Every request is delivered asynchronously. Restrict the callback to the hosted coordinator and settle against stored request state.
function randomNumberCallback(uint256 requestId, uint256 randomNumber) external {
    if (msg.sender != address(vrfSystem)) revert Unauthorized();

    Pending storage request = pendingByRequestId[requestId];
    if (request.player == address(0)) revert RequestNotFound(requestId);
    if (request.settled) revert AlreadySettled(requestId);

    request.settled = true;
    request.randomNumber = randomNumber;

    // settle your game or app logic here
}
5

Deploy only your consumer

Set the hosted coordinator address for the same network as your RPC URL:
cast wallet import deployer --interactive
export ABSTRACT_RPC_URL=https://api.testnet.abs.xyz
export ROLL_COORDINATOR=0x5ab0e04147A2A1BCa1D06da3c1cB48ea04294B5E
Then deploy your own consumer contract with your normal Foundry script flow, using --account deployer when you broadcast.
requestRandomNumberWithTraceId is payable on roll.codes, so callers must send the exact value returned by requestFee().
Prefer a Foundry keystore account over exporting plaintext private keys. Import once with cast wallet import and reuse that account name with forge script --account ....
Requests delivered from the same drand round receive the same base randomNumber. If your app needs a unique value per request within that same round, derive one locally from requestId and randomNumber.

Verify the result

You should end with:
  • a deployed consumer contract
  • a configured roll.codes coordinator address in your deployment inputs
  • a request path that pays requestFee()
  • a callback that only accepts the hosted coordinator

Next steps

Integration pattern

Copy a fuller consumer example with request storage and settlement guards.

Coordinator reference

Keep the request function, fee call, and callback interface beside you while implementing.

Troubleshooting

Fix fee mismatches, unauthorized callbacks, and pending requests.

CLI reference

Review the starter generator flags and output files.
Last modified on March 9, 2026