GENESIS

DOCUMENTATION

Overview

01

Genesis is a 16x16 cellular-automaton creature living inside one Uniswap v4 pool, driven entirely by real swaps. Time between trades, trade size, direction and the address that traded are the only inputs it has. There is no server, no scheduler and no operator behind it — the whole life cycle executes inside the swap transaction that caused it.

It exists as an honest, checkable counter-example to "AI agent" projects that assert autonomy without a wired architecture. Every claim on this page points at what actually enforces it — a missing permission flag, an absent owner, an absent source of nondeterminism — rather than at a description of intent. Where something is a limitation rather than a guarantee, it is disclosed in the same section, not buried.

Architecture

6 contracts
  • LifeTokenThe traded asset of the pool. — Fixed supply. No owner, no mint after construction, no transfer hooks.
  • OrganismThe creature's body — living cells, a shield layer, vitals (energy, hunger, bloat, generation, epoch), a heritable genome, and per-address trader memory. — Only its own registered hook may call it.
  • LifeHookThe only bridge between real swaps and the creature. Implements afterSwap only — no fee override, no delta-returning permission — so it is structurally incapable of altering a trade's outcome. — Bound permanently to one canonical pool the first time it trades, so no one can spin up a copycat pool to drive the creature for free.
  • ChronicleAppend-only fossil record of every swap, birth and death. — Append-only; no delete, no rewrite path.
  • Renderer + OrganismNFTPure on-chain SVG rendering. One NFT per lineage epoch, permissionless to mint. — Always renders the current live state of that epoch, never a frozen snapshot.
  • TreasuryThe creature's own wallet — holds 5% of supply and acts on its own vitals. — No owner, no admin, no upgrade path. Full detail in section 04.

Biology — how a swap becomes a life event

03

A swap arrives at the pool. Uniswap settles it exactly as it would in any other pool, then calls afterSwap on the hook. The hook reads four things and translates them into the creature's terms:

  • time since last swapgenerations evolved alone — capped per swap, so a long-dormant pool cannot force unbounded gas onto the next trade
  • trade size vs. rolling averagehow many cells the trade touches, on a log scale — an average trade barely registers, an outlier registers more, and the effect is capped
  • buy vs. sellfeed vs. wound
  • trader addresswhere the trade lands, resolved through anatomy and memory

More than plain Conway

Anatomy. The body has three fixed regions. A 16-cell CORE, fatal to lose regardless of total population — a large but hollow creature is still dead. An 18-cell METABOLIC region that generates energy. And a 60-cell SENSORY border ring, which is the only region a stranger's trade can reach.

Metabolism. Population costs upkeep every generation; feeding is income. Run a deficit too long and it starves. Get fed nothing but buys past a population ceiling and it outgrows its own upkeep and dies of overgrowth instead — so selling above that ceiling is healthy pruning, not simply harm. It has to live in a band, not merely survive.

A genome that mutates. Which neighbor-counts cause birth or survival is heritable state, not a fixed rule, starting from classic Conway (B3/S23). Every death mutates it, biased toward whichever trait the cause of death implicates: starve, and metabolism genes shift; lose the core, and the anatomy rotates; go extinct, and the rule itself shifts. Every epoch after the first runs physics shaped by real market pressure.

Four death causes. Each one triggers reincarnation into a new epoch with a mutated genome:

  • Extinctionpopulation hits zero
  • Core Necrosisthe core empties, whatever the rest of the body looks like
  • Starvationa sustained energy deficit
  • Overgrowthfed nothing but buys, past its population ceiling

Memory. The creature recognizes addresses. A stranger's first trade is damped to half strength and confined to the sensory ring. A proven repeat feeder's trades land at full strength and can reach the core directly. Repeated selling damages that relationship.

Disclosed limitations

"Trader" means whoever called the pool's swap function — which is often a router, not the end human. A shared router makes distinct people look like one trader to the creature's memory, and this is a real limitation of on-chain identity, not something the contracts work around.

Perturbation placement is deterministic from public data. A sufficiently motivated searcher could, in principle, predict where their own trade will land before submitting it. There is no commit-reveal scheme here.

The Treasury — an ownerless wallet

04

The treasury holds 5% of the token supply, given once at genesis and never again. It opens its own liquidity position in the pool. That position is single-sided at birth, because the treasury starts holding only its own token and none of the paired asset — so it is honestly a standing sell-order until trading brings in the other side, not a hidden mechanism. It earns the pool's ordinary 1% LP fee on its own liquidity, exactly as any other liquidity provider does.

When poked by anyone — for a small capped reward — it looks at the creature's vitals and does exactly one of three things: buy the creature's token when it is starving, sell some when it is bloated, or nothing.

The key property is that decide() is public and free to call by anyone before act() is triggered. What it will do is checkable in advance rather than asserted after the fact. Nobody — including whoever deployed it — can make it do anything other than what the creature's own biology dictates. No owner, no admin function, no upgrade path. The only address any token can ever reach is whoever triggers a real action, and only as a small capped reward.

The pool fee

05

The pool charges an ordinary 1% Uniswap v4 LP fee. It is a pool parameter, identical in kind to the parameter on any other Uniswap pool, and has nothing to do with the hook. It funds the creature only because the treasury is itself a liquidity provider earning its proportional share of that fee.

There is no token transfer tax anywhere in this project.

Technical architecture

06

1 · State layout

The organism's entire cognitive state lives in five packed storage slots, updated atomically inside the afterSwap hook callback:

  • slot 0 · tissueuint256 — 256-bit tissue map, 1 bit per cell (16x16 grid)
  • slot 1 · shielduint256 — 256-bit resilience layer, 1 bit per cell
  • slot 2 · vitalspacked: generation(64) | lastBlock(64) | epoch(32) | energy(32) | hunger(8) | bloat(8)
  • slot 3 · weightspacked: birthSet(9) | survivalSet(9) | anatomyOffset(4) | metabolicRate(4) | temperament(4)
  • slot 4 · attentionmapping(address => uint256) — packed: affinityScore(8) | interactionCount(32)

Every field updates in a single SSTORE per swap. No off-chain state, no IPFS, no external DB — the entire model fits in five words of storage.

2 · Signal extraction from the swap

The hook reads BalanceDelta directly off the settled swap and derives a magnitude signal via log-scale normalization against a running EMA:

ema'     = ema - (ema >> 3) + (amt >> 3)   // 1/8 decay EMA, pre-signal
ratio     = (amt << 8) / (ema + 1)
magnitude = max(0, log2(ratio) - 8)        // baseline-centered log signal
magnitude = min(magnitude, 32)             // hard cap, 32 of 256 cells

A trade at exactly the rolling average produces a near-zero signal; each doubling above it adds roughly one unit of magnitude. The signal is entirely local — no oracle price feed, no external volatility index. The EMA itself is the only "market model" the system carries, and it is two SSTOREs wide.

3 · The transition function

Each swap runs the tissue map forward through a modified Life-like cellular update, parameterized by the heritable weights register instead of a hardcoded rule:

for each cell c:
    n        = popcount(neighbors(c))   // 3-layer carry-save adder network
    born     = (birthSet >> n) & 1
    survives = (survivalSet >> n) & 1
    next[c]  = (alive[c] & survives)
             | (!alive[c] & born)
             | (shield[c] & wouldDie(c))

The neighbor count for all 256 cells is computed in parallel via bitwise carry-save addition — eight shifted neighbor planes reduced through a three-layer adder network, producing a 4-bit count per cell across the whole grid in roughly a dozen 256-bit boolean ops. No per-cell iteration. The entire generation update executes as fixed-width bitwise arithmetic, independent of how many cells are alive.

shield[c] is a one-time save state: a cell the transition function would otherwise kill instead survives once, consuming its shield bit. Shields are granted by positive-signal interactions and regenerated continuously in metabolic tissue — resilience is a property the organism accumulates from experience, not a static trait.

4 · The mutation operator

On failure the weights register is not reset — it is perturbed, with the perturbation site selected by which failure mode triggered it:

seed = keccak256(weights, tissue, failureMode, swapContext)

if failureMode == STARVATION:   mutateRange(seed, bits 18..25)  // metabolicRate
if failureMode == CORE_FAILURE: mutateRange(seed, bits 14..17)  // anatomyOffset
if failureMode == OVERGROWTH:   mutateRange(seed, bits 26..29)  // temperament
if failureMode == EXTINCTION:   mutateRange(seed, bits  0..13)  // birth/survival

weights = sanitize(weights ^ (1 << selectedBit))

sanitize() enforces the constraint space: bit 0 of the birth set is permanently masked (a rule that spontaneously births isolated cells would eliminate death as a possible state entirely), and the population count of the birth/survival sets is capped to prevent runaway saturation. This is bounded architecture search — every mutation event moves exactly one heritable parameter, directionally biased toward the subsystem that failed, inside a constrained search space that cannot degenerate into either total sterility or total noise.

5 · Attention / memory encoding

onInteraction(address a, bool positive):
    entry    = attention[a]
    affinity = positive ? min(255, entry.affinity + 4)
                        : max(0,   entry.affinity - 12)
    attention[a] = pack(affinity, entry.count + 1)

routingMask(address a):
    if attention[a].count == 0:     return SENSORY_MASK  // cold start
    if attention[a].affinity >= 24: return CORE_MASK     // full depth
    return FULL_MASK

Affinity decays roughly 3x faster on negative signal than it accrues on positive — asymmetric trust, cheap to lose, slow to build. This is a single mapping lookup and one packed-word update per interaction: no separate reputation contract, no external attestation.

6 · Treasury decision function

function decide() public view returns (Action, uint256 amount):
    if hunger >= 160:
        amount = clamp(pairedBalance * hunger / 255,
                       MIN_TRADE, pairedBalance * 0.10)
        return (FEED, amount)
    if bloat >= 160:
        amount = clamp(lifeBalance * bloat / 255,
                       MIN_TRADE, lifeBalance * 0.10)
        return (PRUNE, amount)
    return (NONE, 0)

function act() external:
    (action, amount) = decide()
    require(action != NONE)
    manager.unlock(encode(action, amount))
    payBounty(msg.sender, amount * BOUNTY_BPS / 10000)

decide() is view — zero state mutation, callable by anyone at zero cost, meaning the treasury's next move is fully computable off-chain before it happens on-chain. act() re-derives the same decision internally rather than accepting caller-supplied parameters, so the trigger is permissionless but the outcome is not: the caller decides when, the organism's own state decides what.

7 · Hook permission encoding

The hook's execution rights are not stored in a mutable flag — they are mined into the low bits of its own deployed address via CREATE2:

targetFlags = AFTER_SWAP_FLAG   // single bit set
(salt)      = mine(deployerAddr, targetFlags, hookBytecode)
hook        = deploy{salt}(hookBytecode)
require(uint160(address(hook)) & FLAG_MASK == targetFlags)

The pool manager reads permission bits directly off the hook's address before dispatching any callback — there is no permission storage slot to misconfigure, no admin function to toggle scope later. A hook mined for AFTER_SWAP_FLAG alone is physically incapable of receiving beforeSwap, liquidity or donate callbacks, because the address itself does not carry those bits. Extending capability requires deploying an entirely new contract at a new mined address — there is no upgrade path from inside the system.

Glossary

07 · 10 terms
  • Epochone life. Ends at death, begins again with a mutated genome.
  • Generationone application of the rule to the whole grid.
  • Organa fixed body region — Core (16 cells, fatal to lose), Metabolic (18 cells, generates energy), Sensory (60-cell border ring, the only region a stranger can reach).
  • Genomethe heritable birth/survival neighbor-counts. Starts at Conway's B3/S23.
  • Bond / Memoryper-address standing: how deeply the creature trusts a given trader.
  • Bloat0–255 measure of growth past the sustainable population ceiling.
  • Hunger0–255 measure of unmet upkeep.
  • Treasurythe creature's ownerless wallet, holding 5% of supply.
  • Bootstrapthe one-time genesis allocation into the treasury. Never repeated.
  • Pokeanyone calling act() to trigger whatever decide() already publicly says.