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

3 stars 1 forks source link

Fees are not taken from the issuanceValue in the liquidateWithReplacement function. #249

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/LiquidateWithReplacement.sol#L146-L164

Vulnerability details

Impact

Protocol loses the swapFee when the borrowOffer is filled in the executeLiquidateWithReplacement function.

Proof of Concept

When the borrowOffer or the loanOffer is filled, whoever creates the offer pays the swapFee to the fee Recipient.

For example, fees are taken from the borrower in the executeBuyCreditMarket function.

else {
            creditAmountOut = params.amount;
            (cashAmountIn, fees) = state.getCashAmountIn({
                creditAmountOut: creditAmountOut,
                maxCredit: params.creditPositionId == RESERVED_ID ? creditAmountOut : creditPosition.credit,
                ratePerTenor: ratePerTenor,
                tenor: tenor
            });
        }

        if (params.creditPositionId == RESERVED_ID) {
            // slither-disable-next-line unused-return
            state.createDebtAndCreditPositions({
                lender: msg.sender,
                borrower: borrower,
                futureValue: creditAmountOut,
                dueDate: block.timestamp + tenor
            });
        } else {
            //....
        }

        state.data.borrowAToken.transferFrom(msg.sender, borrower, cashAmountIn - fees); //@audit !!
        state.data.borrowAToken.transferFrom(msg.sender, state.feeConfig.feeRecipient, fees);

The liquidateWithReplacement function liquidates a borrower's debt position and replaces the old borrower with a new borrower that has borrowOffer.

But the problem is that, even if the new borrower's borrow offer is filled, the function doesn't take a fee from the new borrower.

issuanceValue = Math.mulDivDown(debtPositionCopy.futureValue, PERCENT, PERCENT + ratePerTenor);
        liquidatorProfitBorrowToken = debtPositionCopy.futureValue - issuanceValue;

        debtPosition.borrower = params.borrower;
        debtPosition.futureValue = debtPositionCopy.futureValue; //@audit doesnt this need to change ? 
        debtPosition.liquidityIndexAtRepayment = 0;

        state.data.debtToken.mint(params.borrower, debtPosition.futureValue);
        state.data.borrowAToken.transferFrom(address(this), params.borrower, issuanceValue);
        //@audit no swapFee is taken the from issuanceValue
        state.data.borrowAToken.transferFrom(address(this), state.feeConfig.feeRecipient, liquidatorProfitBorrowToken);

Normally, if a lender fills the borrower's borrow offer, the borrower pays a fee, but in the liquidateWithReplacement process, the fee is not taken from the issuanceValue.

Tools Used

Manual Review

Recommended Mitigation Steps

Take a swap fee from the issuanceValue.

Assessed type

Other

c4-judge commented 4 months ago

hansfriese marked the issue as satisfactory