Core Contracts

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

Lack of manager role in StabilityPool#liquidateBorrower()

Summary

The StabilityPool#liquidateBorrower() allows both the protocol owner and assigned managers to perform liquidations. However, there is no requirement for managers to have sufficient funds before calling this function, leading to potential trust issues and mismanagement.

Vulnerability Details

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
_update();
// Get the user's debt from the LendingPool.
uint256 userDebt = lendingPool.getUserDebt(userAddress);
uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
if (userDebt == 0) revert InvalidAmount();
@> uint256 crvUSDBalance = crvUSDToken.balanceOf(address(this));
if (crvUSDBalance < scaledUserDebt) revert InsufficientBalance();
// Approve the LendingPool to transfer the debt amount
@> bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
if (!approveSuccess) revert ApprovalFailed();
// Update lending pool state before liquidation
lendingPool.updateState();
// Call finalizeLiquidation on LendingPool
lendingPool.finalizeLiquidation(userAddress);
emit BorrowerLiquidated(userAddress, scaledUserDebt);
}

The function allows any assigned manager to trigger a liquidation without checking if they actually contributed funds to the StabilityPool.

This means managers could be appointed without any financial stake in the protocol, yet still control liquidations.

But in fact, a manager has own allocation.

function addManager(address manager, uint256 allocation) external onlyOwner validAmount(allocation) {
if (managers[manager]) revert ManagerAlreadyExists();
managers[manager] = true;
@> managerAllocation[manager] = allocation;
totalAllocation += allocation;
managerList.push(manager);
emit ManagerAdded(manager, allocation);
}

The protocol relies on trust that managers act in the best interest of the system.

Impact

A manager without personal funds at stake may not act responsibly when liquidating users.

Tools Used

manual

Recommendations

Require managers to validate allocation before liquidating.

function liquidateBorrower(address userAddress) external onlyManagerOrOwner nonReentrant whenNotPaused {
_update();
// Get the user's debt from the LendingPool.
uint256 userDebt = lendingPool.getUserDebt(userAddress);
uint256 scaledUserDebt = WadRayMath.rayMul(userDebt, lendingPool.getNormalizedDebt());
if (userDebt == 0) revert InvalidAmount();
+ if (managers[msg.sender] && managerAllocation[manager] < userDebt) {
+ revert("Not Enough Allocation");
+ }
uint256 crvUSDBalance = crvUSDToken.balanceOf(address(this));
if (crvUSDBalance < scaledUserDebt) revert InsufficientBalance();
// Approve the LendingPool to transfer the debt amount
bool approveSuccess = crvUSDToken.approve(address(lendingPool), scaledUserDebt);
if (!approveSuccess) revert ApprovalFailed();
// Update lending pool state before liquidation
lendingPool.updateState();
// Call finalizeLiquidation on LendingPool
lendingPool.finalizeLiquidation(userAddress);
emit BorrowerLiquidated(userAddress, scaledUserDebt);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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