Core Contracts

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

NFTs Permanently Locked in StabilityPool after Liquidations.

Summary

The LendingPool contract transfers liquidated users' NFTs to the StabilityPool during liquidation, but the StabilityPool contract lacks any functionality to manage, transfer, or withdraw these NFTs, resulting in permanent lockup of valuable house NFTs in the StabilityPool contract.

Vulnerability Details

Let's analyze the relevant code:
In LendingPool.sol, during finalizeLiquidation():

function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
// ...
// 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;
// ...
}

This code transfers all NFTs from liquidated positions to the StabilityPool address. However, examining the StabilityPool.sol contract reveals:

  • No functions to manage received NFTs

  • No administrative functions to rescue or redistribute NFTs

  • No logic to auction or handle received NFTs from liquidations

  • No integration with RAACNFT contract despite receiving NFTs

  • Additionaly is also no implementation of NFT receiving functions (no implentation of onERC721Received function)

This creates a critical issue because:

  • Valuable house NFTs get permanently locked in the StabilityPool contract

  • There's no mechanism to redistribute these NFTs to DEToken holders

  • The protocol loses the ability to recover value from liquidated collateral

  • The economic model breaks as locked NFTs can't be recycled back into the system

The issue is particularly severe because house NFTs represent real estate value, and their permanent lockup removes significant value from the protocol's ecosystem.

PoC

  1. Alice deposits an NFT (tokenId: 1) in LendingPool and borrows assets

  2. Alice's position becomes unhealthy and gets marked for liquidation

  3. Liquidation grace period passes

  4. StabilityPool calls finalizeLiquidation() on LendingPool

  5. NFT with tokenId 1 gets transferred to StabilityPool

  6. NFT is now permanently locked as StabilityPool has no functions to manage or transfer it

Impact

  • Permanent loss of valuable house NFTs during liquidations

  • Breaking of protocol's economic model

  • Loss of collateral value that should be redistributed to stability providers

  • Reduced protocol efficiency as locked NFTs can't re-enter the system

Tools Used

Manual review

Recommendations

Add NFT management functionality to StabilityPool. The code below is just some rough ideas on what you could do.

contract StabilityPool {
// Add NFT handling state variables
mapping(uint256 => bool) public liquidatedNFTs;
uint256[] public liquidatedNFTIds;
// Add function to auction/redistribute NFTs
function handleLiquidatedNFT(uint256 tokenId) internal {
liquidatedNFTs[tokenId] = true;
liquidatedNFTIds.push(tokenId);
// Implement auction or redistribution logic
}
// Add administrative recovery function
function redistributeNFT(uint256 tokenId, address recipient) external onlyOwner {
require(liquidatedNFTs[tokenId], "Not a liquidated NFT");
IRAACNFT(raacNFT).transferFrom(address(this), recipient, tokenId);
liquidatedNFTs[tokenId] = false;
// Remove from liquidatedNFTIds array
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Liquidated RAACNFTs are sent to the StabilityPool by LendingPool::finalizeLiquidation where they get stuck

Support

FAQs

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

Give us feedback!