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:
| Network | Contract Address |
|---|---|
| Horizen Testnet | 0x742862a2f8Dad5399BEAa9eeFCf24c12577d5260 |
| Base Sepolia | 0x3bFeef0b62d2996efaeD228579651fB8c1255018 |
You will interact with this contract to create and manage subscriptions, and to request a random hash.
High-Level Flow
- Create and fund a subscription
- Implement a consumer contract that requests randomness
- Deploy a consumer smart contract linked to that subscription
- Register the consumer contract with the coordinator
- Verify the consumer contract on the explorer
- 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_ONLYCallback function is called as soon as the randomness process proof is verified off-chain -
FINAL_ONLYCallback function is called once the randomness process proof is verified on-chain on zkVerify -
TWO_STAGECallback 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:
- Send a request to the Kurier Oracle
- Trigger the oracle to generate randomness
- 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
callbackGasLimitand 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)gasPriceandactualCostrefunded(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:
- Pick a coordinator deployment (network + address from the table above)
- Create a subscription:
createSubscription() - Fund the subscription:
fundSubscription(subscriptionId)(with the network’s native token) - Deploy your consumer contract with:
- coordinator address
- subscription ID
- a reasonable
callbackGasLimit
- Authorize the consumer on the subscription:
addConsumer(subscriptionId, consumerAddress)- (Optional preflight)
isConsumer(subscriptionId, consumerAddress)
- Request randomness from the consumer by calling
requestRandomHash(...) - Oracle service picks it up and fulfills:
- An indexer watches
RandomHashRequestedevents and queues work - A dispatcher submits
fulfillRandomHashOptimistic(...)and/orfulfillRandomHashFinal(...) - The coordinator calls your consumer callback with the configured
callbackGasLimit
- An indexer watches
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
callbackGasLimitis within coordinator bounds:minCallbackGasLimit <= callbackGasLimit <= maxCallbackGasLimit
Callback fails (no result delivered to consumer)
- Most commonly:
callbackGasLimitis 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(notbase_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.