-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Severity: Medium
Files Affected
cadence/contracts/FlowALPv1.cdc
Description
When _borrowUpdatedTokenState is called (line 1911 in manualLiquidation), it triggers updateForTimeChange() which calls collectInsurance and collectStability. Both functions withdraw from the token's reserves: // collectInsurance, line 1112: let withdrawn <- reserves.withdraw(amount: withdrawAmountU64) // collectStability, line 1176: let withdrawn <- reserves.withdraw(amount: withdrawAmountU64) These withdrawals occur before the liquidation's own withdrawal from reserves at _doLiquidation line 2015: let seizedVault <- self._withdrawFromReserves(type: seizeType, amount: seizeAmount) If the combined insurance + stability fee collection reduces the seize token's reserves below seizeAmount, the liquidation reverts. This is particularly dangerous because:
- The fee collection is time-dependent — the longer since the last update, the larger the fees
- A position could be liquidatable and have sufficient reserves, but the _borrowUpdatedTokenState call that checks its health also drains the reserves needed for liquidation
- This creates a race condition: the first liquidation attempt after a long idle period is most likely to fail
Recommendation
Either (a) check that reserves remain sufficient for pending liquidations before fee collection, (b) cap fee collection to leave a minimum reserve buffer, or (c) allow fee collection to be deferred if reserves are below a threshold.
Parent Issue: #209