GENESIS PROTOCOL

Whitepaper

A fully on-chain game running entirely on a Uniswap v4 hook.

00

Abstract

Mine pixels. Earn ETH. Hash-based placement. Proximity scoring. Accumulator yield.

Genesis is a fully on-chain game where every $GENESIS token is a mineable pixel on a 100x100 grid. The entire game — token minting on buy, pixel placement, strike resolution, scoring, prize pool distribution, and supply burns — lives inside a single Uniswap v4 hook contract. There is no separate game contract. There is no off-chain coordination. There are no oracles or middleware. The hook reacts to every swap, mints or burns pixels accordingly, and runs the strike-based scoring game in lockstep with the trading layer.

This is the first project to use a Uniswap v4 hook as the entire substrate for an on-chain game.

01

What Genesis Is

Genesis is a game disguised as a token. Or a token disguised as a game — the distinction is meaningless because they're the same contract.

Every $GENESIS token corresponds to one cell on a 100x100 grid. There are exactly 10,000 cells and 10,000 tokens. When you buy $GENESIS on Uniswap, the hook prepares pixels for you. When you visit the /claim page and call claimPixels(), those pixels get placed on the grid at deterministic, hash-derived coordinates. When you sell, your pixels burn off the grid in reverse order. When the contract fires a "strike" at a coordinate, nearby pixels score points. At the end of each 6-hour round, the prize pool — funded by a 3% tax on every swap — distributes to holders proportional to how much their pixels scored.

Pixels can be permanently sealed in exchange for a one-time payout based on lifetime score. Sealing burns the underlying token, reduces total supply, and converts the pixel from green to white on the grid forever.

The game has no admin, no team allocation, no upgrade path, and no off-chain components. It runs entirely as a Uniswap v4 hook on Ethereum.

03

The Grid

The grid is a 100x100 lattice — 10,000 cells indexed by (x, y) coordinates from (0,0) to (99,99). Each cell is in one of three states:

EmptyNo pixel placed here
LiveA pixel is placed, owned by a wallet, eligible to score
SealedPermanently locked. Cannot be removed, cannot score
Empty
Live pixel
Sealed

The grid lives entirely on-chain. Occupancy is stored as a packed bitmap (10,000 bits across 313 storage slots). Per-pixel state — owner, current round score, lifetime score, sealed status — is stored in mappings keyed by coordinate. The frontend reads chain state and renders client-side. No IPFS, no metadata server, no centralized rendering service.

04

Buying and Claiming Pixels

BUYING

Buying $GENESIS is a normal Uniswap swap. You send ETH to the pool, the pool returns $GENESIS tokens, and the hook charges a 3% tax routed to the prize pool and seal reserve.

Buying does NOT immediately place pixels on the grid.It gives you tokens tracked as "unclaimed pixels" — they belong to you, but have no coordinate, no score, and no participation in the game.

CLAIMING

To place tokens onto the grid as pixels, call claimPixels() on the hook contract. When you do:

1Hook reads how many tokens haven't been placed yet
2For each unclaimed token, derives a coordinate via keccak256(your_address, your_pixel_ordinal)
3If occupied, re-hashes with incrementing salt until empty cell found
4Pixel placed at coordinate, ownership recorded
5Unclaimed count decremented
YOUR WALLET
Buy 5 GENESIS
tokens received
Call claimPixels()
HOOK CONTRACT
unclaimed[you] += 5
pixels not yet placed
derive coord for each
keccak256(addr, ordinal)
THE GRID
no change on buy
● (12,47) · ● (3,8)
● (44,91) · ● (62,12)
● (78,55)

WHY SEPARATE CLAIM FROM BUY

Auto-placing on every buy would inflate gas costs dramatically. A 50-token purchase would face 50 placement operations in a single swap. By separating: swaps stay cheap, claim cost is paid only when the holder wants to enter the game, and holders can claim batches paying gas once for many pixels.

Pixels that aren't claimed don't score, don't earn, and don't appear on the grid. The frontend shows your unclaimed count and prompts you to claim whenever it's greater than zero.

05

Pixel Placement

Placement is deterministic, hash-derived, and unpredictable in practice. Holders cannot choose coordinates.

coord = keccak256(wallet_address, pixel_ordinal) mod 10000

COLLISION RESOLUTION

If derived coordinate is occupied, the hook re-hashes with an incrementing salt:

uint256 salt = 0;
while (salt < 256) {
    uint16 coord = uint16(
        uint256(keccak256(abi.encode(wallet, ordinal, salt))) % 10000
    );
    if (!_isOccupied(coord)) return coord;
    salt++;
}

Salt loop bounded at 256 iterations. On a half-full grid the expected iterations to find an empty cell is 2. On a 90%-full grid, it's 10. The bound is a safety rail; in practice it's never approached.

WHAT THIS MEANS FOR THE GAME

UnpredictableCannot pre-compute coordinates without knowing exact ordinal at claim time
FairWhales cannot stack pixels in a chosen region — they scatter via hash output
A rollEvery claim reveals landing positions only after the transaction confirms
Valuable luckLanding adjacent to dense regions is mathematically more valuable than landing alone
06

Selling

Selling $GENESIS reverses placement. When tokens leave your wallet via swap:

1Hook detects your balance decreased by N tokens
2Hook removes N of your most recently claimed (non-sealed) pixels
3Removal is LIFO — last placed, first burned
4Sealed pixels are skipped in LIFO traversal — they persist forever
Your pixels:  [P1, P2, P3, P4, P5]
Sell 2 tokens → removes P5, then P4
Remaining:    [P1, P2, P3]

If P3 was sealed → skips P3, removes P5 then P4 anyway

The "burn" here is grid-level, not token-level — tokens go back to the LP unchanged. Total token supply is unaffected by sells. Only sealing reduces total supply.

07

Rounds and the Game Cycle

Genesis runs in 6-hour rounds. Each round is a self-contained scoring cycle. Every swap routes 80% of the 3% hook tax into the round's prize pool. Six strikes fire over six hours, scoring affected pixels.

0:00
Round opens
1:00
Strike 1 fires
2:00
Strike 2 fires
3:00
Strike 3 fires
4:00
Strike 4 fires
5:00
Strike 5 fires
6:00
Strike 6 + Round closes
Accumulator advances · Bounty resets or rolls · Round N+1 opens
08

Strikes

A strike is the core scoring event. Once per hour during a round, the contract fires a strike at a deterministic coordinate derived from recent block state and a strike nonce:

strikeCoord = keccak256(blockhash(block.number - 1), strikeNonce++) mod 10000

Strikes are deterministic given inputs but unpredictable in practice — nobody can predict future block hashes. When a strike lands, it affects a 3x3 area centered on that coordinate:

STRIKE PATTERN (3x3 AREA)
+1
+1
+1
+1
+5
+1
+1
+1
+1
Center: +5 pts
Neighbors: +1 pt each

For each cell in the 3x3 area: if empty, no score. If occupied by a live pixel, score is added. If occupied by a sealed pixel, skipped. A single strike can score up to 9 different pixels owned by up to 9 different wallets.

EDGE HANDLING

If the strike center is at a grid edge, some neighbor positions don't exist and aren't scored. No wraparound — the grid has hard edges.

STRIKE TRIGGERING

Strikes are fired by the platform wallet calling tick(). The function enforces a minimum 1-hour gap. If called too early, it reverts. The platform wallet cannot fire extra strikes, skip strikes, or alter the deterministic coordinate calculation.

09

Proximity Scoring

This is the mechanic that makes Genesis a game rather than a lottery. Your pixel scores when a strike directly hits it (+5), AND when a strike hits any of its 8 neighbors (+1). The more pixels in your local area — yours or anyone else's — the more chances any single strike scores you.

LONE PIXEL
Strike on ★ = +5 Strike on neighbor = 0
CLUSTER PIXEL (★ + 4 neighbors)
Strike on ★ = +5 Strike on any neighbor = +1 each

A pixel in an empty region scores only when a strike lands directly on it. A pixel surrounded by other pixels scores from strikes that hit it AND from strikes hitting any of its 8 neighbors. Other holders' pixels nearby benefit you, simply by existing.

MATHEMATICAL EXPECTATION

For a uniformly random strike on a grid with occupancy ratio p:

E[score per strike] = (1/10000) × 5
                   + (8p × 1/10000) × 1
                 = (5 + 8p) / 10000

Empty region (p ≈ 0):    5 / 10000 per strike
Fully occupied (p = 1):  13 / 10000 per strike  (+160%)

WHY THIS CHANGES THE GAME

Adjacency valueLanding next to existing pixels is more valuable than landing in empty space
Network effectExisting holders benefit when new buyers land nearby — more scoring surface
Sell penaltySelling weakens local scoring for surviving neighbors
Whale resistanceCapital alone does not create zone control — scatter is hash-determined
10

The Bounty Pixel

Each round, the hook designates a single coordinate as the bounty pixel:

bountyCoord = keccak256(blockhash, roundNumber) mod 10000

If a strike's center lands on the bounty coordinate AND a pixel exists there, that center pixel's score is multiplied by the current bounty multiplier. The multiplier starts at 1x, increments by 1 each round a strike misses it, capped at 5x. When hit, resets to 1x.

Round 47(45,23)1xNo strike hitRolls to next round
Round 48(45,23)2xNo strike hitRolls to next round
Round 49(45,23)3xStrike hits (45,23)!5 pts x 3 = 15. Multiplier resets.

You can't choose to own the bounty pixel — coordinates are randomized each round and your placement is hash-determined. Owning the bounty in any given round is a function of how many pixels you have and pure luck.

11

Accumulator Yield

Genesis distributes earnings using a MasterChef-style accumulator pattern — the same math that powers SushiSwap and Curve gauge systems.

THE PROBLEM

Distributing prize pool proportionally would require iterating every scoring pixel at round close. With thousands of scoring pixels, this would exceed block gas limits.

THE SOLUTION

A single global counter — payoutPerScoreAccumulator — increases monotonically at every round close:

payoutPerScoreAccumulator += prizePool / totalScore

Each pixel records the accumulator value at its last settle point. Claimable yield is computed lazily:

claimable = pixel.unsettledScore
          × (currentAccumulator - pixel.lastSettledAccumulator)

This is O(1) per pixel. No iteration over the holder set. Distribution happens automatically as the accumulator advances; claiming materializes the math when the holder calls claim().

LAZY SETTLEMENT IN PRACTICE

Round 47 closes: accumulator = 0.0001234
                 pixel scored 7 pts, holder hasn't claimed.

Round 48 closes: accumulator = 0.0001891
                 pixel scored 0 pts.

Round 49 closes: accumulator = 0.0002445
                 pixel scored 3 pts.

Round 50: holder calls claim()
  → 7 pts × R47 delta + 3 pts × R49 delta
  → computed in O(1) reads
  → holder receives ETH
No iterationScales to any holder count with no gas growth
Holder pays gasClaim cost is the holder's responsibility
Seal compatibleSealed pixels stop accumulating without breaking the math
Provably proportionalDistribution is always correct — the math cannot be gamed
12

Sealing: Deflationary Endgame

Sealing is the deflationary endgame mechanic. Holders can permanently lock a pixel for a one-time payout based on lifetime score.

WHAT SEALING DOES

1Verifies caller owns the pixel
2Verifies at least 100 lifetime score (anti-griefing minimum)
3Settles the pixel — materializes pending yield
4Transfers lifetimeScore × sealRate ETH from seal reserve
5Transfers any pending claimable yield
6Marks pixel as sealed — turns white, excluded from all future strikes
7Burns 1 GENESIS token from caller balance
8Removes pixel from LIFO ownership array (immune to future sells)

WHERE PAYOUTS COME FROM

Sealing is funded by a dedicated seal reserve, NOT the round prize pool. The seal reserve receives 20% of every hook tax. Sealing doesn't drain active round payouts. If temporarily insufficient, the call reverts and the holder waits.

THE DEFLATIONARY EFFECT

Every seal reduces total $GENESIS supply by 1. As more pixels seal, fewer remain to score, but the prize pool keeps growing (funded by trading volume, not pixel count). Per-pixel yield rises for remaining live pixels. In the limit, one pixel surviving would score nearly every strike and earn nearly the entire prize pool every round.

13

The Hook Tax

Every swap on the $GENESIS pool is taxed 3% by the hook, in addition to the standard 0.30% Uniswap LP fee.

Every Swap (Buy or Sell)
0.30%
LP Pool Fee
Locked permanently
3.00% Hook Tax
80%
Round Prize Pool
2.4% of swap
20%
Seal Reserve
0.6% of swap
0.30% LP feeAccumulates to the LP position. LP NFT burned at launch — fee stays permanently locked.
2.40% to prize pool80% of hook tax. Funds round payouts to scoring pixels.
0.60% to seal reserve20% of hook tax. Funds seal payouts to holders who permanently lock pixels.
Total swap cost~3.30% per trade, symmetric on buys and sells.

Coupling rewards to the LP fee tier would force a tradeoff: high LP fees fund the game but discourage trading. By using a dedicated hook tax, the LP fee stays trader-friendly, the game is funded generously, and the seal reserve grows independently.

14

Why a v4 Hook

Genesis is the first project to run a complete on-chain game inside a single Uniswap v4 hook. Everything described in this document happens inside one contract that hooks into the pool's swap lifecycle.

WHAT V4 HOOKS UNLOCKED

Uniswap v4 introduced programmable execution at every pool lifecycle event. For Genesis, the critical hook is afterSwap. Every swap atomically triggers:

1Hook tax calculation and routing (80% prize pool / 20% seal reserve)
2Detection of buy vs sell direction
3On buys: increment buyer unclaimed pixel count (placement deferred)
4On sells: LIFO burn of seller claimed pixels from grid

All of this happens in the same transaction as the swap itself. There is no off-chain bridge, no oracle, no relayer between the trade and the game state.

GENESIS HOOK CONTRACT
AFTER SWAP (automatic)
Hook tax routing — 80% prize pool, 20% seal reserve
On buy: increment unclaimed pixel count
On sell: LIFO burn pixels from grid
PUBLIC USER FUNCTIONS
claimPixels() — place unclaimed pixels onto grid
claim() — withdraw accumulated yield
seal(coord) — permanently seal a pixel
PLATFORM-GATED (maintenance)
tick() — fire hourly strike
closeRound() — advance round after expiry
setPlatformWallet() — rotate operator key
VIEW FUNCTIONS (read-only)
Grid, pixel, and round state
Accumulator and history snapshots
Bounty state and holder stats
Seal preview and unclaimed count

PLATFORM WALLET CAPABILITIES

CAN DO
+Call tick() to fire a strike (rate-limited)
+Call closeRound() after expiry
+Rotate its own key
CANNOT DO
-Mint $GENESIS tokens
-Burn other holders' tokens
-Withdraw from prize pool or seal reserve
-Modify scores or tax rates
-Pause the contract
-Access user funds in any form

STORAGE ARCHITECTURE

gridBitmap[313]Packed occupancy bitmap (10,000 bits across 313 uint256 slots)
pixels[coord]Owner, scores, seal status per coordinate
pixelsOf[wallet]Pixel array per wallet — enables LIFO burn on sell
unclaimedPixels[wallet]Pending unclaimed pixel count per wallet
payoutPerScoreAccumulatorGlobal monotonic accumulator (1e18 scaled)
roundClosedAccumulator[r]Accumulator snapshot at each round close
sealReserveCurrent sealing reserve balance
currentBountyCoordActive bounty coordinate for current round
bountyRolloverMultiplierCurrent bounty multiplier (1-5)

WHY NOT BEFORE V4

v2/v3No hook system. Extra mechanics required separate contracts or token-level modifications that broke composability.
Other AMMsBalancer and others have hook-like systems but lack v4's depth of swap lifecycle integration.
Custom poolsDeploying a new AMM sacrifices Uniswap's existing liquidity layer and routing infrastructure.
15

Risk Disclosures

Smart contract riskThe hook is immutable post-launch. Bugs cannot be patched. Audits reduce but do not eliminate risk.
Game-theoretic riskNovel mechanics may produce unexpected emergent behaviors. Strategies that work early may not work late.
Hook tax riskThe 3% tax creates meaningful per-swap friction. Total cost (LP fee + hook tax) is ~3.3%.
Sealing riskSealing is permanent and irreversible. The token is burned and cannot be recovered. The seal reserve may temporarily lack funds.
Claim riskPixels that aren't claimed don't score and don't earn. Failing to claim is a self-imposed loss.
Platform wallet riskRequired to advance game state. If unavailable, future rounds stall — though existing claims, sealing, and trading continue.
Liquidity riskInitial LP is locked. Market volatility and large sells can produce severe slippage.
Regulatory riskToken mechanics involving rewards may be subject to varying legal interpretations. Not legal advice.
A

Appendix: Core Functions

A. STRIKE RESOLUTION

function _resolveStrike(uint16 centerCoord) internal {
    uint16 cx = centerCoord % 100;
    uint16 cy = centerCoord / 100;

    for (int8 dx = -1; dx <= 1; dx++) {
        for (int8 dy = -1; dy <= 1; dy++) {
            int16 nx = int16(cx) + dx;
            int16 ny = int16(cy) + dy;
            if (nx < 0 || nx >= 100 || ny < 0 || ny >= 100) continue;

            uint16 coord = uint16(uint16(nx) + uint16(ny) * 100);
            if (!_isOccupied(coord)) continue;
            if (pixels[coord].sealed) continue;

            _settlePixel(coord);

            uint64 points = (dx == 0 && dy == 0) ? 5 : 1;

            if (dx == 0 && dy == 0 && coord == currentBountyCoord) {
                points *= bountyRolloverMultiplier;
                bountyHitThisRound = true;
            }

            pixels[coord].currentRoundScore += points;
            currentRoundTotalScore += points;
        }
    }
}

B. CLAIM PIXELS

function claimPixels() external {
    uint256 toPlace = unclaimedPixels[msg.sender];
    require(toPlace > 0, "no unclaimed pixels");

    for (uint256 i = 0; i < toPlace; i++) {
        uint16 coord = _derivePixelCoord(
            msg.sender,
            walletPixelOrdinal[msg.sender]
        );
        _placePixel(coord, msg.sender);
        walletPixelOrdinal[msg.sender]++;
    }

    unclaimedPixels[msg.sender] = 0;
    emit PixelsClaimed(msg.sender, toPlace);
}

C. SEALING

function seal(uint16 coord) external {
    require(pixels[coord].owner == msg.sender, "not owner");
    require(!pixels[coord].sealed, "already sealed");

    _settlePixel(coord);
    require(pixels[coord].lifetimeScore >= 100, "insufficient score");

    uint256 sealPayout  = pixels[coord].lifetimeScore * sealRate;
    uint256 totalPayout = sealPayout + pixels[coord].claimableYield;
    require(sealReserve >= sealPayout, "seal reserve insufficient");

    sealReserve               -= uint128(sealPayout);
    pixels[coord].claimableYield = 0;
    pixels[coord].sealed         = true;

    _burnToken(msg.sender, 1e18);
    _removeFromOwnershipArray(msg.sender, coord);

    payable(msg.sender).transfer(totalPayout);
    emit Sealed(coord, msg.sender, sealPayout, pixels[coord].lifetimeScore);
}
DEPLOYED CONTRACTS · ETHEREUM MAINNET
GENESIS HOOK0x20421fCF882F73bE9b9e8D77814C9768eB7FC044
ETHERSCAN ↗
GENESIS TOKEN0x29F55822C8FaC46f41d3B7a80EC9AD355a92D5C9
ETHERSCAN ↗

Genesis is a game where every $GENESIS token is a coordinate, every claim is a roll, every six hours is a payout, and every seal is a permanent etching on the canvas. The entire mechanic lives inside a single Uniswap v4 hook contract that runs the trading layer, placement layer, scoring layer, distribution layer, and deflationary layer simultaneously.

This is the first time a complete on-chain game has been built this way — entirely as a v4 hook, with no separate game contract, no off-chain coordination, and no middleware between the swap and the gameplay.

Mine pixels. Earn ETH.
Genesis is open-source software with no admin access to user funds and no off-chain components. The smart contract is the complete authority. Read it before you trade.