# Wrong reference index breaks accounting

Reference tick, heap index or slot set from a substitute, so fee, position or operator math is wrong

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2024-02-14. Updated 2026-10-29._

## How it works
Accounting math is relative to a reference point: the current pool tick, the live heap index, the occupied storage slot. When code initializes or updates that reference from a substitute (a nearest tick, an early-returning helper, a slot left populated after removal), derived values are computed against the wrong baseline. The invariant that a value is relative to the true current state breaks silently: numbers stay plausible but no longer match reality.

## Where it shows up
- Fee growth or outside values initialized from a tick other than the pool tick, e.g. nearestTick [E1](https://bugbountylibrary.com/r/c4%3A2021-09-sushitrident-2%3AH-17.md)
- Heap root replacement where maxHeapify early-returns on a tie, so the moved leaf's index-map write never runs [E2](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AM-07.md)
- Array-backed heap removal that decrements count but leaves the vacated last slot populated in storage [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md)
- Stale stored IDs later read back and used as divisors or lookups [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md)

## How to review
Identify every value described as relative to a reference (tick, index, slot) and confirm the reference is the live one, not a cached or approximate substitute. For each mutation, check the invariant holds unconditionally: after root replacement, the moved element's index map is rewritten before any early return; after removal, the vacated slot is cleared, not just the count decremented. For fee math, verify initialization uses the pool tick and that boundary equality cases are handled explicitly. Trace stale values forward to their consumers (division, lookup) and confirm they cannot reach them.

## Variants seen
- Fee growth outside initialized to zero instead of global when a tick equals the reference tick [E1](https://bugbountylibrary.com/r/c4%3A2021-09-sushitrident-2%3AH-17.md)
- Heap root replacement skips index-map update on a tie, corrupting ordering [E2](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AM-07.md)
- Removal leaves stale operator ID in the last slot, later used as a divisor [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md)

## Impact and severity
Incorrect fee accounting for LPs [E1](https://bugbountylibrary.com/r/c4%3A2021-09-sushitrident-2%3AH-17.md), corrupted heap ordering and position lookups [E2](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AM-07.md), and division-by-zero bricking deposits and withdrawals [E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md). Severity rises when the stale value reaches a divisor or a fund-moving path, turning a bookkeeping error into a denial of service or misallocated rewards.

## Why fixes fail
A fix that only guards the visible symptom (e.g. the division) leaves the stale reference in storage; the initialization or cleanup step must be corrected so the invariant holds at the source [E2](https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AM-07.md)[E3](https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md).

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2021-09-sushitrident-2%3AH-17.md
- E2: https://bugbountylibrary.com/r/c4%3A2023-12-revolutionprotocol%3AM-07.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-02-rio-network-core-protocol%3AH-8.md
