Core Contracts

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

FeeCollector Contract's emergencyWithdraw Function Issue

Summary

The emergencyWithdraw function in the FeeCollector contract directly transfers fees to the Treasury contract using safeTransfer. This results in funds being permanently locked.

Vulnerability Details

The emergencyWithdraw function in the FeeCollector contract directly transfers tokens to the Treasury contract using safeTransfer. This results in funds being permanently locked since the withdraw function in the Treasury contract can only extract assets that have been deposited through the deposit function.

In this emergencyWithdraw function, if the token has not been deposited into the Treasury contract via the deposit function, its corresponding balance in the _balances mapping will be zero. When attempting to call the withdraw function for this token, a revert will occur because the withdraw function checks the _balances mapping and finds that there are insufficient funds (i.e., zero balance) for the token requested.

function deposit(address token, uint256 amount) external override nonReentrant {
if (token == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
IERC20(token).transferFrom(msg.sender, address(this), amount);
_balances[token] += amount;
_totalValue += amount;
emit Deposited(token, amount);
}
function withdraw(
address token,
uint256 amount,
address recipient
) external override nonReentrant onlyRole(MANAGER_ROLE) {
if (token == address(0)) revert InvalidAddress();
if (recipient == address(0)) revert InvalidRecipient();
if (_balances[token] < amount) revert InsufficientBalance();
_balances[token] -= amount;
_totalValue -= amount;
IERC20(token).transfer(recipient, amount);
emit Withdrawn(token, amount, recipient);
}
function emergencyWithdraw(address token) external override whenPaused {
if (!hasRole(EMERGENCY_ROLE, msg.sender)) revert UnauthorizedCaller();
if (token == address(0)) revert InvalidAddress();
uint256 balance;
if (token == address(raacToken)) {
balance = raacToken.balanceOf(address(this));
raacToken.safeTransfer(treasury, balance);
} else {
balance = IERC20(token).balanceOf(address(this));
SafeERC20.safeTransfer(IERC20(token), treasury, balance);
}
emit EmergencyWithdrawal(token, balance);
}

Impact

The impact of this vulnerability is significant as it allows funds to become permanently inaccessible within the Treasury contract.

Tools Used

Manual Code Review

Recommendations

Modify the emergencyWithdraw Function: Ensure that all transfers to the Treasury contract utilize the deposit function for appropriate fund handling.

Updates

Lead Judging Commences

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

FeeCollector::_processDistributions and emergencyWithdraw directly transfer funds to Treasury where they get permanently stuck

Support

FAQs

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

Give us feedback!