Розробка provably fair гри HiLo: смарт-контракти та комміт-рівел

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1305 послуг
Розробка provably fair гри HiLo: смарт-контракти та комміт-рівел
Простий
від 1 дня до 3 днів
Часті запитання

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

Етапи блокчейн-розробки

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

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1351
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    951
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1186
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    642
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    922

Provably fair HiLo на блокчейні: комміт-рівел та газ-оптимізація

Гравці в блокчейн-казино часто сумніваються в чесності результату. Коли генератор випадкових чисел прихований, а результат визначається на сервері — довіра падає. Ми відмовляємося від такої моделі. Замість закритого RNG використовуємо комміт-рівел схему: серверний сід фіксується до початку гри, а після — розкривається. Кожен крок верифікується на рівні смарт-контракту. Такий підхід гарантує, що навіть власник казино не може підмінити результат після старту гри. Гравець може відтворити всі карти, використовуючи відкриті сіди.

У нашій реалізації HiLo house edge фіксований і прописаний в контракті — 1%. Жодних прихованих комісій. Мультиплікатор розраховується динамічно на основі ймовірності вгадування, що виключає можливість маніпуляції.

Чому ми не використовуємо Chainlink VRF?

Chainlink VRF — децентралізований рандомайзер, але він повільний: на кожен запит йде 1–2 блоки (~2 секунди на Ethereum). Для гри, де карта має розкриватися миттєво, це неприйнятно. Комміт-рівел схема з детермінованою комбінацією хешів сідів дає результат одразу, без очікування оракула.

Параметр Chainlink VRF Комміт-рівел (наша реалізація)
Затримка результату ~2 сек 0 (миттєво)
Вартість за виклик 10–50 млн gas (~$50) 30–50 тис gas (~$0.10)
Верифікація Через VRF Coordinator Через хеші сідів
Зовнішні залежності Оракул, LINK токен Немає

Комміт-рівел схема в 500 разів дешевше та в 100 разів швидше — ідеальний вибір для HiLo.

Як гравець може перевірити чесність?

Після закінчення гри казино публікує повний серверний сід. Гравець бере цей сід, обчислює keccak256(serverSeed) і порівнює з хешем, який був опублікований до гри. Якщо хеші збігаються — казино не підміняло сід. Потім за формулою _deriveCard з контракту гравець генерує послідовність карт і звіряє з історією.

Згідно зі специфікацією EIP-1967, використання детермінованих функцій на основі хешів гарантує незмінність результату після фіксації сіду.

// Клієнтська верифікація (JavaScript)
import { keccak256, encodePacked } from "viem";

function verifyGame(
  serverSeed: string,
  serverSeedHash: string,
  clientSeed: string,
  cards: number[]
): boolean {
  const computedHash = keccak256(new TextEncoder().encode(serverSeed));
  if (computedHash !== serverSeedHash) return false;

  for (let i = 0; i < cards.length; i++) {
    const combined = keccak256(
      encodePacked(["bytes32", "bytes32", "uint8"], [serverSeedHash, clientSeed as `0x${string}`, i])
    );
    const card = Number(BigInt(combined) % 52n);
    if (card !== cards[i]) return false;
  }

  return true;
}

Як ми це робимо: стек та реалізація

Ми використовуємо Solidity 0.8.20, Foundry для тестування та деплою, і Tenderly для моніторингу. Контракт містить оптимізовану комміт-рівел схему, де кожна карта обчислюється на льоту без зберігання всієї колоди.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract HiLoGame {
    uint8 constant DECK_SIZE = 52;

    struct Game {
        address player;
        bytes32 serverSeedHash;
        bytes32 clientSeed;
        string serverSeed;
        uint256 betAmount;
        uint8 currentCard;
        uint8 position;
        uint256 multiplier;
        bool active;
        bool cashed;
    }

    mapping(bytes32 => Game) public games;
    uint256 public constant HOUSE_EDGE = 100; // 1%

    event GameStarted(bytes32 indexed gameId, address player, uint8 firstCard);
    event CardRevealed(bytes32 indexed gameId, uint8 card, uint256 multiplier);
    event GameCashed(bytes32 indexed gameId, uint256 payout);
    event GameLost(bytes32 indexed gameId, uint8 card);

    function startGame(
        bytes32 serverSeedHash,
        bytes32 clientSeed
    ) external payable returns (bytes32 gameId) {
        require(msg.value > 0, "Bet required");

        gameId = keccak256(abi.encodePacked(
            msg.sender, serverSeedHash, clientSeed, block.timestamp
        ));

        uint8 firstCard = _deriveCard(serverSeedHash, clientSeed, 0);

        games[gameId] = Game({
            player: msg.sender,
            serverSeedHash: serverSeedHash,
            clientSeed: clientSeed,
            serverSeed: "",
            betAmount: msg.value,
            currentCard: firstCard,
            position: 0,
            multiplier: 100, // 1.0x
            active: true,
            cashed: false
        });

        emit GameStarted(gameId, msg.sender, firstCard);
    }

    function revealNextCard(
        bytes32 gameId,
        string calldata serverSeedPartial,
        bool guessHigher
    ) external {
        Game storage game = games[gameId];
        require(game.active, "Game not active");
        require(msg.sender == owner() || msg.sender == gameServer, "Unauthorized");

        uint8 nextCard = _deriveCard(
            game.serverSeedHash,
            game.clientSeed,
            game.position + 1
        );

        bool correct;
        if (guessHigher) {
            correct = _cardValue(nextCard) > _cardValue(game.currentCard);
        } else {
            correct = _cardValue(nextCard) < _cardValue(game.currentCard);
        }

        if (_cardValue(nextCard) == _cardValue(game.currentCard)) {
            correct = false;
        }

        game.position++;
        game.currentCard = nextCard;

        if (!correct) {
            game.active = false;
            emit GameLost(gameId, nextCard);
            return;
        }

        uint256 probability = _calculateProbability(game.currentCard, guessHigher);
        game.multiplier = (game.multiplier * 9900) / probability;

        emit CardRevealed(gameId, nextCard, game.multiplier);
    }

    function cashout(bytes32 gameId) external {
        Game storage game = games[gameId];
        require(game.active, "Game not active");
        require(msg.sender == game.player, "Not your game");

        game.active = false;
        game.cashed = true;

        uint256 payout = (game.betAmount * game.multiplier) / 100;
        payable(game.player).transfer(payout);

        emit GameCashed(gameId, payout);
    }

    function revealServerSeed(bytes32 gameId, string calldata serverSeed) external {
        Game storage game = games[gameId];
        require(!game.active, "Game still active");
        require(
            keccak256(bytes(serverSeed)) == game.serverSeedHash,
            "Invalid server seed"
        );
        game.serverSeed = serverSeed;
    }

    function _deriveCard(
        bytes32 serverSeedHash,
        bytes32 clientSeed,
        uint8 position
    ) internal pure returns (uint8) {
        bytes32 combined = keccak256(abi.encodePacked(serverSeedHash, clientSeed, position));
        return uint8(uint256(combined) % DECK_SIZE);
    }

    function _cardValue(uint8 card) internal pure returns (uint8) {
        return (card % 13) + 1;
    }

    function _calculateProbability(uint8 currentCard, bool higher) internal pure returns (uint256) {
        uint8 value = _cardValue(currentCard);
        uint256 cardsHigher = 13 - value;
        uint256 cardsLower = value - 1;
        if (higher) return (cardsHigher * 100) / 13;
        return (cardsLower * 100) / 13;
    }

    receive() external payable {}
    address public gameServer;
    address public owner;
    constructor() { owner = msg.sender; gameServer = msg.sender; }
    modifier onlyOwner() { require(msg.sender == owner); _; }
}

Які проблеми вирішує комміт-рівел?

Без комміт-рівел гравець не може бути впевнений, що сервер не підмінив результат після ставки. Комміт-рівел знімає цю проблему: хеш сіду фіксується до гри, а сам сід розкривається тільки після. Гравець отримує доказову гарантію, що результат не був змінений. Це необхідно для ліцензійних вимог та довіри користувачів.

Додаткові деталі: чому комміт-рівел вигідніший за VRF?Використання Chainlink VRF збільшує вартість кожної гри в 100–1000 разів і додає затримку. Комміт-рівел не потребує зовнішніх викликів, що критично для ігор з високою частотою раундів.

Процес роботи

  1. Аналітика: обговорюємо механіку, вимоги до RNG, мультиплікатор, house edge, ліміти ставок.
  2. Проектування: архітектура смарт-контракту, вибір схеми комміт-рівел, визначення інтерфейсів.
  3. Розробка: пишемо контракт на Solidity 0.8.20, пишемо тести в Foundry (unit + fuzzing).
  4. Тестування: формальна верифікація за допомогою Slither, Echidna (fuzzing), тестнет-деплой.
  5. Аудит: залучаємо стороннього аудитора (опціонально).
  6. Деплой: деплоїмо на обрану мережу (Ethereum, Polygon, BNB Chain).
  7. Підтримка: моніторинг, оновлення параметрів, допомога гравцям.

Що входить в роботу

  • Вихідний код смарт-контракту з коментарями
  • Документація по верифікації для гравців
  • Інтеграція з фронтендом (React, wagmi, RainbowKit)
  • Тестовий деплой на testnet
  • Деплой на mainnet + налаштування Tenderly моніторингу
  • Навчання команди валідації результатів

Строки та вартість

Базова реалізація (контракт + фронтенд) займає 2–3 тижні. Якщо потрібна формальна верифікація та повний аудит, термін збільшується до 6–8 тижнів. Вартість розраховується індивідуально в залежності від складності та обсягу робіт.

Зверніться до нас, щоб обговорити ваш проєкт. Ми маємо 5+ років досвіду в блокчейн-розробці, реалізували понад 20 ігор та DeFi-продуктів. Гарантуємо provably fair реалізацію та прозорість усіх алгоритмів.

Замовте розробку гри HiLo під ключ — пишіть, оцінимо проєкт за 24 години. Отримайте консультацію з архітектури та газ-оптимізації.

GameFi розробка: ігрова економіка, контракти та on-chain механіка

Ми бачили цей сценарій не раз. Axie Infinity на піку мала великий дохід, але через 18 місяців токен різко знецінився, а аудиторія значно скоротилася. Причина — відсутність sink'ів: гравці заробляли SLP і виводили, а механізмів спалювання не вистачало. Ми пропонуємо GameFi розробку під ключ: від токеноміки до смарт-контрактів, щоб ваша економіка не повторила цю помилку. Оцінимо ваш проєкт на meetup або онлайн. Наш досвід — 5+ років, десятки реалізованих проєктів, включно з аудитом 15+ P2E ігор.

Чому ламається Play-to-Earn економіка?

Інфляційна токеноміка без sink'ів — головна причина смертельної спіралі. Гравець отримує токени за геймплей. Якщо sink'ів (механізмів спалювання або споживання) недостатньо — supply зростає швидше за demand. Ціна падає. Дохід гравця у fiat зменшується. Гравці йдуть.

Правильна конструкція — dual-token модель з чітким розподілом: governance/value token з обмеженим supply і utility/reward token для внутрішньоігрової економіки. Utility token має активно споживатися: крафтинг предметів, апгрейди, entry fees, breeding. Приклади: GODS/FLUX у Gods Unchained, AXS/SLP у Axie (хоча sink'ів там виявилося недостатньо). Ефективна економіка балансує mint та burn: типовий ratio — 1.2—1.5 burn на 1 mint для запобігання інфляції.

Які sink-механізми реально працюють?

Механізм Опис Приклад
Breeding / крафтинг Спалювання utility token за створення нового NFT Axie (але з правильним balancing)
Апгрейди персонажів Кожна еволюція вимагає спалювання токена Більшість P2E RPG
PvP entry fee Вхід у турнір спалює токени, частина йде в призовий пул Splinterlands
Дурабилити предметів Після N боїв предмет ламається, токен витрачається на ремонт Успадковано з MMORPG
Фінансові механіки Стейкінг з lock-up, що виводить токени з обігу на строк DeFi-шари

Наш досвід — десятки реалізованих проєктів у Web3, включно з аудитом 15+ P2E ігор. Ми знаємо, які sink'и працюють у довгостроковій перспективі. Наприклад, у проєкті з breeding RPG ми збільшили спалювання utility token на 300% за рахунок введення «ремеслу зношуваності» та обов'язкових апгрейдів.

On-chain vs Off-chain: де проходить межа

Всю ігрову логіку on-chain виносити не потрібно — кожна транзакція коштує газу і триває 12 секунд. Ігровий цикл — мілісекунди. Баланс:

Компонент On-chain Off-chain Приклади
Ownership активів + NFT предмети, land
Передача/торгівля + Маркетплейси
Фінанси (стейкінг, rewards) + Staking vaults, DAO
Random generation + (через VRF) Chainlink VRF
Ігровий процес + Бойова система, рух
State ігрового світу + Координати, health points
Матчмейкінг + Серверна логіка

Результати геймплею переносяться на блокчейн через signed message від сервера або ZK-proof. Verifiable off-chain з ZK: ігровий сервер генерує ZK-proof коректності сесії, контракт верифікує proof і нараховує винагороду. Реалізації: Cartridge (Starknet), zkSync game rollups.

Реалізація NFT ігрових предметів

Стандарт: ERC-1155 для взаємозамінних предметів (ресурси, consumables) + ERC-721 для унікальних (персонажі, land). ERC-1155 дає до 60% економії на газі при batch transfer у порівнянні з окремими ERC-721 переказами — для гри з сотнями предметів це економія сотень доларів на день.

Як реалізувати динамічні NFT без перевантаження блокчейна?

Характеристики предмета змінюються в процесі гри (experience, durability, upgrades). Два підходи:

  • Fully on-chain: атрибути зберігаються в mapping контракту, tokenURI генерується з атрибутів через SVG/JSON encoding. Дорого за газом при частому оновленні. Використовується для land і ключових активів.
  • Hybrid: атрибути зберігаються off-chain, в tokenURI — hash стану. Оновлення підписується сервером, верифікується on-chain при transfer або продажі. Дешевше, але вимагає довіри до сервера або ZK.

Breeding і crafting. Контракт: два батьківських NFT → оплата utility token (burn) → мінт нового NFT з атрибутами, що залежать від батьків + Chainlink VRF для випадковості. Без VRF майнери можуть маніпулювати рандомом через вибір блоку.

// Simplified breeding with Chainlink VRF
function breed(uint256 parent1Id, uint256 parent2Id) external {
    require(ownerOf(parent1Id) == msg.sender);
    require(ownerOf(parent2Id) == msg.sender);
    require(breedingToken.burnFrom(msg.sender, BREEDING_COST));

    uint256 requestId = vrfCoordinator.requestRandomWords(...);
    pendingBreeds[requestId] = BreedRequest(parent1Id, parent2Id, msg.sender);
}

function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
    BreedRequest memory req = pendingBreeds[requestId];
    uint256 childAttributes = deriveAttributes(req.parent1Id, req.parent2Id, randomWords[0]);
    _mintWithAttributes(req.requester, childAttributes);
}

Маркетплейс і роялті

Вбудований маркетплейс дає контроль над fee структурою та кастомною логікою (заборона торгівлі предметами до певного рівня). Роялті за EIP-2981 — стандарт, але не enforceable: Blur та інші маркетплейси ігнорують on-chain роялті. Для enforcement — whitelist-only transfer (тільки через контракти, що платять роялті). Жертвуємо composability заради захисту прав.

Staking та розподіл винагород

Staking NFT — механіка для утримання гравців. Проблема: нарахування rewards при тисячах стейкерів вимагає постійних транзакцій (дорого). Рішення — reward-per-share паттерн (як у MasterChef від SushiSwap): глобальний accRewardPerShare, при claim або change state перераховується заборгованість за формулою pendingReward = stakedAmount * (accRewardPerShare - userRewardDebt). O(1) складність незалежно від кількості стейкерів. Економія газу — до 70% порівняно з поелементним нарахуванням.

Детальніше про reward-per-shape реалізацію

Алгоритм працює так: при кожному депозиті/знятті стейку або при оновленні глобального пулу (наприклад, додаванні нових токенів винагороди) контракт оновлює accRewardPerShare = totalPendingReward / totalStaked. Потім для конкретного користувача розраховується pending = user.staked * (accRewardPerShare - user.rewardDebt). Після виплати user.rewardDebt встановлюється рівним accRewardPerShare. Це дозволяє не зберігати історію внесків кожного користувача. На практиці ми використовуємо для GameFi проєктів версію з multiplier для врахування різних ваг стейку (наприклад, рідкісні NFT дають більше винагороди).

Процес та терміни

Починаємо з game economics документа: token flows, mint/burn механіки, projected supply schedule, sink analysis. До написання коду економіка моделюється (Cadence, Python simulation).

Як ми будуємо GameFi: 5 етапів

  1. Економічне моделювання — 1-2 тижні. Розробляємо dual-token модель, розраховуємо sink'и, прописуємо стимули для long-term holding.
  2. Розробка токен-контрактів — 2-3 тижні. ERC-20 для governance, ERC-20 для utility, з настроюваною політикою mint/burn.
  3. Смарт-контракти NFT — 3-5 тижнів. ERC-721 / ERC-1155 з dynamic metadata, breeding/crafting, Chainlink VRF.
  4. Staking + rewards — 2-3 тижні. Контракт на базі reward-per-share, інтерфейси для frontend.
  5. Маркетплейс (опціонально) — 2-4 тижні. Кастомний маркетплейс з enforced royalty.

Що входить у роботу

  • Вихідний код усіх смарт-контрактів з тестами (Foundry/Hardhat)
  • Документація архітектури та економіки
  • Інтеграція з Chainlink, Tenderly для моніторингу
  • Аудит коду та формальна верифікація (Slither, Mythril, Echidna)
  • Навчання команди роботі з контрактами
  • Підтримка після деплою (3 місяці)

Базовий GameFi стек (токени + NFT + staking + маркетплейс) — від 8 до 16 тижнів. Повна гра з on-chain рандомом, breeding, dynamic NFT — 4-8 місяців. ZK-based verifiable gameplay — окремий проєкт від 6 місяців.

Зв'яжіться з нами для аудиту вашої токеноміки — оцінимо ризики та доопрацюємо sink-механізми. Замовте розробку GameFi проєкту — отримайте готовий продукт з перевіреною економікою. Наш досвід — десятки реалізованих проєктів у Web3, включно з аудитом 15+ P2E ігор. Гарантуємо стабільність контрактів і прозорість коду. Сертифіковані аудитори перевіряють кожен контракт на типові вразливості (reentrancy, flash loan, oracle manipulation).