The RAACReleaseOrchestrator
contract restricts each beneficiary to a single vesting schedule, meaning that users who participate in both the Private Sale and Public Sale cannot create separate schedules for each category. As a result, the funds invested in the second sale (if a vesting schedule has already been created for the first sale) cannot be vested, potentially causing users to lose their invested funds. This limitation is enforced by the contract's current logic that prevents the creation of multiple schedules per beneficiary.
The RAACReleaseOrchestrator
contract contains a mechanism that prevents the creation of more than one vesting schedule per beneficiary. This is enforced in the createVestingSchedule
function with the following check:
This results in the contract not allowing a beneficiary to create multiple vesting schedules across different categories (e.g., Private Sale and Public Sale). As a result, if a user participates in both sales, they will be able to create only one vesting schedule, and any subsequent investment in the other sale will not be properly vested.
Permanent Loss of Funds: A user who participates in both the Private Sale and Public Sale will only have a vesting schedule created for one of the categories. Their funds in the second sale will not be vested, and the user will lose access to those tokens.
Violation of Expected Functionality: The contract was likely intended to allow multiple vesting schedules for a beneficiary to handle various categories, but the current design fails to support this use case. This could confuse users and lead to a poor user experience.
Manual Code Review
1. Updating the vestingSchedules
variable:
Instead of using:
We will use:
createVestingSchedule
function:We need to modify the check for the existing schedule and change how we assign the vesting schedule:
release
function:The release
function needs to handle the case where a beneficiary has multiple vesting schedules, one for each category. So, it needs to check the schedules for the caller across all categories.
getVestingSchedule
function:This function will need to return the schedule for a specific category, so we will add a parameter to specify which category's vesting schedule the user wants to retrieve.
emergencyRevoke
function:We need to make sure that when we revoke a vesting schedule, we specify the category. This will allow us to revoke a specific schedule and ensure that multiple schedules across different categories can be managed.
getCategoryDetails
function:We'll need to update this function to return details for a specific category and user:
The major change here is that we now use a nested mapping (mapping(address => mapping(bytes32 => VestingSchedule))
), allowing each beneficiary to have multiple schedules, one per category. This modification will also require corresponding changes to other functions that interact with the vesting schedules, as shown above.
By doing this, a beneficiary can participate in both Private Sale and Public Sale and have distinct vesting schedules for each, ensuring their tokens are properly vested and released according to the terms of each sale.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.