Optimistically paid initiation rewards may not get covered when liquidations settle through unhappy flow
Summary
Liquidation initiators are sent rewards when they initiate auctions for liquidatable accounts. The problem is that rewards are paid optimistically and there's no guarantee if the accounts will be able to cover them if settled through the unhappy flow.
Vulnerability Detail
Anyone who sees that an account has become liquidatable can initiate a liquidation through Liquidator::liquidateAccount() and immediately get a reward for it.
The flow is Liquidator::liquidateAccount() => AccountV1::startLiquidation() => LendingPool::startLiquidation(). Here's the code for the last one:
function startLiquidation(address initiator, uint256 minimumMargin_)
external
override
whenLiquidationNotPaused
processInterests
returns (uint256 startDebt)
{
// Only Accounts can have debt, and debtTokens are non-transferrable.
// Hence by checking that the balance of the msg.sender is not 0,
// we know that the sender is indeed an Account and has debt.
startDebt = maxWithdraw(msg.sender);
if (startDebt == 0) revert LendingPoolErrors.IsNotAnAccountWithDebt();
// Calculate liquidation incentives which have to be paid by the Account owner and are minted
// as extra debt to the Account.
(uint256 initiationReward, uint256 terminationReward, uint256 liquidationPenalty) =
_calculateRewards(startDebt, minimumMargin_);
// Mint the liquidation incentives as extra debt towards the Account.
_deposit(initiationReward + liquidationPenalty + terminationReward, msg.sender);
// Increase the realised liquidity for the initiator.
// The other incentives will only be added as realised liquidity for the respective actors
// after the auction is finished.
realisedLiquidityOf[initiator] += initiationReward;
totalRealisedLiquidity = SafeCastLib.safeCastTo128(totalRealisedLiquidity + initiationReward);
// ...
}
The initiator is given a reward for initiating the auction and this reward can be withdrawn immediately afterwards. The issue here is that this is being optimistically paid out to the initiator. There's no guarantee that the auction bids will be able to cover the initiation reward, which will incur losses on the pool. The scenario is only possible to occur in the unhappy flow, which happens when the bidders have failed to pay off the account's outstanding debt in the given cut-off period.
Impact
Losses for the tranches and LPs' when the liquidation is not able to cover the amount of the initiation reward.
Refactor the code so paying out the initiation rewards happens when auctions have been settled (either through the happy or unhappy flow). For the unhappy flow, it should be handled similarly to how liquidationPenalty is currently being handled:
if (openDebt >= liquidationPenalty) {
// "openDebt" is bigger than the "liquidationPenalty" but smaller than the total pending liquidation incentives.
// Don't pay out the "liquidationPenalty" to Lps, partially pay out the "terminator".
realisedLiquidityOf[terminator] += remainder;
}
The same logic should be used for the initiationReward once it's moved there.
NentoR
medium
Optimistically paid initiation rewards may not get covered when liquidations settle through unhappy flow
Summary
Liquidation initiators are sent rewards when they initiate auctions for liquidatable accounts. The problem is that rewards are paid optimistically and there's no guarantee if the accounts will be able to cover them if settled through the unhappy flow.
Vulnerability Detail
Anyone who sees that an account has become liquidatable can initiate a liquidation through
Liquidator::liquidateAccount()
and immediately get a reward for it.The flow is
Liquidator::liquidateAccount()
=>AccountV1::startLiquidation()
=>LendingPool::startLiquidation()
. Here's the code for the last one:The initiator is given a reward for initiating the auction and this reward can be withdrawn immediately afterwards. The issue here is that this is being optimistically paid out to the initiator. There's no guarantee that the auction bids will be able to cover the initiation reward, which will incur losses on the pool. The scenario is only possible to occur in the unhappy flow, which happens when the bidders have failed to pay off the account's outstanding debt in the given cut-off period.
Impact
Losses for the tranches and LPs' when the liquidation is not able to cover the amount of the initiation reward.
Code Snippet
https://github.com/sherlock-audit/2023-12-arcadia/blob/main/lending-v2/src/LendingPool.sol#L861-L886 https://github.com/sherlock-audit/2023-12-arcadia/blob/main/lending-v2/src/LendingPool.sol#L983-L1023
Tool used
Manual Review
Recommendation
Refactor the code so paying out the initiation rewards happens when auctions have been settled (either through the happy or unhappy flow). For the unhappy flow, it should be handled similarly to how
liquidationPenalty
is currently being handled:The same logic should be used for the
initiationReward
once it's moved there.Duplicate of #1