# Partial refund and overpayment accounting

Refunds or charges computed from one iteration, one branch, or a capped amount instead of the true total

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

## How it works
A contract takes more value than it ends up spending, then tries to give back the difference. The bug is that the "difference" is computed from the wrong quantity: only the last loop iteration, only one branch of a state flag, the user-supplied input rather than the amount actually consumed, or a residual derived from an output that a downstream contract silently caps. The invariant that breaks is simple: value in must equal value spent plus value returned, on every path. When the accounting quantity is narrower than the real spend, the surplus stays in the contract or is credited to the wrong party.

## Where to show up
- Loops over swaps/contributions that refund or deduct per iteration, with the refund taken after the loop from a single element [E1](https://bugbountylibrary.com/r/dhl%3A20250427-multitransferswap.md)[E8](https://bugbountylibrary.com/r/c4%3A2023-04-party%3AH-07.md)
- Refund gated on a state flag, where other branches of that flag never forward or return the fee [E4](https://bugbountylibrary.com/r/sherlock%3A2024-11-autonomint%3AM-28.md)
- Wrappers that charge the user-supplied `original_amount` while the inner call returns the amount actually consumed [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-10.md)
- Residual computed as `swapOut - debt` where the callee caps repayment at total debt [E2](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-05.md)
- Escrow taken during a stateful process (vote, stake, initialize) with terminal transitions (cancel, abort) that delete state without unwinding [E5](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-10.md)[E7](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AM-6.md)
- Refund keyed on owner/creator without checking how the position was created (e.g. liquidation path that never paid the fee) [E6](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-16.md)

## How to review
For each function accepting value, enumerate every exit path and confirm: sum(value spent) + sum(value returned) == value received, per user. Check that loop refunds accumulate a running total, not index the last element. Check that any amount charged equals the amount the callee reports as consumed, not the caller's input. Where a downstream call caps an input, confirm the caller handles the capped case and sweeps the remainder. For escrow, list every terminal transition and confirm each has a matching refund path. For flag-gated refunds, walk each branch and confirm the funds are actually spent or returned.

## Variants seen
- Refund from final loop iteration only, intermediate overpayments unaccounted [E1](https://bugbountylibrary.com/r/dhl%3A20250427-multitransferswap.md)
- Residual stranded because downstream caps repayment [E2](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-05.md)
- Charged full input despite partial consumption [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-10.md)
- Refund gated on flag, other branch never refunds [E4](https://bugbountylibrary.com/r/sherlock%3A2024-11-autonomint%3AM-28.md)
- Cancel deletes escrow state without refunding voters [E5](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-10.md)
- Refund paid to owner who never paid the fee [E6](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-16.md)
- Unused initialization amounts locked, only delta pushed [E7](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AM-6.md)
- Batch pre-deduction not rolled back on non-reverting failure [E8](https://bugbountylibrary.com/r/c4%3A2023-04-party%3AH-07.md)

## Impact and severity
Funds stranded in the contract or drained by an attacker who manipulates reported amounts [E1](https://bugbountylibrary.com/r/dhl%3A20250427-multitransferswap.md); permanent loss of user escrow [E5](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-10.md); protocol funds paid as undeserved refunds [E6](https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-16.md). Severity rises when the surplus is attacker-withdrawable or when user principal is escrowed, and when no sweep/recovery path exists [E2](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-05.md).

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20250427-multitransferswap.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-05.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-10.md
- E4: https://bugbountylibrary.com/r/sherlock%3A2024-11-autonomint%3AM-28.md
- E5: https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-10.md
- E6: https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AH-16.md
- E7: https://bugbountylibrary.com/r/sherlock%3A2024-08-flayer%3AM-6.md
- E8: https://bugbountylibrary.com/r/c4%3A2023-04-party%3AH-07.md
