The RAACReleaseOrchestrator contract is designed to manage vesting schedules for token distributions. In its emergency revocation flow, the contract “withdraws” unreleased tokens from a beneficiary’s vesting schedule via the emergencyRevoke function. Specifically, when an emergency revocation is triggered, the unreleased tokens are transferred to the contract itself. The event name EmergencyWithdraw and the transfer call clearly indicate that these tokens are expected to be recovered for future use or reallocation. However, the contract does not implement any function that allows an administrator (or an authorized party) to withdraw these tokens from its balance. Consequently, tokens recovered through emergency revocation become permanently locked within the contract.
Root Cause:
Within the emergencyRevoke function, unreleased tokens from a beneficiary’s vesting schedule are transferred to the RAACReleaseOrchestrator contract’s address via:
This design clearly implies that the tokens are “withdrawn” from the vesting schedule and should later be available for recovery or reallocation. However, the contract does not offer any mechanism to withdraw or “rescue” these tokens from its own balance.
Impact:
Locked Funds: Tokens transferred to the contract via emergency revocation remain permanently locked. This contradicts the likely intent behind the EmergencyWithdraw event and the withdrawal logic, where the admin should later be able to recover and reassign these tokens.
Misallocation Risk: Should an emergency event occur, the inability to reclaim these tokens may result in capital inefficiencies or even unintentional token supply reductions that could affect downstream mechanisms.
Operational Overhead: The absence of a withdrawal function means that, if such a situation arises, the team cannot recover funds for treasury re-allocation or further distribution without a contract upgrade, which is both disruptive and costly.
Emergency Revocation Triggered:
An authorized emergency call is made to revoke a beneficiary’s vesting schedule. The unreleased tokens are calculated and transferred from the vesting allocation into the RAACReleaseOrchestrator’s balance.
Funds Locked in Contract:
As designed, these tokens are no longer held against any beneficiary’s allocation—they now reside within the contract. However, because no withdrawal or rescue function exists, these tokens are effectively “stuck.”
Long-Term Consequences:
In a scenario where multiple emergency revocations occur, significant token amounts may accumulate in the contract. Without a recovery mechanism, these tokens remain inaccessible for any future reallocation, treasury management, or redistribution, contrary to the system’s design intent.
The following Foundry PoC demonstrates the issue clearly. It sets up a vesting schedule, triggers an emergency revocation, and then verifies that the unreleased tokens have been locked in the contract—with no subsequent recovery possible.
Mitigation:
Add a withdrawal (or rescue) function to the RAACReleaseOrchestrator contract. This function should allow an authorized role (e.g., DEFAULT_ADMIN_ROLE) to recover any ERC20 tokens held by the contract. A concise implementation would be:
Benefits:
Recoverability: Enables the recovery of tokens inadvertently locked in the contract following an emergency revocation.
Operational Flexibility: Allows the project to reallocate or redistribute recovered tokens as necessary, preserving capital efficiency.
Alignment with Design Intent: Matches the implied design of the EmergencyWithdraw flow, ensuring that recovered tokens are not permanently stranded.
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.