Разработка крипто-казино
Крипто-казино сочетает три слоя сложности: gambling логика, blockchain инфраструктура и регуляторный ландшафт. В отличие от традиционных казино, blockchain-версия может предоставлять математически доказуемую честность — это конкурентное преимущество, которое стоит реализовывать правильно, а не симулировать.
Архитектурный выбор: on-chain vs off-chain
Первое решение — насколько логика казино идёт on-chain.
Fully on-chain (как Dice, Coinflip контракты): каждая ставка — транзакция, результат детерминирован on-chain randomness (Chainlink VRF). Максимальная прозрачность, но: gas cost на mainnet ($1-5 за ставку), latency 5-15 секунд.
Off-chain с on-chain settlement (как большинство crypto casinos): gameplay off-chain для скорости и UX, финансовые операции (deposit, withdrawal, большие win) on-chain. Баланс в smart contract или в off-chain ledger с on-chain withdrawal.
Hybrid (рекомендуется): мелкие ставки off-chain с периодическим settlement, крупные — on-chain с VRF. State channels для high-frequency gameplay (Poker, Blackjack).
Verifiable Randomness
Provably fair casino не имеет смысла без настоящей verifiable randomness. Опции:
Chainlink VRF v2.5
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
contract CasinoVRF is VRFConsumerBaseV2Plus {
uint256 public subscriptionId;
bytes32 public keyHash;
uint32 constant CALLBACK_GAS_LIMIT = 100_000;
uint16 constant REQUEST_CONFIRMATIONS = 3;
uint32 constant NUM_WORDS = 1;
struct BetRequest {
address player;
uint256 betAmount;
uint256 gameType;
bytes betData; // параметры ставки (number для roulette, etc)
}
mapping(uint256 => BetRequest) public pendingBets;
function placeBet(
uint256 gameType,
bytes calldata betData
) external payable returns (uint256 requestId) {
require(msg.value >= MIN_BET && msg.value <= MAX_BET, "Invalid bet amount");
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: keyHash,
subId: subscriptionId,
requestConfirmations: REQUEST_CONFIRMATIONS,
callbackGasLimit: CALLBACK_GAS_LIMIT,
numWords: NUM_WORDS,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({ nativePayment: false })
)
})
);
pendingBets[requestId] = BetRequest({
player: msg.sender,
betAmount: msg.value,
gameType: gameType,
betData: betData,
});
}
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
BetRequest memory bet = pendingBets[requestId];
delete pendingBets[requestId];
uint256 result = randomWords[0];
// Диспетчеризация по типу игры
if (bet.gameType == GAME_DICE) {
_resolveDice(bet, result);
} else if (bet.gameType == GAME_COINFLIP) {
_resolveCoinflip(bet, result);
} else if (bet.gameType == GAME_ROULETTE) {
_resolveRoulette(bet, result);
}
}
function _resolveDice(BetRequest memory bet, uint256 random) internal {
(uint256 targetNumber, bool rollOver) = abi.decode(bet.betData, (uint256, bool));
// 1-100 включительно
uint256 roll = (random % 100) + 1;
bool win = rollOver ? roll > targetNumber : roll < targetNumber;
if (win) {
uint256 payout = _calculateDicePayout(bet.betAmount, targetNumber, rollOver);
payable(bet.player).transfer(payout);
}
emit DiceResult(bet.player, roll, targetNumber, rollOver, win, bet.betAmount);
}
}
Commit-Reveal схема (альтернатива VRF)
Для off-chain казино с on-chain верификацией:
1. Казино публикует hash(server_seed) до игры
2. Пользователь предоставляет client_seed при ставке
3. Казино раскрывает server_seed после игры
4. Результат = f(server_seed + client_seed + nonce) — верифицируем публично
Это классический provably fair механизм, используемый в Stake.com, BC.Game. On-chain верификация опциональна — достаточно публично верифицируемого алгоритма.
Финансовая архитектура
House bankroll
Casino должно иметь достаточный bankroll чтобы выдерживать дисперсию — серии крупных выигрышей игроков:
contract CasinoBankroll {
uint256 public minBankrollMultiplier = 100; // bankroll должен быть в 100x макс выигрыша
function getMaxBet() public view returns (uint256) {
return address(this).balance / minBankrollMultiplier;
}
// LP провайдеры вносят в bankroll и получают долю прибыли
mapping(address => uint256) public lpShares;
uint256 public totalShares;
function addLiquidity() external payable {
uint256 sharesToMint;
if (totalShares == 0) {
sharesToMint = msg.value;
} else {
sharesToMint = (msg.value * totalShares) / address(this).balance;
}
lpShares[msg.sender] += sharesToMint;
totalShares += sharesToMint;
}
function removeLiquidity(uint256 shares) external {
require(lpShares[msg.sender] >= shares, "Insufficient shares");
uint256 ethAmount = (shares * address(this).balance) / totalShares;
lpShares[msg.sender] -= shares;
totalShares -= shares;
payable(msg.sender).transfer(ethAmount);
}
}
Лимиты и риск-менеджмент
// Защита от крупных потерь за короткое время
contract RiskManager {
uint256 public maxSinglePayout;
uint256 public maxDailyLoss;
uint256 public dailyLossAccumulator;
uint256 public lastResetTimestamp;
modifier checkRisk(uint256 potentialPayout) {
require(potentialPayout <= maxSinglePayout, "Payout exceeds limit");
if (block.timestamp >= lastResetTimestamp + 1 days) {
dailyLossAccumulator = 0;
lastResetTimestamp = block.timestamp;
}
_;
}
function _updateDailyLoss(uint256 payout) internal {
dailyLossAccumulator += payout;
// Если суточные потери превышают лимит — pause casino
if (dailyLossAccumulator > maxDailyLoss) {
_pauseCasino();
}
}
}
Игровые механики
RTP (Return to Player) и house edge
Каждая игра должна иметь четко выраженный house edge:
- Dice (ролл выше 50): house edge ~2% через adjusting payout multiplier
- Coinflip: 50% win, 1.96x payout → house edge ~2%
- Roulette (европейская): 37 числ, 36x payout → house edge 2.7%
- Blackjack: с базовой стратегией ~0.5% house edge
Формула: house edge = 1 - (win_probability × payout_multiplier)
Пример для Dice (roll over 50): win_prob = 50/100 = 0.5, payout = 1.96x → edge = 1 - (0.5 × 1.96) = 2%.
VIP / Rakeback система
Удержание высокодоходных игроков через cashback:
// Rakeback: возврат % от house edge
async function calculateRakeback(userId: string): Promise<number> {
const vipLevel = await getVIPLevel(userId);
const totalWagered = await getTotalWagered(userId, "30d");
const rakebackPercentages = {
BRONZE: 0.05, // 5% от house edge
SILVER: 0.10, // 10%
GOLD: 0.15, // 15%
PLATINUM: 0.20, // 20%
DIAMOND: 0.25, // 25%
};
const rakebackPct = rakebackPercentages[vipLevel];
const houseEdgeEarned = totalWagered * AVG_HOUSE_EDGE;
return houseEdgeEarned * rakebackPct;
}
Live dealer интеграция
Для live казино (blackjack, poker, baccarat) с реальными дилерами — интеграция с Evolution Gaming или Pragmatic Play Live через их B2B API. Это licensing и integration partner relationship, не техническая разработка с нуля.
Регуляторный контекст
Gambling — одна из наиболее регулируемых отраслей. Варианты:
Offshore лицензии: Curacao eGaming (доступно для крипто, ~$20-30k), Malta Gaming Authority (строже, дороже). Многие crypto casinos работают под Curacao.
Sweepstakes модель (США): не gambling технически, а sweepstakes. Не требует gambling лицензии. Stake.us использует эту модель.
Decentralized / no license: dao-governed, fully on-chain. Юридически серая зона, но реализуемо технически.
Технический стек
| Слой | Технология |
|---|---|
| Smart contracts | Solidity + Foundry, Chainlink VRF |
| Backend | Node.js + TypeScript, WebSocket (Socket.io) |
| Database | PostgreSQL + Redis |
| Frontend | React + WebGL (Pixi.js для анимаций) |
| Мобильный | React Native |
| L2 | Arbitrum / Avalanche (низкий газ) |
| Wallet | MetaMask + WalletConnect + embedded |
| Payments | USDT/USDC + ETH + BTC (через LN или layer2) |
Сроки
- Базовые игры (Dice, Coinflip, Crash) + bankroll: 6-8 недель
- 5-8 игр (Plinko, Mines, Slots, Roulette, Blackjack): 12-16 недель
- Провайдер игр (Pragmatic, BGaming интеграция): +3-4 недели
- VIP, affiliate, рефереральная система: +3-4 недели
- Мобильное приложение: +6-8 недель
- Security audit + penetration testing: обязателен, 4-6 недель
- Итого полноценное казино: 5-7 месяцев







