Skip to content
View future-drand's full-sized avatar
  • Joined Aug 19, 2026

Block or report future-drand

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
future-drand/README.md

future-drand

What is future-drand?

future-drand is a pattern for using drand randomness within smart contracts.

The name iterates on "future blockhash" - a flawed, insecure pattern that developers have attempted to use for years.

future-drand is the same concept done properly: commitment to a future value followed by execution.

Using future-drand requires:

  • Committing to a future drand beacon value on-chain
  • Using the src/DrandRegistry.sol to store and verify that value
  • Executing the earlier commitment

Minimal example:

pragma solidity ^0.8.30;

import {IDrandRegistry} from "future-drand/IDrandRegistry.sol";
import {FutureDrandConsumer} from "future-drand/FutureDrandConsumer.sol";

/// @notice One-shot example with no funds or user-supplied outcome inputs.
contract CoinFlip is FutureDrandConsumer {
    uint64 public immutable round;
    bool public settled;
    bool public heads;

    constructor(IDrandRegistry _drand) FutureDrandConsumer(_drand) {
        round = _commitFutureRound(0);
    }

    function settle(bytes calldata signature) external returns (bool) {
        require(!settled);
        settled = true;

        _acceptCarriedProof(round, signature);
        heads = _deriveRandomness(round, bytes32("coinflip")) % 2 == 0;
        return heads;
    }
}

Usage

forge install future-drand/future-drand
import {FutureDrandConsumer} from "future-drand/FutureDrandConsumer.sol";

What is drand?

drand is a distributed randomness beacon operated by the League of Entropy.

The League of Entropy is a group of orgs including Cloudflare, the Ethereum Foundation and many others.

drand's quicknet network publishes a new beacon (random value) every 3 seconds, which anyone can verify on-chain.

Disclaimer: future-drand is not associated with drand or the LoE

Repo Contents

Deployments

Canonical address: 0xbeac0377D6fe8B753767616749AEe539E80F6bE6

Etherscan: 0xbeac0377D6fe8B753767616749AEe539E80F6bE6

Deployed chains: contractscan.xyz/contract/0xbeac0377D6fe8B753767616749AEe539E80F6bE6

Deploy it to any EIP-2537 chain using Arachnid:

cast send --private-key $DEPLOYER_KEY 0x4e59b44847b379578588920cA78FbF26c0B4956C "0x000000000000000000000000000000000000000000000000000000007da4798b$(forge inspect src/DrandRegistry.sol:DrandRegistry bytecode | cut -c3-)"

Init code hash: 0x16134ab9154febf44b1f9e1806385abbcd31adda84dbd2d1a72b80e7bf73f1d2

The factory, salt, hash and address are pinned in CI by test/integration/DeploymentIdentity.t.sol.

Security Assumptions

  • drand randomness is safe and verifiable unless a threshold of League of Entropy operators collude
  • If drand itself migrates or halts, this version of the protocol expires and a new deployment is required. Recovery is the consumer's responsibility
  • BLS verification is a minimal in-repo wrapper over the EIP-2537 precompiles (src/BLS12381.sol); curve, subgroup and canonicality checks are the precompiles' mandated behaviour
  • Consumers are responsible for appropriate reveal timing (see below) and this advice may become invalidated by future updates
  • Everything that selects an outcome (salt, participants, payout rules) must be committed before the target round exists - an input chosen after the beacon is public can be mined to a favorable result
  • These contracts are unaudited. See SECURITY.md

Reveal Timing

A commitment is only secure if it targets a round of drand that is genuinely in the future, so we must carefully consider how block.timestamp is inserted into blocks.

The optional minRequestableRound() buffer (19 seconds) is a recommended floor, analyzed below.

Rounds tick every 3 seconds and a timestamp lands 0-2s into the current round, so an N-round buffer places its target 3N-2 to 3N seconds after the timestamp. Durations below quote the floor.

Ethereum Mainnet

block.timestamp is consensus-enforced to exact slot times and can be trusted not to lag.

Slots and rounds share a fixed phase, so an N-round buffer targets a value published exactly 3N-2 seconds after the timestamp.

An attacker can cheat by withholding a block until the beacon resolves, publishing it only when favorable. To keep that option alive past the slot boundary, the next proposer must also be theirs.

Therefore, an N-round buffer requires k = 1 + floor((3N-2) / 12) consecutive proposers.

Consumers must choose an appropriate buffer based on the value at risk in a single block.

Given one coordinated operator controlling 10% (~$7 billion of staked ETH) or 2% (~$1.4 billion) of Ethereum's proposers:

Min. rounds Attack requires Cost per attempt Window @ 10% Window @ 2%
7 (19s) 2 consecutive slots ~$480 ~20 min ~8 hours
11 (31s) 3 consecutive slots ~$720 ~3 hours ~17 days
15 (43s) 4 consecutive slots ~$960 ~1.4 days ~2.4 years
23 (67s) 6 consecutive slots ~$1,440 ~5 months ~5,900 years
31 (91s) 8 consecutive slots ~$1,920 ~38 years ~15 million years

Proposer assignments are known minutes in advance, so an attacker waits for a run of their own slots rather than forcing one - the windows above are the average wait between chances. Each row leaves the first honest proposer 7 seconds to publish, but if that slot is missed or late, the attacker needs one fewer of their own. A failed attempt forfeits the run's rewards and MEV, and leaves missed slots on-chain that can later be correlated with winning bets.

The deployed default is 7 rounds. Consumers whose single-block value at risk justifies a rarer window should raise _extraRounds - every additional slot (12 seconds) increases the wait 10x for the 10% operator, 50x at 2%. By a 2 minute buffer even the 10% operator waits ~3,800 years, and past two finalized epochs (~13 minutes) the commit block is final before the beacon exists and the attack becomes impossible.

Layer 2s

Note: this research is unverified and every L2 is different - use on L2s at your own risk.

Typically, block.timestamp is controlled by a single sequencer.

Base (OP Stack) and Robinhood Chain (Arbitrum Nitro) are slightly different:

Base (OP Stack) Robinhood Chain (Arbitrum Nitro)
block.timestamp genesis + 2 x block number, a counter asserted by the sequencer, monotonic
how it can lag only by halting block production - a visible outage silently, inside a 96h permitted envelope
observed skew (informal sample) +0.04s -1.50s

On either chain, an innocently lagging sequencer clock could make the recommended target unsafe by default.

However, a beacon cannot exist before the League of Entropy signs it, so every posted beacon is proof of real time:

// a beacon exists for a time this chain claims has not happened yet
uint64 anchor = drand.maxPostedRound(); // 0 until the first beacon is posted
bool clockLagging = anchor != 0 && drand.roundTimestamp(anchor) > block.timestamp;

Consumers can reduce reliance on the sequencer clock by posting a recent beacon and committing in the same transaction:

_acceptCarriedProof(newestRound, signature); // raise the floor to construction time
round = _commitFutureRound(0);               // future relative to the anchor

Carrying fresh proof with a commitment protects against innocent clock lag.

A malicious L2 sequencer could withhold the transaction until the buffer elapses, but only if drand.maxPostedRound() stays stale.

If it is kept fresh by users, the sequencer would also have to censor all beacon submissions for a window while attacking.

Either is severe and overt misbehaviour for an L2 sequencer: withholding shows up in inclusion times, and a lagging clock is visible on-chain. A sequencer prepared to do this could also front-run swaps.

Comparison to Chainlink VRF v2.5

Chainlink VRF is the established, status-quo option for on-chain randomness in 2026.

future-drand trades built-in callback and pre-settlement secrecy for permissionless delivery and automatic cost sharing.

Property future-drand Chainlink VRF v2.5
Randomness Public threshold beacon Request-specific VRF proof
Delivery User, protocol bot, or searcher/bounty Automatic callback
Reuse Each 3s round is shared via public registry Request-scoped; applications can build their own batching
Setup Registry; no account or provider funding Subscription or pre-funded wrapper
Migration surface drand chain identity and public key Coordinator, key hashes, billing and product version
Availability Any EIP-2537 chain Requires Chainlink VRF deployment
Result visibility Public the moment the round is signed Private until callback; operator sees first

Cost sharing

Protocol overhead is one proof submission per round (~204k gas), shared by every outcome that uses that round:

Outcomes sharing a round Protocol gas per outcome
1 ~204k
10 ~20k
100 ~2k

Application settlement runs on top of this and varies by integration.

To estimate dollar cost: gas_price_gwei x eth_price_usd / 1000 = $/M gas

At 0.1 gwei and $2,000/ETH:

  • A fresh proof costs ~$0.04
  • An outcome sharing a round with 99 others pays ~$0.0004 for its randomness.

At those same example prices, a Chainlink VRF v2.5 subscription request:

  • Bills 115k verification gas on top of the application callback (Chainlink's Ethereum example), then a 20-24% premium on both
  • A 200k callback therefore bills ~315k gas: ~$0.063 before the premium, ~$0.076-0.078 after
  • This overhead repeats per request rather than falling with volume
  • Batching is possible, but still protocol independent

Counting protocol overhead only, future-drand is cheaper from 2 outcomes per shared round.

quicknet vs evmnet

drand operates two relevant 3-second randomness networks:

Property quicknet evmnet
Launched 2023 2024
Curve BLS12-381 BN254
Security 120+ bits Approximately 80 bits
Signature 48 bytes compressed 64 bytes
EVM support Requires EIP-2537 Works with older BN254 precompiles
Main advantage Stronger security and modern cryptography Compatibility with older EVM chains
Reference verification cost 140,580 gas 159,274 gas

future-drand uses quicknet for greater security and because EIP-2537 is available on most chains:

Chain EIP-2537
Ethereum yes
Base yes
Arbitrum One yes
OP Mainnet yes
Robinhood Chain yes
Polygon PoS yes
BNB Chain (BSC) yes
Monad yes
Avalanche C-Chain no
HyperEVM no

Popular repositories Loading

  1. future-drand future-drand Public

    Solidity 1