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

Double deduction in lender.sol

Summary

There is a double deduction of the pool balance in the refinance method in lender.sol

Vulnerability Details

The first deduction is here.

// now lets deduct our tokens from the new pool
_updatePoolBalance(poolId, pools[poolId].poolBalance - debt);

the 2nd occurs after the loan is updated.

// update pool balance
pools[poolId].poolBalance -= debt;

Simple POC that shows the issue

function test_double_deduction() public {
vm.startPrank(lender1);
uint256 initPoolBalance = 1000*10**18;
uint256 loanSize = 500*10**18;
Pool memory p = Pool({
lender: lender1,
loanToken: address(loanToken),
collateralToken: address(collateralToken),
minLoanSize: 100*10**18,
poolBalance: initPoolBalance,
maxLoanRatio: 2*10**18,
auctionLength: 1 days,
interestRate: 1000,
outstandingLoans: 0
});
bytes32 poolId = lender.setPool(p);
(,,,,uint256 poolBalance,,,,) = lender.pools(poolId);
assertEq(poolBalance, initPoolBalance);
vm.startPrank(borrower);
collateralToken.approve(address(lender), loanSize);
Borrow memory b = Borrow({
poolId: poolId,
debt: loanSize,
collateral: loanSize
});
Borrow[] memory borrows = new Borrow[](1);
borrows[0] = b;
lender.borrow(borrows);
vm.startPrank(lender2);
Pool memory p2 = 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 poolId2 = lender.setPool(p2);
vm.startPrank(borrower);
Refinance memory r = Refinance({
loanId: 0,
poolId: keccak256(
abi.encode(
address(lender2),
address(loanToken),
address(collateralToken)
)
),
debt: loanSize,
collateral: loanSize
});
Refinance[] memory rs = new Refinance[](1);
rs[0] = r;
lender.refinance(rs);
(,,,,uint256 poolBalance2,,,,) = lender.pools(poolId2);
//this fails because balance is 0 due to a double deduction
//├─ emit log_named_uint(key: Expected, val: 500000000000000000000 [5e20])
//├─ emit log_named_uint(key: Actual, val: 0)
assertEq(poolBalance2, initPoolBalance - loanSize);
}

Impact

High. The owner of the pool can lose up to half the funds if the pool is size 2*debt.

Tools Used

None

Recommendations

Remove the following lines of code from refinance.

// update pool balance
pools[poolId].poolBalance -= debt;

Support

FAQs

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

Give us feedback!