Розробка гри Crash на блокчейні
Crash — азартна гра, в якій множник растьте від 1x вверх і в випадковий момент «крашится». Гравець повинен встигнути вивести ставку до краху. Чим довше чекаєш — тим вище потенціальний виграш, тим вище ризик втратити все.
Ключова особливість blockchain Crash на відміну від традиційного online casino: результат раунду повинен бути provably fair. Гравець не довіряє серверу — він може математично перевірити, що множник краху не був визначений після його ставки. Це досягається через commitment scheme + Chainlink VRF або RANDAO.
Архітектура провабли-фэйр Crash
Commitment + Reveal схема
Оператор публікує hash наступного seed заблаговременно, розкриває seed після фази ставок:
contract CrashGame {
struct Round {
bytes32 seedHash; // hash(seed)—публікується до ставок
bytes32 seed; // розкривається після ставок
uint64 crashPoint; // результат (у basis points: 150 = 1.5x)
uint256 totalBets;
uint256 startTime;
RoundStatus status;
}
function commitNextRound(bytes32 seedHash) external onlyOperator {
rounds[nextRoundId + 1].seedHash = seedHash;
}
function revealAndStart(uint256 roundId, bytes32 seed) external onlyOperator {
Round storage round = rounds[roundId];
require(keccak256(abi.encodePacked(seed)) == round.seedHash, "Seed mismatch");
round.seed = seed;
round.crashPoint = _calculateCrashPoint(seed, roundId);
round.status = RoundStatus.IN_PROGRESS;
}
}
Chainlink VRF V2 Plus
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
uint256 roundId = vrfRequestToRound[requestId];
Round storage round = rounds[roundId];
round.crashPoint = _calculateCrashPoint(randomWords[0]);
emit RoundActive(roundId, round.startTime = uint64(block.timestamp));
}
Формула crash point
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 механіка
struct Bet {
address player;
uint256 amount;
uint64 autoCashoutAt; // 0 = manual
bool cashedOut;
uint64 cashoutMultiplier;
}
function placeBet(uint256 roundId, uint64 autoCashoutAt) external payable {
bets[roundId][msg.sender] = Bet({
player: msg.sender,
amount: msg.value,
autoCashoutAt: autoCashoutAt,
cashedOut: false,
cashoutMultiplier: 0
});
}
function cashout(uint256 roundId) external {
Round storage round = rounds[roundId];
Bet storage bet = bets[roundId][msg.sender];
uint64 currentMultiplier = _getCurrentMultiplier(round.startTime);
require(currentMultiplier <= round.crashPoint, "Already crashed");
bet.cashedOut = true;
uint256 payout = bet.amount * currentMultiplier / 100;
payable(msg.sender).transfer(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. Гравець нажимає → транзакція в mempool → включається в блок (10–12 сек Ethereum). Раунд може крашнутися.
Рішення low-latency: hybrid. Off-chain cashout: гравець підписує запит → game server зберігає підписаний timestamp → on-chain settlement game server доказує що гравець запросив до краху.
Risk Management
function maxAllowedBet() public view returns (uint256) {
return address(this).balance * maxBetPercent / 10_000;
}
Сроки
MVP (Chainlink VRF, manual cashout, базовий UI): 4–6 тижнів. Production (hybrid cashout, batch settlement, bankroll management, regulatory compliance): 10–14 тижнів.







