Разработка 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 часа. Получите консультацию по архитектуре и газ-оптимизации.

Игровая экономика, контракты и on-chain механика

Мы видели этот сценарий не раз. Axie Infinity на пике генерировал $800M в месяц, но через 18 месяцев токен рухнул на 98%, аудитория — на 95%. Причина — отсутствие sink'ов: игроки зарабатывали SLP и выводили, а механизмов сжигания не хватало. Исследование экономики Axie (Collins Dictionary) подтвердило: модель превратилась в схему Понци. Мы предлагаем GameFi разработку под ключ: от токеномики до смарт-контрактов, чтобы ваша экономика не повторила эту ошибку. Оценим ваш проект на meetup или онлайн.

Где ломается 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'ов там оказалось недостаточно).

Какие sink-механизмы реально работают?

  • Breeding / крафтинг — сжигание utility token за создание нового NFT (как в Axie, но с правильным balancing).
  • Апгрейды персонажей — каждая эволюция требует сжигания токена.
  • PvP entry fee — вход в турнир сжигает токены, часть идёт в призовой пул.
  • Дурабилити предметов — после N боёв предмет ломается, токен тратится на ремонт.
  • Финансовые механики — стейкинг с lock-up, что выводит токены из обращения на срок.

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.

Как реализовать динамические 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 и rewards distribution

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

Процесс и сроки

Начинаем с 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 игр.