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

Lack of protection from fee on transfer tokens

Summary

Contract uses the loan token and collateral tokens in order to process the lending and borrowing process.

For each lent token, there is certain amount of collateral is locked from the borrower.

There are no mention about the type of tokens that can be used as collateral. There are certain tokens which will charge fee when transfer. if these tokens are used as collateral, the transferred collateral value could be lesser than the calculated value.

Vulnerability Details

Lets see the borrow function

function borrow(Borrow[] calldata borrows) public {
for (uint256 i = 0; i < borrows.length; i++) {
bytes32 poolId = borrows[i].poolId;
uint256 debt = borrows[i].debt;
uint256 collateral = borrows[i].collateral;
// get the pool info
Pool memory pool = pools[poolId];
// make sure the pool exists
if (pool.lender == address(0)) revert PoolConfig();
// validate the loan
if (debt < pool.minLoanSize) revert LoanTooSmall();
if (debt > pool.poolBalance) revert LoanTooLarge();
if (collateral == 0) revert ZeroCollateral();
// make sure the user isn't borrowing too much
uint256 loanRatio = (debt * 10 ** 18) / collateral;
if (loanRatio > pool.maxLoanRatio) revert RatioTooHigh();
// create the loan
Loan memory loan = Loan({
lender: pool.lender,
borrower: msg.sender,
loanToken: pool.loanToken,
collateralToken: pool.collateralToken,
debt: debt,
collateral: collateral,
interestRate: pool.interestRate,
startTimestamp: block.timestamp,
auctionStartTimestamp: type(uint256).max,
auctionLength: pool.auctionLength
});
// update the pool balance
_updatePoolBalance(poolId, pools[poolId].poolBalance - debt);
pools[poolId].outstandingLoans += debt;
// calculate the fees
uint256 fees = (debt * borrowerFee) / 10000;
// transfer fees
IERC20(loan.loanToken).transfer(feeReceiver, fees);
// transfer the loan tokens from the pool to the borrower
IERC20(loan.loanToken).transfer(msg.sender, debt - fees);
// transfer the collateral tokens from the borrower to the contract
IERC20(loan.collateralToken).transferFrom(
msg.sender,
address(this),
collateral ------------------------------------>>> collateral is received by the contract. this could ne less than actual value.
);
loans.push(loan);
emit Borrowed(
msg.sender,
pool.lender,
loans.length - 1,
debt,
collateral,
pool.interestRate,
block.timestamp
);
}
}

Impact

Accounting issue due to mismatch of recorded value and the actual received value to the contract.

Contract forced to transfer more amount of collateral during repay even though it received less during borrow call.

Tools Used

Manual review.

Recommendations

Don't allow tokens which charge fee during transfer.

Support

FAQs

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