# Aggregate balance check ignores escrow

Caps or balance checks using aggregate balances that include escrowed, locked, or router-held funds

_Area: Smart contract access control and control flow. Seen in 3 disclosed reports; latest 2025-02-26. Updated 2026-10-23._

## How it works
A contract decides whether an operation is allowed by comparing an amount against a balance or cap that is not the balance the operation actually draws from. The check assumes the measured balance equals the caller's free, spendable funds. When part of that balance is escrowed, locked, held by a shared router, or subject to a per-call protocol bound, the assumption breaks: the check passes or fails for the wrong reason, and legitimate operations are blocked or funds become unreachable.

## Where it shows up
- Per-`msg.sender` caps (`balanceOf(msg.sender)`) where a shared router or aggregator is the `msg.sender` [E3](https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md)
- Admin reallocation checks using `totalAmount - amountClaimed` while other paths move the same balance out [E2](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md)
- Wrapper stake paths with no cap matching the downstream protocol's per-request maximum [E1](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AM-06.md)
- Any limit or eligibility check keyed on a balance that escrow, marketplace listing, or staking also touches

## How to review
Identify every path that moves or locks the balance a check reads. The invariant: the quantity compared against a cap or limit must equal the caller's free, unencumbered funds, and every path that removes funds must be reflected in that quantity. For per-call protocol bounds, confirm the wrapper enforces the same min/max on both entry and exit paths [E1](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AM-06.md). For shared routers, confirm limits are tracked per end user, not per router [E3](https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md). For reallocation, confirm claimed, listed, and escrowed amounts are all reconciled [E2](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md).

## Variants seen
- Asymmetric caps: stake uncapped, unstake exceeds downstream per-request maximum, funds locked [E1](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AM-06.md)
- Escrow not reconciled: user lists allocation, admin reallocation reverts on insufficient balance [E2](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md)
- Shared `msg.sender`: router's aggregate balance hits per-wallet deposit limit, all routed deposits revert [E3](https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md)

## Impact and severity
Outcomes ranged from locked/unwithdrawable funds [E1](https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AM-06.md) to griefing that blocks admin reallocation [E2](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md) to denial of service on all deposits through a router [E3](https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md). Severity rises when the blocked path is the only exit or when any user can trigger the blocking state; user-triggerable escrow [E2](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md) and shared-router saturation [E3](https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md) make it worse because one actor blocks everyone.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-07-benddao%3AM-06.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-09.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-12-bakerfi-invitational%3AM-15.md
