Core Contracts

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

Missing Category Tracking in Emergency Revoke of RAACReleaseOrchestrator

Summary

The emergencyRevoke() function fails to update categoryUsed counters, allowing revoked tokens to remain counted towards category limits.

Vulnerability Details

When creatingSchedule() we account for the amount allowed per category. The issue is that emergencyRevoke() do not remove the amount added to a category :

function emergencyRevoke(address beneficiary) external onlyRole(EMERGENCY_ROLE) {
VestingSchedule storage schedule = vestingSchedules[beneficiary];
if (!schedule.initialized) revert NoVestingSchedule();
uint256 unreleasedAmount = schedule.totalAmount - schedule.releasedAmount;
delete vestingSchedules[beneficiary];
if (unreleasedAmount > 0) {
raacToken.transfer(address(this), unreleasedAmount);
emit EmergencyWithdraw(beneficiary, unreleasedAmount);
}
emit VestingScheduleRevoked(beneficiary);
}

Impact

Wrong accounting of how much has been spent per category.
A category that had several schedule canceled can end up with no more schedule as it will be seen as they spent everything, where in reality they did not.

Tools Used

Manual

Recommendations

Store the category in VestingSchedule at creation and delete the unreleased amount from categoryUsed when using emergencyRevoke :

struct VestingSchedule {
uint256 totalAmount;
uint256 startTime;
uint256 duration;
uint256 releasedAmount;
bool initialized;
+ bytes32 category; // Add category tracking
}
function createVestingSchedule(...) {
//..
schedule.category = category;
categoryUsed[category] += amount;
//..
}
function emergencyRevoke(address beneficiary) external onlyRole(EMERGENCY_ROLE) {
VestingSchedule storage schedule = vestingSchedules[beneficiary];
if (!schedule.initialized) revert NoVestingSchedule();
uint256 unreleasedAmount = schedule.totalAmount - schedule.releasedAmount;
delete vestingSchedules[beneficiary];
+ categoryUsed[schedule.category] -= unreleasedAmount;
if (unreleasedAmount > 0) {
raacToken.transfer(address(this), unreleasedAmount);
emit EmergencyWithdraw(beneficiary, unreleasedAmount);
}
emit VestingScheduleRevoked(beneficiary);
}
Updates

Lead Judging Commences

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

RAACReleaseOrchestrator::emergencyRevoke fails to decrement categoryUsed, causing artificial category over-allocation and rejection of valid vesting schedules

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

RAACReleaseOrchestrator::emergencyRevoke fails to decrement categoryUsed, causing artificial category over-allocation and rejection of valid vesting schedules

Support

FAQs

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