# Residual amount credited to wrong bucket

Leftover or surplus after swap/repay booked as debt, refund, or input it never was

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

## How it works
A function computes a leftover (surplus after a swap, unused deposit, or residual after a repay) and then books it into a bucket that does not own it. The assumption that breaks: that the leftover belongs to the caller or to the debt, when in fact it belongs to a treasury, a pool, or nobody. The code then either credits it as input the caller never supplied, sends it somewhere it is lost, or tries to repay debt that does not exist.

## Where it shows up
- Swap or deposit functions that run keeper/rebalance/price-recovery logic before the invariant check, mixing injected funds with caller funds [E1](https://bugbountylibrary.com/r/dhl%3A20261003-malt.md)
- `mint`-style calls taking an upper bound, with a comment claiming a helper like `skim()` refunds the surplus [E2](https://bugbountylibrary.com/r/c4%3A2024-04-noya%3AH-05.md)
- Callbacks computing `residual = swapOutput - debt` and force-approving it into a repay path [E3](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-02.md)
- Invariant checks done on final balances without separating who contributed what [E1](https://bugbountylibrary.com/r/dhl%3A20261003-malt.md)
- Boundary where debt is fully repaid (`cmBorrowed == 0`) but residual still tries to repay [E3](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-02.md)

## How to review
Identify every leftover/surplus/residual value and trace exactly which party it belongs to. The invariant: each unit of value is attributed to its true owner, and no bucket is credited with value it did not supply. Check that injected treasury or keeper funds are excluded from caller-input accounting before any invariant check [E1](https://bugbountylibrary.com/r/dhl%3A20261003-malt.md). Read the actual source of third-party helpers (`skim`, `mint`) rather than trusting comments about where surplus goes [E2](https://bugbountylibrary.com/r/c4%3A2024-04-noya%3AH-05.md). For residuals, confirm the zero-debt and full-repay boundaries are handled and the residual goes to its designated recipient [E3](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-02.md).

## Variants seen
- Treasury rebalance DAI counted as caller swap input, draining Capital Source [E1](https://bugbountylibrary.com/r/dhl%3A20261003-malt.md)
- Surplus assumed refunded by `skim()` but forwarded to Pendle treasury, then MEV-skimmed [E2](https://bugbountylibrary.com/r/c4%3A2024-04-noya%3AH-05.md)
- Residual swap amount force-repaid as extra debt, reverting on full close [E3](https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-02.md)

## Impact and severity
Severe: E1 drained 12,744 DAI from a treasury via a 1 DAI swap. E2 lost excess tokens to a third party. E3 caused denial of service on a normal full-close. Severity rises when the misattributed bucket is a shared treasury or when the residual path is reachable on every user action.

## Evidence
- E1: https://bugbountylibrary.com/r/dhl%3A20261003-malt.md
- E2: https://bugbountylibrary.com/r/c4%3A2024-04-noya%3AH-05.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-10-loopfi%3AM-02.md
