# Cumulative total vs reduced remainder

Comparisons where one operand was already reduced by deductions while the other still counts them

_Area: DeFi accounting and math bugs. Seen in 2 disclosed reports; latest 2025-10-21. Updated 2026-10-25._

## How it works
A check compares two quantities that no longer share a basis. One side is a running total or cap; the other is a remainder that earlier code already reduced by deductions, or a balance that excludes only some of what the user owns. The mutation happens between the two: a variable is subtracted from (or a counter reduced) while the paired total still includes the deducted items. The comparison then passes or fails for the wrong reason — accepting an under-funded state or reverting on a valid one. The invariant that should hold is that both operands have had the same deductions applied.

## Where it shows up
- A loop that mutates a `remaining`/`amount` variable while a separate `sum` still includes already-counted items [E2](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.4.md).
- Earmark/debt accounting where `repay()`/`_forceRepay()` move yield tokens to the Transmuter without burning debt, so the increment is computed against `totalDebt - cumulativeEarmarked` while claims still count the repaid yield [E1](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.12.md).
- "Remaining balance" computed as `total - claimed`, ignoring vested-but-unclaimed amounts the user already owns [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-10.md).

## How to review
For every comparison, trace both operands back to their last mutation and confirm they share the same basis (same deductions applied). The property: any path that reduces a counter must reduce the paired claim/cap by the same amount. For loops, the termination condition must compare the cumulative sum against the original target, not a reduced gap — i.e. `sum >= originalTarget`, never `sum >= amount` after `amount` was decremented [E2](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.4.md). For earmark-style accounting, verify that every path reducing debt also reduces the matching claim counter, including repay-without-burn paths [E1](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.12.md).

## Variants seen
- Earmark increment exceeds `totalDebt - cumulativeEarmarked` because repay moves yield without burning debt; the counter and claim desync [E1](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.12.md).
- UTXO selection compares sum against reduced gap, selecting less than target [E2](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.4.md).
- Vesting transfer ignores vested-but-unclaimed tokens, letting the issuer move user-owned tokens [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-10.md).

## Impact and severity
Outcomes ranged from permanent DoS bricking core functions [E1](https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.12.md) to under-funded selections [E2](https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.4.md) and theft of user-owned vested tokens [E3](https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-10.md). Severity rises when the desynced value gates a hard revert (liveness loss) or ownership of funds.

## Evidence
- E1: https://bugbountylibrary.com/r/cantina%3Aalchemix_may2025%3A3.1.12.md
- E2: https://bugbountylibrary.com/r/cantina%3Acitrea_jul2025%3A3.2.4.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-12-secondswap%3AM-10.md
