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];
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
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);