# Fee-debt cache skipped or clobbered

Fee or debt cache not updated on a path, or overwritten by stale in-memory state

_Area: DeFi accounting and math bugs. Seen in 4 disclosed reports; latest 2024-08-06. Updated 2026-10-24._

## How it works
Fee and debt accounting relies on a cache that must be updated on every path that changes a position. The assumption that breaks: that every path updates it, or that a later write-back preserves it. When a path skips the update, an address accrues value it never earned; when a stale in-memory copy is written back, a credited amount is discarded. Either way the stored bookkeeping drifts from reality.

## Where it shows up
- Transfer/mint hooks that exempt `self`, `zero`, or the pair address from fee-debt caching [E2](https://bugbountylibrary.com/r/c4%3A2022-10-traderjoe%3AH-05.md)
- Fee-total decrements inside `unchecked` blocks [E2](https://bugbountylibrary.com/r/c4%3A2022-10-traderjoe%3AH-05.md)
- Share-minting guarded by a branch keyed on "no new liquidity added" [E1](https://bugbountylibrary.com/r/c4%3A2023-08-goodentry%3AH-04.md)
- Stored principal mutated with raw amounts while debt is computed via a compounded factor [E3](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-11.md)
- A function that caches struct state in memory, calls a helper that writes the same storage slot, then writes the cache back [E4](https://bugbountylibrary.com/r/sherlock%3A2024-02-perennial-v2-3%3AM-5.md)

## How to review
For each stored fee/debt/share field, enumerate every path that can change the position and confirm the cache is updated on all of them, including exempt addresses. Check that any memory-cached struct is not written back after a helper has already written the same slot. The invariant: for every account, stored fee-debt equals the value implied by current global accumulators at the time of the last position change, and no credited amount is lost between credit and persist. Verify share-mint downscaling is gated on the actual condition that makes it necessary, not on a proxy that an attacker controls.

## Variants seen
- Exempt-address fee-debt skip lets pair-held tokens accrue unearned fees, then unchecked subtraction drains reserves [E2](https://bugbountylibrary.com/r/c4%3A2022-10-traderjoe%3AH-05.md)
- Fee downscaling skipped whenever liquidity is added, enabling flash-loan fee theft [E1](https://bugbountylibrary.com/r/c4%3A2023-08-goodentry%3AH-04.md)
- Raw principal update bypasses compounded-factor math, zeroing unlock fees [E3](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-11.md)
- Self-referral/self-liquidation credit overwritten by stale context on settle [E4](https://bugbountylibrary.com/r/sherlock%3A2024-02-perennial-v2-3%3AM-5.md)

## Why fixes fail
Evidence shows fixes that patch one path (e.g. the downscale branch) without auditing the exempt-address or write-back paths leave the same class open elsewhere.

## Impact and severity
High: reserve drain [E2](https://bugbountylibrary.com/r/c4%3A2022-10-traderjoe%3AH-05.md), theft of accrued fees [E1](https://bugbountylibrary.com/r/c4%3A2023-08-goodentry%3AH-04.md), free unlocks [E3](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-11.md), lost user funds [E4](https://bugbountylibrary.com/r/sherlock%3A2024-02-perennial-v2-3%3AM-5.md). Worse when the skipped update is reachable by any caller and the resulting value is claimable in the same transaction.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2023-08-goodentry%3AH-04.md
- E2: https://bugbountylibrary.com/r/c4%3A2022-10-traderjoe%3AH-05.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-11.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2024-02-perennial-v2-3%3AM-5.md
