A Uniswap v4 Hook on X Layer. Over-cap swaps either refuse, or pay LPs through donate + swap inside one transaction. Same exact-input order. Different pool policy. Different onchain outcome.
Featured proof SURGE donate + swap 0x1809…a9a8Three pools, two enforcement modes, one trusted router. Every row links to the OKLink receipt.
MAX_SWAP_EXCEEDED
0xbc20…435a
DAILY_CAP_EXCEEDED
0x7113…771c
hookData
0x4877…843a
No oracle. No offchain matcher. No governance. The Hook checks two policy limits; the Surge router pays LPs before the swap clears.
v1 · policy gate
beforeSwap(amountIn):
if amountIn > maxSwap // revert MAX_SWAP_EXCEEDED
if spentToday + amountIn > cap // revert DAILY_CAP_EXCEEDED
spentToday += amountIn
emit SwapAccepted(poolId, trader, amountIn)
v2 · surge override
surgeRouter.swapWithDonate(amountIn, surgeFee):
require(msg.sender == trustedRouter)
PoolManager.donate(poolKey, surgeFee) // LPs paid first
PoolManager.swap(poolKey, amountIn) // same unlock callback
emit SurgeAccepted(poolId, trader, amountIn, surgeFee)
The refusal is enforced by the Hook, not the UI.
beforeSwap reverts inside Uniswap v4 PoolManager before any liquidity is consumed.
The router only records the caught failure.
The donation is enforced by the trusted router.
The Surge hook reads hookData from beforeSwap but only honors it when the unlock
caller is the registered router. The deployed old router proves the spoof path reverts.
Mock assets, real swaps.
Pools use mUSDC / mETH on X Layer to isolate Hook behavior from token noise. The Hook callback, the
Donate event, and the swap settlement are all on chain 196.
Click any address for the verified source on Sourcify.
node scripts/verify-all.mjs