15,000 USDC
View results
Submission Details
Severity: high

`DSCEngine` liquidation mechanism generates bad debt resulting in the impossibility of users claiming back collateral

Summary

DSCEngine::liquidate function awards a 10% bonus for liquidators in order to further incentivize market makers to liquidate depositors when their health factor is bellow the minimum accepted threshold. Since the stablecoin engine does not have any yield generating mechanism this 10% is from other users that have provided collateral to the project. As such, with each liquidation, collateral is withdrawn from the protocol and future users that wish to withdrawn their deposited collateral by paying back the owed DSC will not be able to.

Vulnerability Details

When a user falls bellow the MIN_HEALTH_FACTOR threshold, anyone can call DSCEngine::liquidate to liquidate him, getting his deposited collateral relative to current prices and an extra 10% bonus, this is by design.

uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
// And give them a 10% bonus
// So we are giving the liquidator $110 of WETH for 100 DSC
// We should implement a feature to liquidate in the event the protocol is insolvent
// And sweep extra amounts into a treasury
// 0.05 * 0.1 = 0.005. Getting 0.055
uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
_redeemCollateral(user, msg.sender, collateral, totalCollateralToRedeem);

A theoretical POC:

  • users deposits collateral up until, but not reaching, his maximum amount as to not fall bellow the health factor

  • prices slightly varies and users falls bellow his health factor and is liquidated

  • the variation in prices is small such that the calculated token amount fro the covered debt, that takes into consideration current price, is just slightly lower then the original collateral

  • the extra 10% bonus that is given will not be offset by this calculation and will be taken from the protocol reserves, meaning from other users' collateral

  • say that all the other collateral is from one single entity, this entity now, cannot be liquidated as there is no more collateral to be provided to the liquidator and the function revers

Impact

  • Liquidations will leave the protocol with bad debt and users will not be able to withdraw their deposits as there would be no more collateral

  • The last major holder, who's collateral is 91% of all deposited collateral will not even be able to be liquidated as it would not be possible since, with the added bonus, it would mean more collateral then existing should be returned, thus the liquidation function will revert

  • A malicious actor can deposit a substantial amount of collateral, almost reaching his health limit, wait for the price to go down and liquidated himself (front running other liquidators) and get the 110% himself, thus retrieving a 10% bonus on each deposit + liquidation routine. This can be used to drain the entire protocol.

Tools Used

Manual analysis

Recommend Mitigation

Remove the 10% bonus mechanism, actually allow less then 100% of collateral to go to liquidators and leave an amount, as fee, to the protocol as there is no incentive for protocol team to actually build using the stablecoin.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.