Shadow mainnet
Myelin’s own mainnet pool is new and starts empty. The Shadow page shows what it would have charged there: it takes the real swaps of real mainnet pools and replays them through Myelin’s model and policy. It only reads. This page explains how, how it was checked, and what it can and cannot tell you.
A fee is not a return
The Shadow page compares fees. A different fee would have changed who traded and how much, so it says nothing about what liquidity providers would have earned. That question is the one the backtest asks, and its answer does not support a claim that liquidity providers would have earned more.
What you see
For one pool at a time, the last 150 swaps: the fee each swapper paid, and the fee Myelin would have charged for the same swap. Four figures sum it up (the mean fee of each, weighted by the size of the swaps; how often Myelin would have charged more; how often it would have sat at its floor or cap), then a chart, with a table behind it, of every swap.
How it is computed
- Read. The
Swapevents of Uniswap’s PoolManager (0x8366a39CC670B4001A1121B8F6A443A643e40951) for one pool id: the newest 663 swaps, and the time of each block. Each event holds the tick after the swap and the fee the swapper paid. - Seed. The oldest swap only seeds the memory, the way
afterInitializeseeds a pool’s memory with its first tick and time. - Replay. For every later swap, the eight numbers the pool would have remembered (from its earlier observations and the time of this swap) go through the model, and the policy turns its output into a fee; then the memory takes in the swap if it is an observation, that is, if the tick is 3 or more ticks from the last observed one and the block is later than the last observation’s. This is the integer code of the hook, in its TypeScript copy: How the fee is set describes each step.
- Warm up. The first 512 swaps only warm the memory up; the 150 swaps after them are the ones shown. The slowest average (weight 1/64 per observation) needs about 190 observations to settle, and within 512 swaps the pools make roughly 220 (HOOKR / ETH), 160 (TORCH / ETH), 70 (NVDA / USDG) and 24 (ETH / USDG), so in the deepest pools it is still filling when the window starts. The research treated the first swaps of every pool the same way, and what the network mostly reads, the time between observations, settles much sooner.
- Compare. The fee paid against the policy’s fee (0.0516% to 0.4127%), swap by swap. The size of a swap is what the swapper paid, valued at the pool’s price after the swap, in USDG for the dollar pools and in ETH for the token / ETH pools; it weights the averages.
The pools
The four pools of the research, each verified on chain (docs/SOURCES.md): the model was trained on all four and its policy was tuned on the first.
| Pool | Its own fee | Hook | Size counted in |
|---|---|---|---|
| ETH / USDG | dynamic, set on every swap | not Myelin | USDG |
| NVDA / USDG | static 0.01% | none | USDG |
| TORCH / ETH | static 0.30% | none | ETH |
| HOOKR / ETH | static 0.25% | none | ETH |
What it can tell you, and what it cannot
It can tell you how the fee schedule of Myelin compares with the one a real market had, in a window you can look at swap by swap: the range it moves in, how often it would have sat at its floor, and how it reacts to a price that jumps. It cannot tell you:
- What liquidity providers would have earned. A higher fee drives some volume away and a lower one attracts some; and a fee’s job is to pay for the swappers who know where the price is going, which this does not measure.
- That the policy fits the pool. It was tuned on ETH / USDG alone. On NVDA / USDG the pool charges 0.01% and Myelin’s floor is 0.0516%, so Myelin charges more on every swap, by construction; that is a fact about the tuning, not about the pool.
- A trend. The window is minutes in a busy pool and hours in a quiet one.
- Like with like. The fee paid is the one in the swap’s event: the pool’s own fee and, where Uniswap has set one, its protocol fee. Read from the pools on 2026-10-21, the protocol fee was 0.0025% on NVDA / USDG, 0.05% on TORCH / ETH, 0.04% on HOOKR / ETH and none on ETH / USDG, in both directions. The policy’s fee is Myelin’s own, before any protocol fee.
- A pool you could use. A Myelin pool on mainnet would be a new pool beside these, with its own liquidity, and the pools these swaps came from stay where they are.
How it was checked
- Against the research and the contracts. The memory is checked on four sequences of 400 real swaps, one per pool, and on scripted cases that include swaps which are not observations: the eight inputs before every swap and the packed memory after it equal the Python reference and the contracts, bit for bit, and so do the model and the policy on their own vectors.
- In the tests.
npm run checkcompares the list of pools with the research’s manifest, and the replay of the page with the replay of the contracts on the golden sequences of the state machine.
Repeat it
The page reads in your browser, through the public RPC, and sends nothing anywhere. You can read the same swaps and replay them in a terminal, with Foundry and Node 22:
cast logs --rpc-url https://rpc.mainnet.chain.robinhood.com --address 0x8366a39CC670B4001A1121B8F6A443A643e40951 --from-block <block> --to-block <block + 1000> "Swap(bytes32 indexed id,address indexed sender,int128 amount0,int128 amount1,uint160 sqrtPriceX96,uint128 liquidity,int24 tick,uint24 fee)" 0xbac3aa3b91584a53a579b3c999a56756e954e59247e497bad1d25a4334bde551
npm run shadow -- eth_usdg
Where the data comes from
The page is built with a snapshot of the four pools, taken when the site was built, so it paints at once and says so (Snapshot, with the time). In the background it reads mainnet again through the public RPC (https://rpc.mainnet.chain.robinhood.com); the first read of a pool takes up to a minute, because the public RPC does not put block times in its logs and limits how fast blocks can be read, and a pool read less than ten minutes ago is not read again. A build can point the page at a faster provider of your own with NEXT_PUBLIC_MAINNET_RPC_URL.
Nothing is ever sent to mainnet: no transaction, no deployment, no wallet. See Risks for what can go wrong with Myelin itself, and Networks and addresses for where it is deployed.