Blackjack на блокчейні: VRF та чесність

Уявіть: ви хочете запустити онлайн-казино з Blackjack на блокчейні. Проблема — як забезпечити випадковість карт, не довіряючи централізованому серверу? В off-chain казино сервер здає карти, але гравець не бачить колоду. On-chain все прозоро — будь-хто може прочитати storage контракту. Якщо ми заздал

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

Часті запитання

Останні роботи

  • 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

Уявіть: ви хочете запустити онлайн-казино з Blackjack на блокчейні. Проблема — як забезпечити випадковість карт, не довіряючи централізованому серверу? В off-chain казино сервер здає карти, але гравець не бачить колоду. On-chain все прозоро — будь-хто може прочитати storage контракту. Якщо ми заздалегідь згенеруємо deck і збережемо, гравець побачить усі майбутні карти. Рішення — commit-reveal з VRF або Mental Poker. Ми використовуємо Chainlink VRF, але з оптимізацією: генеруємо весь deck одним запитом, а потім карти відкриваються поетапно без додаткових VRF. Наша команда з понад 7 років досвіду в Web3 реалізувала 20+ блокчейн-ігор та DeFi-проектів. Зв'яжіться з нами, щоб отримати консультацію з архітектури та аудиту.

Як Chainlink VRF забезпечує випадковість?

Chainlink VRF генерує верифіковане випадкове число off-chain із криптографічним доказом, яке перевіряється on-chain. Ніхто — ні гравець, ні оператор — не може передбачити результат. Це в 10 разів надійніше, ніж зберігання seed на контракті.

Флоу для Blackjack:

  1. Гравець робить ставку, контракт запитує VRF
  2. VRF fulfillment (через callback) — контракт отримує random, генерує deck або перші карти
  3. Гравець вирішує: hit або stand
  4. Якщо hit — новий VRF запит для наступної карти

Проблема з "якщо hit": кожен VRF запит — затримка (1-3 блоки) та додатковий LINK. Для реалтайм-гри некомфортно.

Оптимізація: запитати весь deck одразу — блокчейн казино blackjack

contract Blackjack is VRFConsumerBaseV2Plus { struct Game { address player; uint256 bet; uint8[] deck; // всі 52 карти в зашифрованому порядку uint8 playerIdx; // поточний індекс в декі uint8 dealerIdx; bool active; } mapping(uint256 => Game) public games; // requestId -> game mapping(address => uint256) public playerGame; // player -> gameId function startGame() external payable { require(msg.value >= MIN_BET, "Below minimum bet"); uint256 requestId = s_vrfCoordinator.requestRandomWords( VRFV2PlusClient.RandomWordsRequest({ keyHash: KEY_HASH, subId: subscriptionId, requestConfirmations: 3, callbackGasLimit: 300000, numWords: 1, // одне велике число для shuffle extraArgs: VRFV2PlusClient._argsToBytes( VRFV2PlusClient.ExtraArgsV1({nativePayment: false}) ) }) ); games[requestId] = Game({ player: msg.sender, bet: msg.value, deck: new uint8[](0), playerIdx: 0, dealerIdx: 4, // дилер бере карти з позиції 4 active: false // стане true після fulfillment }); playerGame[msg.sender] = requestId; } function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override { Game storage game = games[requestId]; // Fisher-Yates shuffle детермінований з одного seed uint8[52] memory deck; for (uint8 i = 0; i < 52; i++) deck[i] = i; uint256 seed = randomWords[0]; for (uint8 i = 51; i > 0; i--) { seed = uint256(keccak256(abi.encodePacked(seed))); uint8 j = uint8(seed % (i + 1)); (deck[i], deck[j]) = (deck[j], deck[i]); } // Перші 4 карти одразу здаються: player, dealer, player, dealer game.deck = new uint8[](52); for (uint8 i = 0; i < 52; i++) game.deck[i] = deck[i]; game.active = true; emit GameStarted(requestId, game.player, deck[0], deck[2]); // видимі карти гравця // deck[1] і deck[3] - карти дилера, deck[1] прихована до кінця } } 

Після fulfillment deck зашафлений і зафіксований. Наступні ходи (hit) беруть карти з вже згенерованого deck — без нових VRF запитів. Швидко і дешево.

Чому deck не можна зберігати відкрито?

Але весь deck зберігається в game.deck — публічно! Технічно гравець може прочитати всі майбутні карти з storage.

Рішення: зберігати тільки seed, карти обчислювати детерміновано тільки коли вони «відкриваються»:

// Не храним deck, только seed mapping(uint256 => uint256) private gameSeeds; function getCard(uint256 gameId, uint8 position) private view returns (uint8) { // Детерминированно вычисляем карту из seed и позиции // Карта не в storage — нельзя прочитать заранее return uint8(uint256(keccak256(abi.encodePacked(gameSeeds[gameId], position))) % 52); } 

Це не повністю вирішує проблему: технічно можна симулювати getCard для всіх позицій в тому ж блоці. Повне рішення — Mental Poker протокол з шифруванням кожної карти, але це значно складніше.

Як реалізувати логіку Blackjack в смарт-контракті?

Значення карт: туз = 1 або 11, картинки = 10, інші за номіналом:

function cardValue(uint8 card) internal pure returns (uint8) { uint8 rank = card % 13; // 0-12: туз, 2-10, валет, дама, король if (rank == 0) return 11; // туз (м'яке значення) if (rank >= 10) return 10; // картинки return rank + 1; } function handScore(uint8[] memory cards) internal pure returns (uint8) { uint8 score = 0; uint8 aces = 0; for (uint i = 0; i < cards.length; i++) { uint8 val = cardValue(cards[i]); if (val == 11) aces++; score += val; } // М'який туз стає жорстким (1) якщо bust while (score > 21 && aces > 0) { score -= 10; aces--; } return score; } 

Логіка дилера on-chain: дилер бере карти поки score < 17, зупиняється на 17+ (включаючи soft 17 залежно від правил).

Як управляти банкролом за допомогою Kelly Criterion?

Контракт повинен мати ETH для виплат. House edge в Blackjack ~0.5% при оптимальній стратегії — це реальна маржа. Але дисперсія висока, потрібен достатній bankroll.

Kelly Criterion для максимальної ставки: при edge e та bankroll B, максимальна ставка ≈ B * e / variance. Для Blackjack з edge 0.5% та дисперсією ~1.3 — максимальна ставка ≈ 0.38% від bankroll. На практиці: обмежити максимальну ставку на рівні 1-2% bankroll.

uint256 public constant MAX_BET_PERCENT = 200; // 2% = 200/10000 function maxBet() public view returns (uint256) { return address(this).balance * MAX_BET_PERCENT / 10000; } modifier validBet() { require(msg.value >= MIN_BET && msg.value <= maxBet(), "Invalid bet"); _; } 

Чому UX критичний для блокчейн-блэкджека?

Блокчейн Blackjack потребує ретельного UX для асинхронності. VRF fulfillment — не миттєвий. Гравець натиснув "Deal" — чекає 1-3 блоки до появи карт.

Флоу в UI:

  1. Ставка → startGame() → статус "Dealing..." (чекаємо подію GameStarted)
  2. Карти з'являються → гравець бачить свої 2 карти, одну карту дилера
  3. Hit/Stand → миттєві, із зашафленого deck
  4. Stand → дилер відкриває карти → підсумок → виплата

Для polling подій: wagmi з useWatchContractEvent або WebSocket підключення до ноди.

Стек

Компонент Технологія
Smart contract Solidity 0.8.x + VRF v2.5
Тестування Foundry + VRF mock
Frontend React + wagmi + viem
Мережа Polygon / Arbitrum (низький gas)
Аудит Обов'язковий (gambling + custody коштів)

Аудит контракту: критична безпека

Контракт зберігає ETH та виплачує виграші — помилки в логіці виплат або генерації випадковості ведуть до прямих втрат. Ми використовуємо Slither та Mythril для статичного аналізу, а також рекомендуємо зовнішній аудит у партнерів. Ваша безпека — наша гарантія. Детальніше про аудит смарт-контрактів можна дізнатися в документації Chainlink.

Що входить в розробку блокчейн-блэкджека?

  • Архітектурна документація та вибір протоколу (VRF vs Mental Poker)
  • Смарт-контракт Blackjack з логікою гри та управлінням банкролом
  • Тести на Foundry (unit, fuzz, інтеграційні)
  • Інтеграція Chainlink VRF (v2.5) з підпискою
  • Frontend на React + wagmi + viem з підтримкою гаманців (MetaMask, WalletConnect)
  • Деплой в тестову та основну мережу (Polygon/Arbitrum за вашим вибором)
  • Код-рев'ю та фікси зауважень
  • Навчання вашої команди роботі з контрактом
  • Технічна підтримка на етапі запуску

Порівняння: VRF vs Mental Poker

Критерій Chainlink VRF Mental Poker
Складність реалізації Низька Висока (криптографія)
Швидкість 1-3 блоки 1 раунд (миттєво)
Вартість газу ~300k gas + LINK ~500k gas (шифрування)
Довіра Потрібна довіра до оракула Повністю децентралізовано
Рекомендація Для більшості проектів Для проектів з максимальною децентралізацією
Mental Poker: як це працює? Mental Poker — криптографічний протокол, що дозволяє гравцям роздавати карти без довіреної третьої сторони. Кожна карта шифрується спільним ключем, потім перетасовується і розшифровується. Це забезпечує максимальну децентралізацію, але потребує більше газу та складніший у реалізації.

Терміни орієнтовно

Робочий on-chain Blackjack (смарт-контракт, тести, базовий frontend): від 4 до 5 тижнів. З повним UI, анімаціями, статистикою та мобільною адаптацією: від 8 до 10 тижнів. Вартість розраховується індивідуально після аналізу вимог. Замовте розробку — ми підготуємо детальний план. Зв'яжіться з нами для обговорення вашого проекту.