Quiver brings verifiable on-chain randomness to Robinhood Chain — a two-party commit–reveal protocol where a fair outcome holds as long as either party is honest. Request randomness and get a result your users can verify on-chain.
A naïve blockhash is chosen by the block producer. Quiver instead binds two independent contributions so no single actor can steer the outcome.
The provider posts the tip of a keccak hash chain, chain[N] = keccak²⁵⁶ᴺ(seed). Every value behind it is fixed — and hidden — the moment the commitment is on-chain.
It submits its own committed value and calls request, reserving a sequence number — without either side seeing the other's value yet.
The keeper reveals the provider's value; the coordinator verifies it against the commitment and combines both into a randomNumber, delivered to your callback.
Two values, each committed before either is revealed. The result is a fixed function of both — fair as long as one side is honest.
A moving anchor makes each sequential reveal cost exactly one keccak hash, no matter how many requests the provider has served.
State advances before your callback runs. If it reverts, randomness is buffered and anyone can retry — the provider is still paid.
Every reveal is checked on-chain against the provider's published commitment. A wrong value fails the hash check and is rejected.
Get a callback in your contract, or request and self-reveal. Fold in blockhash when you need provider-unpredictability too.
A TypeScript client, the Fletcher keeper service, and reference consumers (CoinFlip, DiceGame) ship in the box.
QuiverConsumer and call _requestRandomness._fulfillRandomness.@quiver/sdk and viem.import {QuiverConsumer} from "quiver/QuiverConsumer.sol";
contract CoinFlip is QuiverConsumer {
mapping(uint64 => address) public player;
constructor(address quiver, address provider)
QuiverConsumer(quiver, provider) {}
// Request randomness — pays the fee, reserves a sequence number.
function flip(bytes32 userRandom) external returns (uint64 seq) {
seq = _requestRandomness(userRandom);
player[seq] = msg.sender;
}
// The keeper reveals; the coordinator calls your contract back.
function _fulfillRandomness(uint64 seq, address, bytes32 rnd)
internal override
{
bool heads = uint256(rnd) & 1 == 0; // verifiable randomness
// ... settle the bet ...
}
}Games, lotteries, mints, fair ordering, committee selection — anything that needs randomness no one can predict or manipulate.