Quickstart

Everything you need to start requesting onchain randomness. Torinox Protocol is Apache-2.0. Fee is exact 0.000025 ETH. Agents can prefer the x402 path (`/x402/v1/random`, $0.05 USDG via Primer). If a request is not revealed within ~60-90s (6 L1 blocks), call refundRequest to reclaim the fee.

Failed-request economics: The exact request fee is returned, but transaction gas is not. The requester pays request and refund gas. Torinox retains no fee. Torinox bears failed reveal-transaction gas only if a reveal was submitted and reverted.

Quick Start

1. Install the SDK

npm install @diceprotocol/sdk

Published on npm.

2. Request Randomness (Solidity)

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import { IEntropyConsumer } from "@diceprotocol/sdk/solidity/IEntropyConsumer.sol";
import { IEntropy } from "@diceprotocol/sdk/solidity/IEntropy.sol";

contract MyGame is IEntropyConsumer {
    IEntropy public immutable dice;
    address public provider;
    
    mapping(uint64 => bytes32) public results;
    
    constructor(address _dice, address _provider) {
        dice = IEntropy(_dice);
        provider = _provider;
    }
    
    function roll() external payable {
        bytes32 userRandom = keccak256(abi.encodePacked(
            msg.sender, block.timestamp, block.prevrandao, gasleft()
        ));
        
        dice.requestV2{value: msg.value}(provider, userRandom, 200000);
    }
    
    function entropyCallback(uint64 seq, address, bytes32 random)
        internal override {
        results[seq] = random;
    }
    
    function getEntropy() internal view override returns (address) {
        return address(dice);
    }
}

3. Request Randomness (TypeScript)

import { TorinoxProtocol } from '@diceprotocol/sdk';
import { ethers, JsonRpcProvider, Wallet } from 'ethers';

const rpcUrl = 'https://rpc.mainnet.chain.robinhood.com';
const provider = '0x8741b8a825644D9Ef18Faf2DAB5e9b47B900F2b6';
const signer = new Wallet(process.env.PRIVATE_KEY!, new JsonRpcProvider(rpcUrl));
const dice = new TorinoxProtocol({
  rpcUrl,
  contractAddress: '0xd8a0680e7699526b57140ed4eafdcc7219dc0a0c',
});

const fee = await dice.getFee(provider, 200000); // must be exact
const userRandom = ethers.hexlify(ethers.randomBytes(32));
const seqNum = await dice.requestRandom(signer, provider, userRandom, 200000);

Contract Addresses

TorinoxEntropy0xd8a0680e7699526b57140ed4eafdcc7219dc0a0c
Provider0x8741b8a825644D9Ef18Faf2DAB5e9b47B900F2b6
VerifyBlockscout

Network

Chain ID4663
RPChttps://rpc.mainnet.chain.robinhood.com
Fee0.000025 ETH
Reveal Time~1-3 seconds typical

Map to a range

Torinox returns a full bytes32 random value. There is no onchain min/max parameter. Map the revealed word into your range in the consumer contract or offchain client.

Keep the mapping deterministic from randomNumberso anyone can recompute the same result from the reveal.

Solidity (1 to 100)

function entropyCallback(
    uint64 sequenceNumber,
    address,
    bytes32 randomNumber
) internal override {
    // Inclusive range [1, 100]
    uint256 roll = (uint256(randomNumber) % 100) + 1;
    results[sequenceNumber] = randomNumber;
    // use roll ...
}

TypeScript / agent (1 to 100)

// randomNumber is 0x-prefixed hex bytes32 from reveal or x402 response
const roll = (BigInt(randomNumber) % 100n) + 1n; // 1n .. 100n

General form

// Inclusive [lo, hi], with lo >= 0 and hi >= lo
uint256 span = hi - lo + 1;
uint256 value = (uint256(randomNumber) % span) + lo;

For small ranges such as 1-100, modulo on a 256-bit word is fine for practical game use. Bias is negligible. Prefer a fixed, public formula over ad-hoc remapping after the fact.

Weighted picks (loot tables, inverse-backing draws) use the same word: e.g. uint256(randomNumber) % totalWeight, then walk your weight table.

Testnet (builders)

Robinhood Chain Testnet · chain ID 46630

RPC https://rpc.testnet.chain.robinhood.com

TorinoxEntropy 0x43c8A7B1a85384cabf3D3Fd45a15C01F5b51A42D

Provider 0x8741b8a825644D9Ef18Faf2DAB5e9b47B900F2b6

Fee exact 0.000025 ETH · faucet faucet.testnet.chain.robinhood.com

Agent path (x402 + USDG)

Agents pay fixed $0.05 USDG per request over HTTP 402 (Primer facilitator on Robinhood Chain). The gateway sponsors the onchain ETH fee to TorinoxEntropy v10.

  • POST https://diceprotocol.world/x402/v1/random
  • GET https://diceprotocol.world/x402/v1/info · GET /x402/health
  • Asset USDG 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 · network eip155:4663
  • Facilitator https://x402.primer.systems
  • payTo Admin 0x4ACD2C88a239a924E47Fc4995114ca1Bb0CA3CaD

Direct onchain requestV2 with exact ETH getFeeV2() remains fully supported. x402 is the HTTP agent payment surface; price is fixed $0.05 USDG (not ETH-spot dynamic).

Stake subscription (Phase 1+2)

Lock $TORINOX in TorinoxStake to earn a score. Free daily credits are tracked on TorinoxQuota (UTC day) and burned onchain before the gateway sponsors randomness (UTC day). Overflow and non-stakers pay fixed $0.05 USDG.

  • Stake: 0xc091ce59cAC1112A30e4344ced039c25B6cfa174
  • Quota: 0x825AC2A5Ca8D8A6E56dF418C3227a72bD39830F3
  • Page: https://diceprotocol.world/stake/
  • Free call: POST /x402/v1/random/free with personal_sign
  • Lookup: GET /x402/v1/subscription/0x...
  • Tiers: 100k→50/day, 1M→150/day, 10M→400/day; +1 score if lock ≥ 30 days (cap 4 → 1000/day)

Error Reference

InsufficientFeemsg.value does not equal required fee (underpay and overpay both revert)
NoSuchProviderProvider not registered
IncorrectRevelationReveal doesn't match commitment
OutOfRandomnessHash chain exhausted
MaxGasLimitExceededGas limit exceeds maximum

Next: architecture, verification, x402.

Home · RNG for Robinhood Chain · Docs · Architecture · Security · SDK · x402 · GitHub