On-chain Randomness · on KUB

Randomness your contracts can prove.

Provably-fair randomness as a service for onchain games and finance on KUB. Your users sign once, a keeper settles in seconds, and your contract gets a callback. Every result is recomputable from public chain data. No oracle, no VRF service.

Two blocks. One number
nobody could predict.

The number comes from the hash of a future block, unknown to everyone at commit time. Your user signs once; settlement is permissionless, so a keeper (or anyone) reveals it and your contract gets the callback.

01 / Request
requestCallback(seed)
Your user signs ONE transaction. It binds the roll to the next block and pays a small gas-scaled fee. No number exists yet, so nobody can see the outcome.
02 / Seal
blockhash(B+1)
That block gets mined. Its hash did not exist when you committed, so no one (not the player, not you, not a bot) can see the result coming.
03 / Settle
keeper reveals → callback
A keeper (or anyone) reveals once the block is mined: keccak(blockhash, id, requester, seed) is pushed back to your contract. The user never signs a second time.

Atomic grinding is impossible. Because reveal reverts until the next block is mined, an attacker cannot compute the result and revert on a loss inside one transaction. The most common on-chain gambling exploit is closed by construction.

Built to be trusted,
and to be checked.

A primitive that handles value should never overclaim, so we document exactly what it defends and what it does not. It passes 36/36 tests, internal multi-agent passes, and an external hard audit, with no fund-loss bug in the core.

A loser can't dodge
The stake escrows at request; settlement is permissionless (a keeper, the next user, or anyone reveals); on expiry it forfeits. Liveness never depends on one bot.
Atomic-grind proof
Request and reveal cannot share a transaction, so the revert-on-loss attack never reaches the outcome.
Provably fair
Each result is keccak(blockhash, id, requester, seed). Recompute it from public chain data and confirm it was never touched.
No rug, no pause
The only privileged role is the fee recipient (Ownable2Step). It cannot touch randomness, escrows, the fee formula, or pause anything. A leaked owner key risks only future fee revenue.
!
Cap your value
A block producer can bias a single block, the irreducible limit without a real VRF. The honest mitigation is economic: cap the aggregate value per reveal block.

Inherit one contract.
Write one function.

Inherit EntropyConsumer and implement _onRandomness; the base handles the fee, callback auth, anti-spoof, and a recovery path. Open the full SDK & API reference →

GigaKingMint.sol
// inherit the SDK base; bind the live DurianEntropyV2 on KUB (chainId 96)
contract GigaKingMint is EntropyConsumer {
    constructor(address e) EntropyConsumer(e) {}  // 0xE2BA…4caB

    // user signs ONCE: pay the gas-scaled fee, reserve a future-block roll
    function mint() external payable {
        require(msg.value >= entropy.fee(CB_GAS));
        pending[_roll(seed, CB_GAS)] = msg.sender;
    }

    // a keeper reveals; the base calls you back, grind-proof (paid at request)
    function _onRandomness(uint256 id, uint256 r) internal override {
        _mint(pending[id], pickTier(r));
    }
}
Lottery, 6 digits from one reveal
uint256 r = entropy.reveal(drawId);
uint256 winning = r.digits(6);  // 482917
Roulette, one pocket
uint256 r = entropy.reveal(spinId);
uint8 pocket = uint8(r.pick(0, 37));  // 0 to 36

Function reference

requestCallback(seed, consumer, cbGas)pay the fee, get a callback on reveal (what _roll calls); request(seed) is the free, callback-less path
fee(uint32 cbGas) → uint256the gas-scaled fee to send, at the current gas price
seal(id) · reveal(id) → uint256capture the blockhash (≤256 blk) then settle + callback; revealable anytime once sealed (permissionless, idempotent)
status(uint256 id) → uint80 NONE · 1 WAITING · 2 READY · 3 EXPIRED · 4 FULFILLED
results(uint256 id) → uint256the stored randomness (0 until revealed)

One primitive, every game.

Derive as many independent values as you need from a single reveal with the EntropyLib helper. Each demo draw below commits and then waits for a real future block to seal, so it can't be rushed.

Coin flip
Heads or tails for keeps. Stake escrows on commit, settles a block later.
r & 1 == 0 ? HEADS : TAILS
Lottery
One draw, one number, everyone checks the same fair result.
r.digits(6)
Roulette
European single-zero, fair pocket, no keeper bot required.
r.pick(0, 37)
NFT tiers
Random rarity on mint, grind-proof when you commit first.
r.pick(0, weights)

How good is the randomness?

Every value is keccak256 of a real, unpredictable KUB block hash, so the output is uniformly distributed and nothing the caller controls can bias it. Pick any game and run it hundreds of times from a single block, then watch the distribution level out. The one caveat is economic, not statistical: a block producer can bias a single block, so cap per-round value.

Pick a game, then run 600 draws from one future block.

Draw a number,
live on KUB.

Connect a wallet and the draw runs the live DurianEntropy V2 contract: request() then reveal() (the self-serve path, ~0.003 KUB). In production a keeper sends the second transaction, so your users sign once. No wallet? Run a gasless read-only preview.

network KUB Chain · chainId 96
contract0xE2BA…4caB ↗ · live on KUB
entropyhash of a real future block
DURIAN ENTROPY · LIVE DRAW
0
0
0
0
Connect a wallet to draw on-chain.

The details, in full.

Network
KUB Chain · chainId 96
Contract
DurianEntropyV2 · sign-once callback service · the fee recipient is the only privileged role
Fee owner
0x1218…93D5 · receives the protocol fee, transferable (Ownable2Step); no other power
Keeper API
durian-entropy-keeper.pupkaikub.workers.dev/reveal · settles on-ping ~6s
Interface
requestCallback · seal · reveal · status · fee(cbGas)
Entropy
keccak(blockhash, id, requester, seed)
Settlement
Permissionless · seal within 256 blocks, then reveal anytime · keeper settles ~6s
Fee
Gas-scaled, ≈ 0.016 KUB per callback request (200k cbGas) → treasury; free request/reveal path also exists
Compiler
solc 0.8.24 · optimizer 200 · evm paris
Assurance
36/36 tests, internal multi-agent passes, and an external hard audit, with no fund-loss bug in the core
License
Proprietary © Durian (durianfun) · not open source · licensed use of the canonical deployment

Questions, answered
without spin.

Is this a VRF? +
No, and we never call it one. Durian Entropy is blockhash-based commit-reveal randomness, not a cryptographic Verifiable Random Function. It is grind-proof against ordinary users and contracts. The one residual trust assumption, a block producer biasing a single block, is disclosed openly and mitigated with value caps.
How does my user sign only once? +
Your user signs the request. A keeper (the Durian keeper, the next user via self-crank, or anyone) sends the reveal, and your contract gets the callback. There is no on-chain cron, so the second transaction always needs a sender; the keeper is that sender, and your frontend falls back to a user-signed reveal if the keeper is ever down.
Is it safe to use with real value? +
Yes, for the vast majority of on-chain games and randomized mints, when you cap the aggregate value resting on one reveal block. Atomic grinding is impossible by construction, and a losing player cannot dodge (stake escrows at request; settlement is permissionless; expiry forfeits). Very high-stakes outcomes would want a real VRF, and none exists on KUB today.
What does it cost? +
The callback service charges a small gas-scaled fee per request, roughly 0.016 KUB at 200k callback gas, routed to the treasury. A free, callback-less request/reveal path also exists for self-serve integrators. The caller and keeper pay their own gas.
Has it been audited? +
It passes 36/36 tests, internal multi-agent adversarial passes, and an external hard audit with no fund-loss bug in the core (the only confirmed finding was a deploy-time cap-sizing note in a reference consumer, now a required parameter). Every result is recomputable on-chain. We will not claim a formal firm audit until one exists.
What if no one reveals in time? +
A seal captures the blockhash within the 256-block window in one cheap transaction; after that, reveal (and claim) can happen anytime, with no deadline. If nobody seals within the window the request expires and the stake is forfeit, never refunded or re-rolled. In production a keeper seals in ~6s, so a winner can claim whenever.

The randomness layer for onchain finance on KUB.

↓ Guide.md