Status. The contracts are written and pass 16 tests on a fork of Base against the real PoolManager. Nothing is deployed and nothing is audited. $SIPH does not exist yet. Everything below describes how the code works, not a live protocol you can put money into today.

What LVR is

An automated market maker quotes from a curve, not from the market. When an asset's price moves on a venue with real price discovery, the pool's price is briefly stale. Someone trades against that stale price, takes the difference, and the pool ends up correctly repriced.

The pool got rebalanced. The profit from rebalancing it left with the trader. That difference is loss-versus-rebalancing, and on many pairs it exceeds the swap fees the liquidity providers earn over the same period.

There is no invoice. LVR never appears as a line item. The position simply underperforms holding the two assets, block after block, and the value leaves as searcher profit and block-ordering revenue.

Why an AMM cannot see it

A v2 or v3 pool is a fixed function. It charges the same fee on a calm Tuesday and during a violent repricing. It cannot look at who is trading, when in the block they are trading, or how far the price has moved lately — there was nowhere to put that logic.

Closing the leak requires the pool to act on something it knows about a trade before the trade executes. Uniswap v4 hooks are the first time that has been possible.

The arbitrage toll

The first swap of a block against a given pool is the one that captures that pool's LVR — it is the trade that corrects the stale price and collects the gap. SIPHON prices that slot.

The first trade of each block pays baseFee + arbFee. Every trade behind it in the same block pays the ordinary schedule. The arbitrage still happens and the pool is still corrected; the profit from correcting it no longer walks out.

The surcharge is charged as the pool's LP fee. In v4 that means it accrues to the in-range positions themselves — the recapture reaches LPs by exactly the path their ordinary fees do. There is nothing to claim, nothing to distribute, and no second contract holding anyone's money.

The staleness fee

On every swap the rate also carries a term proportional to how much this pool has been moving. The hook keeps a decayed average of the tick change each swap leaves behind and scales it into the fee, capped.

No keeper and no oracle call. Fee income rises precisely when flow is most likely to be toxic, so LPs are compensated for the risk they are actually carrying rather than being picked apart at the moment they are most exposed.

fee = baseFee
    + min(movement * 100, MAX_STALENESS_FEE)
    + (firstSwapOfBlock ? arbFee : 0)

Who gets what

The whole fee — base, staleness and toll — accrues to the pool's in-range liquidity. The protocol's share is taken separately, and only from the toll, and only on the block's first swap. An ordinary swap's fee is the LPs', entirely.

That share accrues as an ERC-6909 claim inside the PoolManager, which means cast balance on the hook reads zero while it piles up. Read pending(currency) instead. collect() redeems it, is permissionless, and can only ever pay the staking pool — the destination is immutable.

What is actually measured

Stated plainly, because the marketing word and the number in storage are not the same thing. The hook cannot know whether a given trader is informed. Nothing on chain can.

What it can measure, with no keeper and no external call, is two things:

Both correlate with toxic flow. Neither is a claim about anybody's intent, and the contract does not pretend otherwise.

The bounds

RateCeilingMeaning
baseFee1.00%The ordinary rate a pool is enrolled at.
arbFee5.00%The most the block's first swap can be surcharged.
staleness2.00%The most the movement term can add, however violent.
protocol share20%Of the toll only, never of an ordinary swap.

Every one of these is compiled in, and the setters can only move within them. There is no upgrade path and no pause. A pool that opts into this hook is opting into a schedule whose ceiling it can read today.

$SIPH stakers

The protocol's share lands in a staking pool. Stake $SIPH, earn whatever was recaptured — in the currencies the pools actually trade, so the pool keeps one accumulator per reward token rather than pretending everything normalises into one.

Rewards are noticed rather than pushed: the hook sends value with a plain transfer, so notify(token) measures the balance above what is already booked and shares the difference. Anyone may call it and there is nothing to choose.

Limits

Contracts

ContractRole
SiphonHookThe schedule. v4 hook, 0x20C8: before-initialize, before-swap, after-swap, before-swap-returns-delta.
SiphonStakingWhere the protocol's share lands. One accumulator per reward token.
SiphonToken$SIPH. Fixed supply, no owner, no mint.

Addresses appear in the console the moment they are deployed.