Core Contracts

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

Use of `transferFrom()` rather than `safeTransferFrom()` for NFTs will potentially lead to the loss of NFTs

Summary

The use of transferFrom() on NFTs may lead to loss of NFTs if not handled appropriately

Vulnerability Details

The LendingPool::finalizeLiquidation() function Allows the Stability Pool to finalize the liquidation after the grace period of a user has expired, when the user's grace period has passed and the finalizeLiquidation() is called by the stability pool the user's NFTs is sent from the contract holding the NFTs address(this) to the stabilityPool (recipient) using the transferFrom() function. This can lead to potential loss of the NFTs if the recipient address doesn't handle or manage NFTs appropriately.

Impact

The standard `transferFrom()` function does not verify whether the recipient address can accept and manage NFTs (i.e., whether the address is a smart contract that implements the necessary interface to handle ERC-721 tokens). If the NFT is sent to a contract that cannot handle it, the token may be irretrievably lost.
```javascript
function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
if (!isUnderLiquidation[userAddress]) revert NotUnderLiquidation();
// update state
ReserveLibrary.updateReserveState(reserve, rateData);
if (block.timestamp <= liquidationStartTime[userAddress] + liquidationGracePeriod) {
revert GracePeriodNotExpired();
}
UserData storage user = userData[userAddress];
uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
isUnderLiquidation[userAddress] = false;
liquidationStartTime[userAddress] = 0;
// Transfer NFTs to Stability Pool
for (uint256 i = 0; i < user.nftTokenIds.length; i++) {
uint256 tokenId = user.nftTokenIds[i];
user.depositedNFTs[tokenId] = false;
@>> raacNFT.transferFrom(address(this), stabilityPool, tokenId);
}
delete user.nftTokenIds;
// Burn DebtTokens from the user
(uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) = IDebtToken(reserve.reserveDebtTokenAddress).burn(userAddress, userDebt, reserve.usageIndex);
// Transfer reserve assets from Stability Pool to cover the debt
IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);
// Update user's scaled debt balance
user.scaledDebtBalance -= amountBurned;
reserve.totalUsage = newTotalSupply;
// Update liquidity and interest rates
ReserveLibrary.updateInterestRatesAndLiquidity(reserve, rateData, amountScaled, 0);
emit LiquidationFinalized(stabilityPool, userAddress, userDebt, getUserCollateralValue(userAddress));
}
```

Tools Used

manual analysis

Recommendations

Using `safeTransferFrom()` is recommended as it includes an additional check to ensure that the destination address can properly interact with NFTs.
```diff
//code
for (uint256 i = 0; i < user.nftTokenIds.length; i++) {
uint256 tokenId = user.nftTokenIds[i];
user.depositedNFTs[tokenId] = false;
- raacNFT.transferFrom(address(this), stabilityPool, tokenId);
+ raacNFT.safeTransferFrom(address(this), stabilityPool, tokenId);
}
delete user.nftTokenIds;
```
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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