Core Contracts

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

Vesting Schedule Created Without Holding Tokens

Summary

The createVestingSchedule function in the RaacReleaseOrchestrator.sol contract sets up vesting schedules for beneficiaries without transferring or holding the corresponding vested tokens. As a result, beneficiaries can later release tokens through the release function, but the contract may not have the required token balance to fulfill the vesting claims.

Vulnerability Details

When a vesting schedule is created via createVestingSchedule, the contract records the vesting parameters but does not receive or escrow the tokens to be vested:

function createVestingSchedule(
address beneficiary,
bytes32 category,
uint256 amount,
uint256 startTime
) external onlyRole(ORCHESTRATOR_ROLE) whenNotPaused {
if (beneficiary == address(0)) revert InvalidAddress();
if (amount == 0) revert InvalidAmount();
if (vestingSchedules[beneficiary].initialized) revert VestingAlreadyInitialized();
if (categoryAllocations[category] == 0) revert InvalidCategory();
uint256 newCategoryTotal = categoryUsed[category] + amount;
if (newCategoryTotal > categoryAllocations[category]) revert CategoryAllocationExceeded();
categoryUsed[category] = newCategoryTotal;
VestingSchedule storage schedule = vestingSchedules[beneficiary];
schedule.totalAmount = amount;
schedule.startTime = startTime;
schedule.duration = VESTING_DURATION;
schedule.initialized = true;
emit VestingScheduleCreated(beneficiary, category, amount, startTime);
}

Later, when the release function is called, the contract attempts to transfer the vested tokens to the beneficiary:

function release() external nonReentrant whenNotPaused {
address beneficiary = msg.sender;
VestingSchedule storage schedule = vestingSchedules[beneficiary];
if (!schedule.initialized) revert NoVestingSchedule();
uint256 releasableAmount = _calculateReleasableAmount(schedule);
if (releasableAmount == 0) revert NothingToRelease();
schedule.releasedAmount += releasableAmount;
schedule.lastClaimTime = block.timestamp;
raacToken.transfer(beneficiary, releasableAmount);
emit TokensReleased(beneficiary, releasableAmount);
}

Without ensuring that the contract holds the tokens at schedule creation, calls to release may revert due to insufficient token balance.

Impact

Beneficiaries expecting to claim vested tokens may be unable to do so if the contract lacks the necessary token balance. This undermines the trust and reliability of the vesting mechanism and can lead to significant operational issues.

Tools Used

Manual code review.

Recommendations

Modify the createVestingSchedule function to transfer the amount of vested tokens into the contract at the time of schedule creation. This ensures that vested tokens are secured and available for release when the vesting period ends:

// Example fix:
raacToken.transferFrom(msg.sender, address(this), amount); // Secure tokens during vesting schedule creation
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!