Core Contracts

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

Untracked `RAAC` tokens in `Treasury` due to direct transfers lead to permanent fund loss

Summary

The Treasury contract receives RAAC tokens distributed by the FeeCollector. However, these tokens are not properly accounted for since the Treasury contract only tracks tokens deposited through Treasury::deposit. As a result, RAAC tokens received via the FeeCollector distribution remain untracked and cannot be withdrawn, leading to permanent loss of these funds.

Vulnerability Details

Problem description

In the FeeCollector::_processDistributions function, RAAC tokens are transferred to the Treasury contract directly instead of being deposited using Treasury::deposit. This means the _balances and _totalValue variables in the Treasury contract are not updated, leaving the transferred tokens effectively inaccessible.

Affected Code in FeeCollector::_processDistributions

function _processDistributions(uint256 totalFees, uint256[4] memory shares) internal {
uint256 contractBalance = raacToken.balanceOf(address(this));
if (contractBalance < totalFees) revert InsufficientBalance();
if (shares[0] > 0) {
uint256 totalVeRAACSupply = veRAACToken.getTotalVotingPower();
if (totalVeRAACSupply > 0) {
TimeWeightedAverage.createPeriod(
distributionPeriod,
block.timestamp + 1,
7 days,
shares[0],
totalVeRAACSupply
);
totalDistributed += shares[0];
} else {
shares[3] += shares[0]; // Add to treasury if no veRAAC holders
}
}
if (shares[1] > 0) raacToken.burn(shares[1]);
if (shares[2] > 0) raacToken.safeTransfer(repairFund, shares[2]);
@> if (shares[3] > 0) raacToken.safeTransfer(treasury, shares[3]); // @audit-issue Treasury will receive RAAC Token
}

Steps to reproduce

  1. The FeeCollector::_processDistributions function transfers RAAC tokens directly to the Treasury contract.

  2. The Treasury contract does not update its internal balance tracking mechanisms for these tokens.

  3. These tokens are effectively locked in the Treasury contract as there is no way to withdraw them.

Impact

  • Funds permanently locked: RAAC tokens sent to the Treasury cannot be withdrawn due to missing balance tracking.

  • Inaccurate financial tracking: The Treasury balance does not reflect actual holdings, leading to inconsistencies in accounting.

Tools Used

Manual Review

Recommendations

Use Treasury::deposit Instead of Direct Transfers

Modify FeeCollector::_processDistributions to deposit tokens using Treasury::deposit rather than transferring them directly:

if (shares[1] > 0) raacToken.burn(shares[1]);
if (shares[2] > 0) raacToken.safeTransfer(repairFund, shares[2]);
- if (shares[3] > 0) raacToken.safeTransfer(treasury, shares[3]);
+ if (shares[3] > 0) Treasury(treasury).deposit(address(raacToken), shares[3]);

By implementing this fix, the Treasury contract will correctly track all RAAC tokens received, ensuring that they remain accessible for withdrawal and use.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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.