The issue was that attempting to withdraw more rETH than Rocket Pool's excess balance reverts Reth.withdraw(), DoS-ing unstake().
Mitigation review
Reth.withdraw() only calls RocketTokenRETHInterface(rethAddress()).burn(amount); if canWithdrawFromRocketPool(_amount) passes. canWithdrawFromRocketPool() correctly checks whether there is enough excess balance to withdraw. This prevents a revert.
If _amount cannot be withdrawn from Rocket Pool, then RocketSwapRouter.swapFrom() is used with a 100% Balancer weight, which should always be available.
Mitigation of H-07: Issue mitigated, with possibility for improvement
Mitigated issue
H-07: Reth.sol: Withdrawals are unreliable and depend on excess RocketDepositPool balance which can brick the whole protocol.
The issue was that attempting to withdraw more rETH than Rocket Pool's excess balance reverts
Reth.withdraw()
, DoS-ingunstake()
.Mitigation review
Reth.withdraw()
only callsRocketTokenRETHInterface(rethAddress()).burn(amount);
ifcanWithdrawFromRocketPool(_amount)
passes.canWithdrawFromRocketPool()
correctly checks whether there is enough excess balance to withdraw. This prevents a revert. If_amount
cannot be withdrawn from Rocket Pool, thenRocketSwapRouter.swapFrom()
is used with a 100% Balancer weight, which should always be available.Possible improvement
RocketSwapRouter.swapFrom()
already burns as much as possible from Rocket Pool so it is enough to direct all calls there.