# Stale price in payout math

Payout or redemption priced from stale, floored, cached, or post-state value instead of current live state

_Area: DeFi accounting and math bugs. Seen in 3 disclosed reports; latest 2025-02-17. Updated 2026-10-23._

## How it works
A payout, premium, or redemption amount is computed from a value that is not the current authoritative state. The assumption that breaks is "the price/level I read is the one that applies right now." Instead the code reads a cached field, a value derived from a floored quantity, a value computed from post-transaction state, or a stored parameter that a ramp should have updated. The result is a rate that diverges from reality, favoring whoever can trigger the divergence.

## Where it shows up
- Redemption/withdrawal math that recomputes collateral level or share price using the amount being withdrawn (post-state) rather than current state [E1](https://bugbountylibrary.com/r/sherlock%3A2024-12-plaza-finance%3AH-2.md).
- Price derived from a tick (floored integer) instead of the stored sqrtPriceX96 [E2](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-03.md).
- Eligibility or price guards that read cached state before a refresh call runs [E3](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md).
- Time-based ramp parameters (A, target price) consumed from stored multipliers instead of recomputed from ramp state [E4](https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-03.md).
- Any consumer of a value that another function is responsible for refreshing.

## How to review
For each payout/price path, identify the authoritative source of the value and confirm the code reads it, not a proxy. The invariant: the value used to price a transaction must equal the value that would be computed from current on-chain state at execution time. Check pre- vs post-transaction state in share/collateral math [E1](https://bugbountylibrary.com/r/sherlock%3A2024-12-plaza-finance%3AH-2.md); confirm sqrtPriceX96 comes from slot0, not getSqrtRatioAtTick(currentTick) [E2](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-03.md); confirm guards run after any refresh they depend on [E3](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md); confirm ramped parameters are recomputed at every consumer, matching getA()/getA2() [E4](https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-03.md).

## Variants seen
- Post-withdrawal estimated collateral level inflating redeem rate [E1](https://bugbountylibrary.com/r/sherlock%3A2024-12-plaza-finance%3AH-2.md).
- Floored tick used to derive sqrt price, breaking V3 liquidity math [E2](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-03.md).
- Stale eligibility check ordered before the refresh call [E3](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md).
- Stored precision multipliers ignoring a target-price ramp [E4](https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-03.md).

## Impact and severity
High: E1 let anyone drain ETH by buying low and redeeming at $100; E2 caused reverts or miscomputed deltas; E3 let disqualified users claim emissions; E4 silently nullified the owner's ramp. Severity rises when the divergence is attacker-triggerable and the payout is directly withdrawable.

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2024-12-plaza-finance%3AH-2.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-03.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-29.md
- E4: https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-03.md
