Navigating to H-04 from the previous contest we can see that there was an issue that was rooted around the logic that the WithdrawQueue.sol contract allows immediate, cost-free deposit and withdrawal requests based on current oracle prices and TVL calculations, which makes it susceptible to MEV and price manipulation exploits.
In H-04, it was shown that the vulnerability arises because the withdrawal amount is determined at the time of the request, rather than at the claim time. This enables attackers to profit from price changes without incurring significant fees, i.e in scenarios where a collateral token's price increases or decreases sharply, attackers can manipulate the system by strategically timing their deposits and withdrawals to gain a larger amount of assets, thereby depleting the value meant for ezETH holders. To mitigate this, it is recommended to perform redemption conversions at both request and claim times, using the lower value for claims if prices decrease, and to introduce rate limits or short delays on deposits.
Now protocol apply the suggested fix to this bug window as shown in this pull request, where it now also attaches a check on the amount of tokens to redeem when the withdrawal is being claimed, see the new claim() function:
function claim(uint256 withdrawRequestIndex) external nonReentrant {
// check if provided withdrawRequest Index is valid
if (withdrawRequestIndex >= withdrawRequests[msg.sender].length)
revert InvalidWithdrawIndex();
WithdrawRequest memory _withdrawRequest = withdrawRequests[msg.sender][
withdrawRequestIndex
];
if (block.timestamp - _withdrawRequest.createdAt < coolDownPeriod) revert EarlyClaim();
// subtract value from claim reserve for claim asset
claimReserve[_withdrawRequest.collateralToken] -= _withdrawRequest.amountToRedeem;
+ // calculate the amount to redeem
+ uint256 claimAmountToRedeem = _calculateAmountToRedeem(
+ _withdrawRequest.ezETHLocked,
+ _withdrawRequest.collateralToken
+ );
+ // update withdraw request amount to redeem if lower at claim time.
+ if (claimAmountToRedeem < _withdrawRequest.amountToRedeem) {
+ _withdrawRequest.amountToRedeem = claimAmountToRedeem;
+ }
+
// delete the withdraw request
withdrawRequests[msg.sender][withdrawRequestIndex] = withdrawRequests[msg.sender][
withdrawRequests[msg.sender].length - 1
];
withdrawRequests[msg.sender].pop();
// burn ezETH locked for withdraw request
ezETH.burn(address(this), _withdrawRequest.ezETHLocked);
// send selected redeem asset to user
if (_withdrawRequest.collateralToken == IS_NATIVE) {
payable(msg.sender).transfer(_withdrawRequest.amountToRedeem);
} else {
IERC20(_withdrawRequest.collateralToken).transfer(
msg.sender,
_withdrawRequest.amountToRedeem
);
}
// emit the event
emit WithdrawRequestClaimed(_withdrawRequest);
}
This implementation sufficiently addresses the "immediate deposit then withdraw issue," justifying the "mitigation confirmed" tag. However, a minor edge case remains.
Since there's no withdrawal claim deadline, a user could theoretically submit a withdrawal request, and when their withdrawal request is ripe for claim after cooldownPeriod, they don't immediately claim if they don't like the amount they'd receive due to the current rate gotten from _calculateAmountToRedeem(), so they could wait for a better deal to appear, and then claim the withdrawal later. However, the uncertainty of this strategy makes it unattractive for malicious actors.
Cause there's no guarantee a more favorable deal will emerge.
Even if a better deal appears, the check if (claimAmountToRedeem < _withdrawRequest.amountToRedeem) prevents users from obtaining a rate higher than the one used in their initial withdrawal request.
Therefore, this attempt at "arbitrage" is now unlikely to be a viable exploit which further proves that H-04 has been sufficiently mitigated.
Lines of code
Vulnerability details
See:
Navigating to H-04 from the previous contest we can see that there was an issue that was rooted around the logic that the
WithdrawQueue.sol
contract allows immediate, cost-free deposit and withdrawal requests based on current oracle prices and TVL calculations, which makes it susceptible to MEV and price manipulation exploits.In H-04, it was shown that the vulnerability arises because the withdrawal amount is determined at the time of the request, rather than at the claim time. This enables attackers to profit from price changes without incurring significant fees, i.e in scenarios where a collateral token's price increases or decreases sharply, attackers can manipulate the system by strategically timing their deposits and withdrawals to gain a larger amount of assets, thereby depleting the value meant for ezETH holders. To mitigate this, it is recommended to perform redemption conversions at both request and claim times, using the lower value for claims if prices decrease, and to introduce rate limits or short delays on deposits.
Now protocol apply the suggested fix to this bug window as shown in this pull request, where it now also attaches a check on the amount of tokens to redeem when the withdrawal is being claimed, see the new
claim()
function:This implementation sufficiently addresses the "immediate deposit then withdraw issue," justifying the "mitigation confirmed" tag. However, a minor edge case remains.
Since there's no withdrawal claim deadline, a user could theoretically submit a withdrawal request, and when their withdrawal request is ripe for claim after
cooldownPeriod
, they don't immediately claim if they don't like the amount they'd receive due to the current rate gotten from_calculateAmountToRedeem()
, so they could wait for a better deal to appear, and then claim the withdrawal later. However, the uncertainty of this strategy makes it unattractive for malicious actors.if (claimAmountToRedeem < _withdrawRequest.amountToRedeem)
prevents users from obtaining a rate higher than the one used in their initial withdrawal request.Therefore, this attempt at "arbitrage" is now unlikely to be a viable exploit which further proves that H-04 has been sufficiently mitigated.