diff --git a/src/contracts/interfaces/IEigenPod.sol b/src/contracts/interfaces/IEigenPod.sol index 4b527adb7..a38f116b1 100644 --- a/src/contracts/interfaces/IEigenPod.sol +++ b/src/contracts/interfaces/IEigenPod.sol @@ -41,7 +41,6 @@ interface IEigenPod { struct Checkpoint { bytes32 beaconBlockRoot; - bytes32 beaconStateRoot; uint256 podBalanceGwei; int256 balanceDeltasGwei; uint256 proofsRemaining; @@ -75,6 +74,8 @@ interface IEigenPod { /// @notice Emitted when a validator is proven for a given checkpoint event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex); + event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex); + /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from beaconchain but not EigenLayer), function withdrawableRestakedExecutionLayerGwei() external view returns (uint64); diff --git a/src/contracts/pods/EigenPod.sol b/src/contracts/pods/EigenPod.sol index 19d36cd2a..cc0b1b43d 100644 --- a/src/contracts/pods/EigenPod.sol +++ b/src/contracts/pods/EigenPod.sol @@ -184,9 +184,7 @@ contract EigenPod is * (see `_updateCheckpoint` for more details) * @dev This method can only be called when there is a currently-active checkpoint. * @param stateRootProof proves a beacon state root against the checkpoint's `beaconBlockRoot` - * @dev Note that if the `beaconStateRoot` has already been verified for this checkpoint, it does - * not need to be verfied again. - * @param proofs Proofs for one or more validator current balances against the checkpoint's `beaconStateRoot` + * @param proofs Proofs for one or more validator current balances against the `beaconStateRoot` */ function verifyCheckpointProofs( BeaconChainProofs.StateRootProof calldata stateRootProof, @@ -203,17 +201,12 @@ contract EigenPod is Checkpoint memory checkpoint = currentCheckpoint; - // If we haven't already proven a state root for this checkpoint, verify - // `stateRootProof` against the block root and cache the result - if (checkpoint.beaconStateRoot == bytes32(0)) { - BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot({ - latestBlockRoot: checkpoint.beaconBlockRoot, - beaconStateRoot: stateRootProof.beaconStateRoot, - stateRootProof: stateRootProof.proof - }); - - checkpoint.beaconStateRoot = stateRootProof.beaconStateRoot; - } + // Verify `stateRootProof` against `beaconBlockRoot` + BeaconChainProofs.verifyStateRootAgainstLatestBlockRoot({ + latestBlockRoot: checkpoint.beaconBlockRoot, + beaconStateRoot: stateRootProof.beaconStateRoot, + stateRootProof: stateRootProof.proof + }); // Process each checkpoint proof submitted for (uint256 i = 0; i < proofs.length; i++) { @@ -227,7 +220,7 @@ contract EigenPod is // the pod when `startCheckpoint` was originally called. int256 balanceDeltaGwei = _verifyCheckpointProof({ beaconTimestamp: beaconTimestamp, - beaconStateRoot: checkpoint.beaconStateRoot, + beaconStateRoot: stateRootProof.beaconStateRoot, proof: proofs[i] }); @@ -552,6 +545,8 @@ contract EigenPod is if (newBalanceGwei == 0) { activeValidatorCount--; validatorInfo.status = VALIDATOR_STATUS.WITHDRAWN; + + emit ValidatorWithdrawn(beaconTimestamp, uint40(validatorInfo.validatorIndex)); } _validatorPubkeyHashToInfo[proof.pubkeyHash] = validatorInfo; @@ -585,7 +580,6 @@ contract EigenPod is Checkpoint memory checkpoint = Checkpoint({ beaconBlockRoot: _getParentBlockRoot(uint64(block.timestamp)), - beaconStateRoot: bytes32(0), podBalanceGwei: podBalanceWei / GWEI_TO_WEI, balanceDeltasGwei: 0, proofsRemaining: activeValidatorCount