Whitepaper

Version 1.1 - July 2026

PDF ↓

Abstract

Torinox Protocol is a commit-reveal randomness oracle deployed on Robinhood Chain (chain ID 4663), an Arbitrum Nitro-based Layer 2 network. It provides onchain verifiable randomness through a hash-chain commitment scheme where a designated provider (the keeper) pre-commits to a sequence of random values and reveals them on-demand. The protocol combines user-contributed randomness with provider-revealed values using Keccak256, producing onchain-verifiable random numbers under the commit-reveal model delivered via callbacks to consuming smart contracts. Torinox Protocol operates as the commit-reveal randomness oracle on Robinhood Chain under a single-provider model, charging an exact fee of 0.000025 ETH. Unrevealed requests can be refunded after ~60-90s via refundRequest (refundDelayBlocks = 6).

1. Introduction

1.1 Problem Statement

Onchain applications - games, lotteries, NFT mints, fair randomized distribution mechanisms - require a source of randomness that is:

  1. Two-party: Neither requester nor provider unilaterally chooses a completed result. The provider can still withhold a reveal.
  2. Verifiable: The randomness can be independently verified after the fact.
  3. Available: The randomness is delivered reliably and within a predictable timeframe.
  4. Economically viable: The cost per request is low enough for widespread adoption.

Robinhood Chain applications need dedicated randomness infrastructure because deterministic contract execution and chain-controlled values are not suitable private randomness sources. Torinox Protocol provides a live commit-reveal option for this use case.

1.2 Solution

Torinox Protocol implements a commit-reveal scheme based on hash chains:

  • A provider generates a chain of 500,000 random values by repeatedly hashing a secret seed with Keccak256.
  • The provider commits the root (final hash) of this chain to the onchain contract during deployment.
  • When a user requests randomness, they contribute their own random value.
  • The provider reveals the next hash in the chain, which the contract verifies by hashing it and checking against the committed root.
  • The final random number is Keccak256(userRandomness ‖ providerContribution ‖ bytes32(0)), combining both parties' inputs with the fixed zero blockhash argument used by requestV2.

Agent-friendly: Immutable contract code, deterministic fees, and documented verification make Torinox Protocol straightforward for AI agents and automation systems to integrate. Agents still need key security, transaction simulation, receipt checks, timeout handling, and explicit refund logic. Agents can also use the live HTTP 402 surface (POST /x402/v1/random) at fixed $0.05 USDG via Primer on Robinhood Chain; the gateway sponsors the on-chain ETH fee. Direct requestV2 with exact ETH fee remains available. A complete SDK repository is published for agent consumption.

2. Architecture

2.1 System Components

┌─────────────────────────────────────────────────────────┐
│                   Robinhood Chain L2                     │
│                                                          │
│  ┌──────────────────────┐    ┌────────────────────────┐ │
│  │   TorinoxEntropy.sol    │    │   Consumer Contract    │ │
│  │   (Oracle Contract)  │◄──►│   (implements          │ │
│  │                      │    │    IEntropyConsumer)    │ │
│  │  - Hash chain state  │    │                        │ │
│  │  - Fee accounting    │    │  - requestV2()         │ │
│  │  - Reveal verification│   │  - entropyCallback()   │ │
│  │  - Callback dispatch │    │                        │ │
│  └──────────┬───────────┘    └────────────────────────┘ │
│             │                                            │
└─────────────┼────────────────────────────────────────────┘
              │
              │ Watch for Requested events
              │ Submit revealWithCallback txs
              │
┌─────────────┼────────────────────────────────────────────┐
│             ▼              Off-chain (Keeper)                │
│  ┌──────────────────────┐                                │
│  │   Tyche Keeper       │                                │
│  │   (Rust service)     │                                │
│  │                      │                                │
│  │  - HTTP log polling │                                │
│  │  - Hash chain compute│                                │
│  │  - Reveal submission │                                │
│  └──────────────────────┘                                │
└──────────────────────────────────────────────────────────┘

2.2 TorinoxEntropy Contract

The onchain contract is immutable (no proxy pattern) and handles:

  • Provider registration: The constructor auto-registers the default provider with its hash chain commitment, chain length, and metadata.
  • Request handling: Users call requestV2() with a user random value and optional gas limit.
  • Reveal verification: The contract verifies the provider's contribution by hashing it and comparing to the stored commitment.
  • Callback dispatch: After verification, calls the consumer's entropyCallback() with the combined random number.
  • Fee accounting: Each request charges an exact fee (0.000025 ETH). Underpay/overpay revert. Unrevealed requests are refundable after ~60-90s via refundRequest. Fees accrue in the contract and are withdrawable by the admin.

2.3 Tyche Keeper

Tyche is a Rust-based off-chain service that:

  1. Monitors the blockchain for Requested events through monitored Robinhood Chain RPC infrastructure.
  2. Computes the reveal value for each request by traversing the precomputed hash chain.
  3. Submits revealWithCallback transactions from the keeper wallet.
  4. Maintains durable request and reveal state for recovery and observability.

2.4 Wallet Separation

RoleAddressKey TypePurpose
Admin0x4ACD...ColdContract admin, fee management
Vault0x918E...ColdFee recipient
Keeper / provider0x8741...HotSubmits reveals and may update provider URI, max hashes, and default callback gas. Cannot change protocol fee/admin or withdraw protocol fees.

3. Cryptographic Design

3.1 Hash Chain Construction

The hash chain is an S/KEY-like construction using Keccak256:

  1. Start with a 32-byte secret seed s.
  2. Compute h₁ = Keccak256(s).
  3. For i = 2..N: compute hᵢ = Keccak256(hᵢ₋₁).
  4. The chain is [h₁, h₂, ..., h_N] where h_N is the root commitment.
  5. Reveal order is reverse: h_N revealed first (sequence 0), then h_(N-1) (sequence 1), etc.

3.2 Random Number Combination

randomNumber = Keccak256(userRandomness ‖ providerContribution ‖ bytes32(0))
  • userRandomness: Provided by the requester. Unknown to the provider at commitment time.
  • providerContribution: The hash chain value at the current sequence number. Unknown to the user at request time.

For a completed reveal, neither requester nor provider can unilaterally choose the output. A provider can still withhold service; eligible requests become refundable after the configured delay.

4. Economic Model

4.1 Fee Structure

  • Fee per request: exact 0.000025 ETH (25,000,000,000,000 wei)
  • Refund delay: 6 L1 blocks (~60-90s) via refundRequest
  • Fee destination: 100% to the contract's accrued fee pool
  • Withdrawal: Admin calls withdrawFees(), sending the full balance to the vault

The contract uses one protocol-level request fee with no provider fee split. Request and reveal transaction gas remain separate from that fee.

4.2 Failed-request economics

A refund returns the exact request fee, but transaction gas is not refunded.

  • The requester pays gas for the original request and for refundRequest.
  • Torinox retains no request fee and earns nothing from an unrevealed, refunded request.
  • If no reveal transaction was submitted, Torinox has no direct reveal-transaction gas cost for that request.
  • If a reveal transaction was submitted but reverted, Torinox bears that failed transaction's gas cost.

4.3 Gas Economics

OperationGas CostETH Cost
Request (consumer)500,0000.0000025
Reveal (keeper)~53,5060.0000051
Callback~500,0000.0000026
Total per request~53,506~0.0000051

5. Smart Contract API

5.1 Core Functions

requestV2(address provider, bytes32 userRandomNumber, uint32 gasLimit) → uint64

Request randomness. Caller must send ETH equal to the provider's fee. Callback gas is max(requested, provider.defaultGasLimit), rounded up to 10,000, bounded by MAX_GAS_LIMIT. A 0 request uses the live default (200,000). If defaultGasLimit is 0, stored callback gas is 0. Returns assigned sequence number.

revealWithCallback(address provider, uint64 sequenceNumber, bytes32 userContribution, bytes32 providerContribution)

Called by keeper to reveal provider's contribution and trigger consumer's callback.

getFee(address provider) → uint128

Returns the current fee for a provider.

withdrawFees(uint128 amount)

Admin-only. Withdraws accrued fees to the vault address.

5.2 Consumer Interface

interface IEntropyConsumer {
    function entropyCallback(
        uint64 sequenceNumber,
        address provider,
        bytes32 randomNumber
    ) internal;

    function getEntropy() internal view returns (address);
}

6. Security Analysis

6.1 Attack Vectors

AttackMitigation
Provider withholds revealNo onchain penalty in v1; relies on service uptime. Future: slashing.
User front-runs revealUser commits random value before provider reveals.
Callback gas griefingEffective callback gas is max(requested, defaultGasLimit), rounded up to 10,000, bounded by MAX_GAS_LIMIT. Live default 200,000: a 0 request becomes 200,000; an explicit larger request is honored. If defaultGasLimit is 0, stored gas is 0. Uses excessivelySafeCall.
Chain exhaustionOutOfRandomness revert when sequence exceeds chain length.
Private key compromiseFour-wallet separation limits blast radius. Keeper cannot steal fees.

7. Integration Guide

7.1 Solidity Integration

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;

    constructor(address _dice, address _provider) {
        dice = IEntropy(_dice);
        provider = _provider;
    }

    function roll(bytes32 userRandom) external payable {
        // Generate userRandom client-side with a CSPRNG and keep it private.
        dice.requestV2{value: msg.value}(provider, userRandom, 200000);
    }

    function entropyCallback(uint64 seq, address, bytes32 random) internal override {
        uint256 result = uint256(random) % 6 + 1; // Torinox roll 1-6
    }

    function getEntropy() internal view override returns (address) {
        return address(dice);
    }
}

7.2 TypeScript SDK

import { TorinoxProtocol } from '@diceprotocol/sdk';

const dice = new TorinoxProtocol({
  rpcUrl: 'https://rpc.mainnet.chain.robinhood.com',
  contractAddress: '0xd8a0680e7699526b57140ed4eafdcc7219dc0a0c',
});

const seqNum = await dice.requestRandom(
  signer,
  providerAddress,
  userRandom,
  200000
);

8. Roadmap

v1.0 - Current (July 2026)
  • ✅ TorinoxEntropy contract deployed on Robinhood Chain mainnet
  • ✅ Tyche keeper operational with auto-reveal
  • ✅ TypeScript SDK
  • ✅ Internal + automated security review (no third-party audit published yet)
v1.1 - Q3 2026
  • Multi-provider support (redundancy)
  • Tyche monitoring dashboard
  • Public reliability and latency metrics
v2.0 - Q4 2026
  • Slashing mechanism for provider non-responsiveness (requires new deployment)
  • Variable fee tiers (basic/premium)
  • Cross-chain expansion to other Nitro L2s

Appendix

TorinoxEntropy: 0xd8a0680e7699526b57140ed4eafdcc7219dc0a0c
Chain ID: 4663
RPC: https://rpc.mainnet.chain.robinhood.com
Explorer: https://robinhoodchain.blockscout.com
Fee: 25,000,000,000,000 wei (0.000025 ETH exact)
x402 agent: https://diceprotocol.world/x402/v1/random · $0.05 USDG
Refund delay: 6 L1 blocks (~60-90s)
Hash chain: 500,000 entries, Keccak256
defaultGasLimit: 200,000

Torinox Protocol is developed and maintained as independent infrastructure for Robinhood Chain. No runtime dependency on another randomness oracle. Architecture and interfaces are adapted from Pyth Entropy under Apache-2.0; see NOTICE.