SocketDocs

Hooks

Dynamic fee

A built-in hook that raises a pool's LP fee after its price moves and lets it decay back to the base fee while trading is calm.

LPs lose the most to traders right after the price moves, when stale quotes get picked off. A fixed fee charges the same in calm and in turmoil. The dynamic-fee hook measures how far each swap moves the pool's price, charges more while recent swaps have been moving it, and lets the extra decay away second by second.

It measures only this pool's own swaps. It reads no external price and needs no keeper. Time is the block timestamp.

How the fee is set#

Fees are in Uniswap v4's units, hundredths of a basis point: 1,000,000 is 100%, and 3,000 is 0.30%. The weight and the decay are shares out of 1,000,000 too.

The hook keeps one number per pool, an exponentially weighted moving average (EWMA) of how many ticks each swap moved the price.

afterSwap folds in the swap's movement:

ewma = ewma × (1 − weight) + |tick moved| × weight

beforeSwap first decays the average for the seconds since the last update, then turns it into a fee:

ewma  = ewma × (1 − min(elapsed × decay, 1))
extra = min(ewma × sensitivity, max_extra)
fee   = min(base_fee + extra, max_fee)

It returns fee with the override flag 0x400000, so PoolManager charges it for this swap.

For example, with a base fee of 3,000 and an average of 40 ticks, the extra is 40 × 100 = 4,000 and the swap pays 7,000, or 0.70%.

0.427%fee for that swap: base 0.30% + 0.128%

EWMA 15.00 ticks after the swap · back to base within 100 s

0 sdashed line: base fee 0.30%120 s

Hook parameters

Settings#

SettingDefaultMeaning
Weight250,000Share of the newest swap's movement in the average (25%).
Sensitivity100Extra fee per tick of average movement (0.01%).
Max extra10,000Ceiling on the extra part (1%).
Decay10,000Share of the average forgotten per second (1%). It is fully gone after 100 s.
Base feeper poolThe fee while the average is zero.
Max feeper poolCeiling on the whole fee.

A pool on this hook is created through DynamicFeeHook.createPool, which stores every setting and initializes the pool in one call. None can change after, and the hook refuses a pool initialized any other way. The app's Create page starts at a max extra of 7,000 with a 1% max fee.

Flags#

The hook has afterInitialize, beforeSwap and afterSwap, plus afterAddLiquidity, afterRemoveLiquidity and both of their returns-delta flags for the buyback share. The pool's fee is the dynamic-fee flag, 0x800000.

The max fee should leave room above the base fee, or the hook has nothing to raise.

What the fee is in a quote#

The Quoter runs beforeSwap at the block it simulates. The swap pays the fee at the block it lands in. Between the two, the average decays, and other swaps may move it. Slippage limits absorb the difference.

Public documentation snapshot · 9 October 2026 · Original page ↗
LOCAL REPLICA · DOCUMENTATION SNAPSHOT