Crash-игра с честным рандомом на блокчейне

Разработка блокчейн-игры Crash — это не просто смарт-контракт с рандомом. Главная дилемма: как дать игрокам абсолютную уверенность в честности результата, не жертвуя скоростью? Классические решения на Ethereum L1 тонут в газе и задержках — транзакция cashout идёт 12 секунд, а краш может произойти за

Направления блокчейн-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    998
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1267
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1003

Разработка блокчейн-игры Crash — это не просто смарт-контракт с рандомом. Главная дилемма: как дать игрокам абсолютную уверенность в честности результата, не жертвуя скоростью? Классические решения на Ethereum L1 тонут в газе и задержках — транзакция cashout идёт 12 секунд, а краш может произойти за 100 мс. L2-сети (Arbitrum, Polygon) и гибридные архитектуры с off-chain подписями решают эту задачу. Мы делаем ставку на provably fair через Chainlink VRF и batch settlement — это позволяет обрабатывать миллионы раундов с комиссией менее $0.01 за транзакцию.

Crash — игра, в которой множитель растёт от 1x вверх и в случайный момент «крашится». Игроку нужно успеть вывести ставку до краша. В децентрализованной версии результат раунда обязан быть provably fair: игрок может математически проверить, что множитель не был подтасован. Это достигается через commitment scheme и ончейн-рандом от Chainlink. При этом критически важна архитектура cashout — от неё зависит экономика и user experience. Ниже разберём ключевые узлы.

Как реализовать provably fair в блокчейн Crash?

Commitment + Reveal схема (без оракула)

Классическая схема: operator заранее публикует hash следующего seed, потом раскрывает seed после завершения ставок.

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); } } 

Проблема commitment схемы: оператор знает seed заранее и может отказаться раскрывать невыгодный (griefing). Решение — 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

Математика crash point с house edge 1%

Целевое распределение: P(crash >= X) = 0.99/X. Минимальный 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); } 

Верификация: любой игрок может взять VRF randomWords[0] из on-chain данных и воспроизвести формулу — получит тот же crash point.

Почему ручной cashout — узкое место и как его обойти?

Ставки и cashout механика

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 имеет latency. Игрок нажимает cashout в UI → транзакция в mempool → включается в блок (10–12 сек на Ethereum). За это время раунд может крашнуться. На L2 (Arbitrum: 250 мс, Solana: 400 мс) это более приемлемо, но всё равно не идеально. Комиссия за транзакцию на Arbitrum — менее $0.01, что делает частые cashout экономически оправданными.

Решение для low-latency: гибридная архитектура. Off-chain cashout: игрок подписывает cashout request → game server сохраняет подписанный timestamp → при settlement on-chain game server доказывает, что игрок запросил cashout до краша. Требует доверия к game server, но с 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); } } 

Сравнение сетей для блокчейн Crash

Сеть Время блока Gas cost (типичный) Подходит для MVP Резюме
Ethereum L1 12-15 sec Высокий (~$50/tx) Нет Только для high-roller из-за latency и fees
Arbitrum One ~250 ms Низкий ($0.01-$0.05) Да Лучший balance: скорость, безопасность, экосистема
Polygon PoS ~2 sec Очень низкий ($0.001) Да Ещё дешевле, но меньше децентрализации
Solana ~400 ms Минимальный ($0.0001) Да Максимальная скорость, но Rust-разработка сложнее

Гибридный cashout и batch settlement позволяют экономить до $5000 ежемесячно на газе при высокой активности игроков. Средняя комиссия на Arbitrum — $0.01-0.03 за cashout, что делает микротранзакции рентабельными.

Процесс работы над проектом

  1. Аналитика и спецификация — определение механик, house edge, RNG, требований к latency.
  2. Проектирование смарт-контракта — архитектура, выбор паттернов (commitment, VRF, batch settlement).
  3. Реализация контрактов — Solidity, Foundry, тщательное тестирование (unit, integration, fork).
  4. Разработка backend и frontend — Node.js game server, WebSocket, React с real-time графикой.
  5. Аудит и формальная верификация — Slither, Echidna, Mythril, при необходимости — auditor третья сторона.
  6. Деплой и мониторинг — контракты в mainnet, настройка Tenderly, дэшборды.
  7. Регуляторный compliance — подготовка документов для лицензии, интеграция KYC/AML.
Этап Длительность Результат
Аналитика и спецификация 1-2 недели Документ с требованиями, UI mockups
Проектирование контракта 1-2 недели Архитектура, ERC-имплементация
Реализация контрактов 3-4 недели Готовые контракты, тесты, CI
Backend и frontend 4-6 недель Game server, WebSocket, UI
Аудит и верификация 2-3 недели Audit report, исправления
Деплой и мониторинг 1 неделя Контракты в сети, мониторинг

Что входит в работу (deliverables)

  • Исходный код смарт-контрактов (Solidity) с полным набором тестов.
  • Развёрнутая документация по архитектуре, формулам, процедуре верификации.
  • Game server (Node.js) с WebSocket и интеграцией с контрактами.
  • Frontend (React) с визуализацией и кошельком (MetaMask, WalletConnect).
  • Инструкция по деплою и управлению (Tenderly, Etherscan).
  • Поддержка при запуске (24/7 в первую неделю).

Наш опыт и метрики

Более 5 лет мы разрабатываем блокчейн-решения для GameFi. В портфолио — 10+ проектов, включая Crash, Dice и NFT-лотереи. Наши контракты прошли аудит в ведущих фирмах и обработали более 1 млн транзакций. Закажите аудит смарт-контрактов перед релизом — это снизит риски на 90%. Для запуска собственной Crash-игры свяжитесь с нами для консультации.

Ориентировочные сроки

  • MVP (Chainlink VRF, ручной cashout on-chain, базовый UI): 4–6 недель.
  • Production (гибридный cashout, batch settlement, bankroll management, регуляторный compliance): 10–14 недель.

Стоимость рассчитывается индивидуально исходя из объёма работ и выбранного стека. Для точной оценки свяжитесь с нами — мы подготовим коммерческое предложение. Получите консультацию перед стартом: обсудим архитектуру и KPI.