Secure, verifiable random number generation without oracles using future block hashes
- 🎯 Overview
- 🔧 How It Works
- ⚡ Why Two-Step Randomness?
- 🔒 Security Analysis
⚠️ Limitations & Considerations
BasedRandomness is a smart contract system that generates cryptographically secure random numbers on-chain without relying on external oracles. It combines DEX pool entropy with future block hashes to create unpredictable, verifiable randomness suitable for gaming, NFT generation, lotteries, and other applications requiring fair random outcomes.
Offical Address: 0x1585f9008e08dc5dc6851994fa2c61371255a0f7 (same for each chain)
🔷 Ethereum Mainnet
🔹 Ethereum Sepolia
🔴 Optimism Mainnet
- 🔐 Oracle-Free: No dependency on external randomness providers
- 🎯 Verifiable: All randomness sources are on-chain and auditable
- ⚡ Gas Optimized: Advanced collision resolution with expanding circle search
- 🔄 Batch Support: Generate multiple random numbers efficiently
- 🛡️ Manipulation Resistant: Two-step process prevents gaming
- 🎮 Gaming Ready: Perfect for NFTs, lotteries, and games
BasedRandomness represents one of the most secure on-chain randomness solutions currently available because it combines multiple independent entropy sources with temporal separation to create an extremely difficult-to-manipulate system.
Why It's Superior:
-
🎯 No Single Point of Failure: Unlike oracle-based solutions, there's no centralized randomness provider that can be compromised or manipulated.
-
⏰ Temporal Separation: The two-step process creates a time gap where manipulation becomes exponentially more difficult:
- Step 1: Entropy locked at block N using DEX + block data
- Step 2: Results determined by blocks N+4 through N+7
- Key Insight: Attacker must predict/control future blocks that don't exist yet
-
🌊 Multiple Entropy Sources: Combines 8 independent sources that change constantly:
- 6 DEX pool balances (USDC/WETH across 3 pools)
- 2 Token total supplies
- Block hashes from multiple future blocks
L1 Ethereum Block Control Analysis:
For an attacker to manipulate BasedRandomness, they would need to control at least 3 consecutive blocks (preparation block + 3 future blocks for standard security).
Current Ethereum Statistics:
- Total Validators: ~1,000,000 validators
- Blocks per day: ~7,200 blocks
- Probability of controlling 1 block: 1/1,000,000 = 0.0001%
Probability Calculations:
Single Block Control: 1/1,000,000 = 0.0001%
Three Consecutive Blocks: (1/1,000,000)³ = 0.000000000001%
For "On-Demand" Manipulation:
- Attacker needs to control blocks at specific times (not random)
- Must coordinate with DEX manipulation simultaneously
- Window of opportunity is extremely narrow (12-second blocks)
Real-World Difficulty:
- Staking Required: ~32 ETH × 3,000 validators =
96,000 ETH ($300M+) - Success Rate: 0.000000000001% chance
- Detection: Unusual validator behavior would be immediately noticed
- Cost vs. Benefit: Manipulation cost far exceeds potential gains
BasedRandomness is perfect for applications requiring unpredictable, fair outcomes:
With based randomness, if you ask 2 or more number in a single range you have 100% secuiry that each numbers generated are unique
🎲 Gaming & Entertainment:
- Need 1 number from 1-6 (dice roll)
- Need 5 numbers from 1-100 (lottery tickets)
- Need 10 unique numbers from 1-52 (card dealing)
- Need 1 number from 1-10000 (rare item drops)
🎨 NFT & Digital Assets:
- Need 8 numbers from 1-100 (trait percentiles)
- Need 3 unique numbers from 1-1000 (color combinations)
- Need 1 number from 1-10000 (rarity determination)
- Need 20 numbers from 0-255 (RGB color generation)
🏆 Contests & Distributions:
- Need 5 unique numbers from 1-1000 (winner selection)
- Need 100 numbers from 1-10000 (airdrop recipients)
- Need 10 unique numbers from 1-100 (prize distribution)
- Need 1 number from 1-participant_count (single winner)
🎯 DeFi & Protocols:
- Need 1 number from 1-100 (liquidation ordering)
- Need 5 numbers from 1-1000 (validator selection)
- Need 10 unique numbers from 1-participant_count (governance sampling)
- Need 1 number from 0-10000 (fee randomization)
🔄 Batch Operations:
- Need 1000 numbers from 1-1000 (full permutation)
- Need 50 unique numbers from 1-100 (sample without replacement)
- Need 100 numbers from 1-6 (multiple dice rolls)
- Need 10 different ranges simultaneously (multi-game support)
BasedRandomness is NOT perfect - no on-chain randomness solution is. Here's why:
-
Theoretical Vulnerabilities:
- Large mining pools could theoretically coordinate with a low chance and a huge investment
-
Practical Limitations:
- Block Dependency: Requires 4+ blocks for security
- Gas Costs: More expensive than pseudo-random
- Timing: Not suitable for real-time applications
-
Risk Assessment:
- High-Value Applications: Use
extraSecurityfor additional blocks - Low-Value Applications: Standard security is sufficient
- Critical Applications: Consider hybrid approaches
- High-Value Applications: Use
🎯 Bottom Line: BasedRandomness provides 99.999999999999% manipulation resistance at a fraction of the cost of oracle solutions, making it ideal for most real-world applications.
BasedRandomness uses a two-step process to ensure unpredictability:
// Locks in parameters using CURRENT block data + DEX entropy
bytes32 requestId = basedRandomness.prepareRandomNumbers(
100, // maxNumber: 1-100 range
10, // count: 10 numbers
entropy, // initial entropy
false, // includeZero: 1-100 (not 0-100)
address(0), // idOwner: msg.sender
0, // extraSecurity: standard 4 blocks
bytes32(0) // auto-generate DEX entropy
);What happens:
- Collects entropy from 6 DEX pools (USDC/WETH balances)
- Combines with block data (
block.number,block.prevrandao) - Generates unique
requestId - Stores request parameters in storage
// Wait 4+ blocks, then generate using FUTURE block hashes
await waitForBlocks(4);
uint256[] memory numbers = basedRandomness.generateRandomNumbers(requestId);What happens:
- Uses block hashes from blocks after preparation
- Combines with stored entropy from Step 1
- Generates unique numbers with collision resolution
- Cleans up transient storage
The two-step process makes manipulation extremely difficult:
- Preparation locks entropy from current block + DEX state or custom entrophy
- Generation uses future blocks that are unpredictable at preparation time
- Triggering generation cannot influence the outcome - it only reveals results based on already-mined blocks
| Traditional Oracle | BasedRandomness |
|---|---|
| ❌ External dependency | ✅ Fully on-chain |
| ❌ Oracle fees | ✅ Gas-only costs |
| ❌ Latency delays | ✅ Predictable timing |
| ❌ Centralization risk | ✅ Decentralized |
- Purpose: Defines the maximum value for generated numbers
- Range: 1 to 2^120 (extremely large range support)
- Examples:
6for dice rolls (1-6)100for percentiles (1-100)1000for participant IDs (1-1000)10000for rare item drops (1-10000)
- Purpose: How many random numbers to generate
- Range: 1 to 1000 (gas optimization limit)
- Examples:
1for single results (winner selection)5for multiple traits (NFT attributes)10for card dealing (poker hand)100for batch operations (multiple users)
- Purpose: Whether to include 0 in the range
- Options:
true: Range is 0 to maxNumber (0-100 = 101 possibilities)false: Range is 1 to maxNumber (1-100 = 100 possibilities)
- Use Cases:
truefor array indices (0-based)falsefor human-readable numbers (1-based)
- Purpose: Who can generate the random numbers
- Options:
address(0): Use msg.sender (caller)specific_address: Only that address can generatecontract_address: Contract controls generation
- Security: Prevents unauthorized generation
- Purpose: Extra blocks to wait beyond standard 4 blocks
- Range: 0 to 50 blocks
- Use Cases:
0: Standard security (4 blocks total)2-5: Medium security (6-9 blocks total)10+: High security (14+ blocks total)
- Trade-off: More security = longer wait time
- Purpose: Provide custom entropy or use auto-generated
- Options:
bytes32(0): Auto-generate from DEX poolscustom_hash: Use your own entropy source
- Recommendation: Use auto-generated for maximum security
- Purpose: Ensures unique request IDs
- Examples:
keccak256(abi.encodePacked(msg.sender, block.timestamp))keccak256(abi.encodePacked("gameId", gameId))keccak256(abi.encodePacked("nft", tokenId))
- Maximum Range: 2^120 (gas optimization ceiling)
- Maximum Count: 500 numbers per request (gas safety limit)
- Minimum Wait: 4 blocks (security requirement)
- Maximum Wait: 54 blocks (4 + 50 extra security)
- EVM Requirement: Cancun-compatible chains only
- Block Dependency: Results available 4-54 blocks after preparation
maxNumbers: Must have length > 0 (required)counts: Length 1 (same for all) OR same length as maxNumbersextraSecurity: Length 1 (same for all) OR same length as maxNumbersincludeZero: Single boolean applies to all requestsidOwner: Single address applies to all requests
- Gas Savings: ~30% less gas than individual requests
- Entropy Sharing: Single DEX call for all requests
- Request Management: Returns array of requestIds for tracking
- Generation: Can generate all at once or individually
- High-Value Applications: Use
extraSecurity=5-10for additional blocks - Public Contests: Use
extraSecurity=2-5to prevent last-minute manipulation - Gaming: Standard security (
extraSecurity=0) is usually sufficient - Always Verify: Check
isRequestReady()before generation
- Store Request IDs: Keep track of requests for later generation
- Event Monitoring: Listen for RandomNumberRequested events
- Error Handling: Handle range exhaustion and timing issues
- Unique Entropy: Use different initialCumulativeHash per request
function prepareRandomNumbers(
uint256 maxNumber, // Maximum value (1 to 2^120)
uint256 count, // Number of random numbers (1 to 1000)
bytes32 initialCumulativeHash, // Initial entropy
bool includeZero, // Include 0 in range
address idOwner, // Who can generate (0x0 = msg.sender)
uint256 extraSecurity, // Extra blocks to wait (0-50)
bytes32 baseEntropyHash // Custom entropy (0x0 = auto-generate)
) external returns (bytes32 requestId);Parameters:
maxNumber: Upper bound for random numbers (1 to 2^120)count: How many random numbers to generate (1 to 1000)initialCumulativeHash: Custom entropy for request ID generationincludeZero:true: Range is 0 to maxNumberfalse: Range is 1 to maxNumber
idOwner: Address authorized to generate numbers (useaddress(0)formsg.sender)extraSecurity: Additional blocks to wait beyond standard 4 blocksbaseEntropyHash: Custom entropy source (usebytes32(0)for DEX-generated entropy)
function generateRandomNumbers(bytes32 requestId)
external returns (uint256[] memory randomNumbers);Requirements:
- Must be called by the
idOwnerfrom preparation - Must wait at least 4 +
extraSecurityblocks - Request must exist and not be already generated
function batchPrepareRandomNumbers(
uint256[] calldata maxNumbers,
uint256[] calldata counts,
bytes32 initialCumulativeHash,
bool includeZero,
address idOwner,
uint256[] calldata extraSecurity,
bytes32 baseEntropyHash
) external returns (bytes32[] memory requestIds);Array Length Rules:
maxNumbers: Must have length > 0counts: Length 1 (same count for all) OR same length asmaxNumbersextraSecurity: Length 1 (same security for all) OR same length asmaxNumbers
function isRequestReady(bytes32 requestId) external view returns (bool);Returns true if enough blocks have passed for secure generation.
event RandomNumberRequested(
bytes32 indexed requestId,
address indexed requester,
uint256 maxNumber,
bool includeZero,
uint256 extraSecurity,
uint256 count
);event RandomNumberGenerated(
bytes32 indexed requestId,
address indexed requester,
uint256 randomNumber
);BasedRandomness combines 8 independent entropy sources:
- USDC Balance Pool 1 - Changes with every swap
- WETH Balance Pool 1 - Changes with every swap
- USDC Balance Pool 2 - Changes with every swap
- WETH Balance Pool 2 - Changes with every swap
- USDC Balance Pool 3 - Changes with every swap
- WETH Balance Pool 3 - Changes with every swap
- USDC Total Supply - Changes with minting/burning
- WETH Total Supply - Changes with minting/burning
Or you pass your own
✅ Low Manipulation Risk:
-
DEX Pool Manipulation:
- Requires significant capital to meaningfully change pool balances
- Temporary - other traders will arbitrage back
- Affects only preparation phase, not generation
-
Block Hash Manipulation:
- Miners cannot predict future block hashes
- Would require controlling multiple consecutive blocks
- Extremely expensive and detectable
-
MEV/Frontrunning:
- Generation triggers cannot change randomness
- Results are deterministic based on already-mined blocks
- No advantage to timing the generation call
- Uses
tstore/tloadopcodes for temporary data - Automatic cleanup prevents storage bloat
- Efficient collision tracking with minimal gas cost
- Maximum Range: 2^120 (gas optimization limit)
- Maximum Count: 1000 numbers per request (gas safety)
- Block Dependency: Requires 4+ blocks for security
- EVM Version: Requires Cancun-compatible chains for transient storage
✅ Excellent For:
- Gaming and NFTs
- Lotteries and contests
- Fair distribution mechanisms
- Procedural generation
❌ Still Not Suitable For:
- High-frequency applications
- Sub-block timing requirements
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ by BasedToschi