Core Contracts

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

Incorrect event parameter emitted when finalizing liquidations

Vulnerability Details

When a borrower is liquidated as a final step the LendingPool::finalizeLiquidation() function is called from the Stability pool, which emits an event with the liquidated user's data. However a wrong parameter will be emitted. Let's look at the function:

function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
...
UserData storage user = userData[userAddress];
// 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;
...
emit LiquidationFinalized(stabilityPool, userAddress, userDebt, getUserCollateralValue(userAddress));

The problem here is that when LendingPool::getUserCollateralValue() is called:

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 borrower's collateral (NFT's) are already deleted, so the function will not loop through any token ids and will return 0. But the event expects liquidated collateral amount.

Impact

  • Low - no harm or loss of funds for the protocol, but will give wrong data to owners.

Tools Used

Manual Review

Recommendations

Store the value before the token id's price is deleted from the user's data.

function finalizeLiquidation(address userAddress) external nonReentrant onlyStabilityPool {
...
UserData storage user = userData[userAddress];
+ uint256 collateralValue = getUserCollateralValue(userAddress);
// 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;
...
- emit LiquidationFinalized(stabilityPool, userAddress, userDebt, getUserCollateralValue(userAddress));
+ emit LiquidationFinalized(stabilityPool, userAddress, userDebt, collateralValue);
Updates

Lead Judging Commences

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

LendingPool::finalizeLiquidation emits 0 collateralLiquidated because it deletes the info required to compute it

Support

FAQs

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

Give us feedback!