Building a Transparent HiLo Game: Commit-Reveal and Gas Optimization

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1All 1305 services
Building a Transparent HiLo Game: Commit-Reveal and Gas Optimization
Simple
from 1 day to 3 days
Frequently Asked Questions

Blockchain Development Services

Blockchain Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1349
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1247
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    949
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1183
  • image_logo-advance_0.webp
    B2B Advance company logo design
    642
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    921

Building a Transparent HiLo Game: Commit-Reveal and Gas Optimization

Players in blockchain casinos often doubt the fairness of outcomes. When the random number generator is hidden and the result is determined server-side, trust plummets. We reject that model. Instead of a closed RNG, we use a commit-reveal scheme: the server seed is fixed before the game starts and revealed afterward. Every step is verifiable at the smart contract level. This approach guarantees that even the casino owner cannot alter the result after the game starts. The player can reproduce all cards using the revealed seeds.

In our HiLo implementation, the house edge is fixed at 1% — no hidden fees. The multiplier is calculated dynamically based on the probability of guessing, eliminating any possibility of manipulation. For example, when the current card is Ace (1) and the player guesses higher, the probability is 92.3%, leading to a multiplier of approximately 1.07x. Conversely, guessing higher on a King yields a 0% chance and immediate loss.

Why we don't use Chainlink VRF?

Chainlink VRF is a decentralized randomizer, but it's slow: each request takes 1–2 blocks (~2 seconds on Ethereum). For a game where cards must be revealed instantly, this is unacceptable. The commit-reveal scheme with a deterministic combination of seed hashes gives an immediate result without waiting for an oracle.

Parameter Chainlink VRF Commit-reveal (our implementation)
Result delay ~2 sec 0 (instant)
Cost per call 10–50M gas (~$50) 30–50K gas (~$0.10)
Verification Via VRF Coordinator Via seed hashes
External dependencies Oracle, LINK token None

The commit-reveal scheme is 500x cheaper and 100x faster — the perfect choice for HiLo.

How can a player verify fairness?

After the game ends, the casino publishes the full server seed. The player takes this seed, computes keccak256(serverSeed), and compares it with the hash that was published before the game. If the hashes match, the casino did not tamper with the seed. Then, using the _deriveCard function from the contract, the player generates the card sequence and cross-checks with the history.

According to the EIP-1967 specification, using deterministic functions based on hashes guarantees the immutability of the result once the seed is committed.

// Client-side verification (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;
}

How we do it: stack and implementation

We use Solidity 0.8.20, Foundry for testing and deployment, and Tenderly for monitoring. The contract contains an optimized commit-reveal scheme where each card is computed on the fly without storing the entire deck.

// 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); _; }
}

What problems does commit-reveal solve?

Without commit-reveal, a player cannot be sure that the server hasn't altered the result after a bet. Commit-reveal removes this issue: the seed hash is fixed before the game, and the seed itself is revealed only afterward. The player gets a provable guarantee that the result was not tampered with. This is essential for licensing requirements and user trust.

Additional details: why commit-reveal is better than VRF?Using Chainlink VRF increases each game's cost by 100–1000x and adds latency. Commit-reveal requires no external calls, which is critical for high-frequency games.

Process of work

  1. Analysis: discuss game mechanics, RNG requirements, multiplier, house edge, bet limits.
  2. Design: smart contract architecture, choose commit-reveal scheme, define interfaces.
  3. Development: write contract in Solidity 0.8.20, write tests in Foundry (unit + fuzzing).
  4. Testing: formal verification with Slither, Echidna (fuzzing), testnet deployment.
  5. Audit: engage third-party auditor (optional).
  6. Deployment: deploy to target network (Ethereum, Polygon, BNB Chain).
  7. Support: monitoring, parameter updates, player assistance.

What's included in the work

  • Smart contract source code with comments
  • Verification documentation for players
  • Frontend integration (React, wagmi, RainbowKit)
  • Testnet deployment
  • Mainnet deployment with Tenderly monitoring setup
  • Training your team on result validation

Timeline and cost

Basic implementation (contract + frontend) starts at $5,000 and takes 2–3 weeks. With full formal verification and audit, the cost is between $10,000 and $20,000, and the timeline extends to 6–8 weeks. Cost is calculated individually based on complexity and scope of work.

Contact us to discuss your project. We have 5+ years of experience in blockchain development and have delivered over 20 games and DeFi products. We guarantee a provably fair implementation and transparency of all algorithms.

Order your HiLo game development — reach out, we'll assess your project within 24 hours. Get a consultation on architecture and gas optimization.

Game Economy, Contracts, and On-Chain Mechanics

We’ve seen this scenario multiple times. Axie Infinity generated substantial revenue monthly at its peak, but within 18 months the token crashed by 98% and the audience by 95%. The cause—lack of sinks: players earned SLP and cashed out, while burn mechanisms were insufficient. An analysis of Axie’s economy (Collins Dictionary) confirmed the model turned into a Ponzi scheme. We provide end-to-end GameFi development: from tokenomics to smart contracts, so your economy doesn’t repeat this mistake. Let’s evaluate your project at a meetup or online.

Play-to-Earn Economy Break Points

Inflationary tokenomics without sinks. Players earn tokens through gameplay. If sinks (burn or consumption mechanisms) are insufficient, supply outpaces demand. Price drops. Player fiat income declines. Players leave. A death spiral.

The right structure is a dual-token model with clear separation: a governance/value token with limited supply and a utility/reward token for in-game economy. The utility token must be actively consumed: item crafting, upgrades, entry fees, breeding. Examples: GODS/FLUX in Gods Unchained, AXS/SLP in Axie (though sinks were insufficient there). Historical data shows that without sinks, token supply inflates by 5–10% monthly, leading to price collapse within 6–9 months.

Effective Sink Mechanisms

  • Breeding/crafting — burning utility token to create a new NFT (e.g., Axie). Typical burn costs range from $5–$15 per action, removing 0.5–2% of total supply annually.
  • Character upgrades — each evolution requires token burning, consuming 0.1–0.3% of circulating supply per upgrade cycle.
  • PvP entry fee — token burn for tournament entry, part goes to prize pool. This can burn up to 0.5% of supply per week in active games.
  • Item durability — item breaks after N battles, token spent on repair. Cost per repair ~$0.50–$2.
  • Financial mechanics — staking with lock-up, removing tokens from circulation for a period. Typical lock-up periods of 30–90 days reduce circulating supply by 15–25%.

On-Chain vs Off-Chain: Boundary and Trade-offs

It’s not necessary to put all game logic on-chain—each transaction costs gas and takes 12 seconds. A game cycle is milliseconds. Balance:

Component On-chain Off-chain Examples
Asset Ownership + NFT items, land
Transfer/Trading + Marketplaces
Finance (staking, rewards) + Staking vaults, DAO
Random generation + (via VRF) Chainlink VRF
Gameplay + Battle system, movement
Game world state + Coordinates, health points
Matchmaking + Server-side logic

Gameplay results are transferred to blockchain via signed messages from server or ZK-proof. Verifiable off-chain with ZK: game server generates ZK-proof of session correctness, contract verifies proof and issues rewards. Implementations: Cartridge (Starknet), zkSync game rollups. Gas savings from batching proofs can reach 90% compared to per-action on-chain validation.

How Does Dual-Token Model Prevent Economic Collapse?

Governance token (limited supply) acts as value store and is used for major decisions. Utility token (minted via gameplay) is consumed by sink mechanisms, ensuring deflationary pressure. The ratio of governance to utility tokens in the initial pool should be 1:10 to 1:20. Simulation shows that a 30% burn rate on utility token keeps supply growth below 3% per year, preserving player income and token price.

Implementation of NFT Game Items

Standard: ERC-1155 for fungible items (resources, consumables) + ERC-721 for unique (characters, land). ERC-1155 provides up to 60% gas savings on batch transfers.

How to Implement Dynamic NFTs Without Overloading the Blockchain?

Item attributes change during gameplay (experience, durability, upgrades). Two approaches:

  • Fully on-chain: attributes stored in contract mapping, tokenURI generated from attributes via SVG/JSON encoding. Expensive in gas with frequent updates (e.g., $0.50 per update). Used for land and key assets.
  • Hybrid: attributes stored off-chain, tokenURI contains state hash. Updates signed by server, verified on-chain during transfer or sale. Cheaper ($0.02 per update) but requires server trust or ZK.

Breeding and crafting. Contract: two parent NFTs → pay utility token (burn) → mint new NFT with attributes dependent on parents + Chainlink VRF for randomness. Without VRF, miners can manipulate randomness via block selection.

// 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);
}

Marketplace and Royalties

An integrated marketplace gives control over fee structure and custom logic (e.g., banning item trading below a certain level). Royalties per EIP-2981 are standard but not enforceable: Blur and other marketplaces ignore on-chain royalties. For enforcement—whitelist-only transfer (only through contracts that pay royalties). Sacrifice composability for rights protection. Typical marketplace fee is 2.5–5% per transaction, generating recurring revenue.

Staking and Rewards Distribution

Staking NFTs is a mechanic for player retention. Problem: distributing rewards with thousands of stakers requires constant transactions (expensive). Solution—reward-per-share pattern (as in MasterChef from SushiSwap): global accRewardPerShare, upon claim or state change, debt is recalculated by formula pendingReward = stakedAmount * (accRewardPerShare - userRewardDebt). O(1) complexity regardless of staker count. Gas savings up to 70% compared to per-element distribution. Over a year with 10,000 stakers, this translates to roughly $40,000 saved in gas.

Why Is Reward-Per-Share Pattern Critical for Scalability?

Direct per-user reward updates cost O(n) per block, consuming more than 200,000 gas for 1,000 stakers. Reward-per-share reduces this to 30,000–50,000 gas per user claim, enabling thousands of stakers. Many early P2E games collapsed under gas costs that exceeded reward value. This pattern scales to tens of thousands without infrastructure overhead.

Process and Timelines

We start with a game economics document: token flows, mint/burn mechanics, projected supply schedule, sink analysis. Before writing code, the economy is modeled (Cadence, Python simulation).

GameFi Building Process: 5 Stages

  1. Economic modeling — 1–2 weeks. Develop dual-token model, calculate sinks, outline incentives for long-term holding.
  2. Token contract development — 2–3 weeks. ERC-20 for governance, ERC-20 for utility, with configurable mint/burn policy.
  3. NFT smart contracts — 3–5 weeks. ERC-721 / ERC-1155 with dynamic metadata, breeding/crafting, Chainlink VRF.
  4. Staking + rewards — 2–3 weeks. Contract based on reward-per-share, interfaces for frontend.
  5. Marketplace (optional) — 2–4 weeks. Custom marketplace with enforced royalty.

Work Deliverables

  • Source code for all smart contracts with tests (Foundry/Hardhat)
  • Architecture and economics documentation
  • Integration with Chainlink, Tenderly for monitoring
  • Code audit and formal verification (Slither, Mythril, Echidna)
  • Team training on contract interaction
  • Post-deployment support (3 months)

Basic GameFi stack (tokens + NFTs + staking + marketplace) — 8 to 16 weeks. Full game with on-chain randomness, breeding, dynamic NFTs — 4–8 months. ZK-based verifiable gameplay — a separate project from 6 months.

Contact us for an audit of your tokenomics—we’ll assess risks and refine sink mechanisms. Order GameFi project development—receive a ready product with proven economy. We guarantee contract stability and code transparency. Our experience includes dozens of implemented Web3 projects, including audits of 15+ P2E games. Get a consultation to start your project.