Skip to content

Latest commit

 

History

History
82 lines (61 loc) · 3.22 KB

055.md

File metadata and controls

82 lines (61 loc) · 3.22 KB

Rapid Walnut Wasp

Medium

Interest-bearing loans will cause unexpected losses for NUMA holders

Summary

Looking at the documentation quote: "Users can borrow against their NUMA holdings to access rETH and stay liquid—interest-free and no fees." Lending & Leverage Borrowers will incur unintended interest charges when borrowing against their NUMA holdings.

Root Cause

It arises from the code implementation in CToken.sol: the borrowFreshNoTransfer function applies interest to all loans through: accountBorrows[borrower].interestIndex = borrowIndex; wich creates a critical mismatch between promised and actual functionality

Internal pre-conditions :

https://github.com/sherlock-audit/2024-12-numa-audit/blob/ae1d7781efb4cb2c3a40c642887ddadeecabb97d/Numa/contracts/lending/CToken.sol#L741 The code enforces interest on all loans, breaking a core documented feature of "interest-free loans against NUMA holdings".

  function borrowFreshNoTransfer(
        address payable borrower,
        uint borrowAmount
    ) internal virtual {
        /* Fail if borrow not allowed */
        uint allowed = comptroller.borrowAllowed(
            address(this),
            borrower,
            borrowAmount
        );
        if (allowed != 0) {
            revert BorrowComptrollerRejection(allowed);
        }

        /* Verify market's block number equals current block number */
        if (accrualBlockNumber != getBlockNumber()) {
            revert BorrowFreshnessCheck();
        }

        /* Fail gracefully if protocol has insufficient underlying cash */
        if (getCashPrior() < borrowAmount) {
            revert BorrowCashNotAvailable();
        }

        /*
         * We calculate the new borrower and total borrow balances, failing on overflow:
         *  accountBorrowNew = accountBorrow + borrowAmount
         *  totalBorrowsNew = totalBorrows + borrowAmount
         */
        uint accountBorrowsPrev = borrowBalanceStoredInternal(borrower);
        uint accountBorrowsNew = accountBorrowsPrev + borrowAmount;
        uint totalBorrowsNew = totalBorrows + borrowAmount;

        /////////////////////////
        // EFFECTS & INTERACTIONS
        // (No safe failures beyond this point)

        /*
         * We write the previously calculated values into storage.
         *  Note: Avoid token reentrancy attacks by writing increased borrow before external transfer.
        `*/
        accountBorrows[borrower].principal = accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = totalBorrowsNew;

        /* We emit a Borrow event */
        emit Borrow(borrower, borrowAmount, accountBorrowsNew, totalBorrowsNew);
    }

Impact

NUMA holders suffer continuous losses through unexpected interest charges on supposedly interest-free loans. For example, with a 5% APR and a 10 ETH loan, users would lose 0.5 ETH annually in unintended interest charges.

PoC

No response

Mitigation

No response