When the Quote Becomes Calldata. The Fork Tests Whether It Holds.
A note on turning a Uniswap quote into API-native calldata, then replaying that transaction against pinned mainnet state.
Part I stopped at the quote layer: route legs, output amounts, API-reported priceImpact, and blockNumber. It recorded what the router proposed. At larger sizes, that proposal became a spread of pools and intermediate hops, not a single price.
A desk sizing an exit acts on that quote; so does a risk pipeline that reads priceImpact as a risk number. On a centralized venue, a mistake there usually stays inside an operator’s scope: an order cancelled, a fill refunded, a replacement issued. Once the quote becomes calldata, there is no venue operator between the user and pool execution, and the failure boundary moves from router proposal to encoded constraints. The quote alone cannot tell whether the next problem is invalid transaction construction, wallet authorization, gas estimation, state drift, ordering, or the final fill.
Part I sliced the quote layer; this post slices one execution layer: build the transaction from the quote, replay it against pinned mainnet state, and check whether the proposal survives, and where the route’s complexity ends up. A valid quote does not mean valid calldata; a successful same-state replay does not mean a mined receipt.
Readable quote, executable calldata
A /quote response can show expected output, minimumAmount, route structure, and blockNumber, but none of those fields execute by themselves. The trade becomes executable only when /swap returns a TransactionRequest: to, data, value, gasLimit, and encoded router instructions.
The chain enforces only what the transaction encodes—most importantly the minimum output condition. Expected output and priceImpact are display fields, not the bytes the Universal Router will run.
The replay is a same-state execution check for the /swap artifact, not a live fill. Fork setup and measured fields are in the run section below.
Uniswap’s Trading API exposes this directly by separating /quote from /swap:
POST /quote
→ POST /swap with the returned quote
→ save TransactionRequest
→ fork at quote.blockNumber
→ seed wallet balance and approvals
→ send API-native calldata
→ measure output-token delta, minimumAmount, and gas
Shell references: quote_to_swap.sh and replay_swap.sh.
The fork replay run
Run ID: 20260619Tpart2v1
I collected nine cells: USDC → WETH, AAVE, and MKR at $100, $10k, and $1M. Routing was Uniswap classic (CLASSIC); protocols V2/V3/V4 via BEST_PRICE; UniswapX excluded.
For each cell I POSTed /quote, then POSTed /swap with the returned quote object and archived both responses. /swap used allowance-based calldata from the Trading API—not SDK reconstruction from route JSON. API simulateTransaction succeeded on all nine cells.
Each cell was replayed on a fresh Anvil mainnet fork at that cell’s quote.blockNumber (blocks 25,350,126–25,350,128), with archive RPC state. I seeded a fixed test wallet with ETH for gas, USDC via anvil_setStorageAt, and USDC → Permit2 → Universal Router approvals. Replay sent exact API-native /swap calldata to the router at 0x66a989…8Af.
A signed-permit collection (20260619Tpart2v0) failed fork replay when permit sigDeadline preceded the pinned quote-block timestamp. That comparison run is archived; the primary evidence is the allowance path above.
Measured per row: fork_status, fork_output_amount, fork_vs_quote_bps, fork_meets_minimum, fork_gas_used, and api_simulation_status.
What the grid shows
All nine cells replayed at pinned state, cleared minimumAmount, and matched the quote at 0 bps: the expected baseline for same block, same pool state, same calldata.
WETH $100 routed through a single V3 hop. Fork gas was 140,975—the simple control.
MKR $1M showed quote-layer output deterioration in Part I. Its seven-hop transaction still replayed at 0 bps and cleared the minimum.
AAVE $1M: fragmented route, same-state pass
Part I flagged AAVE for route fragmentation and summary-field ambiguity. At $1M the quote carried 13 pool legs across five parallel paths (V2/V3/V4 mix). /swap returned 14,366 bytes of calldata. Fork gas was 2,386,700—roughly 17× the WETH $100 control.
Pilot panel: what route stress becomes
The nine-cell replay is a controlled check, but it is too small to say much about route stress more generally. I therefore ran a pilot panel over 28 snapshot labels, 10 assets, and five input sizes: 1,400 intended cells. This was a pipeline pilot, not a historical backtest.
The pilot produced 977 successful /quote + /swap rows. The strongest pattern was payload size: hop count versus calldata bytes had a Pearson correlation of 0.935; path count versus calldata bytes was 0.917.
From that panel I selected 118 stress rows for fork replay. Ninety replayed successfully at pinned state. The remaining 28—all high-complexity SHIB rows—stopped at eth_estimateGas.
Three of those I direct-sent on fresh pinned forks with a 12M gas cap; all three executed at roughly 7M gas and cleared minimumAmount. The timeout was an estimator artifact, not an EVM failure—but that check covers only 3 rows. The remaining 25 still need the same follow-up.
What a fork replay result actually means
The first all-green table raised a scope question: was this evidence, or only a same-state sanity check? Treating replay as one test stopped working once the non-receipts came from different layers.
A non-receipt is not one failure class. Configuration, authorization, estimation, and EVM execution fail at different boundaries.
Closing
Part I stopped at the quote. Here, same-state replay held, route complexity showed up in calldata size, and three SHIB estimator timeouts became roughly 7M-gas executions on bounded forks.
The harder part is keeping the labels straight: estimator timeout, authorization failure, configuration error, and EVM execution are different boundaries, even when all of them produce no mined receipt.
The next falsifiable check is narrow: direct-send the remaining 25 SHIB rows with bounded gas on pinned forks. Inclusion, ordering, MEV, state drift, and realized fill still need receipt-level evidence.
Appendix
- Reproduce:
quote_to_swap.sh(collect/quote+/swap) andreplay_swap.sh(fork replay).- Requires:
curl,jq, Foundry (cast,anvil), Uniswap API key, archive Ethereum RPC. - Replay: fork at
quote.blockNumber→ seed wallet → send saved calldata → check output,minimumAmount, gas. - Estimator check:
SKIP_ESTIMATE=1with a bounded gas cap ifeth_estimateGastimes out.
- Requires:
- Part I ladder: The Price Moves First. DEX Routes Fray Before the Exit. — quote-layer route fraying; collection
20260617T134419Z. - RWA exchange-risk context: Where RWA Exchange Risk Actually Sits. Centralized venues can cancel, refund, or issue replacement objects; a DEX route has no default operator at execution time.
- API references: POST /quote, POST /swap, swapping integration guide.
- Pre-execution tooling: MetaMask security alerts (transaction simulation before signing); Tenderly single simulations and virtual environments (fork simulation).