# When invariants meet time: the vulnerability class conservation cannot detect

> Canonical: https://blazephoenix.xyz/learn/invariants-and-time
> License: CC BY 4.0 (attribution + link) · © 2026 BlazePhoenix
> Updated: 2026-07-29

A conservation law answers how much value exists; it cannot answer when it was earned or who was present. Value earned over time is a path integral, and the lazy rectangle sampled at the endpoint opens a defect class whose signature is that the books stay balanced while the wrong party is paid.

The audit market sells a comforting premise: prove the conservation invariant — the real balance the contract holds is at least what its ledger says it owes, matched to the wei — and the contract is safe. This article destroys that premise. A balanced ledger is not a correct one. Conservation is a statement about quantity: how much value exists. A system that accrues value over time needs a second kind of statement entirely — about TRAJECTORY: when the value was earned, and who was present while it accrued. These are different questions, and no amount of conservation checking answers the second one.

The proof is uncomfortable precisely because it is not a bug in the invariant. A ledger can balance to the wei on every single block and still hand the wrong person the money — because a redistribution of value between participants leaves the totals untouched, so the conservation check is delta-neutral and passes while the trajectory is wrong. "balanceOf ≥ owed" is a real guarantee about solvency and a total silence about fairness, timing and identity. Everything below is evidence for that, and the engineering rules that follow from taking it seriously.

## The shape of a time defect

Every quantity a time-carrying protocol distributes has the same underlying form — a path integral over the interval the participant was present:

> equation: V_i(t0 → t1) = ∫[t0,t1] rate(s) · w_i(s) / W(s) ds — rate(s) is the emission/interest rate at instant s; w_i(s) is participant i's weight; W(s) is the total weight. Value earned is the integral, not a snapshot.

## The rectangle that lies

A lazy implementation does not integrate. It samples a rectangle at the right endpoint: it multiplies the rate now by the elapsed time by the weight now over the total now. That approximation is exact only when every factor is constant across the interval — and each factor that is NOT constant becomes a distinct defect family.

Sample rate at the endpoint and you get RETROACTIVE RE-PRICING: a rate set now is applied to a period already elapsed, so an actor who moves the rate re-prices history they were not charged at. Sample the total weight W at the endpoint and you get JUST-IN-TIME CAPTURE: someone deposits an instant before a distribution and draws a share of value earned during a window they were absent for. Carry a participant weight w_i from a stored scalar that time has invalidated and you get an UNEARNED MULTIPLIER: a number that once described a live commitment keeps paying after the commitment expired.

## The accumulator, in the wild

The dominant on-chain pattern for this integral is the reward-per-share accumulator with a per-user reward-debt term — the lineage that runs through the most-forked staking contracts in the space. A global accumulator advances as value accrues; each user stores a debt equal to their stake times the accumulator at entry, so their claim is the difference. Done right it is the discrete form of the path integral. Its failure modes are a field guide to the whole class.

The canonical one: changing a rate or a weight WITHOUT accruing first. When a new pool is added, or an emission rate changes, the slope of every existing distribution changes; if the accumulators are not advanced to that instant before the slope moves, the already-earned segment is silently re-priced at the new rate. The rule the pattern demands is absolute — advance every accumulator before any write that changes its inputs.

The subtler one is a liveness failure hiding inside the arithmetic. If a user's stored debt is ever computed from a slightly different accumulator value than the current one, the claim subtraction underflows and reverts — and because the claim runs inside withdraw, the user can never remove their stake. The books never went out of balance. The value is simply frozen. A conservation check sees nothing wrong, because nothing about quantity is wrong.

## The second family: the unwritten dual

One family of time defects has nothing to do with integration and everything to do with bookkeeping. Call it the unwritten dual: a state advance whose counterpart is never recorded. A clock is advanced with no matching write anywhere. A debt is reduced on a distressed exit with no matching bad-debt entry. Each creates a quantity the system cannot account for — in the first case a sum owed to nobody and reachable by nobody, in the second a phantom liability.

The dangerous property of this family is that the primary books still balance. Conservation is a delta-neutral check: it verifies the change in the real balance equals the change in what the ledger claims to owe, on both sides of a movement. A pure redistribution — value moving between participants, totals unchanged — is delta-neutral by construction, so the guard passes while the trajectory is wrong. The instrument was working perfectly the entire time. It was simply not measuring the failing quantity.

## Rules that follow

These are engineering rules because they are checkable, not principles because they sound good.

R1 — Advance the accumulator before any write that changes its inputs. Settle the elapsed period first, or the period gets re-priced at a rate that never prevailed across it. This closes the entire retroactive-re-pricing vector at once.

R2 — Distribution and collection move in the same atomic step. Credit before debit and the ledger claims more than it holds; debit before credit and the reverse. A weakened conservation identity that tolerates the gap is exactly the blind spot that hides the next bug.

R3 — Price by what remains, never by a historical scalar. If a multiplier is the price of a commitment, it must be a function of the commitment that is still outstanding, not a number stored when it began. The test is a pure equivalence: two positions identical in principal, debt and remaining term must receive an identical multiplier, whatever path produced them.

R4 — Every clock advance has a named, reachable destination for the value it represents. Advancing time is a state change; if the schedule declines to distribute for that period — which can be entirely correct — the value must still land somewhere nameable and reachable. "Nowhere" is not an accounting outcome; it corrupts the totals for the rest of the system's life.

R5 — One implementation per published quantity. Any figure computed in two places will diverge — not may, will. When a verification number exists in an aggregate view and again in a standalone getter, fixing one leaves the other behind, and the divergence is found only if an independent test rebuilds the number from primitive state. Deduplication here is a security measure, not a tidiness measure.

## The dimension map, and the dimension that hides the rest

A deployed contract lives in more than the two axes of value and time. A working map has at least eight: value conservation (does the money add up), time trajectory (when was it earned and who was present), liveness (can it be frozen or deadlocked), privilege (can an authority drain or redirect it), incentives (is anyone paid to keep it clean), asset boundary (what if a token misbehaves), reporting truthfulness (do the published numbers describe reality), and deployment environment (what does the code assume about the world it runs in — that funding arrives at genesis, that traffic is continuous, that the chain never goes quiet).

Reporting truthfulness is the dimension that hides the others. A protocol that publishes trustless verification numbers is checked, by everyone, THROUGH those numbers. A defect that corrupts the instrument rather than the value is therefore invisible to every other dimension at once: it does not break solvency, it makes the solvency figure overstate or understate for the rest of the contract's life, silently distorting every reading anyone ever takes. The correct test is never that the views are self-consistent — self-consistency is what a wrong number has with itself — but that every published figure is rebuilt from primitive state by an independent party and compared.

The lesson is not that conservation is weak; it is the right first move, and an insolvent state that is unreachable rather than merely observable is a real achievement. The lesson is that recognising a risk is not the same as covering it. Value can be sealed while time is not, and the most reliable predictor of where the next defect lives is the dimension nobody has named yet.

**Verify it yourself:** Take any accumulator-based distribution and construct two positions identical in principal, weight and remaining term but reached by different histories — then check they are paid identically; where they diverge, a stored scalar is pricing a commitment that time has already changed, and no conservation check will ever flag it

Related: https://blazephoenix.xyz/learn/invariant-driven-design · https://blazephoenix.xyz/learn/invariant-driven-design-ai-hallucination · https://blazephoenix.xyz/learn/proof-of-solvency
