# Stale cached balance in accounting

Balance, reserve, or snapshot read before a mutation, then reused in payout, fee, or debt math

_Area: DeFi accounting and math bugs. Seen in 103 disclosed reports; one confirmed bounty: $95,000; latest 2026-09-30. Updated 2026-10-23._

## How it works
Accounting code reads a balance, reserve, or snapshot, then mutates state (transfer, burn, sync, decrement, cache write) and reuses the earlier value. The invariant that breaks: every number feeding share, payout, fee, or debt math must reflect state at the moment of computation. A stale numerator with a shrinking denominator, a mutated reserve never written back, or a snapshot taken before the transfer all let bookkeeping drift from actual balances.

## Where it shows up
- Payout math where the pool balance in the numerator is not decremented per withdrawal
- Load/mutate/store reserve patterns missing a cache/store call on one path [E6](https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AH-01.md)
- Transfer hooks that burn from the pair and call sync before crediting the net amount [E1](https://bugbountylibrary.com/r/dhl%3A20260930-skydao.md)
- Sibling code paths where one branch skips the reserve/delta write-back [E2](https://bugbountylibrary.com/r/dhl%3A20260918-likwid.md)
- Self-transfers where from/to state is cached in memory before the storage mutation [E3](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md)
- Delta snapshots (balanceBefore/balanceAfter) never assigned before the transfer [E7](https://bugbountylibrary.com/r/cantina%3Ajigsaw_june2025%3A3.1.4.md)
- Health checks using last-accrual stored debt instead of interest-previewed debt [E5](https://bugbountylibrary.com/r/sherlock%3A2023-10-aloe%3AH-3.md)
- Branch storing the latest weight where a historical snapshot was used [E8](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5.md)

## How to review
For each accounting value, trace every read and write between the read and its last use. The property: any value feeding share, fee, debt, or payout math is either re-read after the last mutation or provably unchanged. Check that every mutation path has a matching store/cache call [E6](https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AH-01.md), that per-withdrawal numerators decrement, that sync happens after net credit [E1](https://bugbountylibrary.com/r/dhl%3A20260930-skydao.md), that sibling branches write back the same deltas [E2](https://bugbountylibrary.com/r/dhl%3A20260918-likwid.md), that from==to aliasing is handled [E3](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md), that snapshot fields are assigned before use [E7](https://bugbountylibrary.com/r/cantina%3Ajigsaw_june2025%3A3.1.4.md), that health math previews accrued interest [E5](https://bugbountylibrary.com/r/sherlock%3A2023-10-aloe%3AH-3.md), and that a branch stores the same snapshot it derived from [E8](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5.md). Triage: grep for `balanceBefore`, `balanceAfter`, `cache_reserve`, `pairDelta`, `sync(`, `Snapshot`, `lastAccrued`, `borrowBalanceStored`. False positives: caching within a single transaction where no external call or hook can mutate the value is safe.

## Variants seen
- Sync before net credit latching reserve near zero [E1](https://bugbountylibrary.com/r/dhl%3A20260930-skydao.md)
- Frozen pairDelta on one borrow branch [E2](https://bugbountylibrary.com/r/dhl%3A20260918-likwid.md)
- Stale cached shares on self-transfer [E3](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md)
- Mutated reserve not cached, overwritten on reload [E6](https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AH-01.md)
- Uninitialized balanceBefore snapshot [E7](https://bugbountylibrary.com/r/cantina%3Ajigsaw_june2025%3A3.1.4.md)
- Stored last-accrual debt in health checks [E5](https://bugbountylibrary.com/r/sherlock%3A2023-10-aloe%3AH-3.md)
- Latest weight stored where historical snapshot was used [E8](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5.md)

## Why fixes fail
Partial fixes that clear only one field leave other stale accumulators live [E3](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md). Fixing one conversion path leaves the sibling path double-counting.

## Impact and severity
Drained pairs and vaults [E1](https://bugbountylibrary.com/r/dhl%3A20260930-skydao.md)[E2](https://bugbountylibrary.com/r/dhl%3A20260918-likwid.md)[E3](https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md), corrupted utilization and reward accounting [E6](https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AH-01.md), inflated collateral enabling over-borrow [E7](https://bugbountylibrary.com/r/cantina%3Ajigsaw_june2025%3A3.1.4.md), bad-debt-inducing health checks [E5](https://bugbountylibrary.com/r/sherlock%3A2023-10-aloe%3AH-3.md), reverted borrow/poke after redemptions [E8](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5.md). Severity rises when the stale value persists across users or blocks exits.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20260930-skydao.md
- E2: https://bugbountylibrary.com/r/dhl%3A20260918-likwid.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-12-ethereumcreditguild%3AH-02.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2023-12-arcadia%3AH-3.md
- E5: https://bugbountylibrary.com/r/sherlock%3A2023-10-aloe%3AH-3.md
- E6: https://bugbountylibrary.com/r/c4%3A2025-02-blend-v2-audit-certora-formal-verification%3AH-01.md
- E7: https://bugbountylibrary.com/r/cantina%3Ajigsaw_june2025%3A3.1.4.md
- E8: https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.5.md
