Core Contracts

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

Same beneficary can't recreate vesting schedule in RAACReleaseOrchestrator due to lack of update

Summary

The RAACReleaseOrchestrator is a contract which manages the vesting and release of RAAC tokens for various stakeholders. So vestings could be created by createVestingSchedule() and funds could be released by release(). However there is an issue which exists in the vesting mechanism - if UserA is a beneficiary he can't recreate another vesting, even if all the funds are released which would not let the users vest, and hence loss of funds, trust and integrity in the protocol.

Vulnerability Details

  • User can create vesting schedule by createVestingSchedule- it creates the vesting schedule with beneficiary. What it does is sets the vestingSchedules mapping with benefiary address and VestingSchedule struct. So on creating vesting schedule it sets the schedule.initialized = true; :

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();
// Check category allocation limits
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; //@audit not taking into account that, schedule start in past ?
schedule.duration = VESTING_DURATION;
schedule.initialized = true;
emit VestingScheduleCreated(beneficiary, category, amount, startTime);
}
  • Now with release() function, user can release the funds accumulated. So there are two things not taken into account :

    User can't create another vesting or on different categoryAllocations in the same time or even after
    User can't recreate vesting on same categoryAllocations
    User can't also update the vesting amount

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

You can see that even if, it doesn't delete the vestingSchedule for the beneficiary because of which it will be restricted to create another vesting schedule for same beneficiary as there already exist check in the createVestingSchedule:

if (vestingSchedules[beneficiary].initialized) revert VestingAlreadyInitialized();

Impact

  • Inability to use the vesting function more than once by a user

Tools Used

Manual Review

Recommendations

  • Delete the vesting schedule for beneficiary when the vesting duration ends,

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);
+ if (block.timestamp > schedule.startTime + VESTING_DURATION){
+ delete vestingSchedules[beneficiary];
+ }
emit TokensReleased(beneficiary, releasableAmount);
}
Updates

Lead Judging Commences

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

RAACReleaseOrchestrator restricts beneficiaries to a single vesting schedule across all categories, causing funds from secondary investments to be permanently lost

Support

FAQs

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

Give us feedback!