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

`burnDsc` (repay) should not revert if user HF < 1 after the repayment

Summary

The burnDsc function does not allow the user to partially repay his debt when the user's HF < 1 and the newHF after the repay operation is still < 1.

Because of this, the protocol denies to the user the possibility to reduce the amount of collateral that the liquidators will be able to seize.

Vulnerability Details

In general, the collateral provided by the user is a token that he/she does not want to directly sell to purchase the debt token but he/she is willing to put it as collateral to later be able to repay the debt and redeem the whole collateral.

The burnDsc does not allow the user to partially repay his debt when the user's HF < 1 and the newHF after the repay operation is still < 1.

Because of this, the protocol denies to the user the possibility to reduce the amount of collateral that the liquidators will be able to seize.

Impact

The protocol is denying to the user the possibility to reduce the amount of collateral that the liquidators will be able to seize.

Tools Used

Manual + foundry test

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {DSCEngine} from "../../src/DSCEngine.sol";
import {DecentralizedStableCoin} from "../../src/DecentralizedStableCoin.sol";
import {HelperConfig} from "../../script/HelperConfig.s.sol";
import {ERC20Mock} from "@openzeppelin/contracts/mocks/ERC20Mock.sol";
import {Test, console} from "forge-std/Test.sol";
import {StdCheats} from "forge-std/StdCheats.sol";
import {MockV3Aggregator} from "../mocks/MockV3Aggregator.sol";
contract PartialRepayTest is StdCheats, Test {
DSCEngine public dsce;
DecentralizedStableCoin public dsc;
HelperConfig public helperConfig;
address[] public tokenAddresses;
address[] public priceFeedAddresses;
address public ethUsdPriceFeed;
address public btcUsdPriceFeed;
address public weth;
address public wbtc;
uint256 public deployerKey;
uint256 amountCollateral = 10 ether;
uint256 amountToMint = 100 ether;
address public user = address(1);
uint256 public constant STARTING_USER_BALANCE = 10 ether;
uint256 public constant MIN_HEALTH_FACTOR = 1e18;
uint256 public constant LIQUIDATION_THRESHOLD = 50;
function setUp() external {
helperConfig = new HelperConfig();
(ethUsdPriceFeed, btcUsdPriceFeed, weth, wbtc, deployerKey) = helperConfig.activeNetworkConfig();
tokenAddresses = [weth, wbtc];
priceFeedAddresses = [ethUsdPriceFeed, btcUsdPriceFeed];
dsc = new DecentralizedStableCoin();
dsce = new DSCEngine(tokenAddresses, priceFeedAddresses, address(dsc));
dsc.transferOwnership(address(dsce));
if (block.chainid == 31337) {
vm.deal(user, STARTING_USER_BALANCE);
}
ERC20Mock(weth).mint(user, STARTING_USER_BALANCE);
ERC20Mock(wbtc).mint(user, STARTING_USER_BALANCE);
}
function testBurnRevertIfHFBelow() public {
vm.startPrank(user);
ERC20Mock(weth).approve(address(dsce), amountCollateral);
dsce.depositCollateralAndMintDsc(weth, amountCollateral, amountToMint);
vm.stopPrank();
// now let's say that price goes down
int256 ethUsdUpdatedPrice = 18e8; // 1 ETH = $18
MockV3Aggregator(ethUsdPriceFeed).updateAnswer(ethUsdUpdatedPrice);
assertLt(dsce.getHealthFactor(user), 1e18);
// why can't the user try to improve it's position by repaing some debt?
vm.startPrank(user);
dsc.approve(address(dsce), 1);
// reverts without allowing the user to partially repay the debt
// if the HF < 1 after the operation
vm.expectRevert();
dsce.burnDsc(1);
vm.stopPrank();
}
}

Recommendations

The client should remove the check _revertIfHealthFactorIsBroken from the burnDsc allowing the user to always be able to repay the debt.

Support

FAQs

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