Whitepaper
Abstract
This document describes a simple commit–reveal protocol for on‑chain gambling where users place a bet and later reveal a secret to determine the outcome. The design enforces a strict N+1 block reveal to eliminate the ability for users to selectively reveal only when they would win (user abort problem). We discuss the contract interface, timing constraints, economic parameters, operational requirements, security considerations, and potential improvements.
Motivation
Most Web3 applications rely on off-chain randomness sources (oracles, VRF services, centralized APIs) which introduce trust assumptions and potential points of failure. The goal of this protocol is to achieve full on-chain randomness without external dependencies, using only blockchain-native data and cryptographic commitments.
On-chain games that rely on randomness often suffer from user and miner (block producer) manipulation. The user abort problem occurs when a user computes an unfavorable outcome and chooses not to reveal. To address this, we enforce that reveal must occur within 256 blocks after the commit. Failing to reveal within this window forfeits the bet. This provides flexibility for users while still preventing manipulation through selective reveal, as the window is bounded and predictable.
System Overview
Participants:
Player: Commits to a secret and places a bet. Must reveal within 256 blocks.
House / Owner: Configures parameters, provides liquidity, withdraws fees.
Optional Backend/Relayer: A monitoring service that submits the reveal transaction on behalf of the player to improve reliability.
Assets: Native BNB.
Randomness: Derived from player seed, previous block hash, timestamp, and contract salt. Outcome is keccak256(...) % denominator.
Denominator: The size of the outcome space that determines game odds. For example: 2 for coin flip (50% win chance), 6 for dice roll (16.67% win chance), 10 for 1-in-10 games (10% win chance). The denominator directly affects both the win probability (1/denominator) and the payout multiplier (denominator × bet amount).
Win condition: Outcome equals 0; payout is betValue * denominator.
Smart Contract Design
Contract: CRgambling.sol
Key parameters:
denominator: Size of the outcome space (e.g., 2 for coin flip).
salt: Contract-level entropy mixed into randomness.
maxBetAmount: Upper bound on bet size.
commitFee: Flat fee charged per commit; accrues to collectedFees.
deposit: Tracked liquidity provided to cover payouts.
Core functions:
commit(bytes32 hash) payable: Records a bet for the sender; emits Commit.
reveal(bytes32 seed, bytes32 solution): Must be mined within 256 blocks of commit or it reverts. Computes outcome; pays on win; emits Reveal or Loss.
Liquidity and fee management: deposit, withdraw, setCommitFee, setMaxBetAmount.
Protocol Flow
Preparation (off-chain)
Player samples (seed, solution) and computes hash = keccak256(seed, solution).
Commit (on-chain)
Player calls commit(hash) sending betWei.
Contract stores: blockNumber = N, hash, value = betWei - commitFee.
Reveal (on-chain, within 256 blocks)
Within 256 blocks of commit, a transaction calls reveal(seed, solution).
Contract verifies keccak256(seed, solution) == hash and block.number <= N+256.
Contract computes outcome: uint256(keccak256(seed, prevBlockHash, timestamp, salt)) % denominator.
If outcome is 0: pays value * denominator to player; else emits Loss.
The bet entry is deleted after reveal to prevent reuse.
Frontend-Only Implementation Strategy
Flexible Reveal Timing
For frontend-only implementations without a backend relayer, the 256-block reveal window provides significant flexibility and eliminates the need for complex pre-signing strategies.
User-Friendly Approach: The extended timing window allows users to:
Commit their bet and take time to decide when to reveal
Handle network delays and MetaMask signature processes without stress
Manage their own timing without complex automation
Simplified Implementation Strategy:
Preparation Phase: User generates (seed, solution) and computes hash = keccak256(seed, solution). User determines bet amount and gas parameters
Execute Commit: Sign and execute commit(hash) with the bet amount. Monitor for transaction inclusion in block N
Flexible Reveal: User has up to 256 blocks to decide when to reveal. No pre-signing required - user can sign the reveal transaction when they choose, within the time window. This makes the process much more manageable and less stressful.
Critical: Bet Persistence Warning
BET LOSS ON PAGE REFRESH/CLOSE: If you refresh the page or close your browser after placing a bet but before revealing, your bet will be permanently lost. The secret required for the reveal is not stored anywhere - not on the server, not in your browser, and not in your wallet.
STAY CONNECTED: It is absolutely critical that you remain connected to this page with a stable internet connection from the moment you place your bet until you complete the reveal process and see the final result.
NO RECOVERY POSSIBLE: Once you leave the page or lose connection, there is no way to recover your bet or the secret needed to reveal it. The bet will be forfeited after 256 blocks.
Economics
Bet value: value = msg.value - commitFee. commitFee accrues to collectedFees.
Payout: On win, the player receives value * denominator.
Liquidity: The contract tracks theoreticalLiquidity and exposes getLiquidityGap() to compare against actual available balance (balance - collectedFees). Note: the current implementation does not enforce solvency at commit time; the owner should provision adequate liquidity.
Security Considerations
Commit-Reveal Protection Against Manipulation
The commit-reveal mechanism provides strong protection against manipulation by ensuring that no participant can cheat or "baiser" (screw over) others through the randomness generation process. Here's how the cryptographic protection works:
Commitment binding: When a player commits a hash of their (seed, solution), they are cryptographically bound to that specific seed and solution. They cannot change their values after seeing the outcome.
No selective reveal: Players cannot compute the outcome before revealing and then choose to only reveal when they win. The 256-block window forces them to reveal within a bounded timeframe, preventing the user abort problem.
Blockchain entropy integration: The randomness includes the previous block hash, which is unpredictable at commit time, ensuring that even if a player knew their own seed, they cannot predict the final outcome.
Contract salt protection: The immutable contract salt prevents cross-game manipulation and ensures each game instance has unique entropy.
The only exception: The only way someone can be "screwed over" is if a malicious node (miner/validator) refuses to include a reveal transaction for the entire 256-block window. This would cause the player to forfeit their bet, but this attack is:
Economically costly for the attacker (losing block rewards)
Technically difficult (requires sustained censorship for 256 blocks)
Easily detectable and would damage the network's reputation
Mitigated by the 256-block window providing multiple opportunities for inclusion
Critical Implementation Warnings
Miner Manipulation Risk
The contract includes explicit warnings about miner (block producer) manipulation:
Timestamp manipulation: Miners can manipulate block.timestamp within ±15 seconds, affecting the randomness calculation. That is why the smart contract doesn't use the block timestamp.
Transaction censorship: Miners can observe pending reveal transactions and compute outcomes before including them. If they see a winning transaction, they might censor it to include their own winning bet instead. The 256-block window provides more opportunities for such manipulation compared to strict N+1 timing.
Front-running: The commit phase hides the seed and solution, preventing pre-reveal front-running. However, reveal transactions still face standard mempool risks.
Solvency Risk
The contract explicitly warns about potential insolvency:
No liquidity enforcement: The contract does not enforce sufficient liquidity at commit time. Multiple consecutive wins could render the contract insolvent.
Suggested improvement: The contract comments suggest adding require(theoreticalLiquidity >= valueWithoutFee * denominator, "Insufficient liquidity") to prevent over-commitment.
Operational Recommendations
Player UX: Warn that missing the 256-block window forfeits the bet. The extended timing provides flexibility, but users should still monitor their reveals and set appropriate gas fees for timely execution.
Backend relayer: Subscribe to Commit events; maintain a mempool and inclusion tracker. Submit Reveal within the 256-block window with appropriate timing. Use multiple RPC providers and failover; simulate transactions before sending. Handle retries with incrementing priority fees; avoid duplicate reveals.
Monitoring: Track success rates of reveals within the 256-block window. Alert on liquidity shortfalls (getLiquidityGap() > 0).
Future Improvements
Provable randomness: Integrate VRF or randomness beacons (at the cost of latency and oracles).
Inclusion protection: Use private tx relays or MEV-aware tools to reduce censoring/manipulation of winning reveals.
Solvency enforcement: Require sufficient liquidity at commit time; maintain per-bet reserves.
Dynamic reveal window: Consider adjustable reveal windows based on network conditions or user preferences, while maintaining anti-abort properties through bounded timing constraints.
Batching: Aggregate commits and reveals to reduce per-bet overhead where UX allows.
Account Abstraction: Sponsor reveals via paymasters so users don't manage gas for reveals.
