15,000 USDC
View results
Submission Details
Severity: high
Valid

“If the value of the debt drops near to 100% of the amount of the token, it becomes unpayable

Summary

“If the value of the debt drops near to 100% of the amount of the token, it becomes unpayable

Vulnerability Details

 function liquidate(address collateral, address user, uint256 debtToCover)
    external
    moreThanZero(debtToCover)
    nonReentrant
{
    // need to check health factor of the user
    uint256 startingUserHealthFactor = _healthFactor(user);
    if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
        revert DSCEngine__HealthFactorOk();
    }
    // We want to burn their DSC "debt"
    // And take their collateral
    // Bad User: $140 ETH, $100 DSC
    // debtToCover = $100
    // $100 of DSC == ??? ETH?
    // 0.05 ETH
    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);
    // We need to burn the DSC
    _burnDsc(debtToCover, user, msg.sender);

    uint256 endingUserHealthFactor = _healthFactor(user);
    if (endingUserHealthFactor <= startingUserHealthFactor) {
        revert DSCEngine__HealthFactorNotImproved();
    }
    _revertIfHealthFactorIsBroken(msg.sender);
}

when call liquidate this call

      function _redeemCollateral(address from, address to, address tokenCollateralAddress, uint256 amountCollateral)
    private
{
    console.log("s_collateralDeposited[from][tokenCollateralAddress]:",s_collateralDeposited[from][tokenCollateralAddress]);
    console.log("amountCollateral:",amountCollateral);
    s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral;
    emit CollateralRedeemed(from, to, tokenCollateralAddress, amountCollateral);
    bool success = IERC20(tokenCollateralAddress).transfer(to, amountCollateral);
    if (!success) {
        revert DSCEngine__TransferFailed();
    }
} 

And this reverts due to arithmetic over/underflow when trying to perform this operation: s_collateralDeposited[from][tokenCollateralAddress] -= amountCollateral

runt this test in DSCEngineTest.t.sol

  function test__Liquidation_fail() public  {

    vm.startPrank(user);
    ERC20Mock(weth).approve(address(dsce), amountCollateral);
    dsce.depositCollateralAndMintDsc(weth, amountCollateral, amountToMint);
    vm.stopPrank();
  

    //*******in this point user is liquiditable*********** 
    MockV3Aggregator(ethUsdPriceFeed).updateAnswer(10e8);//***********  dropps the price **************
    uint256 userHealthFactor = dsce.getHealthFactor(user);

    ERC20Mock(wbtc).mint(liquidator, amountToMint);
    ERC20Mock(wbtc).mint(address(dsce), amountToMint);
    vm.startPrank(liquidator);
    ERC20Mock(wbtc).approve(address(dsce), amountCollateral);
    dsce.depositCollateralAndMintDsc(wbtc, amountCollateral, amountToMint);
    vm.stopPrank();

    console.log("value of debt in collateral",dsce.getTokenAmountFromUsd(wbtc, amountToMint));

    vm.startPrank(liquidator);
    dsc.approve(address(dsce), amountToMint);
    dsce.liquidate(weth, user, 100 ether); 
    vm.stopPrank();

 

}

the result

Running 1 test for test/unit/DSCEngineTest.t.sol:DSCEngineTest
[FAIL. Reason: Arithmetic over/underflow] 
test__Liquidation_fail() (gas: 562459)
Logs:
  value of debt in collateral 100000000000000000
  tokenAmountFromDebtCovered: 10000000000000000000
  totalCollateralToRedeem: 11000000000000000000
  s_collateralDeposited[from][tokenCollateralAddress]: 10000000000000000000
  amountCollateral: 11000000000000000000

Test result: FAILED. 0 passed; 1 failed; finished in 605.33ms

Failing tests:
Encountered 1 failing test in 
test/unit/DSCEngineTest.t.sol:DSCEngineTest
[FAIL. Reason: Arithmetic over/underflow] 
test__Liquidation_fail() (gas: 562459)

Encountered a total of 1 failing tests, 0 tests succeeded

Impact

debts unpayables are bad for the protocol

Tools Used

manual review

Recommendations

change this logic of liquidation

Support

FAQs

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