20,000 USDC
View results
Submission Details
Severity: high

Unverified Token Repayment in `Lender.sol` Contract

Summary

In the Lender.sol contract, the repay function allows for loan repayments. However, upon reviewing the function, it appears that there is no validation mechanism in place to ensure that the repayment is being made with the correct token (i.e., the loan token). This could potentially allow a malicious actor to repay a loan with a less valuable or even worthless token.

Vulnerability Details

The repay function, as currently implemented, lacks a verification step to ensure that the token being used for repayment matches the original loan token. This opens the possibility for a borrower to repay using a different, possibly worthless, token.

Code Snippet

function repay(uint256[] calldata loanIds) public {
for (uint256 i = 0; i < loanIds.length; i++) {
uint256 loanId = loanIds[i];
// get the loan info
Loan memory loan = loans[loanId];
// calculate the interest
(
uint256 lenderInterest,
uint256 protocolInterest
) = _calculateInterest(loan);
bytes32 poolId = getPoolId(
loan.lender,
loan.loanToken,
loan.collateralToken
);
// update the pool balance
_updatePoolBalance(
poolId,
pools[poolId].poolBalance + loan.debt + lenderInterest
);
pools[poolId].outstandingLoans -= loan.debt;
// transfer the loan tokens from the borrower to the pool
IERC20(loan.loanToken).transferFrom(
msg.sender,
address(this),
loan.debt + lenderInterest
);
// transfer the protocol fee to the fee receiver
IERC20(loan.loanToken).transferFrom(
msg.sender,
feeReceiver,
protocolInterest
);
// transfer the collateral tokens from the contract to the borrower
IERC20(loan.collateralToken).transfer(
loan.borrower,
loan.collateral
);
emit Repaid(
msg.sender,
loan.lender,
loanId,
loan.debt,
loan.collateral,
loan.interestRate,
loan.startTimestamp
);
// delete the loan
delete loans[loanId];
}
}

Impact

This vulnerability has a high impact. It could allow a malicious borrower to effectively repay a loan without actually returning the same value that they borrowed, leading to a loss for the lender. In a worst-case scenario, a borrower could exploit this vulnerability to drain a lender's funds.

Tools Used

Manual Code review

Recommendations

A token verification step should be added to the repay function to ensure that repayments are made with the correct token. This can be done by checking the token being transferred against the loan token recorded when the loan was issued. Below is a sample code snippet to illustrate the recommended changes:

function repay(uint256[] calldata loanIds) public {
for (uint256 i = 0; i < loanIds.length; i++) {
Loan memory loan = loans[loanIds[i]];
IERC20 loanToken = IERC20(loan.loanToken);
require(msg.value == loan.amount, "Incorrect repayment amount");
require(loanToken.transferFrom(msg.sender, address(this), loan.amount), "Token transfer failed");
}
}

In this example, the repay function retrieves the loan details, checks the repayment amount, and then verifies the token being used for repayment. If the token does not match the original loan token, or if the transfer fails for any reason, the transaction is reverted. This ensures that the borrower repays the loan with the correct token and amount.

Support

FAQs

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