THE DIAL
The Dial
THE FEE IS WRITTEN BY THE FLOW
DOCUMENTATION
X The instrument

Documentation

Every Uniswap pool charges a fee, and on every other pool somebody picked that number. Here, nobody picked it. The pool reads how one-sided its own order flow has been and writes its fee from that reading, between a floor and a ceiling that are compiled into the contract.

1 · Why a fee should move at all

A liquidity provider makes money when trading is two-way: buys and sells arrive in roughly equal measure, the position is round-tripped, and the fee is collected twice on the same inventory.

The provider loses money when trading is one-way. A pool that only gets bought is a pool selling its inventory to people who know something it does not — the textbook shape of adverse selection. The direction is irrelevant: a pool that only gets sold is being handed inventory nobody else wants, which is the same problem mirrored.

So the honest signal is not price is going up. It is the flow has stopped being two-way. That is the one thing this hook measures, and the only thing it charges for.

The design decision this rests on A cheaper fee on buys and a dearer one on sells would have been easier to build and easier to market. It would also be arbitrary, and farmable in one line: route the expensive side through the cheap one. Charging for imbalance is symmetric, so there is no cheap side to route into.

2 · How the reading is made

The hook keeps two exponential moving averages — one fed by buy volume, one by sell volume — each decaying by 1/64 on every qualifying swap. The reading is the gap between them, as a share of their total:

imbalance = |emaBuy − emaSell| ÷ (emaBuy + emaSell) 0 → 1 confidence = min(swapCount, 32) ÷ 32 0 → 1 fee = 0.30% + imbalance × confidence × 0.70%

A perfectly balanced book gives imbalance = 0 and the fee rests on the floor. A book where one side has gone quiet drives the ratio toward 1 and the fee toward the ceiling. Nothing else is an input — not price, not time, not an oracle, not an address.

The quote a trader receives is computed in beforeSwap, from state as it stood before their order. The averages are only updated in afterSwap. The consequence is worth stating plainly: no swap is ever charged the fee its own size helped create.

3 · Why the instrument starts silent

imbalance is a ratio, and ratios are reckless when they are thinly fed. On a brand-new pool the very first trade gives |b − 0| ÷ (b + 0) = 1.0 — a perfect reading of total imbalance — whether that trade was 40 ETH or 40 gwei. Taken literally, a fresh pool would sit at its ceiling from transaction one, which is the exact opposite of what the design intends.

So the reading is weighted by confidence, which climbs from 0 to 1 over the first 32 qualifying swaps. It is scale-free, it needs no oracle, and it encodes something true rather than convenient: the instrument does not assert a reading it has not yet earned. The raw ratio stays exposed as-is in imbalance() for anyone who wants to see it unweighted.

Found by the tests, not by inspection This was a real defect in the first version, and it is the reason the warm-up exists. It is documented here rather than quietly patched out, because the shape of the bug — a ratio that is perfectly confident on one sample — is worth more to a reader than the fix.

4 · The band is compiled in

Both ends of the travel are constant in the bytecode. There is no owner, no setter, no proxy, no upgrade path, and no privileged address of any kind.

0.30%FLOOR · BALANCED FLOW 1.00%CEILING · ONE-SIDED FLOW

The strongest claim this project makes is a negative one: the worst this pool can ever charge you is 1.00%, no matter what the flow does, who is deploying, or what anyone later decides. That is not a promise in a document — it is the absence of a function.

5 · Why a hook, and not a token tax

The same idea implemented inside an ERC-20 would have to infer buy versus sell from the shape of a transfer — which address is a pool, which is a router. That inference is fragile, breaks on multi-hop, and can be sidestepped by trading through a contract the token has not been told about.

A Uniswap v4 hook is handed zeroForOne and amountSpecified by the pool manager itself. There is nothing to infer and nothing to spoof: the direction and the size are the call.

The v4 detail that silently breaks this A fee override is only honoured on a pool opened with the dynamic-fee flag. Initialise the same hook against a static-fee pool and the manager will accept the override and ignore it — the dial would appear to work while charging a flat rate forever. The hook therefore reverts in beforeInitialize rather than attach to a pool where it would be decorative.

6 · What it costs to push the dial

The instrument is sized, not merely declared safe:

  • A floor on what counts. Swaps under 0.01 ETH pay the going rate but leave the averages untouched, so dust cannot steer the reading.
  • A cap on what one trade means. Volume above 5 ETH is counted as 5 ETH. A whale registers as a large trade, not as the whole market.
  • Distance. With a 1/64 decay and a 32-swap warm-up, walking the dial across its band takes on the order of a hundred qualifying swaps — and every one of them pays the fee in force at the time.

Put together: cooling the dial before a large buy costs far more in fees paid on the way down than the ~0.7 percentage points it could possibly save. The attack is not forbidden, it is priced — which is the only form of resistance that survives contact with someone motivated.

7 · Sealed epochs

Every 64 qualifying swaps the hook closes an epoch: it folds that period's readings into a running hash chained onto the previous one, and emits it. Each seal therefore commits to the entire history behind it.

This makes the record checkable by anyone, with no trust in this page and no cooperation from the deployer: replay the events from the pool's first block, recompute the chain, and it must reproduce the on-chain chainHash exactly. If a single reading were misreported, the chain diverges and stays diverged.

8 · Parameters

NameValueWhat it does
MIN_FEE3000 · 0.30%The floor. Where balanced two-way flow settles.
MAX_FEE10000 · 1.00%The ceiling. Hard, and unreachable-past by construction.
ALPHA_DEN64EMA decay per qualifying swap.
WARMUP_SWAPS32Swaps before the reading is asserted at full weight.
EPOCH_SWAPS64Swaps per sealed, chained epoch.
minSwap0.01 ETHBelow this a swap pays, but does not steer.
sizeCap5 ETHCeiling on how much one trade can weigh.
hook flags0x20C0beforeInitialize · beforeSwap · afterSwap
pool feeDYNAMICRequired; a static-fee pool is refused at initialise.

9 · What this is not

Stating the limits is part of the design, not a disclaimer bolted to the end of it.

  • It is not protection from loss. A fee that rises with imbalance compensates liquidity providers for adverse selection. It does not prevent it, and it cannot make a falling position profitable.
  • It is not a price oracle. The hook never reads a price. Heavy one-way flow is what it sees; whether that flow was right about anything is outside its knowledge.
  • It is not a promise of volume. Aggregators route on execution quality, so a pool sitting near its ceiling will lose flow to a cheaper venue — by design. The dial cooling off is the system working, not failing.
  • It is not governed. There is nobody to petition if the band turns out to be wrong. That is the cost of there being nobody who can widen it either.

10 · Status

The contracts are written and tested against a fork of Ethereum mainnet — including an end-to-end case proving the pool manager actually applies the override, so that a warm dial demonstrably buys less for the same input, and a case asserting the band is never crossed across two hundred swaps.

The protocol is deployed and verified on Ethereum mainnet — hook, router and LP manager — and carries this site's address in its own bytecode, so anyone holding the hook address can find the documentation without trusting a link they were sent.

No token exists and no pool is open against it yet. The instrument on the front page therefore reads its floor with zero confidence: that is the true resting state of a hook nobody has swapped through, not a placeholder. The slider there is labelled a simulator because it is one.

ETHEREUM · UNISWAP V4 · The instrument · NO OWNER · NO SETTER · NO UPGRADE PATH