20,000 USDC
View results
Submission Details
Severity: high
Valid

Updating pool balance twice

Summary

In the refinance function the new pool balance is updated twice which leads to the pool balance being lower than expected.

Vulnerability Details

In the Lender contract in the refinance function the balance is updated twice - once by calling the _updatePoolBalance function and once by subtracting the pool balance with the debt.

Impact

This leads to the pool balance being lower than it is and every time someone refinances the pool balance is lowered twice.
If the owner tries to get his money from the pool he won't be able to collect the full amount if there are people that refinanced their loans to that pool.

Proof Of Concept

`
Add this as state variables to the test to work correctly:

Borrow[] borrowArray;
Refinance[] refinances;

Add this test in the Lender.t.sol contract and run it to see the vulnerability:

function testRefinancing() public {
    vm.startPrank(lender1);
    Pool memory p = Pool({
        lender: lender1,
        loanToken: address(loanToken),
        collateralToken: address(collateralToken),
        minLoanSize: 100*10**18,
        poolBalance: 1000*10**18,
        maxLoanRatio: 2*10**18,
        auctionLength: 1,
        interestRate: 1000,
        outstandingLoans: 0
    });
    lender.setPool(p);
    vm.stopPrank();

    vm.startPrank(lender2);
    Pool memory p1 = Pool({
        lender: lender2,
        loanToken: address(loanToken),
        collateralToken: address(collateralToken),
        minLoanSize: 100*10**18,
        poolBalance: 1000*10**18,
        maxLoanRatio: 2*10**18,
        auctionLength: 1,
        interestRate: 1000,
        outstandingLoans: 0
    });
    lender.setPool(p1);
    vm.stopPrank();

    bytes32 currentPoolId = lender.getPoolId(lender1, address(loanToken), address(collateralToken));
    bytes32 currentPoolId2 = lender.getPoolId(lender2, address(loanToken), address(collateralToken));

    vm.startPrank(borrower);
    Borrow memory borrow = Borrow({
        poolId: currentPoolId,
        debt: 200e18,
        collateral: 100e18
    });
    
    borrowArray.push(borrow);
    lender.borrow(borrowArray);

    Refinance memory refinance = Refinance({
        loanId: 0,
        poolId: currentPoolId2,
        debt: 300e18,
        collateral: 150e18
    });
    refinances.push(refinance);
    lender.refinance(refinances);
    vm.stopPrank();

    (,,,,uint256 poolBalance2,,,,) = lender.pools(currentPoolId2);
    (,,,,uint256 poolBalance,,,,) = lender.pools(currentPoolId);

    console.log("Borrower balance: ", loanToken.balanceOf(borrower));
    console.log("Borrower balance: ", collateralToken.balanceOf(borrower));
    console.log("Pool2 balance: ", poolBalance2);
    console.log("Pool1 balance: ", poolBalance);
    console.log("Lender contract balance: ", collateralToken.balanceOf(address(lender)));
}

In this test we see that after refinancing I am only borrowing 300 loan tokens and then the pool balance is updated from 1000 loan tokens to 400 loan tokens which is twice the 300 borrowed loan tokens.

Tools Used

Visual Studio Code, Foundry

Recommendations

Remove one of the lines where the pool balance is updated.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!