The emergencyRevoke
function is intended to allow a trusted emergency role to revoke a beneficiary's vesting schedule and recover any unreleased tokens in emergency situations (e.g., if the contract is compromised). However, the function mistakenly transfers the unreleased tokens to the contract itself (address(this)
) rather than to the caller (a trusted emergency role). This misdirection can lead to the tokens being locked within the contract, thereby hindering immediate access and reallocation during a critical emergency.
Emergency Revoke Functionality:
The emergencyRevoke
function is designed to cancel a vesting schedule and recover any remaining tokens:
Instead of transferring the unreleased tokens to a trusted party (such as msg.sender
or a designated recovery address), the function calls:
which directs the tokens to the contract's own address.
Intended Behavior vs. Implementation:
Intended Behavior:
In an emergency, a trusted account (with the EMERGENCY_ROLE
) should be able to recover the unreleased tokens immediately, allowing them to manage or reallocate the tokens appropriately.
Actual Behavior:
The unreleased tokens are inadvertently transferred to address(this)
, leaving them locked within the contract and inaccessible to the emergency role. This undermines the purpose of having an emergency revocation mechanism.
Documentation vs. Implementation Mismatch:
The comments in the code and the emergency functionality suggest that a recovery of tokens is necessary in critical situations. However, transferring tokens to the contract itself contradicts this goal, potentially delaying or preventing rapid emergency intervention.
Locked Funds:
Unreleased tokens become stuck in the contract, rendering them inaccessible for immediate reallocation or recovery by the emergency team.
Delayed Emergency Response:
In a crisis, the emergency role might be unable to promptly recover or redistribute funds, which could exacerbate the situation, especially if rapid action is required to mitigate an exploit or security breach.
Assume:
A beneficiary has a vesting schedule with a total allocation of 1,000 tokens, with 400 tokens already released.
An emergency scenario occurs, prompting the emergency role to revoke the vesting schedule.
Steps:
The emergency role calls emergencyRevoke(beneficiary)
.
The function calculates the unreleased tokens as:
Instead of transferring 600 tokens to the emergency role (or a designated recovery address), the function transfers the tokens to the contract itself:
Result:
The 600 tokens remain locked within the contract, preventing the emergency role from accessing them during the crisis.
Correct the Transfer Destination:
Modify the emergencyRevoke
function so that unreleased tokens are transferred to msg.sender
(the emergency role executing the function) or to a pre-designated secure address:
This adjustment ensures that the tokens are immediately available for emergency management.
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.