code-423n4 / 2024-06-size-findings

3 stars 1 forks source link

Liquidator receives a dust amount as a reward due to an incorrect calculation of the liquidatorProfitCollateralToken #260

Closed howlbot-integration[bot] closed 4 months ago

howlbot-integration[bot] commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-06-size/blob/8850e25fb088898e9cf86f9be1c401ad155bea86/src/libraries/actions/Liquidate.sol#L95-L100

Vulnerability details

Impact

When the liquidation is profitable, the liquidatorReward is the minimum between assignedCollateral - debtInCollateralToken and a percentage of the future value (5% of future value as specified in Governance Variables & Fees). This liquidatorReward is then added to debtInCollateralToken, and the result is stored in the liquidatorProfitCollateralToken variable.

This mechanism ensures that the liquidator receives up to a fixed 5% reward on the loan's face value when the liquidation is profitable.

However, when the liquidatorReward is determined in executeLiquidate(), the min() function from the Math library is called with two arguments denominated in different assets:

As a result, the liquidator will receive 5% of the future value most of the time, since the likelihood of a 6-decimal amount being less than an 18-decimal amount is high.

This liquidatorReward, resulting from the min() call, will be added to the debtInCollateralToken and the result will be stored in the liquidatorProfitCollateralToken variable, which is returned by the executeLiquidate() function.

liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

If 5% of the futureValue in USDC is the minimum compared to assignedCollateral - debtInCollateralToken, an amount in USDC (6 decimals) will be added to an amount in ETH (18 decimals): liquidatorProfitCollateralToken = debtInCollateralToken e18 + liquidatorReward e6

Proof of Concept

Let's consider the following scenario where 1 ETH = 1 USDC and liquidationRewardPercent = 5%.

Since assignedCollateral is greater than debtInCollateralToken (1510 > 1470), the following block executes to calculate liquidatorReward and liquidatorProfitCollateralToken:

if (assignedCollateral > debtInCollateralToken) {
            uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtPosition.futureValue, state.feeConfig.liquidationRewardPercent, PERCENT)
            );
            liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

However, 50 USDC is worth 73.529 ETH, which is greater than 40 ETH.

liquidatorProfitCollateralToken is calculated by adding debtInCollateralToken (18 decimals) to liquidatorReward (6 decimals):

liquidatorProfitCollateralToken = debtInCollateralToken + liquidatorReward;

As a result, the liquidator receives a dust amount as a reward.

Tools Used

Manual Review

Recommended Mitigation Steps

Utilize debtInCollateralToken (ETH) instead of debtPosition.futureValue (USDC) to compute the 5% liquidation reward in executeLiquidate():

uint256 liquidatorReward = Math.min(
                assignedCollateral - debtInCollateralToken,
                Math.mulDivUp(debtInCollateralToken, state.feeConfig.liquidationRewardPercent, PERCENT)
            );

Assessed type

Decimal

c4-judge commented 4 months ago

hansfriese marked the issue as duplicate of #21

c4-judge commented 3 months ago

hansfriese marked the issue as satisfactory