Skip to content

Latest commit

 

History

History
100 lines (77 loc) · 3.96 KB

File metadata and controls

100 lines (77 loc) · 3.96 KB

Bubbly Inky Sawfish

Medium

Users can lower the interest rate by dividing a loan into multiple smaller loans

Summary

The LenderCommitmentGroup_Smart.getMinInterestRate() function calculates the minimum APR for borrowing. However, this APR is determined based on the utilization ratio, which includes the newly borrowed amount. This allows borrowers to reduce the APR by dividing a loan into multiple smaller loans.

Root Cause

The LenderCommitmentGroup_Smart.getMinInterestRate() function calculates the minimum APR for borrowing. https://github.com/sherlock-audit/2024-11-teller-finance-update/blob/main/teller-protocol-v2-audit-2024/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol#L1017-1023

  function getMinInterestRate(uint256 amountDelta) public view returns (uint16) {
        return interestRateLowerBound + 
        uint16( uint256(interestRateUpperBound-interestRateLowerBound)
@>      .percent(getPoolUtilizationRatio(amountDelta )
        
        ) );
    } 

However, the APR is calculated based on the utilization ratio, which includes the newly borrowed amount. This allows borrowers to reduce the APR by dividing a loan into multiple smaller loans, creating an unfair advantage for them over other users. https://github.com/sherlock-audit/2024-11-teller-finance-update/blob/main/teller-protocol-v2-audit-2024/packages/contracts/contracts/LenderCommitmentForwarder/extensions/LenderCommitmentGroup/LenderCommitmentGroup_Smart.sol#L1002-1015

    function getPoolUtilizationRatio(uint256 activeLoansAmountDelta ) public view returns (uint16) {

        if (getPoolTotalEstimatedValue() == 0) {
            return 0;
        }

        return uint16(  Math.min(                          
                            MathUpgradeable.mulDiv( 
@>                              (getTotalPrincipalTokensOutstandingInActiveLoans() + activeLoansAmountDelta), 
                                10000  ,
                                getPoolTotalEstimatedValue() ) , 
                        10000  ));

    }

Internal pre-conditions

interestRateLowerBound = 0 interestRateLowerBound = 800 // 8% current total estimated value = $20000 current borrowed value = $5000

External pre-conditions

none

Attack Path

If Alice borrows $10000 USD at once, the APR is (5000 + 10000) / 20000 * 8% = 6%

However, Alice borrow $10000 as follows.

  1. Alice is going to borrow $10000.
  2. Alice borrows $1,000 repeatedly for a total of 10 times.

Then the APR for each 1000 USD is: (5000 + 1000) / 20000 * 8% = 2.4% (6000 + 1000) / 20000 * 8% = 2.8% (7000 + 1000) / 20000 * 8% = 3.2% (8000 + 1000) / 20000 * 8% = 3.6% (9000 + 1000) / 20000 * 8% = 4.0% (10000 + 1000) / 20000 * 8% = 4.4% (11000 + 1000) / 20000 * 8% = 4.8% (12000 + 1000) / 20000 * 8% = 5.2% (13000 + 1000) / 20000 * 8% = 5.6% (14000 + 1000) / 20000 * 8% = 6%

(2.4 + 2.8 + ... + 6) / 10 = 4.2

Therefore, the borrower will only pay an APR of 4.2% on the $10,000 loan. As a result, Alice lowers the interest rate from 6% to 4.2% by splitting a $10,000 loan into ten separate loans of $1,000 each.

Impact

Users can lower the interest rate by dividing a loan into multiple smaller loans.

PoC

none

Mitigation

Middle value should be used instead of end value.

    function getPoolUtilizationRatio(uint256 activeLoansAmountDelta ) public view returns (uint16) {

        if (getPoolTotalEstimatedValue() == 0) {
            return 0;
        }

        return uint16(  Math.min(                          
                            MathUpgradeable.mulDiv( 
-                               (getTotalPrincipalTokensOutstandingInActiveLoans() + activeLoansAmountDelta), 
+                               (getTotalPrincipalTokensOutstandingInActiveLoans() + (activeLoansAmountDelta + 1) / 2), 
                                10000  ,
                                getPoolTotalEstimatedValue() ) , 
                        10000  ));

    }