Uniswap v4 hook
The pool is sitting on money.
A Uniswap v4 hook that reclaims the mispricing a swap leaves behind, for the pool's own traders and LPs. It never runs the arbitrage and never fetches a price off-chain.
A pool quoting the wrong price is money on a table.
One ETH/USDC pool: 100 ETH, 300,000 USDC, price 3,000, Binance 3,000. Rohan buys 10 ETH and pays 33,333 USDC. That overpayment is price impact, the cost of consuming depth. Not a bug. But the pool now quotes 3,704 while the world still says 3,000. Vik the arb bot buys 10 ETH on Binance for 30,000, sells into the pool for 33,333, and hands most of the profit to a block builder for ordering.
| Pool marked to truth | ETH | USDC | Value at 3,000 |
|---|---|---|---|
| Start | 100 | 300,000 | 600,000 |
| After Rohan | 90 | 333,333 | 603,333 |
| After Vik | 100 | 300,000 | 600,000 |
For one moment the pool was $3,333 richer. It held the value, then handed all of it back.
The surcharge is not a new charge on anyone. It is the pool declining to hand back what is already sitting in its own reserves.
Rohan cannot be charged. He already paid, and the payment landed in the pool. Backdraft keeps a slice of that value in escrow when a swap narrows the gap, then splits it at settlement.
The whole mechanism, in fifteen seconds.
Scrub through block time. White is the pool tick, grey is the reference. Inside the dashed band the gap is under 65 ticks and the hook is blind by design. Switch regimes: the code has no if for the exogenous case. An empty ledger is the attribution result.
Empty. No gap yet.
Charged only on a narrowing swap, priced on the widest the gap ever reached, so splitting the close saves nothing.
Runs when the gap closes. The trader pot scales by explained = min(ledger / peak gap, 1). A poisoning dust swap buys almost nothing.
Two regimes, one hook. The split falls out of the ledger.
A trade moved the pool.
- Trigger
- A swap knocks the pool off truth
- Who pays
- The originating traders
- Ledger
- Populated, explains the full gap
- Settlement
- Traders get alpha, pro rata on contribution
The world moved, the pool went stale.
- Trigger
- Information arrives, no trade does
- Who pays
- The LPs, loss versus rebalancing
- Ledger
- Empty, explained is 0
- Settlement
- 100% to LPs, no branch
The earlier design used a binary empty ledger means exogenous. That was poisonable: one dust swap reclassifies a 200 tick gap as endogenous and claws the trader share back from LPs. Now the trader pot scales by explained = min(totalContribution / maxAbsGap, 1). Two manufactured ticks on a 200 tick gap buy 1% of the pot, less than the dust swap costs to make.
All of it lives in pool state, never the mempool.
A gap opens, accrues a ledger, and settles across the swap and liquidity path. Drag it around, zoom in, or play the flow to walk one gap through the hook.
Drag to pan. Scroll to zoom. Drag any node to move it. Orange dots are the points where the hook acts.
The reference price
Not the deepest pool, the most traded. The v3 0.01% ETH/USDC spot tick was the most corrected source across calm, volatile, USDT stressed, and one second truth conditions. An own pool EMA is 16.6 times worse: a pool cannot detect its own staleness from its own history.
Split from the guard
The fast pool is fresh but thin, 5% of pair liquidity would corrupt it. So the deep v3 0.05% pool guards it. If deep spot drifts from deep TWAP, or fast spot drifts from deep spot, by more than 50 ticks, the hook freezes. No credit, no surcharge. An unreliable reference produces inaction, not a wrong charge.
65gap threshold in ticks, from measured p100 error
50guard deviation in ticks, 6.6% to 10.1% freeze
74kreference gas, two stage read on the swap path
228 to 58worst case error in bps, cut by the guard
Everything else runs the arbitrage or fetches a price off-chain. Backdraft does neither.
Reference chosen by measured accuracy
Four market conditions, one consistent ordering. The source that gets corrected most often wins. We report the margin rather than claim a magnitude.
Reference split from guard across fee tiers
Freshest source for the price, deepest source for manipulation detection. The only arrangement that gets both properties at once.
Threshold derived from measured p100 error
65 ticks is the max of a 14,351 block window, with the honest note that a two day max is not a bound. Deployments must monitor realized error and version the threshold.
WhatTheHook
Runs the arb itself, needs two or more connected pools, no path for the exogenous case.
Detox Hook
Pyth to detect arb, capture, redirect. Fixed payee, no attribution, no trader leg.
ArbHook, Chainlink CRE
Off-chain compute, LPs only.
Truncated Oracle
Caps per block tick movement. Publishes a price, does not detect its own staleness.
am-AMM, LVR auctions
Auction the right to be the arbitrageur. Never touch the trader who created the opportunity.
Where we stand
The fee tier ordering is in the literature and reading external pools is not new. Doing all three at once has no precedent we can find.
The blind spot is exactly where the action is.
We will surcharge genuine traders
No on-chain signal separates a bot from someone who happened to sell into a stale quote. We frame it as a price on consuming a stale quote, not a penalty on intent, and it nets out over time.
Blind below 65 ticks, frozen in roughly 10% of volatile blocks
Plausibly the very blocks where dislocation value concentrates. The dollar weighted share lost to the blind spot is a never cut measurement and goes in the README either way.
Claim economics exclude small participants
Pull based, per gap, per address. A retail rebate is often smaller than the gas to claim it, so in practice the trader leg pays whales and bots.
tx.origin attribution
Works through the Universal Router, breaks for ERC-4337 and batched transactions. The demo uses direct swaps.
This is capture, not elimination
The arbitrage still happens and price discovery still works. We change who keeps the proceeds, from a block builder to the pool's own participants.