The flood

A basin collects for hours.
The gauge sees one pulse.

Rain falls over a whole catchment, quietly, everywhere at once. The gauge at the mouth records a flood some hours later. Nobody thinks the flood is when the rain fell.

A liquidity vault is the same shape and is read the other way round. Fee income accrues across the pool continuously; the vault learns about it in one harvest transaction; and the share price — the only number anybody reads — moves at the gauge rather than in the catchment.

Measured on Robinhood Chain

Income does not trickle in

Every Uniswap V3 Swap over a contiguous window of 30,000 blocks — about 0.84 hours at this chain's 0.101-second blocks — read straight from the node with no key, no vendor and no proxy. 176,526 swaps across 1,209 pools.

Each swap's fee is computed from the amounts carried in the event itself and the pool's own fee tier. There are no prices anywhere in this measurement: income is measured per pool, in that pool's own input token, and every figure published is a share — a quantity a price cannot change. This chain has no oracle, and a dollar figure here would be the least reliable number on the page.

A block here is 0.101 seconds. "Most blocks pay nothing" would be true of a perfectly even income stream at that granularity, so it is not the interesting figure and it is not the one to quote. The same question asked of whole minutes is, and both are below.
Blocks paying the median pool nothing98.8%
Whole minutes paying it nothing6.0%
Share of the window's fees in its busiest 1% of blocks99.6%
Pools measured40 of 1,209 seen
Minimum swaps to be measured at all40

One number is missing on purpose. How long you must hold before your realised income is within 10% of the pool's own mean rate did not fit inside the window for any of the 40 pools measured. The honest report of a censored statistic is that it was censored, not the censoring bound printed as though it were the answer.

What it costs

One block of standing there

The sequence below is executed against the compiled contract on Robinhood Chain, twice: once with instant recognition, once with the unlock on. Nothing is arithmetic on paper. executed

The sequence

  1. A vault has been running and holds 1,000,000 units.
  2. A depositor arrives with an amount equal to the vault, one block before a harvest.
  3. A harvest of 1% of TVL lands.
  4. 1 block later, the depositor leaves.

It is run twice more, with and without the visitor, so what the standing holder loses is a real counterfactual on the same contract at the same blocks — not the visitor's gain asserted to be somebody's loss.

50.00bps of its own stake, taken by the visitorinstant recognition
0.001389bps, same sequence, unlock on36,000 blocks · ~60.6 min
49.50bps the standing holder losesinstant recognition
36,000×the difference one constructor argument makesand unlockBlocks is 36,000
The ratio is not a coincidence and not a claim: releasing over n blocks hands one block's worth of the harvest to whoever is present, so the answer is n. Reading 36,000 out of the contract is the arithmetic confirming itself.

The two share prices

instant unlocked blocks →
The same income, the same harvests. Silt is a vault that credits each harvest in the block it arrives; water is the same contract with unlockBlocks set. Both end in exactly the same place — that is P11 on the contract page, and it is checked on chain rather than drawn.

Every row executed

HarvestVisitorInstant (bps)Unlocked (bps)Ratio
0.05% of TVL0.1x TVL 4.55 0.000126 36,018×
0.05% of TVL1x TVL 2.50 0.000069 36,007×
0.05% of TVL5x TVL 0.83 0.000023 36,013×
0.25% of TVL0.1x TVL 22.73 0.000631 36,001×
0.25% of TVL1x TVL 12.50 0.000347 36,001×
0.25% of TVL5x TVL 4.17 0.000116 36,003×
1% of TVL0.1x TVL 90.91 0.002525 36,001×
1% of TVL1x TVL 50.00 0.001389 36,000×
1% of TVL5x TVL 16.67 0.000463 36,000×

A smaller visitor takes more per unit of its own stake, because it dilutes the existing holders less on the way in. The largest single arrival is not the worst case for the arriver — it is the worst case for everyone else.

And the part that is not a fix

HarvestDwellInstant (bps)Unlocked (bps)Ratio
1% of TVL1 block 50.00 0.001389 36,000×
1% of TVL600 blocks (~1 min) 50.00 0.833333 60×
1% of TVL3,600 blocks (~6 min) 50.00 5.0000 10×
1% of TVL36000 blocks (the whole unlock) 50.00 50.0000
The unlock does not forbid the capture. It prices it by time held. A visitor who stays the whole unlock window takes exactly what the instant vault would have given them — and by then they have been a holder for the whole window, which is the only thing anybody was asking for. A mechanism that made the last row zero would be a lockup, and this contract does not have one.

Where this comes from

Bond markets settled this in the seventeenth century

A bond quotes a clean price and settles at a dirty price: clean plus the interest accrued since the last coupon. The reason is exactly the one above. If it settled clean, whoever held the bond on the coupon date would take the entire coupon and everyone who sold the day before would get none of the interest they had genuinely earned — so the price would jump on the coupon date and the day before it would be worth trading.

An ERC-4626 vault quotes one price, and it is the clean one. totalAssets() counts what has landed. Spate keeps the same single price and moves the accrual into the contract instead: harvested income is credited over the interval rather than at the instant it arrives, so the number the vault publishes is already the dirty one. dirtyPricePerShare() is a public view beside it, so the gap is visible rather than argued about.

This is not a new idea in DeFi either — a linear profit unlock is the standard fix and several vault frameworks ship one. What is unusual is publishing what it is worth, with the sequence executed, and admitting that the mechanism prices the capture by time rather than abolishing it.