Skip to main content
Version: Testnet

Random Hash Oracle Guide

This guide walks through how to request a random hash using the Kurier Random Hash Oracle. The process is subscription-based and involves deploying a consumer contract that can request randomness from the oracle coordinator.

Oracle Coordinator Contracts

The Kurier Random Hash Oracle Coordinator is deployed on the following networks:

NetworkContract Address
Horizen Testnet0x742862a2f8Dad5399BEAa9eeFCf24c12577d5260
Base Sepolia0x3bFeef0b62d2996efaeD228579651fB8c1255018

You will interact with this contract to create and manage subscriptions, and to request a random hash.


High-Level Flow

  1. Create and fund a subscription
  2. Implement a consumer contract that requests randomness
  3. Deploy a consumer smart contract linked to that subscription
  4. Register the consumer contract with the coordinator
  5. Verify the consumer contract on the explorer
  6. Call the randomness request function

Step 1: Create and Configure a Subscription

Randomness requests are paid for via subscriptions. Each consumer contract must be explicitly authorized to use a subscription.

1.1 Create a Subscription

Call the following function on the coordinator contract: createSubscription()

This returns a subscriptionId, which will be used throughout the rest of the setup.

1.2 Fund the Subscription

Fund the subscription with the network’s native token so it can pay for randomness requests: fundSubscription(subscriptionId)

Make sure to send enough funds to cover at least one request.


There is a script to automate these two steps. Download the setup-subscription script here.

Prerequisites

This script uses Foundry’s cast CLI to send transactions and call contract functions.

If you don’t already have Foundry installed, run:

curl -L https://foundry.paradigm.xyz | bash
foundryup

Verify installation:

cast --version
Environment Variables

Before running the script, set the PRIVATE_KEY environment variable:

export PRIVATE_KEY="0xYOUR_PRIVATE_KEY"

or create an .env file with PRIVATE_KEY="0xYOUR_PRIVATE_KEY"

If you are using a .env file, load it into your shell before running the script:

set -a
source .env
set +a
Download the Script

Download the setup-subscription script here.

Make it executable:

chmod +x setup-subscription.sh
Run the Script
./setup-subscription.sh

It will prompt for the network, amount to fund (default to 0.05 ether), and optionally the consumer contract address.

On success, the script will:

  • Create a subscription
  • Fund it with the specified amount
  • Optionally add a consumer
  • Print the created SUBSCRIPTION_ID

Step 2: Implement the Consumer Contract

Your consumer contract is responsible for:

  • Calling the Kurier Oracle coordinator to request randomness
  • Receiving the oracle callback with the random hash

At a minimum, the contract must:

  • Store the subscription ID
  • Store the coordinator contract address
  • Expose a function (e.g. requestRandomHash) that forwards the request to the coordinator
function requestRandomHash() external {
coordinator.requestRandomHash(
subscriptionId,
// additional parameters
);
}

Coordinator requestRandomHash Parameters

Your consumer contract must forward randomness requests to the coordinator using the following function:

function requestRandomHash(
uint64 subscriptionId,
uint32 callbackGasLimit,
FulfillmentMode mode,
bytes calldata callbackData
) external returns (bytes32 requestId);

This function registers a randomness request, charges the associated subscription, and schedules a callback to the consumer contract.

Parameter Details

subscriptionId (uint64)

The subscription ID used to pay for the randomness request.

  • Must be created and funded beforehand
  • The calling consumer contract must be added to this subscription (this is step 4 of this flow)
  • Requests will revert if the subscription is unfunded or unauthorized

callbackGasLimit (uint32)

The maximum amount of gas that the coordinator is allowed to use when calling back into the consumer contract.

  • Must be high enough to cover your fulfillment logic
  • If too low, the callback will fail and randomness will not be delivered
  • Gas is charged against the subscription

Guidance:

  • Use a minimal value for simple storage updates
  • Increase cautiously if your fulfillment logic is more complex

mode (FulfillmentMode)

Controls how and when the oracle triggers the callback on the randomness request.

Options include OPTIMISTIC_ONLY, FINAL_ONLY, TWO_STAGE

  • OPTIMISTIC_ONLY Callback function is called as soon as the randomness process proof is verified off-chain

  • FINAL_ONLY Callback function is called once the randomness process proof is verified on-chain on zkVerify

  • TWO_STAGE Callback function will be triggered both when the randoness process proof is verified off-chain and again when verified on-chain on zkVerify

Choose the mode that best matches your latency and execution guarantees.

callbackData (bytes)

Opaque, user-defined data that is passed back to the consumer contract during fulfillment.

  • Can encode application-specific context
  • Useful for correlating requests with internal state
  • Interpreted entirely by the consumer contract

Step 3: Deploy the Consumer Smart Contract

Deploy your ConsumerSmartContract after implementing the request logic.

Constructor parameters typically include:

  • The subscription ID (subscriptionId)
  • The Kurier Oracle coordinator address

Step 4: Add the Consumer Contract to the Subscription

Once the consumer contract is deployed, authorize it to use the subscription: addConsumer(subId, consumerContractAddress)

⚠️ Randomness requests will fail unless the consumer contract is added to the subscription.

There is a add-consumer.sh script that can be used to send this transaction. It will prompt for the network, subscription ID, and consumer contract address. Your private key is read from your environment variables.

If you want to preflight authorization, you can query:

isConsumer(uint64 subscriptionId, address consumer) external view returns (bool)

Step 5: Verify the Consumer Contract

After deployment, verify the ConsumerSmartContract on the block explorer. While this is not required for requesting randomness, it is strongly recommended.

Contract verification allows you to:

  • Interact with the contract through the explorer UI
  • Debug requests and responses more easily
  • Confirm constructor parameters were set correctly

Skipping this step will not affect oracle functionality, but it may make troubleshooting more difficult.


Step 6: Request a Random Hash

Once everything is set up and the consumer contract has been added to the subscription, you can test the oracle flow.

Call the following function on your consumer contract: requestRandomHash()

This will:

  1. Send a request to the Kurier Oracle
  2. Trigger the oracle to generate randomness
  3. Call back into your consumer contract with the random hash

Costs & Fees (What gets paid, and by whom)

Random hash requests are paid for from the subscription balance (i.e. the balance owned by the subscription owner, not end users unless you build that into your app).

At a high level, each request costs:

  • Oracle fee (oracleFee): a fixed fee charged at request time.
  • Gas cost: the coordinator reserves funds based on callbackGasLimit and settles actual cost at fulfillment time.

Query the current fee and config (example: Base Sepolia)

COORD="0x3bFeef0b62d2996efaeD228579651fB8c1255018"
RPC_URL="https://sepolia.base.org"

cast call "$COORD" "oracleFee()(uint256)" --rpc-url "$RPC_URL"
cast call "$COORD" "maxGasPrice()(uint256)" --rpc-url "$RPC_URL"
cast call "$COORD" "maxCallbackGasLimit()(uint32)" --rpc-url "$RPC_URL"
cast call "$COORD" "minCallbackGasLimit()(uint32)" --rpc-url "$RPC_URL"

Estimate the required subscription balance for a request

The coordinator exposes estimators you can use off-chain:

cast call "$COORD" \
"estimateRequestCostBreakdown(uint32,uint8)(uint256,uint256,uint256)" \
<CALLBACK_GAS_LIMIT> <MODE> \
--rpc-url "$RPC_URL"

Observe what was charged after fulfillment

After fulfillment, the coordinator emits a GasSettled event that includes:

  • gasUsed (measured around the callback, plus settlement overhead)
  • gasPrice and actualCost
  • refunded (if reservation > actual cost)

This is useful for building UIs that show the “oracle fulfillment cost” for a request.


End-to-end integration checklist (Coordinator + Oracle service)

This is the practical order of operations most teams use:

  1. Pick a coordinator deployment (network + address from the table above)
  2. Create a subscription: createSubscription()
  3. Fund the subscription: fundSubscription(subscriptionId) (with the network’s native token)
  4. Deploy your consumer contract with:
    • coordinator address
    • subscription ID
    • a reasonable callbackGasLimit
  5. Authorize the consumer on the subscription:
    • addConsumer(subscriptionId, consumerAddress)
    • (Optional preflight) isConsumer(subscriptionId, consumerAddress)
  6. Request randomness from the consumer by calling requestRandomHash(...)
  7. Oracle service picks it up and fulfills:
    • An indexer watches RandomHashRequested events and queues work
    • A dispatcher submits fulfillRandomHashOptimistic(...) and/or fulfillRandomHashFinal(...)
    • The coordinator calls your consumer callback with the configured callbackGasLimit

Troubleshooting (common failure modes)

“Not authorized consumer” / request reverts immediately

  • Your consumer contract was not added to the subscription.
  • Fix: call addConsumer(subscriptionId, consumerAddress) and re-try.

Wallet / RPC can’t estimate gas for the request transaction

This is often how a revert surfaces in wallets.

  • Check subscription is funded
  • Check consumer is authorized
  • Check the request’s callbackGasLimit is within coordinator bounds:
    • minCallbackGasLimit <= callbackGasLimit <= maxCallbackGasLimit

Callback fails (no result delivered to consumer)

  • Most commonly: callbackGasLimit is too low for your consumer’s fulfillment logic.
  • Fix: measure callback gas usage in tests / simulation, then request with a higher callbackGasLimit.

Verifying contracts on Base Sepolia with Foundry

Foundry’s chain name uses a hyphen:

  • Use --chain base-sepolia (not base_sepolia)

Summary

To successfully request a random hash from the Kurier Oracle, make sure you have:

  • Created a subscription
  • Funded the subscription with the network’s native token
  • Implemented a consumer contract that forwards requests to the coordinator
  • Deployed a consumer contract using the subscription ID
  • Added the consumer contract to the subscription
  • (Optional) Verified the consumer contract on the explorer
  • Called requestRandomHash() on the consumer contract

Once configured, your consumer contract can safely and repeatedly request random hashes from the Kurier Oracle.