# Liquidation ordering and bad-debt write-off

Liquidation paths that seize or release value before pulling repayment, or skip writing off bad debt

_Area: DeFi oracles, liquidations and flash loans. Seen in 2 disclosed reports; latest 2024-04-06. Updated 2026-11-02._

## How it works
Liquidation moves value in two directions: collateral out to the liquidator, repayment in from the liquidator. The assumption that breaks is that these two legs are atomic and symmetric — that the contract can always complete the second leg after starting the first, and that every liquidation path leaves the books reflecting only solvent assets. When repayment is pulled *after* collateral is released, the contract can be momentarily short of the very asset it must transfer, so the call reverts [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md). When a liquidation path settles collateral but never subtracts the unrecoverable remainder from `totalAssets`, the pool keeps reporting value it does not have, and whoever exits first takes it [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md).

## Where it shows up
- `liquidate()` functions where `transferFrom` of the repayer's funds appears *after* the seize/withdraw block [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md).
- Self-liquidation or same-market liquidation paths where `seizeMarket == repayMarket` [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md).
- Two liquidation entry points (e.g. `liquidate` vs `liquidateClean`) that update accounting differently [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md).
- Bad-debt branches that return early without reducing `totalAssets` [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md).
- Emergency/shutdown redemption functions that become permissionless and let the caller pass a list of positions [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md).

## How to review
For every liquidation path, trace the order of the two legs and ask: at the instant collateral leaves, does the contract still hold enough of the repayment asset to pay out? The invariant is that the contract is never required to transfer an asset it has not yet received. Separately, check the accounting invariant: after any liquidation, `totalAssets` must equal the value of assets the protocol can actually recover. Confirm each path — including the "clean" variant — writes off the shortfall when collateral is exhausted [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md). For shutdown paths, check whether the caller can choose which positions to act on and whether the bonus makes that choice profitable [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md).

## How finders spotted it
- Compared two liquidation functions and noticed one never subtracted bad debt while the other did, reasoning from the `totalAssets` invariant [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md).
- Read `liquidate()` line by line and saw `transferFrom` at line 613 executing after seize/withdraw at line 693, then confirmed the self-market revert with a Foundry PoC [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md).
- Noticed that after shutdown `urgentRedemption` was permissionless and accepted caller-chosen `troveIds`, enabling cherry-picking of troves whose bonus exceeded cost [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md).

## Variants seen
- Missing bad-debt write-off inflating `totalAssets`, creating a first-exit advantage [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md).
- Repayment pulled after collateral release, reverting self-market liquidation under high utilization [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md).
- Permissionless emergency redemption with caller-selected troves draining collateral for a bonus [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md).

## Impact and severity
E1 leaves later lenders absorbing losses early redeemers escaped — a solvency and fairness break [E1](https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md). E2 blocks liquidation exactly when utilization is highest, i.e. when it is most needed, risking bad debt accumulation [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md). E3 drains a specific collateral asset (sUSDe) from ActivePool once the branch is shut down [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md). Impact rises with how much liquidity is borrowed [E2](https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md) and with how freely the caller can pick targets [E3](https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md).

## Evidence
- E1: https://bugbountylibrary.com/r/c4%3A2022-08-frax%3AH-02.md
- E2: https://bugbountylibrary.com/r/sherlock%3A2024-04-interest-rate-model%3AM-11.md
- E3: https://bugbountylibrary.com/r/dhl%3A20250702-activepoolurgentredemption.md
