# Stale checkpoint accounting drift

Checkpoints that correct a total in only one direction, or overwrite pending state, leaving phantom balances

_Area: DeFi accounting and math bugs. Seen in 2 disclosed reports; latest 2026-05-18. Updated 2026-11-02._

## How it works
Accounting code often pre-credits a predicted value (capacity, pending epoch, ownership) and reconciles later. The bug is that reconciliation only handles one direction of the delta, or overwrites scheduling state without checking what was already there. The stored total then drifts from reality: it is too high (phantom capacity that can be spent) or out of step with a second layer of accounting (per-user vs global). The broken assumption is that the correction branch always fires, or that a checkpoint is only ever written once.

## Where it shows up
- A reconcile step guarded by an inequality (`if (actual > predicted)`) with no `else` to subtract over-credit [E3](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md).
- Developer comments asserting an inequality "must always hold" — the unhandled case is usually the negation [E3](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md).
- Per-account scheduling fields (`_pendingEpochs[account]`) assigned unconditionally on every deposit/redemption [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md).
- Two settlement layers: a global aggregate flywheel and a per-user flywheel gated on different state [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md).
- Guards that validate recipient state at transfer time (`_isPublicVault(to)`) rather than binding it immutably [E2](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md).
- Permissionless deposits or transfers on behalf of an address that has not acted yet [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md)[E2](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md).

## How to review
For every pre-credit/reconcile pair, enumerate both signs of the delta and confirm each is handled. The invariant: after any checkpoint, the stored total equals the recomputed true total, for increases and decreases alike. For per-account state, the invariant is that a pending marker is never moved later by an unrelated party's action; check whether a write is conditional on the field being unset. For two-layer accounting, confirm the user layer and global layer advance on the same trigger. For recipient guards, ask whether the check can be satisfied by acting before the recipient exists (predicted CREATE addresses).

## How finders spotted it
- Read the settlement flywheel and noticed `_pendingEpochs` overwritten on every deposit without checking for an existing entry, while the global flywheel used separate pending fields — implying divergence [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md).
- Read `transferFrom`'s `_isPublicVault(to)` guard, saw it was time-of-transfer only, and that CREATE addresses are predictable [E2](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md).
- Read `checkpoint()`'s settlement branch, distrusted the comment that the inequality "has to be always true", and hypothesized a year boundary where inflation drops [E3](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md).

## Variants seen
- Per-user pending epoch overwritten by a tiny third-party deposit, desyncing user and global settlement [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md).
- Lien transferred to a predicted future vault address before deployment, corrupting vault accounting [E2](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md).
- Upward-only correction of `effectiveBond` leaving phantom mintable capacity at inflation-decreasing year boundaries [E3](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md).

## Impact and severity
Share mispricing and fund loss in the vault, compounding as pending epochs are pushed repeatedly and corrupting vault-wide accounting, not one position [E1](https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md). Phantom bond capacity (~412k OLAS) that can be minted [E3](https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md). Misattributed vault accounting from a pre-deployment transfer [E2](https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md). Impact rises with how far the drift reaches (global vs single user) and whether the phantom value is spendable.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2023-05-perennial%3AH-1.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-01-astaria%3AM-04.md
- E3: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AM-09.md
