# Per-side checks ignore cumulative state

Checks that validate one side, one trade, or one call instead of summed net state across calls

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

## How it works
A guard validates a single quantity in isolation — one side's stake, one trade's margin, one call's shift — while the real invariant is about the *sum* of those quantities or the *net* position across repeated calls. Because each individual value stays under the limit, every call passes, and the accumulated effect exceeds what the user actually owns or what the protocol intended. The broken assumption is that "each item is within bounds" implies "the total is within bounds."

## Where it shows up
- Functions that check two variables separately (long vs short, away vs toward) instead of their sum [E1](https://bugbountylibrary.com/r/c4%3A2021-08-floatcapital%3AH-03.md)
- Pending/epoch accumulators that are not updated between calls, so repeated calls in the same epoch each re-pass the same check [E1](https://bugbountylibrary.com/r/c4%3A2021-08-floatcapital%3AH-03.md)
- Fee or utilization formulas keyed off a maker's open notional without netting offsetting trades [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AM-10.md)
- Margin or fee transfers computed from absolute position size rather than the delta [E3](https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AM-13.md)
- Whitelisted or fee-exempt actors whose actions still move the accounting [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AM-10.md)

## How to review
Identify the true invariant (e.g. total shifted ≤ user's stake; net margin moved = change in position). Then check that the code enforces it against the *cumulative* value: are per-side amounts summed before comparison? Are accumulators persisted so a second call in the same epoch sees the first? For fees and margin, is the amount derived from the delta, not the absolute size? Confirm that any actor who can move the accounting (including fee-exempt makers) pays the corresponding cost or is netted out.

## Variants seen
- Per-side stake check, repeated calls before a price update shift more than staked [E1](https://bugbountylibrary.com/r/c4%3A2021-08-floatcapital%3AH-03.md)
- Utilization ratio inflated by offsetting maker trades, raising fees paid by others [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AM-10.md)
- Absolute-size margin transfer drained by round-tripping open/close in one tx [E3](https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AM-13.md)

## Impact and severity
Loss of other users' staked tokens [E1](https://bugbountylibrary.com/r/c4%3A2021-08-floatcapital%3AH-03.md), arbitrary fee increases borne by traders [E2](https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AM-10.md), and pool funds locked as margin blocking all user actions until manual rebalance [E3](https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AM-13.md). Severity rises when the exploit is repeatable within one transaction or epoch and when no state update or cost gates repetition.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2021-08-floatcapital%3AH-03.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-02-perpetual%3AM-10.md
- E3: https://bugbountylibrary.com/r/c4%3A2023-03-polynomial%3AM-13.md
