there is not check that can avoid that user can liquidate himself
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
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
manual review
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();
}
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.