A price oracle tells you what something is worth. This measurement tells you whether you can actually sell it. Three unrelated markets, one recurring gap: the number on the screen and the number you get when you press the button are further apart than they look.
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.
| Token | Size | ParaSwap only | KyberSwap only | Best of six |
|---|---|---|---|---|
| LDO | $100,000 | −11.29% | −4.22% | −0.71% |
| LDO | $1,000,000 | no quote | −85.14% | −8.51% |
| PENDLE | $100,000 | no quote | −6.61% | −0.79% |
| PENDLE | $1,000,000 | no 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.
This is not a question of one aggregator being consistently better. Change the notional and the winner changes:
| Token | $100 | $1,000 | $10,000 | $100,000 | $1,000,000 |
|---|---|---|---|---|---|
| WETH | 1inch | 1inch | 1inch | 1inch | 1inch |
| LINK | 1inch | 1inch | 1inch | 1inch | KyberSwap |
| MKR | KyberSwap | KyberSwap | KyberSwap | KyberSwap | KyberSwap |
| CRV | 1inch | 1inch | 1inch | 1inch | KyberSwap |
| LDO | 1inch | 1inch | 1inch | CoW | CoW |
| PENDLE | 1inch | 1inch | 1inch | 1inch | CoW |
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.
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.
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.
| Claim | Published (v17) | Corrected |
|---|---|---|
| SPY, sell $100 | 0.90% · PUBLISHED IN ERROR | 99.93% |
| AAPL, sell $10,000 | 2.82% · PUBLISHED IN ERROR | 99.85% |
| Tokens that cannot be sold | six of eight · PUBLISHED IN ERROR | one of nine |
build_pool_table.py.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.
| Token | $100 | $1,000 | $10,000 | $100,000 |
|---|---|---|---|---|
| SPY | 99.93% | 99.93% | 99.91% | 99.71% |
| AAPL | 99.93% | 99.92% | 99.85% | 99.06% |
| GOOGL | 99.99% | 99.95% | 99.53% | 97.97% |
| NVDA | 99.99% | 99.89% | 99.48% | 96.50% |
| TSLA | 99.89% | 99.77% | 99.07% | 96.75% |
| RDDT | 99.32% | 99.32% | 99.24% | 93.12% 90.1–96.6 |
| AMC | 99.75% | 99.62% | 97.08% 86.1–99.0 | 74.55% 28.5–83.6 |
| GME | 99.49% | 99.37% | 97.97% 36.9–98.6 | 17.33% 3.7–22.5 |
| QQQ | 6.46% | 1.83% | 0.26% | 0.03% |
QQQ is the one token that cannot be sold at any size. $100 returns $6.46 and $100,000 returns $30. It is not a size effect and not a moment: all twelve rounds agree to within a tenth of a percent. Every other token on this chain returns at least 93% of a $100,000 sell.
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.
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:
| In the hash | Why |
|---|---|
| Block height | State anchor |
| poolId | Identifies 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 |
| Status | Filled / 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.
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):
code/verify.py — replays every quote at a given block, recomputes the hash, compares it to the recorddata/2026-09-04/rounds.jsonl and quotes.jsonl.gz (v2 rounds; the defective v1 09-03 data was removed)code/rhchain.py — pool enumeration and Quoter calls; stock_pools.json is the pool table from a full-chain scanREADME.md — the full rhdepth-v2 specification and run instructionsEvery 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 live directory data/2026-09-04/, which grows past what this text describes.
You need an archive node for Robinhood Chain (historical eth_call; public endpoints typically retain only the last ~128 blocks of state):
| 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.
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.
| Keyword | Matched | No 24h volume | Checked | Tradeable | One-sided | Borderline | Empty |
|---|---|---|---|---|---|---|---|
| bitcoin | 238 | 54 | 78 | 0 | 47 | 15 | 16 |
| ethereum | 188 | 62 | 66 | 0 | 46 | 4 | 16 |
| election | 1,154 | 900 | 108 | 8 | 86 | 7 | 7 |
| fed | 82 | 65 | 75 | 14 | 31 | 14 | 16 |
| trump | 510 | 107 | 114 | 4 | 27 | 71 | 12 |
| nba | 69 | 65 | 59 | 21 | 33 | 2 | 3 |
| china | 24 | 9 | 24 | 2 | 14 | 3 | 5 |
| gpt | 100 | 26 | 72 | 7 | 27 | 11 | 27 |
| Total | 2,365 | 1,288 | 596 | 56 | 311 | 127 | 102 |
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.
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. Nine errors over six days, each producing a precise number that looked like an insight. Seven were caught before anything was published. Two were not: they are marked below, and the section they corrupted is corrected above. A process that genuinely self-corrects will eventually catch something late — what matters is which side of publication each one landed on, so that is stated.
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.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.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.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.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.