Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Users with crvUSD deposits cannot borrow from the lending pool

Summary

The borrow() function should allow users who have deposited NFTs or crvUSD into the lending pool to borrow. However, users who deposit only crvUSD into the lending pool but do not deposit NFTs are unable to borrow, despite the documentation stating that borrowing is allowed against crvUSD deposits and NFTs.

Vulnerability Details

function borrow(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
if (isUnderLiquidation[msg.sender]) revert CannotBorrowUnderLiquidation();
UserData storage user = userData[msg.sender];
uint256 collateralValue = getUserCollateralValue(msg.sender);
if (collateralValue == 0) revert NoCollateral();
// Update reserve state before borrowing
ReserveLibrary.updateReserveState(reserve, rateData);
// Ensure sufficient liquidity is available
_ensureLiquidity(amount);
console.log("amount", amount);
// Fetch user's total debt after borrowing
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
// Ensure the user has enough collateral to cover the new debt
if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
// Update user's scaled debt balance
uint256 scaledAmount = amount.rayDiv(reserve.usageIndex);
// Mint DebtTokens to the user (scaled amount)
(bool isFirstMint, uint256 amountMinted, uint256 newTotalSupply) = IDebtToken(reserve.reserveDebtTokenAddress).mint(msg.sender, msg.sender, amount, reserve.usageIndex);
// Transfer borrowed amount to user
IRToken(reserve.reserveRTokenAddress).transferAsset(msg.sender, amount);
user.scaledDebtBalance += scaledAmount;
// reserve.totalUsage += amount;
reserve.totalUsage = newTotalSupply;
// Update liquidity and interest rates
ReserveLibrary.updateInterestRatesAndLiquidity(reserve, rateData, 0, amount);
// Rebalance liquidity after borrowing
_rebalanceLiquidity();
emit Borrow(msg.sender, amount);
}
function getUserCollateralValue(address userAddress) public view returns (uint256) {
UserData storage user = userData[userAddress];
uint256 totalValue = 0;
for (uint256 i = 0; i < user.nftTokenIds.length; i++) {
uint256 tokenId = user.nftTokenIds[i];
uint256 price = getNFTPrice(tokenId);
totalValue += price;
}
return totalValue;
}

The function determines the user’s collateral using getUserCollateralValue(), which only considers NFTs and does not include crvUSD deposits.

Users who deposit crvUSD but no NFTs will have collateralValue == 0, causing the NoCollateral() revert.

This contradicts the intended protocol behavior, which should allow users to borrow against either crvUSD deposits or NFTs.

POC

Scenario: User Cannot Borrow Despite Depositing crvUSD

Step 1: User Deposits crvUSD

  • User deposits 5,000 crvUSD into the lending pool.

  • The system should allow borrowing against this deposit.

Step 2: User Attempts to Borrow

  • User tries to borrow 2,000 crvUSD.

  • The function calls getUserCollateralValue(), which only considers NFTs.

  • Since the user has no NFTs, collateralValue == 0.

  • The function reverts with NoCollateral(), preventing the user from borrowing.

Impact

Users who deposit crvUSD without NFTs are unfairly restricted from borrowing.

The function contradicts the documentation, which states that borrowing is possible against crvUSD deposits.

Tools Used

Manual Review

Recommendations

Modify getUserCollateralValue() to Include Deposited crvUSD

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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