20,000 USDC
View results
Submission Details
Severity: medium

Pools with the `same` loan and collateral tokens can be `created`

Summary

Lending pools with the same tokens can be created by calling Lender.setPool()

Vulnerability Details

During pool creation setPool() is called but this function has no checks stopping the same token from being used as the lending and collateral token. This can be catastrophic because there is no point in the creation of pools with the same tokens.

File:Lender.sol
function setPool(Pool calldata p) public returns (bytes32 poolId) {
// validate the pool
if (
p.lender != msg.sender ||
p.minLoanSize == 0 ||
p.maxLoanRatio == 0 ||
p.auctionLength == 0 ||
p.auctionLength > MAX_AUCTION_LENGTH ||
p.interestRate > MAX_INTEREST_RATE
) revert PoolConfig();
// check if they already have a pool balance
poolId = getPoolId(p.lender, p.loanToken, p.collateralToken);
// you can't change the outstanding loans
if (p.outstandingLoans != pools[poolId].outstandingLoans)
revert PoolConfig();
uint256 currentBalance = pools[poolId].poolBalance;
if (p.poolBalance > currentBalance) {
// if new balance > current balance then transfer the difference from the lender
IERC20(p.loanToken).transferFrom(
p.lender,
address(this),
p.poolBalance - currentBalance
);
} else if (p.poolBalance < currentBalance) {
// if new balance < current balance then transfer the difference back to the lender
IERC20(p.loanToken).transfer(
p.lender,
currentBalance - p.poolBalance
);
}
emit PoolBalanceUpdated(poolId, p.poolBalance);
if (pools[poolId].lender == address(0)) {
// if the pool doesn't exist then create it
emit PoolCreated(poolId, p);
} else {
// if the pool does exist then update it
emit PoolUpdated(poolId, p);
}
pools[poolId] = p;
}

Impact

This goes against the intentions of the developers as it breaks the concept of a lending pool and has other unexpected consequences

Tools Used

Manual Review

Recommendations

Checks should be added to prevent the same tokens from being used.

function setPool(Pool calldata p) public returns (bytes32 poolId) {
// validate the pool
if (
p.lender != msg.sender ||
p.minLoanSize == 0 ||
p.maxLoanRatio == 0 ||
p.auctionLength == 0 ||
p.auctionLength > MAX_AUCTION_LENGTH ||
p.interestRate > MAX_INTEREST_RATE || p.loanToken = p.collateralToken) revert PoolConfig();
// More code..

Support

FAQs

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