Fair Random Crash Game on Blockchain

Developing a blockchain Crash game is not just a smart contract with randomness. The core dilemma: how to give players absolute confidence in the fairness of the result without sacrificing speed? Classic solutions on Ethereum L1 drown in gas and delays — a cashout transaction takes 12 seconds, while

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1441
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    998
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1267
  • image_logo-advance_0.webp
    B2B Advance company logo design
    713
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1003

Developing a blockchain Crash game is not just a smart contract with randomness. The core dilemma: how to give players absolute confidence in the fairness of the result without sacrificing speed? Classic solutions on Ethereum L1 drown in gas and delays — a cashout transaction takes 12 seconds, while a crash can occur in 100 ms. L2 networks (Arbitrum, Polygon) and hybrid architectures with off-chain signatures solve this. We bet on provably fair via Chainlink VRF and batch settlement — this allows processing millions of rounds with a fee of less than $0.01 per transaction.

Crash is a game where the multiplier grows from 1x upward and randomly "crashes" at some point. The player must withdraw the bet before the crash. In a decentralized version, the round result must be provably fair: the player can mathematically verify that the multiplier was not rigged. This is achieved via a commitment scheme and on-chain randomness from Chainlink. The cashout architecture is critically important — it determines the economy and user experience. Below we break down the key nodes.

How to implement provably fair in a blockchain Crash game?

Commitment + Reveal scheme (without oracle)

Classic scheme: the operator pre-publishes the hash of the next seed, then reveals the seed after bets close.

contract CrashGame { struct Round { bytes32 seedHash; bytes32 seed; uint64 crashPoint; uint256 totalBets; uint256 startTime; RoundStatus status; } enum RoundStatus { ACCEPTING_BETS, IN_PROGRESS, CRASHED, CASHOUT_PHASE } function commitNextRound(bytes32 seedHash) external onlyOperator { require(rounds[nextRoundId].status == RoundStatus.CRASHED, "Previous not finished"); rounds[nextRoundId + 1].seedHash = seedHash; } function revealAndStart(uint256 roundId, bytes32 seed) external onlyOperator { Round storage round = rounds[roundId]; require(round.status == RoundStatus.ACCEPTING_BETS, "Wrong status"); require(keccak256(abi.encodePacked(seed)) == round.seedHash, "Seed mismatch"); round.seed = seed; round.crashPoint = _calculateCrashPoint(seed, roundId); round.status = RoundStatus.IN_PROGRESS; round.startTime = uint64(block.timestamp); emit RoundStarted(roundId, round.crashPoint); } } 

Problem with commitment scheme: the operator knows the seed in advance and may refuse to reveal an unfavorable one (griefing). Solution — VRF.

Chainlink VRF V2 Plus: trustless random

import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol"; contract CrashGame is VRFConsumerBaseV2Plus { uint256 private immutable s_subscriptionId; bytes32 private immutable s_keyHash; mapping(uint256 => uint256) public roundToVrfRequest; mapping(uint256 => uint256) public vrfRequestToRound; function closeAndRequestRandom(uint256 roundId) external onlyOperator { Round storage round = rounds[roundId]; require(round.status == RoundStatus.ACCEPTING_BETS, "Wrong status"); round.status = RoundStatus.IN_PROGRESS; uint256 requestId = s_vrfCoordinator.requestRandomWords( VRFV2PlusClient.RandomWordsRequest({ keyHash: s_keyHash, subId: s_subscriptionId, requestConfirmations: 1, callbackGasLimit: 100_000, numWords: 1, extraArgs: VRFV2PlusClient._argsToBytes( VRFV2PlusClient.ExtraArgsV1({nativePayment: false}) ) }) ); roundToVrfRequest[roundId] = requestId; vrfRequestToRound[requestId] = roundId; } function fulfillRandomWords( uint256 requestId, uint256[] calldata randomWords ) internal override { uint256 roundId = vrfRequestToRound[requestId]; Round storage round = rounds[roundId]; uint256 rand = randomWords[0]; round.crashPoint = _calculateCrashPoint(rand); round.seed = bytes32(rand); emit RoundActive(roundId, round.startTime = uint64(block.timestamp)); } } 

Chainlink VRF documentation: "VRF provides cryptographic proofs that the random number was generated using the block data and the oracle's secret key."

Crash point formula

Crash point math with 1% house edge

Target distribution: P(crash >= X) = 0.99/X. Minimum crash = 1.00x.

function _calculateCrashPoint(uint256 rand) internal pure returns (uint64) { uint256 h = rand % 1_000_000_000; if (h < 10_000_000) return 100; // 1.00x uint256 crashPoint = 990_000_000 * 100 / h; if (crashPoint < 100) return 100; if (crashPoint > 100_000) return 100_000; return uint64(crashPoint); } 

Verification: any player can take the VRF randomWords[0] from on-chain data and reproduce the formula — they will get the same crash point.

Why manual cashout is a bottleneck and how to bypass it?

Bet and cashout mechanics

struct Bet { address player; uint256 amount; uint64 autoCashoutAt; bool cashedOut; uint64 cashoutMultiplier; } mapping(uint256 => mapping(address => Bet)) public bets; function placeBet(uint256 roundId, uint64 autoCashoutAt) external payable { Round storage round = rounds[roundId]; require(round.status == RoundStatus.ACCEPTING_BETS, "Not accepting bets"); require(msg.value >= MIN_BET && msg.value <= MAX_BET, "Invalid amount"); require(bets[roundId][msg.sender].amount == 0, "Already bet"); bets[roundId][msg.sender] = Bet({ player: msg.sender, amount: msg.value, autoCashoutAt: autoCashoutAt, cashedOut: false, cashoutMultiplier: 0 }); rounds[roundId].totalBets += msg.value; emit BetPlaced(roundId, msg.sender, msg.value, autoCashoutAt); } function cashout(uint256 roundId) external { Round storage round = rounds[roundId]; Bet storage bet = bets[roundId][msg.sender]; require(round.status == RoundStatus.IN_PROGRESS, "Round not active"); require(bet.amount > 0 && !bet.cashedOut, "No active bet"); uint64 currentMultiplier = _getCurrentMultiplier(round.startTime); require(currentMultiplier <= round.crashPoint, "Round already crashed"); bet.cashedOut = true; bet.cashoutMultiplier = currentMultiplier; uint256 payout = bet.amount * currentMultiplier / 100; payable(msg.sender).transfer(payout); emit CashedOut(roundId, msg.sender, currentMultiplier, payout); } function _getCurrentMultiplier(uint64 startTime) public view returns (uint64) { uint256 elapsed = block.timestamp - startTime; uint256 multiplier = 100 + (elapsed * elapsed * 2); return uint64(multiplier > 100_000 ? 100_000 : multiplier); } 

Manual cashout on-chain has latency. The player clicks cashout in the UI → transaction goes to mempool → gets included in a block (10–12 sec on Ethereum). During that time, the round may crash. On L2 (Arbitrum: 250 ms, Solana: 400 ms) this is more acceptable, but still not ideal. Transaction fee on Arbitrum is less than $0.01, making frequent cashouts economically viable.

Solution for low-latency: hybrid architecture. Off-chain cashout: player signs a cashout request → game server stores the signed timestamp → during on-chain settlement, the game server proves the player requested cashout before the crash. This requires trust in the game server but with cryptographic accountability.

Off-chain batch settlement

struct CashoutRecord { address player; uint64 multiplier; bytes signature; } function settleBatch( uint256 roundId, CashoutRecord[] calldata cashouts ) external onlyOperator { Round storage round = rounds[roundId]; require(round.status == RoundStatus.CRASHED, "Round not crashed"); for (uint i = 0; i < cashouts.length; i++) { CashoutRecord calldata c = cashouts[i]; Bet storage bet = bets[roundId][c.player]; require(!bet.cashedOut, "Already settled"); require(c.multiplier <= round.crashPoint, "Invalid multiplier"); _verifyCashoutSignature(roundId, c.player, c.multiplier, c.signature); bet.cashedOut = true; bet.cashoutMultiplier = c.multiplier; uint256 payout = bet.amount * c.multiplier / 100; payable(c.player).transfer(payout); } } 

Network comparison for blockchain Crash

Network Block time Gas cost (typical) Suitable for MVP Summary
Ethereum L1 12-15 sec High (~$50/tx) No Only for high-rollers due to latency and fees
Arbitrum One ~250 ms Low ($0.01-$0.05) Yes Best balance: speed, security, ecosystem
Polygon PoS ~2 sec Very low ($0.001) Yes Even cheaper, but less decentralized
Solana ~400 ms Minimal ($0.0001) Yes Maximum speed, but Rust development is harder

Hybrid cashout and batch settlement can save up to $5000 monthly on gas with high player activity. Average fee on Arbitrum — $0.01-0.03 per cashout, making microtransactions profitable.

Our work process

  1. Analysis and specification — defining mechanics, house edge, RNG, latency requirements.
  2. Smart contract design — architecture, pattern selection (commitment, VRF, batch settlement).
  3. Contract implementation — Solidity, Foundry, thorough testing (unit, integration, fork).
  4. Backend and frontend development — Node.js game server, WebSocket, React with real-time graphics.
  5. Audit and formal verification — Slither, Echidna, Mythril, third-party auditor if needed.
  6. Deployment and monitoring — contracts on mainnet, Tenderly setup, dashboards.
  7. Regulatory compliance — document preparation for license, KYC/AML integration.
Stage Duration Result
Analysis and specification 1-2 weeks Requirements document, UI mockups
Contract design 1-2 weeks Architecture, ERC implementation
Contract implementation 3-4 weeks Ready contracts, tests, CI
Backend and frontend 4-6 weeks Game server, WebSocket, UI
Audit and verification 2-3 weeks Audit report, fixes
Deployment and monitoring 1 week Contracts on network, monitoring

What is included in the work (deliverables)

  • Source code of smart contracts (Solidity) with full test suite.
  • Detailed documentation on architecture, formulas, verification procedure.
  • Game server (Node.js) with WebSocket and contract integration.
  • Frontend (React) with visualization and wallet (MetaMask, WalletConnect).
  • Deployment and management guide (Tenderly, Etherscan).
  • Launch support (24/7 for the first week).

Our experience and metrics

Over 5 years, we have developed blockchain solutions for GameFi. Our portfolio includes 10+ projects, including Crash, Dice, and NFT lotteries. Our contracts have been audited by leading firms and processed over 1 million transactions. Order a smart contract audit before release — it reduces risks by 90%. To launch your own Crash game, contact us for a consultation.

Estimated timelines

  • MVP (Chainlink VRF, manual on-chain cashout, basic UI): 4–6 weeks.
  • Production (hybrid cashout, batch settlement, bankroll management, regulatory compliance): 10–14 weeks.

Cost is calculated individually based on scope and chosen stack. For an accurate estimate, contact us — we will prepare a commercial proposal. Get a consultation before starting: we'll discuss architecture and KPIs.