15,000 USDC
View results
Submission Details
Severity: medium

user can liquidate himself

Summary

there is not check that can avoid that user can liquidate himself

Vulnerability Details

function liquidate(address collateral, address user, uint256 debtToCover)//user can liquidate himself 
    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);//@audit can user liquidate all dsc ?
    // We need to burn the DSC
    _burnDsc(debtToCover, user, msg.sender);

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

no there is any comprobation that avoid liquidate himself

run this test in DSCEngineTest.t.sol

  function test_Liquidation_himself() public  {
    console.log("balance user before mint weth ",amountToMint/1e18);
    vm.startPrank(user);
    ERC20Mock(weth).approve(address(dsce), amountCollateral);
    dsce.depositCollateralAndMintDsc(weth, amountCollateral, amountToMint);
    vm.stopPrank();
    int256 ethUsdUpdatedPrice = 18e8; // 1 ETH = $18

    console.log("balance user atfer mint weth",ERC20Mock(weth).balanceOf(user));

    //*******in this point user is liquiditable*********** 
    MockV3Aggregator(ethUsdPriceFeed).updateAnswer(ethUsdUpdatedPrice);
    uint256 userHealthFactor = dsce.getHealthFactor(user);

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

    console.log("balance user after liquidate weth",ERC20Mock(weth).balanceOf(user)/1e18);

}

the resul of test

Running 1 test for 
test/unit/DSCEngineTest.t.sol:DSCEngineTest
[PASS] test_Liquidation_himself() (gas: 339509)
Logs:
  balance user before mint weth  100
  balance user atfer mint weth 0
  balance user after liquidate weth 6

Test result: ok. 1 passed; 0 failed; finished in 851.97ms

Impact

the liquidators are a part important of protocols as this.This vulnerability can avoid users to try liquidate others user and this is bad for the protocol

Tools Used

manual review

Recommendations

add a require(user!=msg.sender);

function liquidate(address collateral, address user, uint256 debtToCover)//user can liquidate himself 
    external
    moreThanZero(debtToCover)
    nonReentrant
{
  + require(user!=msg.sender);
    // need to check health factor of the user
    uint256 startingUserHealthFactor = _healthFactor(user);
    if (startingUserHealthFactor >= MIN_HEALTH_FACTOR) {
        revert DSCEngine__HealthFactorOk();
    }

Support

FAQs

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