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

Lender.sol#refinance() - The debt is subtracted twice from the new pool.

Summary

The debt is subtracted twice from the new pool.

Vulnerability Details

Currently whenever a loan is refinanced the debt is subtracted twice from the new pool's poolBalance. This isn't supposed to happen as the new pool's owner will lose twice as much from his poolBalance while his outstandingLoans will be equal to the debt, meaning there will be funds he will lose.

POC:

function testRefinanceIsSubtractedTwice() public {
// Lender1 creates a pool
vm.startPrank(lender1);
Pool memory lender1Pool = Pool({
lender: lender1,
loanToken: address(loanToken),
collateralToken: address(collateralToken),
minLoanSize: 100*10**18,
poolBalance: 1000*10**18,
maxLoanRatio: 2*10**18,
auctionLength: 1 days,
interestRate: 1000,
outstandingLoans: 0
});
bytes32 lender1PoolId = lender.setPool(lender1Pool);
vm.stopPrank();
// Borrower takes out a loan from Lender1 equal to half his pool
vm.startPrank(borrower);
Borrow memory b = Borrow({
poolId: lender1PoolId,
debt: 500*10**18,
collateral: 500*10**18
});
Borrow[] memory borrows = new Borrow[](1);
borrows[0] = b;
lender.borrow(borrows);
vm.stopPrank();
// Lender2 creates his own pool with the same loan and collateral token.
// For simplicity sake he will have basically the same pool as Lender1
vm.startPrank(lender2);
Pool memory lender2Pool = Pool({
lender: lender2,
loanToken: address(loanToken),
collateralToken: address(collateralToken),
minLoanSize: 100*10**18,
poolBalance: 1000*10**18,
maxLoanRatio: 2*10**18,
auctionLength: 1 days,
interestRate: 1000,
outstandingLoans: 0
});
bytes32 lender2PoolId = lender.setPool(lender2Pool);
// Borrower decides to refinance his entire loan and use Lender2's pool to do so
vm.startPrank(borrower);
Refinance memory r = Refinance({
loanId: 0,
poolId: lender2PoolId,
debt: 500*10**18,
collateral: 500*10**18
});
Refinance[] memory rs = new Refinance[](1);
rs[0] = r;
lender.refinance(rs);
vm.stopPrank();
// We can see that Lender2's pool is equal to zero
(,,,,uint256 lender2PoolAfterRefinancing,,,, uint256 outstandingLoans) = lender.pools(lender2PoolId);
assertEq(lender2PoolAfterRefinancing, 0);
assertEq(outstandingLoans, r.debt);
}

Impact

Loss of funds for the new lender of the loan.

Tools Used

Manual review
Foundry

Recommendations

Remove this line.

Support

FAQs

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