Independent measurement · v18 · corrected 2026-09-04

Nine tokens, one chain, one day, one size
Six came back at 93% or more. Three did not.

A price oracle tells you what something is worth. This measurement tells you whether you can sell it, and what it costs when you do. On 2026-09-04 this page reported that a $100,000 sale of QQQ returned 0.03%. On 2026-09-25 the same measurement, run at block 72,245,711 against every venue we could enumerate, put the cost of the same sale at 0.35% — and SPY at the same size at 0.41%. What changed between the two dates is not the market; it is the list of venues we were looking at (error 12).

Tokenized QQQ · corrected after publication
$99.90
Best among the venues we enumerated at block 54,088,399 (2026-09-04); method and windows are in error 12, and we do not claim that list is exhaustive. This page first reported that selling $100 of QQQ returned $6.46. Quoted against every pool in the v4 PoolManager at the same block, it returned $99.67: the pool that wins at that size cannot fill the $10,000 probe that selects our pool table, so it was never a candidate — error 11. A second AMM deployment on this chain was outside that scan: on a round trip it returned 99.90% at $100 and $99,736 at $100,000, where the v4-only figure was $30; a one-sided sale returns less — error 12. USDG-quoted pools only.
Prediction markets · one-sided
52.2%
Of 596 books checked: you can buy in, you cannot get out
Same screen, same asset class
0.35%
Two dates, two scopes. On 2026-09-04 this page reported 0.03% returned for a $100,000 QQQ sale. Re-measured on 2026-09-25 at block 72,245,711, against every venue we could enumerate, the same sale costs 0.35%; SPY at the same size costs 0.41%. The gap is our enumeration, not the market (see error 12).
Finding one · On-chain aggregators

Asking one aggregator can overstate the cost by an order of magnitude

Published slippage figures almost always come from a single aggregator. This measurement queries six at once: CoW, KyberSwap, ParaSwap, 0x, 1inch and LiFi. Same moment, same token, same notional size, taking the best result a buyer could actually get.

The gap is not a few basis points. It is several times over.

Ethereum · 2026-08-31 · sell side · median price impact relative to the $100 tier. "No quote" means the source explicitly declined to price that size. That is a measurement, not a failed call.
TokenSizeParaSwap onlyKyberSwap onlyBest of six
LDO$100,000−11.29%−4.22%−0.71%
LDO$1,000,000no quote−85.14%−8.51%
PENDLE$100,000no quote−6.61%−0.79%
PENDLE$1,000,000no quote−60.23%−49.12%
CRV$100,000−6.06%−2.38%−1.82%
MKR$100,000−3.99%−1.01%−1.01%
UNI$1,000,000−6.65%−1.94%−1.21%
AAVE$1,000,000−3.58%−2.38%−1.06%

The extreme case is LDO at $1M: KyberSwap alone reports −85%, best-of-six is −8.5%. Anyone writing "on-chain liquidity is terrible" from a single source is off by a factor of ten.

And the best source changes with size

This is not a question of one aggregator being consistently better. Change the notional and the winner changes:

Best-quoting source at each size tier. LDO and PENDLE switch from 1inch to CoW at large sizes. CoW runs batch auctions with solver quotes, which is not strictly comparable to immediate AMM routing; that caveat travels with the data.
Token$100$1,000$10,000$100,000$1,000,000
WETH1inch1inch1inch1inch1inch
LINK1inch1inch1inch1inchKyberSwap
MKRKyberSwapKyberSwapKyberSwapKyberSwapKyberSwap
CRV1inch1inch1inch1inchKyberSwap
LDO1inch1inch1inchCoWCoW
PENDLE1inch1inch1inch1inchCoW

Solana: an exit ladder from a single source

Jupiter is the only quotable source on Solana, so the figures below are subject to the finding above and probably overstate the true cost. They are included because the magnitudes still say something.

SOL−0.13%
TRUMP−8.38%
PENGU−9.65%
WIF−26.71%
BONK−87.21%
PYTH−92.90%
JTO−93.41%
JUP−97.17%
Price impact on a $1,000,000 sell relative to the $100 tier · Jupiter · 2026-08-31 · ~102 samples per cell

A note on what these numbers mean. "−92.90%" means: at current on-chain liquidity, a sell order of that size would be filled down to that level. It does not mean "you will lose 92%". An order that size would most likely be refused rather than filled, and you can split it or route through a CEX. What the number tells you is the cost of dumping it in one go, and that at $1M these tokens have no executable market at all.

The $10,000 tier is closer to a real position: BONK −28.70%, PYTH −15.25%, WIF −3.40%, JTO −2.42%. All are CEX-listed tokens with meaningful daily volume.

Finding two · Tokenized stocks · corrected

The previous version of this section was wrong

Everything this section said in the version published on 4 September is void: that six of eight tokenized stocks could not be sold, that $100 of SPY returned $0.90, and that AAPL fell off a cliff above $1,000. None of it holds.

The cause was mine, not the market's. The scan that builds the pool table silently skipped block ranges that failed. It found about 55 pools where the chain has 25,122, and the handful it did find were mostly the shallow ones. I measured those and reported the result as a property of the asset.

What the earlier version published, against a re-measurement of the same thing. These figures are shown only so the size of the error is visible without going back to the superseded page.
ClaimPublished (v17)Corrected
SPY, sell $1000.90% · PUBLISHED IN ERROR99.93%
AAPL, sell $10,0002.82% · PUBLISHED IN ERROR99.85%
Tokens that cannot be soldsix of eight · PUBLISHED IN ERRORone of nine

What changed in the method

  • Complete pool table. The scan now aborts on any failed block range instead of skipping it. Of 25,122 initialised pools, 1,027 pair a stock token with USDG; 125 of those can fill $10,000. The eight that return the most are kept per token. Selection is reproducible: build_pool_table.py.
  • Same-pool round trip. Buy in one pool, sell the whole position back through that same pool. The previous method took the best buy pool and the best sell pool separately and derived a rate between them; that rate belongs to no actual pool and produced recovery figures above 100%, which cannot persist. A closed loop needs no rate assumption and must come in under 100%.
  • Nine tokens, USDG-quoted pools only. AMC was absent from the earlier table because its pools were among those the broken scan missed.

Corrected measurements

Twelve rounds over 5.1 hours, every 30 minutes, each pinned to a single block. Every size filled in every round; nothing was unquotable. Where a figure moves between rounds, the p10–p90 range is given underneath.

Robinhood Chain (chainId 4663) · 12 rounds, one every 30 minutes · 2026-09-04 07:30 → 12:42 UTC · blocks 54,088,399 → 54,270,401. Same-pool round trip: buy with USDG, sell the whole position back through the same pool — both legs are quoted against the same block’s book, so this is the cost of trading against a static book, not a realised round trip, and that is why the figure degrades with size (see error 13). Median share of notional recovered, with the p10–p90 range. No round failed to fill at any size, so the "could not fill" count is zero throughout and is omitted.
Token$100$1,000$10,000$100,000
SPY99.93%99.93%99.91%99.71%
AAPL99.93%99.92%99.85%99.06%
GOOGL99.99%99.95%99.53%97.97%
NVDA99.99%99.89%99.48%96.50%
TSLA99.89%99.77%99.07%96.75%
RDDT99.32%99.32%99.24%93.12%
90.1–96.6
AMC99.75%99.62%97.08%
86.1–99.0
74.55%
28.5–83.6
GME99.49%99.37%97.97%
36.9–98.6
17.33%
3.7–22.5
QQQ6.46%1.83%0.26%0.03%

QQQ is where this table's own method shows its limit. At the $100,000 rung this table reports 0.03%, and that figure is v4-only: a second AMM deployment on the same chain returned 99.90% at the same block (error 12). At $100 and $1,000 this table was wrong — the excluded pool wins there, and quoting it lifts those rungs from 6.46% and 1.83% to 99.67% and 98.62%. The reason is in how the table is built: pools are selected with a $10,000 probe, and a pool that cannot fill $10,000 is dropped before it is ever a candidate. The pool that wins QQQ at small sizes is one of those — it is absent from the table by construction, not by accident.

Quoted instead against every initialized QQQ/USDG pool in the v4 PoolManager, at three pinned blocks — the all-venues figures are in error 12:

block$100$1,000$10,000$100,000
54,088,399 (09-04)99.67%98.62%0.26%0.03%
61,129,566 (09-12)99.29%99.21%91.11%0.03%
70,427,772 (09-23)97.34%2.19%0.35%0.04%

The pool that serves the small sizes is one contract, 0xf9568ec0… (fee 0.30%), and its capacity — the largest notional it will quote — went $9,841 → $10,506 → $287 across those three blocks: a fall of about thirty-four times in nineteen days, after rising once first. So the size QQQ can absorb is not a property of the token. It is however much capital someone is willing to leave in a cheap pool. At the $10,000 rung alone the answer went 0.26% → 91.11% → 0.35%, a factor of more than three hundred. Naming a collapse threshold would be naming one day's reading.

Unaffected: every other token on this chain returns at least 93% through the $10,000 size; at $100,000 only GME and AMC fall further, to 17% and 75%. Both statements were re-checked against the chain at the same blocks and hold.

GME and AMC are where size still bites, and they are the two tickers retail sentiment concentrates in. Both are fine up to $1,000. GME at $100,000 returns 17% and never exceeded 23% in any round; AMC at the same size ranges from 28% to 84% depending on when you ask. The medians alone would hide that: the reason both carry a range is that a single number would misrepresent them.

One observation, not yet a finding. Both GME and AMC improved markedly during the window — GME at $10,000 went from about 30% to 98% and stayed there, while AMC at $100,000 climbed steadily from 18% to 83% without reversing. The two shapes are different enough that they are unlikely to share a cause, and neither is explained by anything measured here. This is a single day's observation. Whether it repeats is not something one session can establish, and it is recorded here as an open question rather than a result. As of 2026-09-06 GME has reverted below 25% at $100,000 and is still falling; the shape does not persist. That is being measured and will be reported separately.

Update, 2026-09-14. The direction held and the path was not straight. GME at $100,000 fell from a daily median of 95.3% on 2026-09-05 to 5.1% on 2026-09-14, measured over 48 rounds a day, but not monotonically: it rose on 09-11, 09-12 and 09-14, reaching 15.1% on 09-12 before falling back. The sentence above is a point-in-time reading and holds as of its own date.

Reproducibility

You do not have to trust me. Run it yourself.

Every figure above comes from an on-chain call, and an on-chain call at a given block height is deterministic: the same inputs produce the same output for anyone, at any time, in any language.

So each round of measurement emits a hash whose preimage contains only fields a third party can reproduce exactly:

Canonical preimage, rhdepth-v2. Integers are hashed as decimal strings: uint256 exceeds JavaScript's safe integer range, and passing them as numbers loses precision silently. Each round yields 36 canonical records (9 tokens × 4 sizes, one closed round trip each); the run makes many more calls than that, probing every candidate pool, but only the winning pool's figures enter the hash.
In the hashWhy
Block heightState anchor
poolIdIdentifies the pool
Input amount (raw integer)Call parameter
Midpoint amount (raw integer)Tokens received before selling back
Output amount (raw integer)Chain return value, deterministic
StatusFilled / insufficient liquidity
Timestamps, network latency✗ excluded: nobody else can reproduce them
Slippage, recovery and other derived floats✗ excluded: float serialisation differs across languages

Verified in practice: replaying every round trip independently for the first v2 round (block 54,088,399) reproduces the recorded hash byte for byte.

Run it yourself

This page ships with the raw data and the verification script, with no third-party dependencies (code/evm.py is a from-scratch implementation needing only Python 3 and curl):

Every figure on this page corresponds to a snapshot of 12 rounds ending at block 54,270,401, published as data/snapshot-v18-12r/. That directory does not change after publication, so its checksums will always match. Collection continues in the dated live directories under data/, which grow past what this text describes.

You need an archive node for Robinhood Chain to recompute the published snapshot (historical eth_call). The public endpoint rpc.mainnet.chain.robinhood.com keeps only a short rolling window of state: between about 3,100 and 5,900 blocks — roughly five to ten minutes — observed across 2026-09-11 to 2026-09-15. The window moves, and different state-reading methods have disagreed at the same depth, so treat it as a range rather than as a figure. An archive endpoint has no such window. Corrected 2026-09-15: this paragraph previously said "~128 blocks" — about thirteen seconds — understating the window by a factor of twenty-four even at the lowest value observed. A round taken within that window can therefore be recomputed against the public endpoint with no key and no archive access.

export RHCHAIN_RPC="https://<archive endpoint>" python3 code/verify.py 54088399

What this gives you is verifiability, not decentralization. The right to publish these hashes is centralised, and that is a fact. But it does not ask you to trust the publisher: replay the block, and it either matches or it does not. The thing being trusted is arithmetic, not me.

The on-chain ledger

Recomputing a round proves the numbers were not changed. It does not, on its own, prove they were not computed today. An append-only ledger on Robinhood Chain records each round's hash, so the commitment carries its own timestamp — the one in the transaction that wrote it.

Deployed on the Robinhood Chain iteration network (chainId 46630) at 0xc4f7c2ed489d9f521d65b43cc4929d3c642c6fb9, in block 119,878,215, transaction 0xa0dd3b2f…, canon rhdepth-v2. Those values are transcribed from deployments.jsonl in the ledger repository, which is append-only and is the place to check them; as of 2026-09-22 02:35 UTC there was no deployment on mainnet (chainId 4663). That is a statement about a moment, not a plan: deployments.jsonl is the file to check, and it is append-only, so a mainnet entry appearing there later does not change this sentence.

One round, one call:

cast call 0xc4f7c2ed489d9f521d65b43cc4929d3c642c6fb9 \ "getRoundHash(uint64)(bytes32,uint8)" 61129566 \ --rpc-url https://rpc.testnet.chain.robinhood.com

Compare what comes back against the roundKeccak and canon for that block in data/. A returned canon of 0 means the round was never recorded, which is unambiguous because the contract refuses to deploy with canon 0 and every recorded round therefore carries 2 or more; it is not a round stored as zero.

As of 2026-09-16 the ledger was deployed and empty: latestCommittedBlock() returned 0, and the call above returned zeros. The backfill of the published rounds was written and rehearsed but not yet executed. The ledger is an additional anchor, not the primary one. The primary anchor is that rounds.jsonl is published in git: any change after the fact stays in the history. A ledger can be redeployed; the published record cannot be quietly rewritten.

Update, 2026-09-19 — the backfill has run. The call above now returns 0x2c645bebf891401f1fd75a39168496a88a45bfed59105c42f780f5b65421a2d2 and canon 2 for block 61,129,566. That answer will not change: the watermark only moves forward, so no block at or below it can be written — an attempt reverts with BlocksNotIncreasing.

610 rounds are committed, through block 64,907,249, in ten transactions. Publication continues daily while commits are written in batches, so the newest published rounds are not on the chain yet — 96 rounds as of 2026-09-19 (2026-09-17 and 2026-09-18). At that same date, a round published after 2026-09-16 returns canon 0, while block 61,129,566 returns canon 2. Both are reproducible today, which is the cheapest way to check that canon 0 means what this page says it means.

Update, 2026-09-23 — the ledger is now on mainnet, and everything above stays true. A second EvidenceLedger was deployed on Robinhood Chain mainnet (chainId 4663) at 0x7f5446b920e09531f443ce951076cbaed09dfab6, in block 70,145,346, transaction 0x854d1b03…, canon rhdepth-v2, owner 0x6768cEF3…. That key has never owned the iteration-network ledger, and that is checkable rather than asserted: contract 0xc4f7c2ed… has exactly one OwnershipTransferred event — 0x0 to 0x9d55…35E2, in its own deployment block — and no OwnershipTransferStarted at all, so ownership there never moved. The backfill of 850 published rounds through block 69,196,861 landed in fourteen transactions. The paragraphs above are not superseded: they are statements about chainId 46630, which still holds what they say it holds, and the watermark there only moves forward.

The same round returns the same hash on both chains. Block 61,129,566 returns 0x2c645bebf891401f1fd75a39168496a88a45bfed59105c42f780f5b65421a2d2 and canon 2 on mainnet as well — the hash is the round's own, and the canon is what the commit passes in, so neither depends on which ledger you ask. A round that was quarantined rather than published — block 53,808,204, in a rhdepth-v1 directory — returns canon 0 on both, and now does so by construction: it sits below the first committed block, and the watermark has passed it.

Finding three · Prediction markets

The same gap, in an unrelated market

Every prediction market shows a price on its interface. Pull the actual order book and few of them can be traded.

More interesting than an outright empty book is the one-sided market: real depth on the ask, dozens of levels absorbing tens of thousands of dollars, while every bid sits at a dust price of 0.01. You can buy in at 0.99; when you want out, 0.01 is the only bid. Plenty of levels, all at prices that cannot catch you.

9.4%
Tradeable
56
52.2%
One-sided
311
21.3%
Borderline
127
17.1%
Empty quote
102
2026-09-03 07:10 UTC · Polymarket + Kalshi + Pascal, 38,775 active markets · eight whole-word keyword searches · only the highest-volume markets in each set were checked. Criteria for "tradeable": spread ≤ 0.10, ≥ 3 ask levels, book absorbs ≥ $200, and best bid > 0.02.
KeywordMatchedNo 24h volumeCheckedTradeableOne-sidedBorderlineEmpty
bitcoin23854780471516
ethereum1886266046416
election1,15490010888677
fed82657514311416
trump5101071144277112
nba696559213323
china2492421435
gpt10026727271127
Total2,3651,28859656311127102

Two details stand out.

For bitcoin and ethereum, the tradeable count is zero. Across 144 checked books, not one had both sides standing; they are almost all one-sided or empty. Meanwhile nba has 21 of 59 tradeable and fed has 14 of 75. A busier topic does not mean a more tradeable one.

54.5% of matched markets had no trades in 24 hours. Searching election returns 1,154 markets, 900 of them silent. On the interface they look identical to the active ones.

Method

Our instruments lied to us nineteen times

Every one of these is attached to the number it touched and to the side of publication it fell on, and what each corrupted is corrected where it lives. This section is here because it is the reason the figures on this page can be trusted — not a reason they cannot.

This section does not usually appear in a report like this. It is here because it explains something more important: why almost nobody does independent executability measurement.

Not because it is hard, but because instruments lie quietly. Nineteen errors, each producing a precise number that looked like an insight. Eight were caught before anything was published. Eleven were not — 08, 09, 10, 11, 12, 13, 14, 15, 16, 17 and 18 — and what each one corrupted is corrected where it lives. One of those eleven was reported by a reader rather than found here, which had not happened before. Another of them is the correction to that one, which carried an error of its own. A process that genuinely self-corrects will eventually catch something late; what matters is which side of publication each one landed on, so each entry carries its side and this paragraph counts them.

01
Depth overstated by a factor of a million
Limitless returns order-book sizes as 6-decimal fixed point. The trade path divided by 1e6; the book path did not. So "average price to fill $10,000" always equalled the top-of-book price and the whole ladder was flat. 99.9% of rows looked like this, and not one of them raised an error.
02
"Kalshi is 100% empty quotes"
Kalshi returns top-of-book with its market list; depth requires one call per market with no batch endpoint. So we only stored the top level and n_ask was always 1. Apply a "≥ 3 ask levels" test and it fails 100% by construction. That was an artefact of our collection, not a property of their market. Publishing that about a regulated exchange once would be enough to destroy the "independent measurement" claim.
03
74% of the market list had already expired
The Polymarket enumeration passed active=true&closed=false, and those two flags do not exclude expired markets. 74% of the list was dead, the 20,000-market budget was spent on them, and the cursor never reached the currently active set. The symptom was "searching bitcoin returns 3 results". It also contaminated the statistics: dead markets have no book, so they were classified as empty quotes and dragged the tradeable share down.
04
A market with no bids classified as tradeable
With no bids, bid1 = 0, so spread = ask − 0 = ask. Whenever the ask was cheap (say 0.05) the spread came in under 0.10 and passed the test, for a market with not a single bid in it. The output before the fix read "spread 1.000 · ✅ tradeable", which is self-contradictory. Correcting it cut that category by more than half.
05
An alert that fired every day for nothing
The health check kept its list of "slow sources" hardcoded. After one source's interval changed from 600s to 1800s the list was not updated, so it appeared once every three rounds while still being counted as "should be present every round". The multi-source quorum dropped from 89% to 43% and the alert fired daily with nothing actually wrong underneath. The same class of error — one fact written down in two places, then drifting apart — occurred four times in three days.
06
"On-chain tokenized stock pools are basically empty" — this was wrong
The first scan concluded that every pool had a ~92% round-trip loss, and that nearly went into the report. The cause: this chain produces a block every 100 milliseconds, so its 53.41 million blocks are about 62 days, and we had only scanned the most recent 4 million — about 4.6 days. That window contained nothing but freshly minted launchpad pools; the real stock-token pools were created in the chain's first days, entirely outside the scan. A full-chain rescan reversed the conclusion: NVDA and TSLA are genuinely tradeable. "The last N blocks" means a completely different span on different chains, and any block-windowed analysis has to convert to time first.
07
The 64 rows in a round came from 64 different moments
The collector recorded one block number at the start of a round, then made every call against "latest". A round takes 60–85 seconds and the chain advances roughly 700 blocks in that time. Two things break: the recorded block does not match the state the data came from, so nobody can ever verify it; and the rows within a round do not match each other, which breaks the premise of a same-moment cross-section. This one was caught by the verification script — it failed on its first run — and would otherwise have persisted silently. Fixed by pinning the whole round to one block height, at the cost of requiring an archive node.
08
The pool table was 0.2% complete — found after publication
The scan that builds the pool table skipped block ranges that failed instead of stopping. It returned 55 pools where the chain has 25,122, and the ones it happened to catch were mostly shallow. Every tokenized-stock figure in the previous version was measured against those pools: SPY's real round trip at $100 is 99.93%, not 0.90%, and the AAPL "size cliff" does not exist. Pool count is not a proxy for depth either — AMC has among the most pools of any token and among the fewest that can fill $10,000. Any pool table built before the scan was made fail-loud has to be discarded, not patched.
09
A metric that could exceed 100% — found after publication
The old measurement took the best buy pool and the best sell pool separately, then derived a rate between them to size the sell. That rate belongs to no actual pool. It produced round-trip recoveries above 100% — buy and immediately sell back at a profit — which cannot persist for more than a few seconds in any real market. The replacement closes the loop inside one pool, needs no rate assumption, and cannot exceed 100% by construction: if it ever does, that is a bug announcing itself.
10
The pool table was correct when it was built, and stale when it was used
A round is replayed against stock_pools.json. That file was built on 2026-09-04, and the last pool in it was initialised at block 53,983,886. A round taken on 2026-09-12 sits at block 61,129,566 — 7,145,680 blocks later. In between, a QQQ/USDG pool was created that the table never saw. The $100 QQQ figure measured 6.58% against that table; measured against the chain, it is about 95.56%. One cell, one date, no error message: the table was not wrong, it was out of date. This is not the same defect as #08 — #08 was a scan that returned incomplete results, this is a complete snapshot of an earlier chain. What caught it was a question about provenance: which date is that table from? Nothing in the monitoring had a reason to look. The fix is not to rebuild the table in place — replaying an old block against a new table produces different rows and a different hash, so every already-published round would fail verification at once. What is needed is a versioned table: each round records which table it was replayed against, and the verifier selects by record. That is a change to the serialisation contract, so it is scheduled deliberately rather than patched in.
11
The rule that builds the pool table cannot see the pools that win at small sizes
The entry above is about a table that went stale. This one is about the rule that builds it, which does not go stale — it excludes pools by design. Every candidate is probed with a $10,000 buy and dropped if it cannot fill one, so a pool that can fill $300 and not $10,000 is never a candidate — and $100 and $1,000 are exactly the sizes at which such a pool wins. Quoted against every initialized QQQ/USDG pool in the v4 PoolManager rather than against the table (a second AMM deployment was outside that scan — see error 12), at this page's own window block 54,088,399, QQQ returns 99.67% at $100 and 98.62% at $1,000. The table said 6.46% and 1.83%, and the sentence built on it said QQQ cannot be sold at any size. The pool doing that work is one contract, fee 0.30%, and its capacity — the largest notional it will quote — has been $9,841 → $10,506 → $287 across three pinned blocks, so what QQQ can absorb is not a property of the token at all. Unlike the entry above, rebuilding the table does not fix this — the probe would still be there. The fix is to select pools per size rather than once, which changes the method and is scheduled as such. Found 2026-09-23, after the ten above and after the film that names them. It was caught by a question that needed an archive endpoint to answer: does that cell survive a quote against every pool on the chain, at the block it claims?
12
The scan covered one venue, and the sentence said it covered the chain
Entries 10 and 11 both rest on a phrase: quoted against every initialized QQQ/USDG pool. That was true of one venue and false of the chain. The pools came from the v4 PoolManager’s Initialize events — a method that finds only venues matching a pattern we already knew. Re-enumerating by counterparty flow (each stock token’s Transfer logs, asking every address that both sends and receives it what it is) found at least three more venue classes, including pools from two further factories and a reserve-based AMM that is not standard UniV2. The fee tiers are not a fixed menu either (values of 50, 150 and 250 all appear). At this page’s own window block the QQQ figures were wrong at every rung and always in the same direction: the venue absorbing the order looked far worse than it was. Corrected, using the same method this page’s table uses (both legs quoted against the same pinned block’s book):
block$100$1,000$10,000$100,000
54,088,39999.8999%99.8984%99.8837%99.7363%
61,129,56699.8999%99.8984%99.8839%99.7371%
70,427,77299.8999%99.8986%99.8857%98.1465%
So QQQ at 54088399 returns 99.8999% at $100 and 99.7363% at $100,000. We do not claim this list of venues is exhaustive. What we can state is which windows we searched and by what criterion. The method that found these — flow, not pattern — replaces the method that missed them; per-size pool selection remains a method change and is scheduled as such. How it was nearly missed: three people read the same fee() field within an hour and got three values, and all three assumed someone had mistyped. The field moves with the block. Separately, a quarantined dataset was read here as if it were the published series, because its quarantine lived only in a directory name that did not survive syncing.
13
The caption described the trade, but not the reference state
The table’s caption says same-pool round trip: buy with USDG, sell the whole position back through the same pool. The collector does do that — same pool, and it sells the amount actually bought. What it does not do is carry the buy’s effect into the sell: both legs are quoted against the same pinned block, so the sell leg is priced against the book as it was before the buy. That is why the figure is not a realised round trip, and why it is worth keeping. A realised round trip in one pool returns (1−f)² almost exactly — the price impact is undone by the leg that retraces it — which is why a realised round trip cannot see depth at all. Quoting both legs against a held-constant book costs roughly twice the one-sided impact plus the fees, and it degrades with size. So no number in the table changes; the label does. And it exposes a deeper problem with the field we proposed to the SEC: a round trip blends the buy and sell directions, while a forced seller walks one. The raw fields for the anomalous cell (block 70,427,772, $100,000): buy side 1.7354%, sell side 0.1214% — a 14.3× asymmetry, because the liquidity is lopsided. A forced seller faces the sell side only.
14
A block's state root was reported as a revert selector
The collector's first err_record() took the first 0x… string it found in the human-readable part of a JSON-RPC error and reported ten characters of it as a selector. It was the leading four bytes of the stateRoot of the block that round was pinned to, and a 60-character truncation then in place had cut it six characters short of the closing bracket, so it did not look like the start of a bracketed string. Nothing reverted: the public endpoint was pruning the pinned block's state while the round was still running (missing trie node / layer stale), and a round takes 110–122 s against a state window this page measures at five to ten minutes. It was published before it was understood — in addendum 3 of the second series' pre-registration — and corrected in addendum 4. The collector now takes selector only from error.data, records a failure kind, and retries a state-unavailable call. Same class as the truncation itself: a quantity produced by our own parsing, read as a property of the object. Found 2026-09-27, after publication. The film says thirteen and card 4 shows 13 — both are dated 2026-09-26 artefacts, and this is the fourteenth.
15
A description that reads as a stored field — in three published places at once
Every transfer of a tokenised stock is accompanied by a second log from the same contract, with the same sender and recipient, whose two data words are the amount moved and that amount multiplied by a per-asset factor. The factor is therefore the ratio of two numbers in the log: no field holds it, and no event on the token names it. (A getter does exist and is documented — uiMultiplier(), ERC-8056 — and the issuer's own docs add that their oracle already incorporates the multiplier into the price. This project first reported "no getter we could find", having guessed at names like index() and sharePrice() instead of reading the extension. Corrected the same day, and the exposure this described is narrower than first written: an oracle-priced collateral value is not carrying this drift.) Three published texts said otherwise — "each token carries a per-asset index, observable on chain" (pre-registration addendum 2, §3), "Each tokenised stock … carries a per-asset index" (measurements/index-priced-test/README.md), and a docstring in code/read_accrual_index.py that described the log as holding a fixed-point index in one of its words. Each reads as something a reader can go and fetch, and a reader who goes looking finds two amounts instead. The same addendum states the mechanism correctly in its §1, which is how this survived: one document, one precise passage and one loose one, and the loose one was the passage likely to be quoted. All three now carry the correction, in the form each document allows: the pre-registration is dated and nothing below its banner is ever edited, so the banner states that §3's wording is withdrawn and the original sentence stays visible underneath; the measurement note and the docstring are corrected in place and say in the file which description was wrong. Found 2026-09-29, after publication, by writing the letter that the description was meant to support.
16
A change detector that could only see the value fall
The month-long sampler for that factor compares consecutive samples by intersecting the exact interval each sample's logs imply. Its first published version tested only whether the previous interval sat above the next one — a fall. The factor rises. So the detector could not fire on the event it exists to find, and would have reported "no change in September" for an asset whose own output, three lines higher, printed two different values. What caught it was that contradiction, in the script's own printout, about forty minutes after it was pushed: two distinct sampled values with zero changes is not a fact about the chain, it is a broken test. The comparison is now symmetric and names the direction, and the file records that it shipped otherwise. This is entry 5 inverted — an alert that could never fire, where that one fired for nothing — and it is why the month's figures were still unpublished when it was found: a number does not get read out of an instrument that has not been shown able to move. Found 2026-09-29, after publication, before any figure used it.
17
A fact about state, published as a fact about the chain
The verification block of every weekly issue said no rolling provable window exists on this chain. That is true of state and false of events. Measured on the public endpoint on 2026-10-09: at 200,000 blocks back eth_getBalance returns historical state is not available, while eth_getLogs over the same fifty-block range returns 524 events, and events are still served 20,000,000 blocks back — at 50,000,000 the query times out, which is a timeout and not an absence. So where events are served, realised execution over a past period is publicly recheckable, and that sentence had been denying it. A reader reported this, by pulling the event logs by hand; of the entries caught after publication it is the first that was not found inside this project. The claim is now read from a re-runnable measurement — code/measure_retention.py and measurements/rh-retention/retention-2026-10-09.json — instead of being held as a literal, and the generator refuses to publish an issue without it. Same family as several entries above: a limit on what I could obtain, written as a property of the thing.
18
A cost limit, published as a depth limit
The correction above carried the next error. It said events are still served 20,000,000 blocks back, and that at 50,000,000 the query times out — the timeout was real and was labelled a timeout, but the figure went where a retention boundary goes, and into a summary field named deepest_logs_served_blocks_back. Re-measured on 2026-10-11 with nothing changed but the span, fifty blocks narrowed to five: the same depth answers in under two seconds and returns thousands of rows. Logs are served at least 50,000,000 blocks back. What the earlier run found there was the cost of an unfiltered query, not the edge of the index — and this endpoint has two query caps, neither of them retention: 10,000,000 blocks of span and 10,000 matched rows, each named by the node in its own refusal. The probe now separates proven (rows came back), from answered (returned without error, which a node that has dropped its log index can also do), from refused, and escalates to a narrower span before concluding anything from a refusal. Published in this archive and in the measurement artifact of 2026-10-09; corrected where both live. Found 2026-10-11, after publication.
19
A pruned block filed as our own rate limit, because its state root ended in 429
While rebuilding the probe above, the state ladder came back with six rungs marked error and the brackets computed over them — our own request rate reading as the chain’s retention. Pacing and a backoff fixed that. The fix then produced a quieter one: a rung whose answer was historical state 602f…3c429 is not available — unambiguously pruned — was classified as rate-limited, because the verdict was decided by testing whether the message contained 429, and that block’s state root happens to end in those digits. The rung was dropped from the retention bracket without a word. A status code is now matched as a whole token, never as a substring of a message that carries an opaque identifier, and the classifier has a drill whose arms are seven real messages from this endpoint — including that one — which must land in seven different buckets. Found 2026-10-11, before any figure from the rebuilt probe was published.

And one obstacle that is not a bug

Measuring at all can get you rate-limited. ParaSwap (now Velora) allows roughly 5,000 calls a day on the free tier, counted per egress IP rather than per key, and not separated by domain. We sent 5,622 in a day and got a solid 11 hours of 429s starting 23:31 UTC on 31 August, until the rolling window cleared.

0x disabled our key entirely on 4 September, after two notices about the quote-to-fill ratio. We stopped calling them rather than retrying, and 0x is excluded from the comparison until that is resolved.

But the barrier is not uniform, and that turns out to be the more useful finding. Asked the same question, 1inch replied that quote-only use is fine, that they have no quote-to-fill rule, and that they had never throttled a single one of our calls — with the condition that the free tier is for non-commercial use, which this is. So "independent measurement is impossible" is not an industry fact. It is the result of asking each provider, one at a time, and getting different answers. The barrier is not the code and not a universal policy. It is that almost nobody asks.

Admitting what is missing is more credible than pretending to be complete. Most of these errors surfaced only because figures were checked against the raw data; two of them survived to publication and were caught only when a re-run forced a correction. "Only about 10% of Polymarket markets are tradeable" was written into external copy and then withdrawn; "on-chain tokenized stock pools are all empty" had an entire section drafted before it was overturned. This is the reason to write a verification tool: the first errors it catches are your own.

Limits

What this data cannot be used for

  • The time depth is days, not months. On-chain data starts 2026-08-30, prediction markets 08-29. Every conclusion is a cross-section and supports no time-series claim. "Who is better in the long run" needs weeks of samples at minimum.
  • Solana has only one quote source. Jupiter is the only one available, so that ladder has no cross-source comparison, and by the first finding it probably overstates the true cost.
  • Prediction markets were sampled by keyword, not surveyed. Eight keywords, and only the highest-volume markets in each set were checked. Spot-checking 50 from the tail found 45 with no retrievable order book at all — but it is still a sample.
  • Limitless is missing from this pull. Its market-list endpoint returned empty at sampling time and it is excluded from the totals. That happened three times in three days; treat its availability as uncertain.
  • Kalshi only supports a degraded verdict. It publishes top-of-book only, so its results are marked "depth unknown", and the bias is toward overstating the tradeable share, not understating it.
  • "Cannot be executed" is not "you will lose X%". A refused quote means the size cannot be filled at current liquidity. It is not a cost you would actually pay.
  • Tokenized stocks cover USDG-quoted pools only. Some tokens also have ETH/WETH pools, excluded here; a token could be deeper against a different quote asset. TSLA is known to have additional depth in an ETH pool.
  • The pool table has no external cross-check. It is internally consistent — the scan aborts rather than skipping a failed range, and this run had none — but nothing independent confirms it is complete. DexScreener counts uninitialised pools in its liquidity figures and is not used as a reference; the block explorer's API is behind anti-bot protection.
  • The pool table stops at block 53,983,886. That is 2026-09-04 04:34 UTC, about three hours before the first measured round, and pools created after that block are not in the table at all. So every row in this report means "the best route among the pools in this table", never "the best route on the chain". One row is known to be affected and is recorded as error 10 above; which others are is what an incremental scan will establish.
  • 0x is absent. Its key was disabled on 4 September, so the aggregator comparison in the first section reflects the six sources available on 31 August, not today's five.
  • Only 5.1 hours and 12 rounds. The "depth is stable" conclusion covers a short window and does not extrapolate across days, weekends or earnings. Behaviour while US markets are closed is outside this report's window; it is being recorded now.
  • Quotes are not fills. Every figure comes from a simulated Quoter call, not an executed trade. Real execution is affected by MEV, slippage protection and gas, and is generally worse rather than better.
  • The prediction-market figures are a 2026-09-03 snapshot. Event markets expire; the batch of 49 earnings markets referenced there has since ended with the earnings season, so a re-check will not return the same match counts.