Introducing Mayavi: Tokenomics Simulation with Real Mainnet in the Loop
A forked-EVM, agent-based, RL-trainable engine that produces VC-grade tokenomics reports — and proves it with bit-exact replays of real on-chain events.
Part of the Foundations series.
Token launches get modeled in spreadsheets. Spreadsheets do not catch oracle shocks, cascade liquidations, or the 14-decimal divergence between a textbook swap and what actually clears on Uniswap V3 at a specific block. Mayavi is the engine we built to close that gap: a simulator that drives real mainnet EVM state through real protocol contracts, agent by agent, step by step, with a Gymnasium-compatible RL surface on top.
This post is the first in a 15-part series. Each later post zooms in on one piece — a protocol adapter, an RL training run, an incident replay, or the deployment that ties it all together. This one is the map.
What Mayavi is, in one breath
Three sentences:
- Forked mainnet, not mocks. Every run is a
pyrevmfork of a pinned block on a real chain. The Aave V3 Pool you call is the Aave V3 Pool that was deployed at that block. - Agent-based. Borrowers, liquidators, oracle-shock injectors, and
vesting recipients are just
Agentsubclasses scheduled by a PSUB-style loop. Add a new behavior and it composes with the rest. - Gym-trainable. The same simulation step that produces the HTML report
is also a
gymnasium.Env.step(). A PPO policy trains against the literal on-chain protocol — no synthetic reward function approximating it.
Why fork mainnet
The cheapest way to write a tokenomics sim is to mock the swap, mock the oracle, and use a textbook AMM curve. It runs in milliseconds and it lies in basis points. Real Uniswap V3 has tick liquidity gaps; real Aave has interest accrual that depends on the exact block; real chainlink oracles round to 8 decimals in places you don't expect.
Mayavi pays the cost of forking real state because that is the only way to make a claim like the one below survive an adversarial review.
A later post in this series ("The Credibility Wall") walks through the EIGEN replay end-to-end. The point here is that bit-exactness is a feature, not a marketing slogan, and the credibility of every other claim depends on it.
What's in the engine
A six-layer stack, each thin enough to fit in a session:
| Layer | Lives in | What it does |
|---|---|---|
| EVM kernel | mayavi/evm/ | pyrevm fork wrapper + storage cache + ABI helpers |
| Simulation | mayavi/sim/ | PSUB-style scheduler, state, hooks (e.g. MarketSnapshotHook) |
| Agents | mayavi/agents/ | Agent ABC, reference borrowers / liquidators / vesting recipients |
| Protocols | mayavi/protocols/ | Aave V3, SparkLend (Aave V3 fork), Compound V3 (Comet), Curve StableSwap |
| Chains | mayavi/chains/ | Per-chain registry — addresses + identity dispatched by chain_id |
| Gym + RL | mayavi/gym_env/, mayavi/rl/ | gymnasium.Env wrappers; Ray RLlib local + Modal A10G |
A run produces three things: a self-contained Plotly HTML report, a
machine-readable eval.json digest, and (if you ask) an OG image plus a short
screencast. Everything ships through the same bundle pipeline (mayavi artifact <run_id>) so it doesn't matter whether the consumer is a human
reading the report, a website embedding the report, or a CI job parsing the
JSON.
What it covers right now
A 21-bundle matrix across six EVM chains and four protocols, all rendered on the same shape-aware report template:
| Metric | Value | Note |
|---|---|---|
| EVM chains | 6 | mainnet, BNB, Polygon, Arbitrum, Base, Optimism |
| Protocol adapters | 4 | Aave V3, SparkLend, Compound V3 (Comet), Curve StableSwap |
| Scenario types | 19 | borrower, depeg-cascade, vesting-cliff, launch-replay, ... |
| Committed bundles | 21 | report.html + eval.json per bundle |
| Unit tests | 1,523 | every push (CI quota permitting) |
| Sim-to-real gates | 7 / 7 | Quoter bit-exact, replay, depeg, vesting, fork-cache, determinism, gym-env |
The Aave V3 mainnet borrower run lives below. It is a four-step run against the real Aave V3 Pool at block 19,000,000; the borrower's health factor, debt, and collateral are read from on-chain storage, not modeled.
- run_id
- 15e7ab737034
- generated_at
- 2026-05-14T13:45:57+00:00
- scenario.name
- aave_borrower_demo
- scenario.protocol
- aave-v3
- scenario.chain
- mainnet
- scenario.chain_id
- 1
- scenario.fork_block
- 19,000,000
- scenario.horizon_steps
- 4
RL findings, in advance
Three policies have been trained against real on-chain state so far. The honest summary:
We deliberately publish the ones where the heuristic wins. A simulator that can't reproduce a known-good policy is not credible as a tool for finding new ones.
The four pillars
Every PR in the repo ships five things together, called out under their own headings in the PR body:
- Code — the change itself.
- Tests — unit (
pytest -m "not fork and not slow"), fork (pytest -m forkagainst a pinned block, nightly), slow, modal as applicable. - Validation — a measurable assertion: delta < X bps, coverage ≥ Y%, exit 0, schema check.
- Verification — the exact commands a reviewer can run.
- Documentation — which docs changed.
No "tests later." No follow-up PRs for missing pillars. This is the discipline that makes the bit-exact claim above survive audit.
What's next in the series
The remaining 14 posts:
- Foundations (2 more): Why fork mainnet vs mock, and an architecture tour of the agent scheduler + Gym wrapper.
- Protocol coverage (4): Aave V3 dispatch across six chains, Compound V3 Comet, the SparkLend thin-adapter pattern, and Curve StableSwap depeg cascades.
- RL agent reports (3): Borrower training (local vs Modal), the vesting saturation story, and the liquidator vs heuristic showdown.
- Incident replays (2): EIGEN Season 1 end-to-end, ENA vesting cliff.
- Platform & pipeline (3): The 21-bundle matrix, why determinism is a feature, and the Modal + Vercel + DuckDB deployment.
Subscribe via the RSS feed, or read along as posts ship.