# Untrusted balance and empty-state checks

Checks or amounts read from live balances or zero-equality that any outsider can flip

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

## How it works
A check or derived amount reads state an outsider can move, instead of protocol-recorded state. Two roots share a symptom:

1. **Live-balance reads.** `balanceOf(address(this))` or a user balance is treated as if only the protocol moved it. A direct transfer changes the value, flipping a comparison or inflating a derived amount [E1](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md)[E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md)[E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md).
2. **Empty/zero-state equality.** A zero-amount call passes allowance math but still fires a side effect the author assumed unreachable, because equality checks like `currentShares == shares` are true at zero [E3](https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md)[E4](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md).

A third, adjacent shape: a strict post-transfer assertion (`balanceOf(...) == 0`) on a balance outsiders can donate to [E6](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md).

## Where it shows up
- `balanceOf(address(this))` used in a validation or comparison, not a user-supplied amount [E1](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md)[E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md)[E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md)
- Redemption passing the full live balance to a paired-token transfer [E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md)
- Equality checks (`currentShares == shares`) true for zero-debt/empty state [E3](https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md)
- Functions gating a state change behind an allowance/transfer check but never rejecting `amount==0` [E4](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md)
- Post-transfer assertions like `balanceOf(...) == 0` on a balance outsiders can donate to [E6](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md)
- Token balance used as a proxy for "has collateral" where downstream logic needs real liquidity [E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md)

## How to review
Invariant: any value used in a check or amount must come from protocol-recorded state (user-supplied parameter, internal accounting), not a balance an outsider can move. Internal accounting means a stored counter updated only by protocol entry points:

```
// unsafe: userStake = token.balanceOf(user)
// safe:
userStake[user] += amt; // on deposit
userStake[user] -= amt; // on withdraw
```

Triage cheapest-grief first:
1. Zero/empty paths — confirm `amount==0` is rejected and equality checks exclude the empty case [E3](https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md)[E4](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md).
2. Donation paths — for each `balanceOf` read, ask who can change it and whether the paired token is minted proportionally [E1](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md)[E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md)[E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md).
3. Post-transfer assertions — confirm the asserted balance is one the protocol fully controls [E6](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md).

## Variants seen
- Direct transfer inflates derived stake, reverting a vote-creation comparison [E1](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md)
- Donated tokens lack paired FYTs, blocking redemption [E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md)
- `repay(0)` triggers full-repay cleanup on zero-debt loan [E3](https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md)
- `borrow(0)` forces victim into a market via allowance side effect [E4](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md)
- 1-wei bathToken flips a `has collateral` branch, blocking position opening [E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md)
- Post-transfer zero-balance assertion broken by dust donation [E6](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md)

## Why fixes fail
Guarding one entry point leaves other paths moving the same balance [E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md). Fixes must switch to internal accounting, reject `amount==0`, and avoid strict zero-balance post-conditions.

## Impact and severity
Frozen funds [E2](https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md), griefed positions [E3](https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md)[E4](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md), blocked vote creation [E1](https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md), blocked position opening [E5](https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md), bricked withdrawals and sweeping [E6](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md)[E8](https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md). As general guidance, severity rises when the grief is cheap (1 wei) and the victim cannot recover without admin action.

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.14.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2022-10-illuminate%3AH-14.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-15.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-6.md
- E5: https://bugbountylibrary.com/r/c4%3A2023-04-rubicon%3AM-27.md
- E6: https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02.md
- E7: https://bugbountylibrary.com/r/sherlock%3A2023-01-derby%3AM-5.md
- E8: https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-07.md
