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

Double balance subtraction leads to removing the loanToken amount permanently

Summary

The Lender::refinance() subtracts the new pool's balance twice, resulting in removing the loanToken amount permanently.

Vulnerability Details

The refinance() subtracts the new pool's balance twice in L636 and L698. Subsequently, the new pool's loanToken amount will be removed permanently. The pool's lender (owner) or even the protocol admin will not be able to retrieve the removed amount.

...
// now lets deduct our tokens from the new pool
@> _updatePoolBalance(poolId, pools[poolId].poolBalance - debt);
pools[poolId].outstandingLoans += debt;
...
loans[loanId].collateral = collateral;
// update loan interest rate
loans[loanId].interestRate = pool.interestRate;
// update loan start timestamp
loans[loanId].startTimestamp = block.timestamp;
// update loan auction start timestamp
loans[loanId].auctionStartTimestamp = type(uint256).max;
// update loan auction length
loans[loanId].auctionLength = pool.auctionLength;
// update loan lender
loans[loanId].lender = pool.lender;
// update pool balance
@> pools[poolId].poolBalance -= debt;
...
  • 1st balance subtraction: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L636

  • 2nd balance subtraction: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L698

Impact

Every time the refinance() is executed, the new pool's loanToken amount will be removed permanently. This vulnerability can affect every pool regardless of what kind of loanToken is. Hence, I consider this vulnerability a high-risk issue.

Tools Used

Manual Review

Recommendations

I recommend removing the 2nd balance subtraction.

...
// now lets deduct our tokens from the new pool
_updatePoolBalance(poolId, pools[poolId].poolBalance - debt);
pools[poolId].outstandingLoans += debt;
...
loans[loanId].collateral = collateral;
// update loan interest rate
loans[loanId].interestRate = pool.interestRate;
// update loan start timestamp
loans[loanId].startTimestamp = block.timestamp;
// update loan auction start timestamp
loans[loanId].auctionStartTimestamp = type(uint256).max;
// update loan auction length
loans[loanId].auctionLength = pool.auctionLength;
// update loan lender
loans[loanId].lender = pool.lender;
// update pool balance
- pools[poolId].poolBalance -= debt;
...

Support

FAQs

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