Varve Open the app

The record

One number is in the log. The other one isn’t

ERC-4626 is a good standard. It has one hole, and the hole is invisible until the chain stops answering questions about the past.

A share price has two halves and they are not alike

A share price is totalAssets / totalSupply. Those two numbers have completely different fates in the record, and nobody says so.

The supply is safe. ERC-20 requires a Transfer on every mint and every burn, with the zero address on one side, so the supply at any past block is a sum over events any node still holds. It is reconstructible for ever, from a pruned node, with no archive and no indexer.

The assets are not. totalAssets() is a storage read, and it moves when income arrives, when a loss is taken and when a fee is charged — none of which the standard has an event for. So the numerator survives only where something else happens to pin it.

The two events

The standard defines exactly two: Deposit(sender, owner, assets, shares) and Withdraw(sender, receiver, owner, assets, shares). Both fire when a holder does something. Neither fires when the vault does.

Income arriving is a silent increase in totalAssets(). A loss is a silent decrease. A performance fee is a silent mint. Every one of them moves the share price, and the share price lives in a storage slot with no event attached to it.

What that costs, exactly

Give the standard its due first, because the flattering version of this argument is wrong. A Deposit carries both assets and shares, so it does pin the conversion rate at that instant. A vault's price is recoverable at every block where somebody entered or left.

What it cannot give you is the price at any other moment — and those are the moments you want, because they are the ones where you were holding and nobody happened to transact. Measured across the 49 live ERC-4626 vaults on Robinhood Chain: the median vault has a recoverable price on 0.0000% of the blocks in a common 4.7-day window, and the typical gap between two knowable moments is 3.4 days.

On a chain with deep archival state that is an inconvenience. On this one it is not, because the state that would answer is gone in 10.2 minutes.

Why a varve

A varve is the couplet of sediment a lake lays down in one year: pale silt washed in during the meltwater season, dark organic mud settling under winter ice. Count the couplets and you have a calendar, and the calendar is exact because each layer was laid down while the year it records was happening.

The Lake Suigetsu core is the famous one. Forty-five metres of continuous laminations, more than 50,000 of them, and because they are continuous they became the calibration curve that everybody else's radiocarbon dates are read against. There is no procedure for recovering a layer that was never laid down. The record is the only history there is.

The Lake Suigetsu core at the Fukui Varve Museum: 45 metres of annual layers, read back 50,000 years.
The Lake Suigetsu core at the Fukui Varve Museum. The labels on the wall are years before present; the far end is 65,000. Phonon.b, CC BY-SA 4.0.

What Varve writes

Every mutation that can move the share price writes one Layer:

event Layer(uint64 indexed n, uint8 indexed kind, uint128 assets, uint128 supply)

assets and supply together are the share price at that block, to the last unit, with no division performed by the writer and no oracle anywhere. kind is one of four: a genesis marker, a deposit, a withdrawal, income arriving, or the vault being marked down. The last two are the ones the standard has no event for at all.

One word for the whole series

Writing the layers is not enough on its own. A reader who replays the logs has no way to know whether they got all of them — an indexer that dropped a layer looks exactly like an honest one.

So the contract also keeps a running commitment:

chronology = keccak256(abi.encode(chronology, n, kind, assets, supply, block.number))

One storage word, updated on every layer. Replay the Layer logs, recompute the accumulator, and compare it against the word the contract holds now. A missing layer gives a different word. A reordered pair gives a different word. An invented layer gives a different word. Ten minutes of state is enough to audit an unbounded history, because one word is enough.

Those three claims are properties 3, 4 and 5, and 4 and 5 are negative controls: without them property 3 proves only that some hash equals some hash.

What this is not

It is not a claim that events are cheap — a layer costs about 1,100 gas, and the site would rather say so than pretend otherwise. It is not a claim that nobody could index the vault themselves; they could, and then the history exists as long as their indexer does and a reader has to trust it. And it is not a claim about this chain being unusual. The Uniswap V3 pools on the same chain put their price in the event and their history is complete forever, which is exactly why the finding is about a standard rather than about a node.