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

16 stars 14 forks source link

Avci - Lack of Borrower Liquidation Check in `TakeOverDebt` Function #184

Closed sherlock-admin2 closed 11 months ago

sherlock-admin2 commented 11 months ago

Avci

medium

Lack of Borrower Liquidation Check in TakeOverDebt Function

Summary

Lack of Borrower Liquidation Check in TakeOverDebt Function

Vulnerability Detail

The "take over debt" function within the borrowing contract lacks a crucial check to determine whether the borrower is already liquidatable before allowing the debt takeover.

Impact

The lack of a check to assess the borrower's liquidation status means that any user can initiate a debt takeover without verifying the health and eligibility of the borrower. This could lead to unwarranted and frequent debt takeovers, which will destabilize the lending protocol.

Code Snippet


 function takeOverDebt(bytes32 borrowingKey, uint256 collateralAmt) external {
        BorrowingInfo memory oldBorrowing = borrowingsInfo[borrowingKey];
        // Ensure that the borrowed position exists
        (oldBorrowing.borrowedAmount == 0).revertError(ErrLib.ErrorCode.INVALID_BORROWING_KEY);

        uint256 accLoanRatePerSeconds;
        uint256 minPayment;
        {
            // Update token rate info and retrieve the accumulated loan rate per second for holdToken
            (, TokenInfo storage holdTokenRateInfo) = _updateTokenRateInfo(
                oldBorrowing.saleToken,
                oldBorrowing.holdToken
            );
            accLoanRatePerSeconds = holdTokenRateInfo.accLoanRatePerSeconds;
            // Calculate the collateral balance and current fees for the oldBorrowing
            (int256 collateralBalance, uint256 currentFees) = _calculateCollateralBalance(
                oldBorrowing.borrowedAmount,
                oldBorrowing.accLoanRatePerSeconds,
                oldBorrowing.dailyRateCollateralBalance,
                accLoanRatePerSeconds
            );
            // Ensure that the collateral balance is greater than or equal to 0
            (collateralBalance >= 0).revertError(ErrLib.ErrorCode.FORBIDDEN);
            // Pick up platform fees from the oldBorrowing's holdToken and add them to the feesOwed
            currentFees = _pickUpPlatformFees(oldBorrowing.holdToken, currentFees);
            oldBorrowing.feesOwed += currentFees;
            // Calculate the minimum payment required based on the collateral balance
            minPayment = (uint256(-collateralBalance) / Constants.COLLATERAL_BALANCE_PRECISION) + 1;
            (collateralAmt <= minPayment).revertError(
                ErrLib.ErrorCode.COLLATERAL_AMOUNT_IS_NOT_ENOUGH
            );
        }
        // Retrieve the old loans associated with the borrowing key and remove them from storage
        LoanInfo[] memory oldLoans = loansInfo[borrowingKey];
        _removeKeysAndClearStorage(oldBorrowing.borrower, borrowingKey, oldLoans);
        // Initialize a new borrowing using the same saleToken, holdToken
        (
            uint256 feesDebt,
            bytes32 newBorrowingKey,
            BorrowingInfo storage newBorrowing
        ) = _initOrUpdateBorrowing(
                oldBorrowing.saleToken,
                oldBorrowing.holdToken,
                accLoanRatePerSeconds
            );
        // Add the new borrowing key and old loans to the newBorrowing
        _addKeysAndLoansInfo(newBorrowing.borrowedAmount > 0, borrowingKey, oldLoans);
        // Increase the borrowed amount, liquidation bonus, and fees owed of the newBorrowing based on the oldBorrowing
        newBorrowing.borrowedAmount += oldBorrowing.borrowedAmount;
        newBorrowing.liquidationBonus += oldBorrowing.liquidationBonus;
        newBorrowing.feesOwed += oldBorrowing.feesOwed;
        // oldBorrowing.dailyRateCollateralBalance is 0
        newBorrowing.dailyRateCollateralBalance +=
            (collateralAmt - minPayment) *
            Constants.COLLATERAL_BALANCE_PRECISION;
        //newBorrowing.accLoanRatePerSeconds = oldBorrowing.accLoanRatePerSeconds;
        _pay(oldBorrowing.holdToken, msg.sender, VAULT_ADDRESS, collateralAmt + feesDebt);
        emit TakeOverDebt(oldBorrowing.borrower, msg.sender, borrowingKey, newBorrowingKey);
    }

https://github.com/sherlock-audit/2023-10-real-wagmi/blob/b33752757fd6a9f404b8577c1eae6c5774b3a0db/wagmi-leverage/contracts/LiquidityBorrowingManager.sol#L395C1-L464C8

Tool used

Manual Review

Recommendation

Consider implementing these logics to the function

sherlock-admin2 commented 11 months ago

1 comment(s) were left on this issue during the judging contest.

tsvetanovv commented:

Invalid. This according to Sherlock documentation enters the category "User mistake"