diff --git a/src/core/ExoCapsule.sol b/src/core/ExoCapsule.sol index 7eb1d1f0..83ec0a8c 100644 --- a/src/core/ExoCapsule.sol +++ b/src/core/ExoCapsule.sol @@ -24,11 +24,11 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul event WithdrawalSuccess(address, address, uint256); /// @notice Emitted when a partial withdrawal claim is successfully redeemed event PartialWithdrawalRedeemed( - bytes32 pubkey, uint256 withdrawalTimestamp, address indexed recipient, uint64 partialWithdrawalAmountGwei + bytes32 pubkey, uint256 withdrawalEpoch, address indexed recipient, uint64 partialWithdrawalAmountGwei ); /// @notice Emitted when an ETH validator is prove to have fully withdrawn from the beacon chain event FullWithdrawalRedeemed( - bytes32 pubkey, uint256 withdrawalTimestamp, address indexed recipient, uint64 withdrawalAmountGwei + bytes32 pubkey, uint64 withdrawalEpoch, address indexed recipient, uint64 withdrawalAmountGwei ); /// @notice Emitted when capsuleOwner enables restaking event RestakingActivated(address indexed capsuleOwner); @@ -136,7 +136,8 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul ) external onlyGateway returns (bool partialWithdrawal, uint256 withdrawalAmount) { bytes32 validatorPubkey = validatorContainer.getPubkey(); Validator storage validator = _capsuleValidators[validatorPubkey]; - partialWithdrawal = withdrawalProof.slotRoot.getWithdrawalEpoch() < validatorContainer.getWithdrawableEpoch(); + uint64 withdrawalEpoch = withdrawalProof.slotRoot.getWithdrawalEpoch(); + partialWithdrawal = withdrawalEpoch < validatorContainer.getWithdrawableEpoch(); if (!validatorContainer.verifyValidatorContainerBasic()) { revert InvalidValidatorContainer(validatorPubkey); @@ -158,14 +159,14 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul if (partialWithdrawal) { // Immediately send ETH without sending request to Exocore side - emit PartialWithdrawalRedeemed(validatorPubkey, withdrawalTimestamp, capsuleOwner, withdrawalAmountGwei); + emit PartialWithdrawalRedeemed(validatorPubkey, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); _sendETH(capsuleOwner, withdrawalAmountGwei * GWEI_TO_WEI); } else { // Full withdrawal validator.status = VALIDATOR_STATUS.WITHDRAWN; validator.restakedBalanceGwei = 0; // If over MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = 32 * 1e9, then send remaining amount immediately - emit FullWithdrawalRedeemed(validatorPubkey, withdrawalTimestamp, capsuleOwner, withdrawalAmountGwei); + emit FullWithdrawalRedeemed(validatorPubkey, withdrawalEpoch, capsuleOwner, withdrawalAmountGwei); if (withdrawalAmountGwei > MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) { uint256 amountToSend = (withdrawalAmountGwei - MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) * GWEI_TO_WEI; _sendETH(capsuleOwner, amountToSend); @@ -278,8 +279,6 @@ contract ExoCapsule is ReentrancyGuardUpgradeable, ExoCapsuleStorage, IExoCapsul BeaconChainProofs.WithdrawalProof calldata proof ) internal view { // To-do check withdrawalContainer length is valid - // Get withdrawal timestamp from timestamp root - uint256 withdrawalTimestamp = proof.timestampRoot.fromLittleEndianUint64(); bytes32 withdrawalContainerRoot = withdrawalContainer.merklelizeWithdrawalContainer(); bool valid = withdrawalContainerRoot.isValidWithdrawalContainerRoot(proof); if (!valid) { diff --git a/src/libraries/BeaconChainProofs.sol b/src/libraries/BeaconChainProofs.sol index 04863a05..745dd8a0 100644 --- a/src/libraries/BeaconChainProofs.sol +++ b/src/libraries/BeaconChainProofs.sol @@ -20,6 +20,19 @@ library BeaconChainProofs { uint256 internal constant BEACON_STATE_FIELD_TREE_HEIGHT = 5; + uint256 internal constant DENEB_FORK_TIMESTAMP = 1_710_338_135; + uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_CAPELLA = 4; + uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT_DENEB = 5; // After deneb hard fork, it's + + // increased from 4 to 5 + // SLOTS_PER_HISTORICAL_ROOT = 2**13, so tree height is 13 + uint256 internal constant BLOCK_ROOTS_TREE_HEIGHT = 13; + + //Index of block_summary_root in historical_summary container + uint256 internal constant BLOCK_SUMMARY_ROOT_INDEX = 0; + //HISTORICAL_ROOTS_LIMIT = 2**24, so tree height is 24 + uint256 internal constant HISTORICAL_SUMMARIES_TREE_HEIGHT = 24; + uint256 internal constant VALIDATOR_TREE_HEIGHT = 40; // MAX_WITHDRAWALS_PER_PAYLOAD = 2**4, making tree height = 4 @@ -29,6 +42,7 @@ library BeaconChainProofs { // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconblockbody uint256 internal constant EXECUTION_PAYLOAD_INDEX = 9; + uint256 internal constant SLOT_INDEX = 0; // in beacon block header // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader uint256 internal constant STATE_ROOT_INDEX = 3; @@ -36,7 +50,10 @@ library BeaconChainProofs { // in beacon state // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconstate uint256 internal constant VALIDATOR_TREE_ROOT_INDEX = 11; + uint256 internal constant HISTORICAL_SUMMARIES_INDEX = 27; + // in execution payload header + uint256 internal constant TIMESTAMP_INDEX = 9; //in execution payload uint256 internal constant WITHDRAWALS_INDEX = 14;