# Unrealized PnL omitted from health checks

Margin and liquidation checks that ignore pending orders, unrealized PnL, or floating accrual, or use mismatched state

_Area: DeFi oracles, liquidations and flash loans. Seen in 11 disclosed reports; latest 2025-06-27. Updated 2026-10-23._

## How it works
A solvency or margin check is only as correct as the set of balances it sums. The root cause here is that a health check computes an account's or pool's value from a subset of its true economic position: it reads realized balances, committed state, or share counts, but omits unrealized PnL, pending orders, floating accrual, or pending fees that other code paths do apply. When two paths disagree about what "collateral" or "position" means, one of them is wrong, and a user can act through the lenient path to appear healthy while actually underwater, or appear unhealthy while actually fine.

## Where it shows up
- A margin/health function and a liquidation function that read different state (e.g. `currentPosition` vs `latestPosition`) [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AH-2.md).
- Open-position checks that credit pending-order price adjustments while protect/liquidation checks do not [E2](https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AM-2.md).
- Liquidation previews that read share balances before a repay path mutates pool-level accrual [E3](https://bugbountylibrary.com/r/sherlock%3A2024-07-exactly-stacking-contracts%3AM-8.md).
- Available-liquidity math that subtracts only realized losses, not unrealized PnL of open positions [E4](https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-17.md).
- Collateral-release paths (reduce margin, partial close) that recompute leverage without current oracle PnL [E5](https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-20.md).
- Collateral factors applied asymmetrically to realized vs unrealized buckets [E6](https://bugbountylibrary.com/r/cantina%3Ahmx_january2025%3A3.1.1.md).
- Two components computing "collateral" differently, one excluding pending fees [E7](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-7.md).
- Fill prices unbounded relative to quote, letting self-matched accounts manufacture uPnL [E8](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AM-6.md).

## How to review
The invariant: every path that decides solvency, margin, or liquidation must sum the same complete set of components — realized + unrealized PnL, pending orders, floating accrual, pending fees — using the same state snapshot and the same collateral factors. Enumerate each such path and diff the terms. Check ordering: a preview must run after, or replicate, any accrual the repay path applies. Check that fill prices are bounded relative to the quote so locked value cannot be zeroed.

## Variants seen
- State mismatch between margin and liquidation checks [E1](https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AH-2.md).
- Asymmetric pending-order adjustment across open vs protect [E2](https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AM-2.md).
- Preview-before-accrual ordering bug [E3](https://bugbountylibrary.com/r/sherlock%3A2024-07-exactly-stacking-contracts%3AM-8.md).
- Unrealized PnL excluded from pool liquidity [E4](https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-17.md) and from margin release [E5](https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-20.md).
- Asymmetric collateral factor on realized/unrealized [E6](https://bugbountylibrary.com/r/cantina%3Ahmx_january2025%3A3.1.1.md).
- Pending fees excluded from one collateral calc [E7](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-7.md).
- Unbounded fill price inflating uPnL [E8](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AM-6.md).

## Impact and severity
Wrongful liquidation of healthy accounts, unliquidatable bad debt, insolvency of pools, and drained collateral. Severity rises when small TVL plus per-action fees lets an attacker force liquidation cheaply [E7](https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-7.md), and when self-matched accounts can manufacture uPnL at no cost [E8](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AM-6.md).

## Evidence
- E1: https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AH-2.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2025-01-perennial-v2-4-update%3AM-2.md
- E3: https://bugbountylibrary.com/r/sherlock%3A2024-07-exactly-stacking-contracts%3AM-8.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-17.md
- E5: https://bugbountylibrary.com/r/sherlock%3A2024-05-elfi-protocol%3AH-20.md
- E6: https://bugbountylibrary.com/r/cantina%3Ahmx_january2025%3A3.1.1.md
- E7: https://bugbountylibrary.com/r/sherlock%3A2023-10-perennial%3AM-7.md
- E8: https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AM-6.md
