sherlock-audit / 2023-10-real-wagmi-judging

16 stars 14 forks source link

0xJuda - Unfair distribution of liquidation bonus in LiquidityBorrowingManager#repay during emergency withdrawal #141

Closed sherlock-admin closed 11 months ago

sherlock-admin commented 11 months ago

0xJuda

medium

Unfair distribution of liquidation bonus in LiquidityBorrowingManager#repay during emergency withdrawal

Summary

The liquidation bonus calculation in the LiquidityBorrowingManager's repay function currently results in an unfair distribution. When an emergency exit is initiated, the entire liquidation bonus is allocated to the last lender who withdraws their funds.

Vulnerability Detail

Liquidation bonus is calculated in LiquidityBorrowingManager borrow function. As you can see below, the base value is multiplied by number of loans.

LiquidityBorrowingManager.sol#L479-L484

// Calculating liquidation bonus based on hold token, borrowed amount, and number of used loans
uint256 liquidationBonus = getLiquidationBonus(
    params.holdToken,
    cache.borrowedAmount,
    params.loans.length
);

Note: The params.loans.length value is used here as a multiplier inside of getLiquidationBonus.

LiquidityBorrowingManager.sol#L683-L703

function getLiquidationBonus(
    address token,
    uint256 borrowedAmount,
    uint256 times
) public view returns (uint256 liquidationBonus) {
    // Retrieve liquidation bonus for the given token
    Liquidation memory liq = liquidationBonusForToken[token];

    if (liq.bonusBP == 0) {
        // If there is no specific bonus for the token
        // Use default bonus
        liq.minBonusAmount = Constants.MINIMUM_AMOUNT;
        liq.bonusBP = dafaultLiquidationBonusBP;
    }
    liquidationBonus = (borrowedAmount * liq.bonusBP) / Constants.BP;

    if (liquidationBonus < liq.minBonusAmount) {
        liquidationBonus = liq.minBonusAmount;
    }
    liquidationBonus *= times; // @audit - Multiplied by number of used loans.
}

When analyzing the LiquidityBorrowingManager repay function, it is evident that due to the code structure the entire bonus goes to the last lender who initiates emergency withdrawal becuase only then the completeRepayment boolean value equals true.

LiquidityBorrowingManager.sol#L602-L606

// If loansInfoLength is 0, remove the borrowing key from storage and get the liquidation bonus
if (completeRepayment) {
    LoanInfo[] memory empty;
    _removeKeysAndClearStorage(borrowing.borrower, params.borrowingKey, empty);
    feesAmt += liquidationBonus;
} else {

This is unfair to other lenders because the liquidation bonus was calculated from their loans as well. Moreover, this vulnerability may lead to backrunning, as lenders may try to position themselves behind other lenders' transactions.

Impact

The current system has an unfair distribution of the liquidation bonus, which can potentially incentivize backrunning by lenders.

Code Snippet

LiquidityBorrowingManager.sol#L465 LiquidityBorrowingManager.sol#L479-L484 LiquidityBorrowingManager.sol#L683-L703 LiquidityBorrowingManager.sol#L532 LiquidityBorrowingManager.sol#L602-L606

Tool used

Manual Review

Recommendation

During an emergency withdrawal, it is advised to calculate a fair portion of the liquidation bonus for each lender based on their loaned positions, ensuring a more equitable distribution.

Duplicate of #105