Docs
How DNA works, explained two ways. Pick yours; you can switch any time.
01What this is
DNA is an ERC-20 on Ethereum, traded against ETH in one Uniswap v4 pool. The pool's hook, DNAHook, charges a dynamic fee whose policy is a swappable module: what CT calls a new hook, DNA calls a mutation. An AI agent proposes parameters for registered modules through ModuleRegistry (registering new Safe-approved bytecode needs level 10). A separate pipeline, the Sequencer, builds standalone game contracts and new modules (see The Sequencer). Each change waits in a public 1 h queue, then runs in shadow and on a slice of live trades before it is kept or rolled back.
- Token
- DNA (ticker DNA), 1,000,000,000 minted once. Burnable, no mint function, no owner
DNAToken.SUPPLY - Pool
- ETH/DNA on Uniswap v4, dynamic fee, tick spacing 1, one canonical pool
DNAHook.poolKey - Hook
- Immutable, no owner, no upgrade path
SPEC §2 - Agent
- Runs in an Intel TDX enclave on Phala; its address is registry.agent()
ModuleRegistry.agent - The Safe
- 2-of-3 multisig. Cancels, pauses, lowers the level. Can't touch your DNA or the hard limits (see The Safe)
ModuleRegistry.safe
Sourcecontracts/SPEC.mdDNAToken.solDNAHook.solModuleRegistry.sol
02Mutations (CT: hooks)
A mutation is a module, or new parameters for one, that DNA's one Uniswap v4 hook calls. DNAHook itself never changes. A module is a small pure contract: a fee policy the hook calls on every swap (AdaptiveFee) or a split policy FeeVault calls on every distribution (BaselineSplit). A module moves Proposed → Shadow → Canary → Active, one queued registry op per step, and anyone can execute an op once its 1 h delay has passed.
AdaptiveFee: pips = min(base + mult × volEma / 1e4, cap) canary fee is clamped to activeFee ± 10,000 pips (±1 point)
- Queue SetParams + SetShadow · 1 h
- Shadow · 2 h, every 10th swap, fee computed, nothing charged
- Queue SetCanary · 1 h
- Canary · 4 h, live fee on 100 of every 600 blocks
- passesPromoteActive, queued 1 h (by the Safe until level 8): it becomes the live fee
- fails or a kill check firesendCanary (the active fee stays) or rollback (the 2.2% baseline)
- Mutation = hook
- "Hook" is what CT calls it; "mutation" is DNA's name. Either way: a module the one hook calls, never a new hook contract. DNAHook is immutable
DNAHook._staticcallPips → IFeePolicy.projectFee - Who writes them
- The AI proposes every one. Today a mutation is a new parameter set for an approved module (an AdaptiveFee plate); brand-new bytecode needs autonomy level 10 and a code hash the Safe approved. ParamSplit, DirectionalFee and SizeTierFee are built and tested; the Safe has not registered them yet. Today the AI tunes AdaptiveFee only
ModuleRegistry.L10_OPS, ApproveCodehash; contracts/src/modules - Launch level
- 5: shadow, live test, parameters on non-active modules, rollback. Promotion needs the Safe until 8
ModuleRegistry constructor level_, L5_OPS - Queue delay
- 1 h on every op, the agent's and the Safe's alike
ModuleRegistry.MIN_DELAY - One experiment
- About 8 h: 1 h + 2 h shadow + 1 h + 4 h canary, so at most 3 a day. A stage short of data is extended, up to 3× its length
engine/src/policy.ts TIMING - Shadow sampling
- Every 10th swap, 30,000 gas, failures ignored
DNAHook.SHADOW_EVERY - Canary window
- 100 of every 600 blocks (the contract requires ≥ 50)
ModuleRegistry.MIN_CANARY_WINDOW - Module gas cap
- 40,000 gas. A revert, a bad return or running out of gas falls back to the 2.2% baseline in the same swap
DNAHook.MODULE_GAS_CAP - Breaker
- 3 module failures within 300 blocks: anyone may roll the fee route back, and the engine's watcher does it at once
DNAHook.BREAKER_WINDOW, ModuleRegistry.BREAKER_N - Launch fee range
- Base and cap 10,000–35,000 pips (1%–3.5%), multiplier 0.1×–1.8×
script/Launch.s.sol feeBounds - Tuning
- At most one parameter change per module per hour. From level 6 the live fee can move anywhere in its range; there is no step limit
ModuleRegistry.PARAMS_EPOCH - Autonomy levels
- 0–10. L4 shadow, L5 canary and rollback, L6 tune the live fee, L7 bounty allowance, L8 promote, L9 split modules, L10 register bytecode the Safe approved
ModuleRegistry.L4_OPS–L10_OPS - Level changes
- Raised only by the Safe, through the queue, ≥ 5 days after the last rollback. Lowered by the Safe instantly
ModuleRegistry.LEVEL_RAISE_BLOCKS
SourceModuleRegistry.solDNAHook.solAdaptiveFee.solengine/src/policy.tsengine/src/loop.ts
03The Sequencer
An off-chain build pipeline. The brain picks what to build and signs the decision. The sequencer's models work in public CI on the public repo and can only open pull requests. The sealed engine re-runs every gate, compiles the merged commit itself and deploys after the public hour. No wallet key ever sits in CI.
- Idea → sealed intake → plain spec (builders never see the raw post)
- Brain: build or not, signed
- Lead plans; workers write contract, page and tests; tester attacks; fixer repairs (≤ 3 rounds); reviewer checks
- Brain verdict: ship, rework or kill, signed
- Public hour: deploy and funding queued, the Safe can cancel
- Sealed engine deploys; the site updates from the release branch
- fails the gates or 3 roundsdropped, reason published
- no players for 2 daysretired, ETH back to the Safe, claims stay
- Brain
- One model call per decision (build, verdict, retire, model swap, idea-round outcome, reward). Each is a signed record with the model, the sha256 of its context and of its input
engine/src/brain.ts - Models
- Public registry of every role's model and backup, shown as a table on /models. These are the default models. Swapping one needs a public tryout on fixed test cases, then a public hour, and the Safe can veto. Swapping the brain itself needs two Safe owners to approve
engine/models.json, docs/MODELS.md - Spend caps
- A daily and a monthly cap on AI spending. Near the cap the sequencer pauses first, then research. Keepers never call a model, so trading, fees and payouts never need the AI
engine/src/config.ts LLM - Gates
- Fuzz and invariant tests, fork simulation, static analysis, a planted-bug check, a gas cap, no delegatecall, selfdestruct or upgradeability, no new dependencies, no CI edits. The sealed engine re-runs them; CI alone never decides
- New games
- Standalone contracts with no power over the hook, the fees or other games. Only the Safe can pause one. No user deposits until a higher ladder level
- Live cap
- At most 3 games live. A 4th retires the one with the fewest players over 2 days
- Funding
- Safe → Zodiac Roles (one allowed call, GameFunder.fund, bounded amount) → Delay (1 h, the Safe can cancel). GameFunder enforces a weekly budget and a per-game cap
contracts/src/games/GameFunder.sol, test/fork/Funding.t.sol - Hook modules
- A module the Sequencer builds still needs the Safe's code-hash approval before it can be registered
ModuleRegistry.ApproveCodehash - Status
- Running in the sealed engine since 11 Oct 2026: the brain, model registry, spend caps, funding path (fork-tested), module library, idea rewards, idea routing, X wallet links and the sequencer's build loop
Sourceengine/src/brain.tsengine/models.jsonModelsGameFunder.solThe Sequencer map
04Hard limits
The hook is immutable. No proxy admin, no upgrade key, not even for us. These are constants in immutable bytecode. No key can change them, the Safe's included.
- Project fee cap
- 50,000 pips (5.00%): every module's answer is clamped to it. Only the launch tax (blocks 0 to 8) is above it
DNAHook.MAX_PROJECT_FEE - Baseline fee
- 22,000 pips (2.2%) when no module is active or a module fails. With Programmable's fee on top, traders pay 2.5%
DNAHook.BASELINE_PROJECT_FEE - Launch fee
- The baseline slides linearly from 30,000 to 22,000 pips (3% to 2.2%; 3.3% to 2.5% for traders) over the first hour after pool initialization, then stays at 2.2%. It applies only as the baseline/fallback (no module active, or a module failed). The clock is set once, at initialization. Blocks 0 to 8 pay the launch tax instead (90% down to 10%, to BuybackBurn)
DNAHook.LAUNCH_PROJECT_FEE, LAUNCH_DECAY - Platform fee
- 3,000 pips (0.30%) on top: Programmable's launchpad fee, not ours (the share its profile 3.6.0 binds)
DNAHook.PLATFORM_FEE - Canary clamp
- ±10,000 pips (±1 point) around the active fee
DNAHook.CANARY_MAX_DELTA - Supply
- 1,000,000,000 DNA, minted once. There is no mint function, so supply only goes down
DNAToken.SUPPLY - Launch liquidity
- Two positions, both owned by 0xdEaD: the whole supply as one DNA-only position, and the launch buy's DNA with the rest of the launch ETH as one full-range position. Bootstrap reverts unless ownerOf == 0xdEaD for each
Bootstrap.DEAD - Launch buy
- Its DNA is locked in the full-range position. Only the excess the position could not pair, about 47,000 DNA, was burned. Bootstrap ends holding nothing
Bootstrap.initialize - Launch tax
- 900,000 pips (90%) in the pool's first block, 100,000 less each block after: blocks 0 to 8 pay 90% down to 10%, plus the platform fee. All of it goes to BuybackBurn. The launch buy itself pays the normal fee
DNAHook.LAUNCH_TAX, LAUNCH_TAX_STEP, LAUNCH_TAX_BLOCKS - Launch caps
- For 4 minutes after launch: at most 20,000,000 DNA (2% of supply) out of the pool per block, net of sells, and at most 10,000,000 DNA (1%) bought per sending wallet (tx.origin) in all, gross (sells don't count back), enforced from block 4. DNA's own buybacks are never taxed, capped or counted
DNAHook.LAUNCH_BLOCK_CAP, LAUNCH_WALLET_CAP, LAUNCH_CAP_WINDOW - Liquidity lock
- No liquidity can be added for 4 minutes after launch, except by the launch transaction. Removing liquidity is never blocked
DNAHook.LiquidityLocked - Added liquidity
- LiquidityVault only adds; it has no withdraw or decrease path
LiquidityVault.add - Queue
- 1 h minimum delay on every registry op
ModuleRegistry.MIN_DELAY - Split bounds
- Buyback 20–50%, liquidity 20–50%, treasury 10–40%, games 0–20%, summing to 100%. Anything else falls back to 35/35/30/0
FeeVault.currentSplit - Game bounds
- Draws every 12 h–3 d, prize ≤ 3 ETH, per-wallet cap 0.5–2%, idea reward ≤ 25% of the idea reserve
GamePot constants
What can change, inside those bounds: the fee (1%–3.5% at launch), the split, and the game settings.
SourceDNAHook.solDNAToken.solBootstrap.solFeeVault.solLiquidityVault.solSPEC §1 constants
05Where fees go
Fees are taken in ETH, on the swap's ETH leg. The project fee is minted to FeeVault as ERC-6909 claims; the platform fee goes to PlatformRevenue, whose only recipient is Programmable: it is the launchpad's fee, not DNA's.
fee = gross × (projectPips + 3,000) / 1e6 project = floor(gross × projectPips / 1e6) → FeeVault platform = fee − project → PlatformRevenue baseline = 22,000 + 8,000 × (1 h − elapsed) / 1 h for the first hour after initialization, then 22,000
- Swap pays DNA's fee (2.2% baseline, 1%–3.5% tuned) + Programmable's 0.30% (not ours), in ETH
- FeeVault.distribute(), anyone, at ≥ 0.05 ETH
- 35%BuybackBurn: buys DNA and burns it
- 35%LiquidityVault: adds liquidity, never removes it
- 30%Treasury: ETH to the Safe
- 0% nowGamePot: 70% jackpot, 30% idea rewards. Games share turns on later (up to 20%)
- Project fee
- 2.2% default (2.5% with the platform fee); the AI tunes it inside 1%–3.5%
DNAHook.BASELINE_PROJECT_FEE, Launch.s.sol feeBounds - Launch fee
- The baseline slides linearly from 30,000 to 22,000 pips (3% to 2.2%; 3.3% to 2.5% for traders) over the first hour after pool initialization, then stays at 2.2%. It applies only as the baseline/fallback (no module active, or a module failed). The clock is set once, at initialization. Blocks 0 to 8 pay the launch tax instead (90% down to 10%, to BuybackBurn)
DNAHook.LAUNCH_PROJECT_FEE, LAUNCH_DECAY - Platform fee
- 0.30% on top, to an immutable recipient: Programmable's launchpad fee, not ours (Programmable profile 3.6.0)
DNAHook.PLATFORM_FEE, PlatformRevenue.recipient - Launch split
- 3,500 / 3,000 / 2,500 / 1,000 bps (buyback / liquidity / treasury / games)
BaselineSplit.split - Split fallback
- 3,500 / 3,500 / 3,000 / 0 if the split module is rolled back. The games stop; nothing else does
FeeVault.BASELINE_* - Buyback
- ≤ 1 ETH per call, 1 h cooldown (≤ 24 ETH a day), 0.50% price limit. Pays only the 0.30% platform share, no project fee. All bought DNA is burned
BuybackBurn.MAX_SIZE, COOLDOWN - Liquidity adds
- Every ≥ 4 h, an ETH-only range 2,000 ticks wide just above the price
LiquidityVault.COOLDOWN, WIDTH - Games
- GamePot splits arrivals 70% jackpot / 30% idea reserve, each capped at 15 ETH. Overflow goes to the buyback
GamePot.JACKPOT_BPS, POT_CAP, RESERVE_CAP - Who triggers it
- Anyone: distribute, process, add and sync are permissionless. The engine's keepers call them
FeeVault, BuybackBurn, LiquidityVault, GamePot
SourceDNAHook.solFeeVault.solBaselineSplit.solBuybackBurn.solLiquidityVault.solPlatformRevenue.sol
06Holder jackpot
Every DNA holder is in. Tickets are a time-weighted average balance over the draw window, built in the enclave from the full Transfer history and committed on-chain as a Merkle root. One Chainlink VRF v2.5 word, delivered after the list is fixed, picks 10 winners, who split the prize equally (at least 0.25 ETH).
tickets = floor( Σ balance × seconds × mult / (windowSeconds × 10,000) / 1e18 ) mult = 10,000 (×1) for held DNA, the staking weight (×2–×4) for staked DNA eligible iff the unweighted average balance ≥ minBalance cap: find L so every wallet above L gets exactly L and L ≤ capBps / 10,000 × Σ tickets ticket_j = keccak256(abi.encode(rand, j)) mod totalTickets, j = 0, 1, … until 10 distinct wallets (at most 32 tickets) share = prize / 10; unfilled places and dust stay in the pot
- The AI posts the window's rules (cap, minimum, excluded exchanges) with its reasoning, anchored before the window opens
- Window closes; the AI posts root, total tickets and holders
- 1 h veto: the Safe can cancel, a watchdog rebuilds the list
- requestDraw: VRF, 3 confirmations
- anyone settles with the leaf and proof of every ticket the walk draws; one transaction pays all 10
- wallet accepts ETHits share is pushed in the same transaction
- wallet rejects ETHthat winner claims within 7 days, else the share goes back to the pot
- ticket's wallet already won or is excludedskipped; the next ticket is drawn
- Draw window
- 24 h by default; the AI sets it within 12–24 h (the chain allows 12 h–3 d). A window is drawn only if its rules were anchored on-chain before it opened; otherwise its pot carries over
engine/src/games.ts GAME_POLICY.maxInterval, engine/src/jackpot.ts paramsOf; GamePot.MIN_INTERVAL, MAX_INTERVAL - Per-wallet cap
- 2%, or 1% while a draw in the last two windows had 100+ wallets. Wallets above the cap are cut down to it. Chain bounds 0.5% to 2%. The cap is per wallet, so one person can split across wallets
engine/src/tickets.ts capForWindow, CAP_POLICY; GamePot.MIN_CAP_BPS / MAX_CAP_BPS - Too few wallets
- Fewer than 50 eligible wallets: no level fits even a 2% cap, so there is no draw and the pot carries over
engine/src/tickets.ts waterfill - Minimum balance
- 1,000 DNA average over the window (chain bounds 100–1,000,000)
engine/src/jackpot.ts JACKPOT_POLICY, GamePot.MIN_BALANCE_FLOOR / CEIL - List veto
- 1 h after postList; the list must be posted within 24 h of the window's end
GamePot.LIST_DELAY, LIST_GRACE - Winners
- Ten distinct wallets, equal shares, at most 32 tickets drawn. Fewer wallets in the list means fewer winners; the rest stays in the pot
GamePot.WINNERS, MAX_TICKETS, settle - Timing target
- The AI picks the interval so a draw is worth about 1 ETH, up to 24 h, and changes it only when the move is over 25%
engine/src/games.ts GAME_POLICY - Prize
- min(pot − VRF top-up, 3 ETH), and at least 0.25 ETH (0.025 per winner) or the draw waits. The top-up refills the VRF subscription to 0.1364 ETH (the whole 0.1364 ETH while the subscription is empty), so the first draw needs a pot of 0.3864 ETH
GamePot.PRIZE_CAP, MIN_PRIZE, SUB_MIN - Pot cap
- 15 ETH; anything above goes to the buyback
GamePot.POT_CAP - Gas gate
- No draw while the VRF cost would be more than 20% of the prize
GamePot.MAX_COST_BPS - Payout
- Each share pushed with 50,000 gas; the settle reverts rather than starve a push. A failed push becomes a claim within 7 d; after that anyone returns it to the pot
GamePot.PUSH_GAS, CLAIM_WINDOW - VRF stall
- No answer in 36 h: the draw is aborted and the same list is requested again
GamePot.VRF_TIMEOUT - Excluded on-chain
- The Safe, its signers and team wallets, the agent and anchor keys, the protocol contracts, the PoolManager, 0x0 and 0xdEaD
GamePot.isExcluded - Excluded off-chain
- PlatformRevenue, Bootstrap, and exchange wallets listed in the params before the window
engine/src/tickets.ts - Known limit
- The list is fixed before the random number, so a VRF operator who withholds an answer would know the winners first. Bounded by the 3 ETH prize cap
SPEC §13
SourceGamePot.solConvictionVault.solengine/src/tickets.tsengine/src/jackpot.tsPlay: the live pot
07Staking
ConvictionVault holds staked DNA in non-transferable positions. One weight function serves both jackpot tickets and votes.
weight = amount × min(tierMult × streakMult, 40,000) / 10,000 tierMult (hundredths) = 200 / 250 / 300 while the term runs, 200 after streakMult (hundredths) = 125 at 2 d, 150 at 5 d, 200 at 10 d of position age
- Minimum stake
- 10,000 DNA
ConvictionVault.MIN_LOCK - Terms
- 12 h ×2, 3 d ×2.5, 7 d ×3
ConvictionVault.term, tierMult - After the term
- ×2 while it stays staked
ConvictionVault.currentWeight - Streak
- ×1.25 at 2 d, ×1.5 at 5 d, ×2 at 10 d
ConvictionVault.streakMult - Ceiling
- ×4 combined (a 7 d term at a 10 d streak is ×4, not ×6)
ConvictionVault.MAX_MULT - Not staked
- Held DNA counts ×1 for the jackpot. It does not vote
engine/src/tickets.ts - Vote eligibility
- A position votes once it is 12 h old at the ballot's start
ConvictionVault.MIN_AGE - Withdraw
- Any time after the term in force. recommit starts a new term and keeps the streak
ConvictionVault.withdraw, recommit - Who can't stake
- The Safe, its signers, team wallets and the AI's keys
ConvictionVault.lock
08Mutation vote
MutationBoard runs ballots over candidate parameter sets. Votes pick what is tested next, never what is kept: the winner still goes through queue, shadow and canary.
- Cadence
- At most one ballot per 48 h
MutationBoard.BALLOT_EVERY - Veto
- Voting opens 1 h after the proposal. The Safe can cancel a ballot until it is resolved
MutationBoard.VETO_WINDOW - Voting
- 24 h, 3 options
MutationBoard.VOTING - Weight
- vault.weightAt(position, ballotStart): staked positions only, streak included. Re-voting moves your weight
MutationBoard.vote - Winner
- Highest tally; ties and an all-zero ballot go to the lowest index
MutationBoard.winner - Proposer
- The agent (level ≥ 5) or the Safe
MutationBoard.MIN_LEVEL - 1% gate
- The AI proposes ballots only while ≥ 1% of supply is staked. Below that it runs its own picks, labelled "AI pick (votes open at 1% staked)"
engine/src/games.ts ballotMinStakedBps - On-chain record
- ballotRun(ballot, option, registryOpId) while the op is queued, or ballotSkipped(reason)
MutationBoard.ballotRun
09Mystery mutation
A commit-reveal on MutationBoard. The payload is a candidate parameter vector; after the reveal it is gated and tested like any other candidate.
commitment = keccak256(salt32 ‖ payload)
- Seal
- seal(commitment, revealAt), revealAt between seal + 2 d and seal + 7 d. One sealed at a time
MutationBoard.REVEAL_MIN, REVEAL_MAX - Cadence
- The engine seals one a week, set to open 2 d 1 h after the seal
engine/src/games.ts mysteryEveryS - Reveal
- Anyone with the salt and payload (≤ 2,048 bytes), within 24 h of revealAt. After that it can be marked broken
MutationBoard.REVEAL_WINDOW, MAX_PAYLOAD - Outcome
- mysteryRun(id, registryOpId) if it passes the gates, else mysteryRejected(id, reason)
MutationBoard.mysteryRun - Veto
- The Safe can cancelSeal
MutationBoard.cancelSeal - Check it
- The Play page recomputes the commitment in your browser after a reveal
web/app/play/MysteryCheck.tsx
SourceMutationBoard.solPlay
10Idea rewards
GamePot pays idea rewards from its idea reserve (30% of the games share). The brain picks each amount inside the contract caps; every reward is escrowed, waits 1 h in public, and the Safe can cancel it.
- A build ships, or a fee experiment is kept
- The brain signs a reward record and calls queueReward(to, amount, ideaRef)
- 1 h public queue: the Safe can cancelReward
- after 1 hanyone calls payReward: ETH is sent to the recipient
- push failsa 7-day claim, like an unclaimed prize; unclaimed, it returns to the jackpot
- Queue
- queueReward(to, amount, ideaRef) by the agent (level ≥ 5, not paused) or the Safe; the amount leaves the reserve at once, into escrow
GamePot.queueReward - Size
- At least 0.01 ETH and at most 25% of the idea reserve per reward
GamePot.queueReward, MAX_REWARD_BPS, MIN_REWARD - Daily cap
- At most 25% of the reserve queued per rolling day (measured at the day's first queue)
GamePot.MAX_REWARD_BPS, dayBudget - Public hour
- Payable 1 h after it is queued. payReward is open to anyone and pays only while the agent is not paused
GamePot.payReward - Veto
- The Safe can cancelReward until it is paid; the escrow goes back to the reserve
GamePot.cancelReward - Never to
- The Safe, the agent, the protocol's contracts or the excluded list: the same set the jackpot excludes
GamePot.isExcluded - Reserve cap
- 15 ETH; arrivals above it go to the buyback
GamePot.RESERVE_CAP - Who is paid
- IdeaMarket ideas: the submitter's address, read on-chain. X ideas: the wallet the author's X account linked by posting @contractdna and one 0x address, and nothing else (public; any other words make it no link). The first link counts at once and gets one reply; a change takes effect 48 h later, announced on the site. At most 3 link posts a day
engine/src/bindings.ts BINDING_LIMITS, rewards.ts REBIND_DELAY_MS - Hold
- A reward with no linked wallet, or no room under the caps, waits up to 30 days. Then it is dropped and the money stays in the reserve
engine/src/policy.ts REWARD_HOLD_DAYS - Status
- Fee-idea rewards and X wallet links run now. Build-idea rewards start with the Sequencer's first shipped build
engine/src/idea-queue.ts - Events
- RewardQueued, RewardPaid, RewardCancelled
GamePot
11Ideas
Two doors into IdeaMarket: X mentions, filtered by the engine and submitted by the agent at zero stake, or a direct on-chain submit with a stake. Each 24 h round settles on its own.
A = stake on accepted ideas, R = stake on rejected ideas accepted position s → s + floor(s × R / A); rejected → 0; void → s; A = 0 → everyone gets s back
- Post on X tagging @contractdna
- Gate: any account, no links, no duplicates
- Screen: fee / build / impossible / question / chat / joke / shill / spam, scored out of 30; then 1 idea per person per round (live: per UTC day)
- Top 16 of the round submitted at the start of the next
- outcome proposed in timefinal 24 h later unless the Safe cancels; accepted backers split the rejected stakes
- no outcome within 3 danyone finalizes the round as void: every stake refunded
- Round
- 24 h
IdeaMarket.ROUND_LENGTH - Direct submit
- ≥ 10,000 DNA opening stake (refundable) + 1,000 DNA burned
IdeaMarket.MIN_SUBMIT, SUBMIT_FEE - Stake limits
- ≥ 1,000 DNA per stake; ≤ 1,000,000 per address per round; ≤ 2,000,000 per idea
IdeaMarket.MIN_STAKE, MAX_PER_ADDRESS, MAX_PER_IDEA - Slots
- 128 a round: 112 public, 16 for the agent's X intake
IdeaMarket.MAX_IDEAS, MAX_AGENT_IDEAS - Outcome
- The Safe or the agent proposes within 3 d of the round's end; final after 24 h; the Safe can cancel
IdeaMarket.RESOLVE_WINDOW, MIN_DELAY - Lock-up
- At most about 5 d (24 h round + 3 d + 24 h)
SPEC §10.2 - Who judges
- "Accepted" means picked for implementation after research and a red team. The oracle is the team's agent: the brain judges each round and signs the outcome. It is public for 1 h before the agent proposes it on-chain, and 2 Safe owners can veto it; then the Safe has 24 h to cancel
SPEC §10.1, engine/src/ideas.ts
12Genome Vaults
GenomeVaults is an ERC-721 with at most 50 live tokens. A mint locks exactly 200,000 DNA in the contract; a burn returns it with the vault's unclaimed ETH in the same transaction. Only the Safe funds it, over an exact block window of fee inflows, and the ETH is shared per eligible vault through an accumulator.
fund(fromBlock, toBlock): fromBlock must equal fundedThrough (no window skipped or paid twice); value + carry split per eligible vault, the remainder carried pending(id) = accPerToken − max(debt, accAfter[mintSeq + 1]); a vault minted since the last fund earns from the one after it
- Live vaults
- At most 50; a burned slot goes to the next mint, lowest free slot first
GenomeVaults.MAX_LIVE, _takeSlot - Deposit
- Exactly 200,000 DNA per mint, returned in full by burn; nobody else can move it
GenomeVaults.DEPOSIT, mint, burn - Funding
- The Safe only, over the block window since the last fund, finalized blocks only. The signers decide the amount; their script proposes half of the treasury's fee share in the window
GenomeVaults.fund, engine/scripts/vault-fund.ts - Eligibility
- A vault joins at the first fund after its mint and earns from every fund after that
GenomeVaults.pendingCount, eligible - Transfer
- A standard ERC-721; unclaimed ETH stays with the vault, so a buyer gets it. 2.5% royalty to the Safe
GenomeVaults.ROYALTY_BPS - Admin
- No owner mint, no upgrade. The Safe can pause new mints only, never a burn or a claim
GenomeVaults.setMintPaused - Art
- 50 images, one per slot, named in on-chain metadata with a strand that grows with what the vault earned
GenomeVaults.tokenURI - On X
- Every mint, fund and burn is a plain post with its transaction; a reply about the vaults states only what the contract says
engine/src/vaults.ts
The vaults earn only what the Safe sends. A fund is a signed Safe transaction over a public block window; nothing here is automatic, and nothing is promised.
SourceGenomeVaults.solengine/src/vaults.tsengine/scripts/vault-fund.tsVaults: the 50 slots, the contract and the collection
13How to check us
Three things are checkable: where the agent key lives, which code holds it, and what it decided. None of it is needed for the safety of your tokens; the contracts bound every key.
- Enclave
- The agent key is made and kept inside an Intel TDX machine on Phala. Phala's key service releases it only to code on the on-chain allow-list
/proof - Allow-list
- A DstackApp on Ethereum owned by a 1 h timelock: the first code version is allowed when the app is created, every later change waits 1 h in public, and only the Safe can propose or cancel one
/proof - Status
- Live since 11 Oct 2026. The release record (image digest, compose hash, measurements, log key) is pinned, and /proof checks a fresh quote against it
/proof - Records
- Every decision is an enclave-signed record: the model's output plus the chain data it judged, by block hash
engine/src/records.ts - Brain decisions
- Signed records carrying the model and the sha256 of its context and input
engine/src/brain.ts - Models
- The public registry lists every role's model and backup (table on /models). These are the default models. A swap is a signed model-change record: a public tryout on fixed test cases, then a public hour, and the Safe can veto. Swapping the brain itself needs two Safe owners to approve
engine/models.json - Anchors
- anchor(root, uri) on ModuleRegistry. The agent's queue ops wait until their record's anchor is mined; each day's log head is anchored too
ModuleRegistry.anchor - In your browser
- /proof checks a fresh TDX quote, the compose hash and any record's signature
web/app/proof - From the CLI
- node scripts/verify.ts checks the same against Intel's collateral service
engine/scripts/verify.ts - Jackpot lists
- A separate watchdog with no keys rebuilds every ticket list and pages the Safe on a mismatch
engine/scripts/watchdog.ts - Not claimed
- That a text really came from a given model, or that the system is "trustless". Trust remains in Intel TDX, Phala's governance and the Safe
/proof
SourceProof pageModelsModuleRegistry.solengine/scripts/verify.ts
14The Safe
The Safe is a 2-of-3 multisig whose address is immutable in every contract. Its fast powers only stop things; anything else it does goes through the same public 1 h queue as the agent.
- Instant brakes
- cancel any queued op, pauseAgent, lowerLevel, rollback, endCanary
ModuleRegistry.cancel, pauseAgent, lowerLevel, rollback - Game vetoes
- cancelList (jackpot), cancelBallot, cancelSeal, cancelReward, cancelDrawInterval, cancelOutcome (ideas)
GamePot, MutationBoard, IdeaMarket - Queued like anyone
- register modules, set parameters, promote, raise the level, rotate the agent key, approve bytecode: all public for 1 h first
ModuleRegistry.queue - Cannot
- Change any constant (5% cap, supply, queue delay, split bounds), alter the hook, remove liquidity, move anyone's DNA or staked DNA, or take the jackpot or the idea reserve
SPEC §1, §13 - Receives
- The 30% treasury share of project fees, in ETH
FeeVault.distribute - Also
- Telegram /halt, /mute and /delete for signers: they only stop the engine or its posting, or remove one of its own posts
/proof
15Risks
Read this before you buy, stake or submit anything.
- Price
- DNA can lose all its value. Nothing here promises a price or a return
- Code
- The contracts are new. They have tests, fuzzing, invariant suites and static analysis; no third-party audit is published in the repo
contracts/audit/slither.md - The fee
- From level 6 the AI can move the live fee anywhere in 1%–3.5% once an hour, with no step limit
SPEC §3 - Jackpot
- A random draw. The prize is capped at 3 ETH and draws pause when the pot or the gas makes them uneconomic. It is not a yield
GamePot - Idea market
- Stakes on rejected ideas are lost. Funds can be locked about 5 days. The judge is the team's agent and the Safe can veto
IdeaMarket - Sequencer
- AI-written contracts can have bugs. The gates and the Safe lower the risk without removing it. New games start without user deposits
- Dependencies
- Intel TDX, Phala, Chainlink VRF, Uniswap v4, Programmable, the three Safe signers and the AI model providers
- Uniswap
- A future Uniswap protocol fee would apply on top of DNA's fees
SPEC §2 - Other pools
- Anyone can open another DNA pool (Uniswap v2, v3 or v4 without DNA's hook, or another exchange), and nobody can stop it. Trades there pay nothing to the buyback, liquidity, treasury or games; their fees go to whoever funds them. Wallets and aggregators may route through them when they quote better, or before they support the hook. Only the pool on the trade page funds DNA; the engine lists every other one it finds there, with the share of volume they take
DNAHook._beforeInitialize - Who can play
- 18+. You decide whether the games are legal where you live