Summary
veRAACToken::enableEmergencyWithdraw implements the withEmergencyDelay modifier to control the execution of the function according to the block.timestamp previously set.
function enableEmergencyWithdraw() external onlyOwner withEmergencyDelay(EMERGENCY_WITHDRAW_ACTION) {
emergencyWithdrawDelay = block.timestamp + EMERGENCY_DELAY;
emit EmergencyWithdrawEnabled(emergencyWithdrawDelay);
}
Vulnerability Details
The problem relies on the fact that veRAACToken::enableEmergencyWithdrawis the function that sets the emergency action parameters, not the one that will perform the action. The modifier should be placed on the veeRAACToken::emergencyWithdrawfunction,
The scheduleTime will always be zero because the veRAACToken::enableEmergencyWithdrawis the function that would update the variable.
modifier withEmergencyDelay(bytes32 actionId) {
uint256 scheduleTime = _emergencyTimelock[actionId];
if (scheduleTime == 0) revert EmergencyActionNotScheduled();
if (block.timestamp < scheduleTime + EMERGENCY_DELAY) revert EmergencyDelayNotMet();
_;
delete _emergencyTimelock[actionId];
}
Impact
The emergency functionality is blocked.
Tools Used
Code Review
Recommendations
Remove the withEmergencyDelaymodifier from the veRAACToken:: enableEmergencyWithdrawfunction.
- function enableEmergencyWithdraw() external onlyOwner withEmergencyDelay(EMERGENCY_WITHDRAW_ACTION) {
+ function enableEmergencyWithdraw() external onlyOwner {
emergencyWithdrawDelay = block.timestamp + EMERGENCY_DELAY;
emit EmergencyWithdrawEnabled(emergencyWithdrawDelay);
}
- function emergencyWithdraw() external nonReentrant {
+ function emergencyWithdraw() external nonReentrant withEmergencyDelay(EMERGENCY_WITHDRAW_ACTION){
if (emergencyWithdrawDelay == 0 || block.timestamp < emergencyWithdrawDelay)
revert EmergencyWithdrawNotEnabled();
LockManager.Lock memory userLock = _lockState.locks[msg.sender];
if (userLock.amount == 0) revert NoTokensLocked();
uint256 amount = userLock.amount;
uint256 currentPower = balanceOf(msg.sender);
delete _lockState.locks[msg.sender];
delete _votingState.points[msg.sender];
_burn(msg.sender, currentPower);
raacToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdrawn(msg.sender, amount);
}