15,000 USDC
View results
Submission Details
Severity: medium

liquidate() Lack of restriction that liquidator cannot be a `onlyOwner`

Summary

DecentralizedStableCoin onlyOwner with mint and burn privileges is not restricted to being a liquidator

Vulnerability Details

There should be a restriction for DecentralizedStableCoin onlyOwner with mint and burn privileges to be a liquidator, this will also prevent single point of failure in this function

src/DSCEngine.sol:
228 */
229: function liquidate(address collateral, address user, uint256 debtToCover)
230: external
231: moreThanZero(debtToCover)
232: nonReentrant
233: {
234: // need to check health factor of the user
235: uint256 startingUserHealthFactor = _healthFactor(user);
236: if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
237: revert DSCEngine__HealthFactorOk();
238: }
239: // We want to burn their DSC "debt"
240: // And take their collateral
241: // Bad User: $140 ETH, $100 DSC
242: // debtToCover = $100
243: // $100 of DSC == ??? ETH?
244: // 0.05 ETH
245: uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
246: // And give them a 10% bonus
247: // So we are giving the liquidator $110 of WETH for 100 DSC
248: // We should implement a feature to liquidate in the event the protocol is insolvent
249: // And sweep extra amounts into a treasury
250: // 0.05 * 0.1 = 0.005. Getting 0.055
251: uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
252: uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
253: _redeemCollateral(user, msg.sender, collateral, totalCollateralToRedeem);
254: // We need to burn the DSC
255: _burnDsc(debtToCover, user, msg.sender);
256:
257: uint256 endingUserHealthFactor = _healthFactor(user);
258: if (endingUserHealthFactor <= startingUserHealthFactor) {
259: revert DSCEngine__HealthFactorNotImproved();
260: }
261: _revertIfHealthFactorIsBroken(msg.sender);
262: }

Impact

Tools Used

Manuel Code Review

Recommendations

src/DSCEngine.sol:
228 */
229: function liquidate(address collateral, address user, uint256 debtToCover)
230: external
231: moreThanZero(debtToCover)
232: nonReentrant
233: {
234: // need to check health factor of the user
235: uint256 startingUserHealthFactor = _healthFactor(user);
236: if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
237: revert DSCEngine__HealthFactorOk();
238: }
+ require(user == onlyOwner, "owner can't do it");
239: // We want to burn their DSC "debt"
240: // And take their collateral
241: // Bad User: $140 ETH, $100 DSC
242: // debtToCover = $100
243: // $100 of DSC == ??? ETH?
244: // 0.05 ETH
245: uint256 tokenAmountFromDebtCovered = getTokenAmountFromUsd(collateral, debtToCover);
246: // And give them a 10% bonus
247: // So we are giving the liquidator $110 of WETH for 100 DSC
248: // We should implement a feature to liquidate in the event the protocol is insolvent
249: // And sweep extra amounts into a treasury
250: // 0.05 * 0.1 = 0.005. Getting 0.055
251: uint256 bonusCollateral = (tokenAmountFromDebtCovered * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;
252: uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
253: _redeemCollateral(user, msg.sender, collateral, totalCollateralToRedeem);
254: // We need to burn the DSC
255: _burnDsc(debtToCover, user, msg.sender);
256:
257: uint256 endingUserHealthFactor = _healthFactor(user);
258: if (endingUserHealthFactor <= startingUserHealthFactor) {
259: revert DSCEngine__HealthFactorNotImproved();
260: }
261: _revertIfHealthFactorIsBroken(msg.sender);
262: }

Support

FAQs

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