# Partial fill residual accounting bugs

Partial fills that strand or misreport the unfilled remainder, or revert on leftover amounts

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

## How it works
A partial fill splits one operation into a filled part and a leftover. The code assumes the two halves are handled symmetrically: the leftover is re-registered, re-counted, or returned. When that assumption breaks, the leftover is either dropped from bookkeeping (so a balance stays inflated) or overwritten by a value that does not match the real balance (so a residual is under-reported). Either way the contract's internal numbers drift from the tokens it actually holds.

## Where it shows up
- A function overwrites a return/amount variable with the result of an external call (delegatecall, aux action, swap) instead of measuring the actual balance delta [E1](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-07.md).
- Partial-fill branches that remove the old quote/order but only re-add it for one party, or subtract only the filled portion from a locked balance [E2](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-6.md).
- Equality assertions between intermediate amounts across two hops, where the second hop can consume only part of the input [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-09.md).
- Per-party accounting structures (pending lists, locked balances, residual amounts) updated in different places.

## How to review
For every partial path, trace each party's and each token's accounting and confirm the invariant: after the operation, recorded balances equal actual token balances, and filled + leftover = original. Check that any amount taken from an external call's return value is reconciled against the real balance delta at the contract, not trusted blindly [E1](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-07.md). Check that a split quote is re-registered and its locked value adjusted for every party [E2](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-6.md). Check that equality checks tolerate `amount_remaining > 0` when `min_out` is met [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-09.md).

## Variants seen
- Residual under-reported because `tokenOut` is set to an external exit amount rather than the contract's held balance [E1](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-07.md).
- Locked balance permanently inflated because only the filled value is subtracted and the new partial quote is not re-added [E2](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-6.md).
- Valid swap reverts because an interim-equality assertion ignores partial consumption [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-09.md).

## Impact and severity
Funds stuck in the contract [E1](https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-07.md), permanently locked PartyB funds [E2](https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-6.md), and random reverts blocking valid swaps [E3](https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-09.md). Severity rises when the leftover is large, when no recovery path exists, and when the mismatch is silent rather than reverting.

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2024-07-loopfi%3AM-07.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2023-06-symmetrical%3AH-6.md
- E3: https://bugbountylibrary.com/r/c4%3A2024-08-superposition%3AM-09.md
