code-423n4 / 2024-01-salty-findings

11 stars 6 forks source link

Liquidator will potentially receive less than maxReward #758

Open c4-bot-7 opened 9 months ago

c4-bot-7 commented 9 months ago

Lines of code

https://github.com/code-423n4/2024-01-salty/blob/main/src/stable/CollateralAndLiquidity.sol#L165-L169

Vulnerability details

Bug Description

In the Salty protocol, when a user's collateralized position (using WETH and WBTC) becomes undercollateralized, there's a mechanism in place for liquidation. During such an event, the liquidator is rewarded with a percentage (default 5%) of the liquidated user's collateral.

uint256 rewardedWBTC = (reclaimedWBTC * rewardPercent) / 100;
uint256 rewardedWETH = (reclaimedWETH * rewardPercent) / 100;

The protocol also sets a maxRewardValueForCallingLiquidation, intended to cap the liquidator's reward. However, an issue arises due to the method of calculating this cap, which can result in the liquidator receiving less than the maximum reward value, even when the total reward (sum of the value of rewardedWBTC and rewardedWETH) equals or exceeds the cap:

if ( rewardValue > maxRewardValue )
    {
    rewardedWBTC = (rewardedWBTC * maxRewardValue) / rewardValue;
    rewardedWETH = (rewardedWETH * maxRewardValue) / rewardValue;
    }

The rounding down in the calculation can lead to a situation where the actual reward value is less than maxRewardValueForCallingLiquidation, despite the initial reward being greater or equal to this threshold.

Impact

This discrepancy can discourage liquidators from participating in the liquidation process, as they might not receive the full reward they are expecting. This could potentially affect the protocol's overall health and stability.

Proof of Concept

A mathematical example illustrates the issue:

rewardPercent = 5;
collateralBTC = 100;
collateralETH = 100;
BTCValue = 51
ETHValue = 51
maxRewardValue = 500

rewardedWBTC = (100 * 5) / 100 = 5
rewardedWETH = (100 * 5) / 100 = 5

rewardValue = 5*51 + 5*51 = 510;

// rewardedWBTC = (rewardedWBTC * maxRewardValue) / rewardValue;
rewardedWBTC = (5*500)/510 = 4 // rounded down from 4.9

// rewardedWETH = (rewardedWETH * maxRewardValue) / rewardValue;
rewardedWETH = (5*500)/510 = 4 // rounded down from 4.9

receivedValue = 4 * 51 + 4 * 51 = 408 //which is below the max

In this example, the liquidator expects to receive a reward value up to maxRewardValueForCallingLiquidation, but due to rounding down, the actual received value is less, even though the sum of rewardedWBTC and rewardedWETH initially exceeds the cap.

This is a simplified example as actually the maxRewardValueForCallingLiquidation = 500 ether;. So in reality the rounding error will not be as severe as in the example as the values are way higher. Nevertheless the rounding will lead to a user potentially receiving less than the maxRewardValueForCallingLiquidation although he would fulfill the requirements to receive it.

Tools Used

Manual Review

Recommended Mitigation Steps

To address this issue, the protocol could consider an alternative approach where, instead of distributing collateral as a reward, the liquidator is minted maxRewardValueForCallingLiquidation in USDS. The collateral gained from liquidation would then back the newly minted stablecoin. This method ensures that the liquidator receives a reward value that accurately reflects the maxRewardValueForCallingLiquidation, maintaining the incentive for liquidation and aligning with the protocol's economic design.

Assessed type

Math

c4-judge commented 9 months ago

Picodes changed the severity to QA (Quality Assurance)

Picodes commented 9 months ago

Interesting report but of Low severity in my opinion considering rounding in favor of the protocol seems suitable here and the suggested mitigation is more a design change