Core Contracts

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

`FeeCollector::emergencyWithdraw' permanently locks tokens in Treasury

Summary

`FeeCollector::emergencyWithdraw' permanently locks tokens in Treasury

Vulnerability Details

FeeCollector::emergencyWithdraw transfer its entire balance of token to Treasury contract.

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

Treasury contract has deposit and withdraw function to receive and handle any token.

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

Due to _balances per token tracking in deposit and withdraw, the Treasury can handle only tokens it receives using the deposit method. The Treasury can't move tokens received from the FeeCollector via direct ERC20::transfer.

Impact

emergencyWithdraw permanently locks tokens.

Tools Used

Recommendations

Edit FeeCollector::emergencyWithdraw function to:

  • approve treasury

  • call Treasury::deposit to transferFrom tokens.

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!