How Darwinian works
The complete architecture of a self-evolving trader swarm — from the parent orchestrator’s tick loop down to a single child agent placing a perp trade and paying its own gas in USDC.
The parent tick
Every SWARM_TICK_INTERVAL_SECONDS (default 300s), the parent runs one orchestrator pass:
- Fetch a market snapshot from Hyperliquid’s public
infoendpoint. - For every living child, run
decideChild(agent, market)— a DNA-weighted decision that may open, close, or skip a trade. - Score every child via
scoreAgent(). - Terminate the bottom 10% by Sharpe × (1 − maxDD).
- Mutate the top
SPAWN_FROM_TOP_Ksurvivors’ DNA using Claude Opus and the dead-siblings lineage as input. - Create a Circle Wallet for each new child via
createChildWallet(agentId); fund withCHILD_CAPITAL_USDC. - Park anything above
TREASURY_IDLE_THRESHOLD_USDCin USYC for yield.
The tick is exposed as POST /api/tick; the dashboard button at the top of the home page triggers it manually for demos. In production it’s a Vercel scheduled function.
Agent DNA
DNA is a fixed-shape genome of 10 traits. The mutation space is small enough that the LLM produces coherent variants and big enough that drift across generations is meaningful.
| trait | range | meaning |
|---|---|---|
| leverage | int 1..10 | position leverage on the venue |
| timeframe | 1m / 5m / 1h / 4h | decision cadence |
| momentum | 0..1 | weight on directional follow-through |
| meanRev | 0..1 | weight on inverse-momentum |
| funding | 0..1 | weight on funding-rate basis |
| sentiment | 0..1 | weight on news/sentiment proxy |
| stopLossPct | 0.5..5 | leveraged stop |
| takeProfitPct | 0.5..10 | leveraged target |
| positionSizePct | 1..25 | % of bankroll per trade |
| riskOffDrawdownPct | 5..30 | drawdown → park to USYC |
The four signal weights (momentum, meanRev, funding, sentiment) sum to ~1.0 — they’re a probability distribution over decision sources, not free knobs.
Fitness function
We use a cheap, transparent metric: Sharpe × (1 − maxDrawdown) over the agent’s trade history. Reasons:
- Sharpe captures risk-adjusted return.
- The (1 − maxDD) multiplier punishes blow-ups that Sharpe alone forgives.
- Cohort-normalized so the bottom decile is meaningful even on flat days.
For production we’d switch to time-weighted returns and add a turnover penalty; the proxy above is enough for the hackathon window.
Mutation engine
src/swarm/mutation.tscalls Claude Opus 4.7 with the parent’s DNA and up to five recently-terminated siblings in the same lineage. The system prompt tells the model to:
- Diverge from traits correlated with dead siblings.
- Preserve traits correlated with survivors.
- Mutate 2–4 traits meaningfully; carry the rest forward.
- Respect bounds (leverage 1..10, weights sum to ~1).
- Return a short rationale string so we can audit.
If ANTHROPIC_API_KEY is unset, the engine falls back to a deterministic local heuristic (jitter weights, nudge leverage away from dead average). The fallback lets the swarm tick run end-to-end in dev without paying for tokens.
Circle Wallets — per-agent custody
Every child gets its own developer-controlled Circle Wallet at birth. Architecture:
src/circle/client.ts— singleton initialized withCIRCLE_API_KEY+CIRCLE_ENTITY_SECRET; blockchain pinned toARC-TESTNET.src/circle/wallets/factory.ts— lazily creates a wallet set on first use, thencreateWallets({ blockchains: ['ARC-TESTNET'], count: 1 })per child.src/circle/wallets/balance.ts— reads USDC balance for any walletId viagetWalletTokenBalance.- Without creds, the factory returns a deterministic mock so the demo never bricks.
One wallet per agent means: every trade, every gas charge, every PnL movement is provable from onchain transfers — no shared custody noise.
Child trading loop
decideChild() in src/swarm/child.ts runs a tiny three-step logic:
- Risk-off check. If realized drawdown ≥
dna.riskOffDrawdownPct, skip the tick. - Open-position management. If a position is open, compute leveraged move; close if stop-loss or take-profit triggered.
- New position scan. Score every tracked asset by
dna.momentum·momentum1h + dna.meanRev·(-momentum1h) + dna.funding·(-fundingRate) + dna.sentiment·noise. Open the highest-magnitude signal that clears the threshold; size bypositionSizePctof bankroll.
The perps venue is Hyperliquid for reads (public infoendpoint, no auth) and trade execution (EIP-712 signing wallet funded from the child’s Circle Wallet via CCTP/Gateway when the venue is on a different chain).
Lineage memory
Every termination produces a TerminationReport: dna, trades, PnL curve, Sharpe, maxDD, causeOfDeath. The report is pinned to IPFS via Pinata; the resulting CID is emitted as an AgentTerminated(agentId, cid) event on the on-Arc LineageRegistry contract.
New children read their immediate predecessors’ reports at birth and pass them into the mutation prompt. Lineage memory is therefore not a database — it’s an addressable, replayable sequence of cause-of-deaths anyone can audit.
explore lineage trees →Treasury — USYC + Gateway
The parent treasury is a single logical balance composed of three things:
- USDC — dry powder, ready to fund the next generation.
- USYC — idle capital parked for yield via the USYC Teller. Withdrawn just-in-time when a spawn cycle needs the funds.
- EURC — buffer for FX agents to take USDC↔EURC legs via StableFX.
The dashboard surfaces a single Unified Balance via Circle’s Gateway — operators see one number, regardless of which chain the capital is on.
Stack at a glance
- Frontend · Next.js 16 (App Router), Tailwind 4, EB Garamond + Geist.
- Agent runtime · TypeScript, Anthropic SDK (Opus 4.7 parent mutation engine, Sonnet 4.6 reserved for child reasoning).
- Onchain · Arc Testnet (chain id 5042002), Circle Wallets SDK, CCTP v2, Gateway, Paymaster.
- Contracts · Solidity + Foundry, deployed via ARC CLI.
LineageRegistry+TreasuryVault. - Storage · IPFS (Pinata) for termination reports; on-Arc registry for CIDs.
- Perps · Hyperliquid primary, dYdX fallback.
- Indexers · Envio / Goldsky available — see indexers.
- AA · ERC-4337 optional via Pimlico / Zerodev — see AA providers.
Non-goals
- Beating a specific benchmark over a specific window — fitness is relative; the swarm explores, it doesn’t back-test.
- Human-in-the-loop dashboards. Operators can watch and emergency-stop, but no human signs trades.
- Long-running monolith children. Children are cheap, disposable, and replaced often — that’s the substrate exploit.
- Cross-chain other than via CCTP / Gateway. Arc is canonical; other chains are venues, not homes.