ETH Price: $3,415.96 (+2.10%)

Contract

0x5c86e9609fbBc1B754D0FD5a4963Fdf0F5b99dA7
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x61012060174455652023-06-09 22:15:59533 days ago1686348959IN
 Create: EigenPod
0 ETH0.0744449521.81429106

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EigenPod

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 24 : EigenPod.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/utils/AddressUpgradeable.sol";

import "../libraries/BeaconChainProofs.sol";
import "../libraries/BytesLib.sol";
import "../libraries/Endian.sol";

import "../interfaces/IETHPOSDeposit.sol";
import "../interfaces/IEigenPodManager.sol";
import "../interfaces/IEigenPod.sol";
import "../interfaces/IDelayedWithdrawalRouter.sol";
import "../interfaces/IPausable.sol";

import "./EigenPodPausingConstants.sol";

/**
 * @title The implementation contract used for restaking beacon chain ETH on EigenLayer 
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice The main functionalities are:
 * - creating new ETH validators with their withdrawal credentials pointed to this contract
 * - proving from beacon chain state roots that withdrawal credentials are pointed to this contract
 * - proving from beacon chain state roots the balances of ETH validators with their withdrawal credentials
 *   pointed to this contract
 * - updating aggregate balances in the EigenPodManager
 * - withdrawing eth when withdrawals are initiated
 * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
 *   to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
 */
contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, EigenPodPausingConstants {
    using BytesLib for bytes;

    // CONSTANTS + IMMUTABLES
    uint256 internal constant GWEI_TO_WEI = 1e9;

    /// @notice Maximum "staleness" of a Beacon Chain state root against which `verifyOvercommittedStake` may be proven. 7 days in blocks.
    uint256 internal constant VERIFY_OVERCOMMITTED_WINDOW_BLOCKS = 50400;

    /// @notice This is the beacon chain deposit contract
    IETHPOSDeposit public immutable ethPOS;

    /// @notice Contract used for withdrawal routing, to provide an extra "safety net" mechanism
    IDelayedWithdrawalRouter public immutable delayedWithdrawalRouter;

    /// @notice The single EigenPodManager for EigenLayer
    IEigenPodManager public immutable eigenPodManager;

    /// @notice The amount of eth, in gwei, that is restaked per validator
    uint64 public immutable REQUIRED_BALANCE_GWEI;

    /// @notice The amount of eth, in wei, that is restaked per ETH validator into EigenLayer
    uint256 public immutable REQUIRED_BALANCE_WEI;

    /// @notice The owner of this EigenPod
    address public podOwner;

    /**
     * @notice The latest block number at which the pod owner withdrew the balance of the pod.
     * @dev This variable is only updated when the `withdraw` function is called, which can only occur before `hasRestaked` is set to true for this pod.
     * Proofs for this pod are only valid against Beacon Chain state roots corresponding to blocks after the stored `mostRecentWithdrawalBlockNumber`.
     */
    uint64 public mostRecentWithdrawalBlockNumber;

    // STORAGE VARIABLES
    /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from the Beacon Chain but not from EigenLayer), 
    uint64 public restakedExecutionLayerGwei;

    /// @notice an indicator of whether or not the podOwner has ever "fully restaked" by successfully calling `verifyCorrectWithdrawalCredentials`.
    bool public hasRestaked;

    /// @notice this is a mapping of validator indices to a Validator struct containing pertinent info about the validator
    mapping(uint40 => VALIDATOR_STATUS) public validatorStatus;

    /// @notice This is a mapping of validatorIndex to withdrawalIndex to whether or not they have proven a withdrawal for that index
    mapping(uint40 => mapping(uint64 => bool)) public provenPartialWithdrawal;

    /// @notice Emitted when an ETH validator stakes via this eigenPod
    event EigenPodStaked(bytes pubkey);

    /// @notice Emitted when an ETH validator's withdrawal credentials are successfully verified to be pointed to this eigenPod
    event ValidatorRestaked(uint40 validatorIndex);

    /// @notice Emitted when an ETH validator is proven to have a balance less than `REQUIRED_BALANCE_GWEI` in the beacon chain
    event ValidatorOvercommitted(uint40 validatorIndex);
    
    /// @notice Emitted when an ETH validator is prove to have withdrawn from the beacon chain
    event FullWithdrawalRedeemed(uint40 validatorIndex, address indexed recipient, uint64 withdrawalAmountGwei);

    /// @notice Emitted when a partial withdrawal claim is successfully redeemed
    event PartialWithdrawalRedeemed(uint40 validatorIndex, address indexed recipient, uint64 partialWithdrawalAmountGwei);

    /// @notice Emitted when restaked beacon chain ETH is withdrawn from the eigenPod.
    event RestakedBeaconChainETHWithdrawn(address indexed recipient, uint256 amount);

    modifier onlyEigenPodManager {
        require(msg.sender == address(eigenPodManager), "EigenPod.onlyEigenPodManager: not eigenPodManager");
        _;
    }

    modifier onlyEigenPodOwner {
        require(msg.sender == podOwner, "EigenPod.onlyEigenPodOwner: not podOwner");
        _;
    }

    modifier onlyNotFrozen {
        require(!eigenPodManager.slasher().isFrozen(podOwner), "EigenPod.onlyNotFrozen: pod owner is frozen");
        _;
    }

    modifier hasNeverRestaked {
        require(!hasRestaked, "EigenPod.hasNeverRestaked: restaking is enabled");
        _;
    }

    /// @notice Checks that `blockNumber` is strictly greater than the value stored in `mostRecentWithdrawalBlockNumber`
    modifier proofIsForValidBlockNumber(uint64 blockNumber) {
        require(blockNumber > mostRecentWithdrawalBlockNumber,
            "EigenPod.proofIsForValidBlockNumber: beacon chain proof must be for block number after mostRecentWithdrawalBlockNumber");
        _;
    }

    /**
     * @notice Based on 'Pausable' code, but uses the storage of the EigenPodManager instead of this contract. This construction
     * is necessary for enabling pausing all EigenPods at the same time (due to EigenPods being Beacon Proxies).
     * Modifier throws if the `indexed`th bit of `_paused` in the EigenPodManager is 1, i.e. if the `index`th pause switch is flipped.
     */
    modifier onlyWhenNotPaused(uint8 index) {
        require(!IPausable(address(eigenPodManager)).paused(index), "EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager");
        _;
    }

    constructor(
        IETHPOSDeposit _ethPOS,
        IDelayedWithdrawalRouter _delayedWithdrawalRouter,
        IEigenPodManager _eigenPodManager,
        uint256 _REQUIRED_BALANCE_WEI
    ) {
        ethPOS = _ethPOS;
        delayedWithdrawalRouter = _delayedWithdrawalRouter;
        eigenPodManager = _eigenPodManager;
        REQUIRED_BALANCE_WEI = _REQUIRED_BALANCE_WEI;
        REQUIRED_BALANCE_GWEI = uint64(_REQUIRED_BALANCE_WEI / GWEI_TO_WEI);
        require(_REQUIRED_BALANCE_WEI % GWEI_TO_WEI == 0, "EigenPod.contructor: _REQUIRED_BALANCE_WEI is not a whole number of gwei");
        _disableInitializers();
    }

    /// @notice Used to initialize the pointers to addresses crucial to the pod's functionality. Called on construction by the EigenPodManager.
    function initialize(address _podOwner) external initializer {
        require(_podOwner != address(0), "EigenPod.initialize: podOwner cannot be zero address");
        podOwner = _podOwner;
    }

    /// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
    function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable onlyEigenPodManager {
        // stake on ethpos
        require(msg.value == 32 ether, "EigenPod.stake: must initially stake for any validator with 32 ether");
        ethPOS.deposit{value : 32 ether}(pubkey, _podWithdrawalCredentials(), signature, depositDataRoot);
        emit EigenPodStaked(pubkey);
    }

    /**
     * @notice  This function verifies that the withdrawal credentials of the podOwner are pointed to
     * this contract. It also verifies the current (not effective) balance  of the validator.  It verifies the provided proof of the ETH validator against the beacon chain state
     * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer.
     * @param oracleBlockNumber is the Beacon Chain blockNumber whose state root the `proof` will be proven against.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs 
     * @param proofs is the bytes that prove the ETH validator's balance and withdrawal credentials against a beacon chain state root
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs 
     * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyWithdrawalCredentialsAndBalance(
        uint64 oracleBlockNumber,
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs calldata proofs,
        bytes32[] calldata validatorFields
    )
        external
        onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_CREDENTIALS)
        // check that the provided `oracleBlockNumber` is after the `mostRecentWithdrawalBlockNumber`
        proofIsForValidBlockNumber(oracleBlockNumber)
    {
        require(validatorStatus[validatorIndex] == VALIDATOR_STATUS.INACTIVE,
            "EigenPod.verifyCorrectWithdrawalCredentials: Validator must be inactive to prove withdrawal credentials");

        require(validatorFields[BeaconChainProofs.VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX] == bytes32(_podWithdrawalCredentials()),
            "EigenPod.verifyCorrectWithdrawalCredentials: Proof is not for this EigenPod");
        // deserialize the balance field from the balanceRoot
        uint64 validatorCurrentBalanceGwei = BeaconChainProofs.getBalanceFromBalanceRoot(validatorIndex, proofs.balanceRoot);
        
        // make sure the balance is greater than the amount restaked per validator
        require(validatorCurrentBalanceGwei >= REQUIRED_BALANCE_GWEI,
            "EigenPod.verifyCorrectWithdrawalCredentials: ETH validator's balance must be greater than or equal to the restaked balance per validator");

        // verify ETH validator proof
        bytes32 beaconStateRoot = eigenPodManager.getBeaconChainStateRoot(oracleBlockNumber);
        BeaconChainProofs.verifyValidatorFields(
            validatorIndex,
            beaconStateRoot,
            proofs.validatorFieldsProof,
            validatorFields
        );

        // verify ETH validator's current balance, which is stored in the `balances` container of the beacon state
        BeaconChainProofs.verifyValidatorBalance(
            validatorIndex,
            beaconStateRoot,
            proofs.validatorBalanceProof,
            proofs.balanceRoot
        );
        // set the status to active
        validatorStatus[validatorIndex] = VALIDATOR_STATUS.ACTIVE;

        // Sets "hasRestaked" to true if it hasn't been set yet. 
        if (!hasRestaked) {
            hasRestaked = true;
        }

        emit ValidatorRestaked(validatorIndex);

        // virtually deposit REQUIRED_BALANCE_WEI for new ETH validator
        eigenPodManager.restakeBeaconChainETH(podOwner, REQUIRED_BALANCE_WEI);
    }

    /**
     * @notice This function records an overcommitment of stake to EigenLayer on behalf of a certain ETH validator.
     *         If successful, the overcommitted balance is penalized (available for withdrawal whenever the pod's balance allows).
     *         The ETH validator's shares in the enshrined beaconChainETH strategy are also removed from the StrategyManager and undelegated.
     * @param oracleBlockNumber The oracleBlockNumber whose state root the `proof` will be proven against.
     *        Must be within `VERIFY_OVERCOMMITTED_WINDOW_BLOCKS` of the current block.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs 
     * @param proofs is the proof of the validator's balance and validatorFields in the balance tree and the balanceRoot to prove for
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to 
     *                                    the StrategyManager in case it must be removed from the list of the podOwner's strategies
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs
     * @dev For more details on the Beacon Chain spec, see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyOvercommittedStake(
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs calldata proofs,
        bytes32[] calldata validatorFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    ) external onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_OVERCOMMITTED) {
       // ensure that the blockNumber being proven against is not "too stale", i.e. that the validator was *recently* overcommitted.
        require(oracleBlockNumber + VERIFY_OVERCOMMITTED_WINDOW_BLOCKS >= block.number,
            "EigenPod.verifyOvercommittedStake: specified blockNumber is too far in past");

        require(validatorStatus[validatorIndex] == VALIDATOR_STATUS.ACTIVE, "EigenPod.verifyOvercommittedStake: Validator not active");

        // deserialize the balance field from the balanceRoot
        uint64 validatorCurrentBalanceGwei = BeaconChainProofs.getBalanceFromBalanceRoot(validatorIndex, proofs.balanceRoot);        

        require(validatorCurrentBalanceGwei < REQUIRED_BALANCE_GWEI,
            "EigenPod.verifyOvercommittedStake: validator's balance must be less than the restaked balance per validator");
        
        // verify ETH validator proof
        bytes32 beaconStateRoot = eigenPodManager.getBeaconChainStateRoot(oracleBlockNumber);
 
        /**
         * If validator's balance is zero, then either they have fully withdrawn or they have been slashed down zero.
         * If the validator *has* been slashed, then this function can proceed. If they have *not* been slashed, then
         * the `verifyAndProcessWithdrawal` function should be called instead.
         */
        if (validatorCurrentBalanceGwei == 0) {
            uint64 slashedStatus = Endian.fromLittleEndianUint64(validatorFields[BeaconChainProofs.VALIDATOR_SLASHED_INDEX]);
            require(slashedStatus == 1, "EigenPod.verifyOvercommittedStake: Validator must be slashed to be overcommitted");
            //Verify the validator fields, which contain the validator's slashed status
            BeaconChainProofs.verifyValidatorFields(
                validatorIndex,
                beaconStateRoot,
                proofs.validatorFieldsProof,
                validatorFields
            );
        }
        // verify ETH validator's current balance, which is stored in the `balances` container of the beacon state
       BeaconChainProofs.verifyValidatorBalance(
            validatorIndex,
            beaconStateRoot,
            proofs.validatorBalanceProof,
            proofs.balanceRoot
        );

        // mark the ETH validator as overcommitted
        validatorStatus[validatorIndex] = VALIDATOR_STATUS.OVERCOMMITTED;

        emit ValidatorOvercommitted(validatorIndex);

        // remove and undelegate shares in EigenLayer
        eigenPodManager.recordOvercommittedBeaconChainETH(podOwner, beaconChainETHStrategyIndex, REQUIRED_BALANCE_WEI);
    }

    /**
     * @notice This function records a full withdrawal on behalf of one of the Ethereum validators for this EigenPod
     * @param withdrawalProofs is the information needed to check the veracity of the block number and withdrawal being proven
     * @param validatorFieldsProof is the information needed to check the veracity of the validator fields being proven
     * @param withdrawalFields are the fields of the withdrawal being proven
     * @param validatorFields are the fields of the validator being proven
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to 
     *        the EigenPodManager to the StrategyManager in case it must be removed from the podOwner's list of strategies
     * @param oracleBlockNumber is the Beacon Chain blockNumber whose state root the `proof` will be proven against.
     */
    function verifyAndProcessWithdrawal(
        BeaconChainProofs.WithdrawalProofs calldata withdrawalProofs, 
        bytes calldata validatorFieldsProof,
        bytes32[] calldata validatorFields,
        bytes32[] calldata withdrawalFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    )
        external
        onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_WITHDRAWAL)
        onlyNotFrozen
        /** 
         * Check that the provided block number being proven against is after the `mostRecentWithdrawalBlockNumber`.
         * Without this check, there is an edge case where a user proves a past withdrawal for a validator whose funds they already withdrew,
         * as a way to "withdraw the same funds twice" without providing adequate proof.
         * Note that this check is not made using the oracleBlockNumber as in the `verifyWithdrawalCredentials` proof; instead this proof
         * proof is made for the block number of the withdrawal, which may be within 8192 slots of the oracleBlockNumber. 
         * This difference in modifier usage is OK, since it is still not possible to `verifyAndProcessWithdrawal` against a slot that occurred
         * *prior* to the proof provided in the `verifyWithdrawalCredentials` function.
         */
        proofIsForValidBlockNumber(Endian.fromLittleEndianUint64(withdrawalProofs.blockNumberRoot))
    {
        /**
         * If the validator status is inactive, then withdrawal credentials were never verified for the validator,
         * and thus we cannot know that the validator is related to this EigenPod at all!
         */
        uint40 validatorIndex = uint40(Endian.fromLittleEndianUint64(withdrawalFields[BeaconChainProofs.WITHDRAWAL_VALIDATOR_INDEX_INDEX]));
        
        require(validatorStatus[validatorIndex] != VALIDATOR_STATUS.INACTIVE,
            "EigenPod.verifyOvercommittedStake: Validator never proven to have withdrawal credentials pointed to this contract");

        // fetch the beacon state root for the specified block
        bytes32 beaconStateRoot = eigenPodManager.getBeaconChainStateRoot(oracleBlockNumber);

        // Verifying the withdrawal as well as the slot
        BeaconChainProofs.verifyWithdrawalProofs(beaconStateRoot, withdrawalProofs, withdrawalFields);
        // Verifying the validator fields, specifically the withdrawable epoch
        BeaconChainProofs.verifyValidatorFields(validatorIndex, beaconStateRoot, validatorFieldsProof, validatorFields);

        uint64 withdrawalAmountGwei = Endian.fromLittleEndianUint64(withdrawalFields[BeaconChainProofs.WITHDRAWAL_VALIDATOR_AMOUNT_INDEX]);

        //check if the withdrawal occured after mostRecentWithdrawalBlockNumber
        uint64 slot = Endian.fromLittleEndianUint64(withdrawalProofs.slotRoot);

        /**
         * if the validator's withdrawable epoch is less than or equal to the slot's epoch, then the validator has fully withdrawn because
         * a full withdrawal is only processable after the withdrawable epoch has passed.
         */
        // reference: uint64 withdrawableEpoch = Endian.fromLittleEndianUint64(validatorFields[BeaconChainProofs.VALIDATOR_WITHDRAWABLE_EPOCH_INDEX]);
        if (Endian.fromLittleEndianUint64(validatorFields[BeaconChainProofs.VALIDATOR_WITHDRAWABLE_EPOCH_INDEX]) <= slot/BeaconChainProofs.SLOTS_PER_EPOCH) {
            _processFullWithdrawal(withdrawalAmountGwei, validatorIndex, beaconChainETHStrategyIndex, podOwner, validatorStatus[validatorIndex]);
        } else {
            _processPartialWithdrawal(slot, withdrawalAmountGwei, validatorIndex, podOwner);
        }
    }

    function _processFullWithdrawal(
        uint64 withdrawalAmountGwei,
        uint40 validatorIndex,
        uint256 beaconChainETHStrategyIndex,
        address recipient,
        VALIDATOR_STATUS status
    ) internal {
        uint256 amountToSend;

        // if the validator has not previously been proven to be "overcommitted"
        if (status == VALIDATOR_STATUS.ACTIVE) {
            // if the withdrawal amount is greater than the REQUIRED_BALANCE_GWEI (i.e. the amount restaked on EigenLayer, per ETH validator)
            if (withdrawalAmountGwei >= REQUIRED_BALANCE_GWEI) {
                // then the excess is immediately withdrawable
                amountToSend = uint256(withdrawalAmountGwei - REQUIRED_BALANCE_GWEI) * uint256(GWEI_TO_WEI);
                // and the extra execution layer ETH in the contract is REQUIRED_BALANCE_GWEI, which must be withdrawn through EigenLayer's normal withdrawal process
                restakedExecutionLayerGwei += REQUIRED_BALANCE_GWEI;
            } else {
                // otherwise, just use the full withdrawal amount to continue to "back" the podOwner's remaining shares in EigenLayer (i.e. none is instantly withdrawable)
                restakedExecutionLayerGwei += withdrawalAmountGwei;
                // remove and undelegate 'extra' (i.e. "overcommitted") shares in EigenLayer
                eigenPodManager.recordOvercommittedBeaconChainETH(podOwner, beaconChainETHStrategyIndex, uint256(REQUIRED_BALANCE_GWEI - withdrawalAmountGwei) * GWEI_TO_WEI);
            }
        // if the validator *has* previously been proven to be "overcommitted"
        } else if (status == VALIDATOR_STATUS.OVERCOMMITTED) {
            // if the withdrawal amount is greater than the REQUIRED_BALANCE_GWEI (i.e. the amount restaked on EigenLayer, per ETH validator)
            if (withdrawalAmountGwei >= REQUIRED_BALANCE_GWEI) {
                // then the excess is immediately withdrawable
                amountToSend = uint256(withdrawalAmountGwei - REQUIRED_BALANCE_GWEI) * uint256(GWEI_TO_WEI);
                // and the extra execution layer ETH in the contract is REQUIRED_BALANCE_GWEI, which must be withdrawn through EigenLayer's normal withdrawal process
                restakedExecutionLayerGwei += REQUIRED_BALANCE_GWEI;
                /**
                 * since in `verifyOvercommittedStake` the podOwner's beaconChainETH shares are decremented by `REQUIRED_BALANCE_WEI`, we must reverse the process here,
                 * in order to allow the podOwner to complete their withdrawal through EigenLayer's normal withdrawal process
                 */
                eigenPodManager.restakeBeaconChainETH(podOwner, REQUIRED_BALANCE_WEI);
            } else {
                // otherwise, just use the full withdrawal amount to continue to "back" the podOwner's remaining shares in EigenLayer (i.e. none is instantly withdrawable)
                restakedExecutionLayerGwei += withdrawalAmountGwei;
                /**
                 * since in `verifyOvercommittedStake` the podOwner's beaconChainETH shares are decremented by `REQUIRED_BALANCE_WEI`, we must reverse the process here,
                 * in order to allow the podOwner to complete their withdrawal through EigenLayer's normal withdrawal process
                 */
                eigenPodManager.restakeBeaconChainETH(podOwner, uint256(withdrawalAmountGwei) * GWEI_TO_WEI);
            }
        // If the validator status is withdrawn, they have already processed their ETH withdrawal
        }  else {
            revert("EigenPod.verifyBeaconChainFullWithdrawal: VALIDATOR_STATUS is WITHDRAWN or invalid VALIDATOR_STATUS");
        }

        // set the ETH validator status to withdrawn
        validatorStatus[validatorIndex] = VALIDATOR_STATUS.WITHDRAWN;

        emit FullWithdrawalRedeemed(validatorIndex, recipient, withdrawalAmountGwei);

        // send ETH to the `recipient`, if applicable
        if (amountToSend != 0) {
            _sendETH(recipient, amountToSend);
        }
    }

    function _processPartialWithdrawal(uint64 withdrawalHappenedSlot, uint64 partialWithdrawalAmountGwei, uint40 validatorIndex, address recipient) internal {
        require(!provenPartialWithdrawal[validatorIndex][withdrawalHappenedSlot], "EigenPod._processPartialWithdrawal: partial withdrawal has already been proven for this slot");

        provenPartialWithdrawal[validatorIndex][withdrawalHappenedSlot] = true;
        emit PartialWithdrawalRedeemed(validatorIndex, recipient, partialWithdrawalAmountGwei);

        // send the ETH to the `recipient`
        _sendETH(recipient, uint256(partialWithdrawalAmountGwei) * uint256(GWEI_TO_WEI));
    }

    /**
     * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address
     * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain.
     * @dev Called during withdrawal or slashing.
     */
    function withdrawRestakedBeaconChainETH(
        address recipient,
        uint256 amountWei
    )
        external
        onlyEigenPodManager
    {
        // reduce the restakedExecutionLayerGwei
        restakedExecutionLayerGwei -= uint64(amountWei / GWEI_TO_WEI);

        emit RestakedBeaconChainETHWithdrawn(recipient, amountWei);

        // transfer ETH from pod to `recipient`
        _sendETH(recipient, amountWei);
    }

    /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false
    function withdrawBeforeRestaking() external onlyEigenPodOwner hasNeverRestaked {
        mostRecentWithdrawalBlockNumber = uint32(block.number);
        _sendETH(podOwner, address(this).balance);
    }

    // INTERNAL FUNCTIONS
    function _podWithdrawalCredentials() internal view returns(bytes memory) {
        return abi.encodePacked(bytes1(uint8(1)), bytes11(0), address(this));
    }

    function _sendETH(address recipient, uint256 amountWei) internal {
        delayedWithdrawalRouter.createDelayedWithdrawal{value: amountWei}(podOwner, recipient);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[46] private __gap;
}

File 2 of 24 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
     * initialization step. This is essential to configure modules that are added through upgrades and that require
     * initialization.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }
}

File 3 of 24 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 4 of 24 : ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 5 of 24 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 6 of 24 : BeaconChainProofs.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity =0.8.12;

import "./Merkle.sol";
import "../libraries/Endian.sol";

//Utility library for parsing and PHASE0 beacon chain block headers
//SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization
//BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
//BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate
library BeaconChainProofs {
    // constants are the number of fields and the heights of the different merkle trees used in merkleizing beacon chain containers
    uint256 internal constant NUM_BEACON_BLOCK_HEADER_FIELDS = 5;
    uint256 internal constant BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT = 3;

    uint256 internal constant NUM_BEACON_BLOCK_BODY_FIELDS = 11;
    uint256 internal constant BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT = 4;

    uint256 internal constant NUM_BEACON_STATE_FIELDS = 21;
    uint256 internal constant BEACON_STATE_FIELD_TREE_HEIGHT = 5;

    uint256 internal constant NUM_ETH1_DATA_FIELDS = 3;
    uint256 internal constant ETH1_DATA_FIELD_TREE_HEIGHT = 2;

    uint256 internal constant NUM_VALIDATOR_FIELDS = 8;
    uint256 internal constant VALIDATOR_FIELD_TREE_HEIGHT = 3;

    uint256 internal constant NUM_EXECUTION_PAYLOAD_HEADER_FIELDS = 15;
    uint256 internal constant EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT = 4;


    uint256 internal constant NUM_EXECUTION_PAYLOAD_FIELDS = 15;
    uint256 internal constant EXECUTION_PAYLOAD_FIELD_TREE_HEIGHT = 4;


    // HISTORICAL_ROOTS_LIMIT	 = 2**24, so tree height is 24
    uint256 internal constant HISTORICAL_ROOTS_TREE_HEIGHT = 24;

    // HISTORICAL_BATCH is root of state_roots and block_root, so number of leaves =  2^1
    uint256 internal constant HISTORICAL_BATCH_TREE_HEIGHT = 1;

    // SLOTS_PER_HISTORICAL_ROOT = 2**13, so tree height is 13
    uint256 internal constant STATE_ROOTS_TREE_HEIGHT = 13;
    uint256 internal constant BLOCK_ROOTS_TREE_HEIGHT = 13;


    uint256 internal constant NUM_WITHDRAWAL_FIELDS = 4;
    // tree height for hash tree of an individual withdrawal container
    uint256 internal constant WITHDRAWAL_FIELD_TREE_HEIGHT = 2;

    uint256 internal constant VALIDATOR_TREE_HEIGHT = 40;
    //refer to the eigenlayer-cli proof library.  Despite being the same dimensions as the validator tree, the balance tree is merkleized differently
    uint256 internal constant BALANCE_TREE_HEIGHT = 38;

    // MAX_WITHDRAWALS_PER_PAYLOAD = 2**4, making tree height = 4
    uint256 internal constant WITHDRAWALS_TREE_HEIGHT = 4;

    //in beacon block body
    uint256 internal constant EXECUTION_PAYLOAD_INDEX = 9;

    // in beacon block header
    uint256 internal constant STATE_ROOT_INDEX = 3;
    uint256 internal constant PROPOSER_INDEX_INDEX = 1;
    uint256 internal constant SLOT_INDEX = 0;
    uint256 internal constant BODY_ROOT_INDEX = 4;
    // in beacon state
    uint256 internal constant STATE_ROOTS_INDEX = 6;
    uint256 internal constant BLOCK_ROOTS_INDEX = 5;
    uint256 internal constant HISTORICAL_ROOTS_INDEX = 7;
    uint256 internal constant ETH_1_ROOT_INDEX = 8;
    uint256 internal constant VALIDATOR_TREE_ROOT_INDEX = 11;
    uint256 internal constant BALANCE_INDEX = 12;
    uint256 internal constant EXECUTION_PAYLOAD_HEADER_INDEX = 24;
    uint256 internal constant HISTORICAL_BATCH_STATE_ROOT_INDEX = 1;

    // in validator
    uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1;
    uint256 internal constant VALIDATOR_BALANCE_INDEX = 2;
    uint256 internal constant VALIDATOR_SLASHED_INDEX = 3;
    uint256 internal constant VALIDATOR_WITHDRAWABLE_EPOCH_INDEX = 7;
    
    // in execution payload header
    uint256 internal constant BLOCK_NUMBER_INDEX = 6;
    uint256 internal constant WITHDRAWALS_ROOT_INDEX = 14;

    //in execution payload
    uint256 internal constant WITHDRAWALS_INDEX = 14;

    // in withdrawal
    uint256 internal constant WITHDRAWAL_VALIDATOR_INDEX_INDEX = 1;
    uint256 internal constant WITHDRAWAL_VALIDATOR_AMOUNT_INDEX = 3;

    //In historicalBatch
    uint256 internal constant HISTORICALBATCH_STATEROOTS_INDEX = 1;

    //Misc Constants
    uint256 internal constant SLOTS_PER_EPOCH = 32;

    bytes8 internal constant UINT64_MASK = 0xffffffffffffffff;



    struct WithdrawalProofs {
        bytes blockHeaderProof;
        bytes withdrawalProof;
        bytes slotProof;
        bytes executionPayloadProof;
        bytes blockNumberProof;
        uint64 blockHeaderRootIndex;
        uint64 withdrawalIndex;
        bytes32 blockHeaderRoot;
        bytes32 blockBodyRoot;
        bytes32 slotRoot;
        bytes32 blockNumberRoot;
        bytes32 executionPayloadRoot;
    }

    struct ValidatorFieldsAndBalanceProofs {
        bytes validatorFieldsProof;
        bytes validatorBalanceProof;
        bytes32 balanceRoot;
    }

    struct ValidatorFieldsProof {
        bytes validatorProof;
        uint40 validatorIndex;
    }

    /**
     * 
     * @notice This function is parses the balanceRoot to get the uint64 balance of a validator.  During merkleization of the
     * beacon state balance tree, four uint64 values (making 32 bytes) are grouped together and treated as a single leaf in the merkle tree. Thus the
     * validatorIndex mod 4 is used to determine which of the four uint64 values to extract from the balanceRoot.
     * @param validatorIndex is the index of the validator being proven for.
     * @param balanceRoot is the combination of 4 validator balances being proven for.
     * @return The validator's balance, in Gwei
     */
   function getBalanceFromBalanceRoot(uint40 validatorIndex, bytes32 balanceRoot) internal pure returns (uint64) {
        uint256 bitShiftAmount = (validatorIndex % 4) * 64;
        bytes32 validatorBalanceLittleEndian = bytes32((uint256(balanceRoot) << bitShiftAmount));
        uint64 validatorBalance = Endian.fromLittleEndianUint64(validatorBalanceLittleEndian);
        return validatorBalance;
    }

    /**
     * @notice This function verifies merkle proofs of the fields of a certain validator against a beacon chain state root
     * @param validatorIndex the index of the proven validator
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proof is the data used in proving the validator's fields
     * @param validatorFields the claimed fields of the validator
     */
    function verifyValidatorFields(
        uint40 validatorIndex,
        bytes32 beaconStateRoot,
        bytes calldata proof, 
        bytes32[] calldata validatorFields
    ) internal view {
        
        require(validatorFields.length == 2**VALIDATOR_FIELD_TREE_HEIGHT, "BeaconChainProofs.verifyValidatorFields: Validator fields has incorrect length");

        /**
         * Note: the length of the validator merkle proof is BeaconChainProofs.VALIDATOR_TREE_HEIGHT + 1.
         * There is an additional layer added by hashing the root with the length of the validator list
         */
        require(proof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyValidatorFields: Proof has incorrect length");
        uint256 index = (VALIDATOR_TREE_ROOT_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex);
        // merkleize the validatorFields to get the leaf to prove
        bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields);

        // verify the proof of the validatorRoot against the beaconStateRoot
        require(Merkle.verifyInclusionSha256(proof, beaconStateRoot, validatorRoot, index), "BeaconChainProofs.verifyValidatorFields: Invalid merkle proof");
    }

    /**
     * @notice This function verifies merkle proofs of the balance of a certain validator against a beacon chain state root
     * @param validatorIndex the index of the proven validator
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proof is the proof of the balance against the beacon chain state root
     * @param balanceRoot is the serialized balance used to prove the balance of the validator (refer to `getBalanceFromBalanceRoot` above for detailed explanation)
     */
    function verifyValidatorBalance(
        uint40 validatorIndex,
        bytes32 beaconStateRoot,
        bytes calldata proof,
        bytes32 balanceRoot
    ) internal view {
        require(proof.length == 32 * ((BALANCE_TREE_HEIGHT + 1) + BEACON_STATE_FIELD_TREE_HEIGHT), "BeaconChainProofs.verifyValidatorBalance: Proof has incorrect length");

        /**
        * the beacon state's balance list is a list of uint64 values, and these are grouped together in 4s when merkleized.  
        * Therefore, the index of the balance of a validator is validatorIndex/4
        */
        uint256 balanceIndex = uint256(validatorIndex/4);
        balanceIndex = (BALANCE_INDEX << (BALANCE_TREE_HEIGHT + 1)) | balanceIndex;

        require(Merkle.verifyInclusionSha256(proof, beaconStateRoot, balanceRoot, balanceIndex), "BeaconChainProofs.verifyValidatorBalance: Invalid merkle proof");
    }

    /**
     * @notice This function verifies the slot and the withdrawal fields for a given withdrawal
     * @param beaconStateRoot is the beacon chain state root to be proven against.
     * @param proofs is the provided set of merkle proofs
     * @param withdrawalFields is the serialized withdrawal container to be proven
     */
    function verifyWithdrawalProofs(
        bytes32 beaconStateRoot,
        WithdrawalProofs calldata proofs,
        bytes32[] calldata withdrawalFields
    ) internal view {
        require(withdrawalFields.length == 2**WITHDRAWAL_FIELD_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawalProofs: withdrawalFields has incorrect length");

        require(proofs.blockHeaderRootIndex < 2**BLOCK_ROOTS_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawalProofs: blockRootIndex is too large");
        require(proofs.withdrawalIndex < 2**WITHDRAWALS_TREE_HEIGHT, "BeaconChainProofs.verifyWithdrawalProofs: withdrawalIndex is too large");
       
        // verify the block header proof length
        require(proofs.blockHeaderProof.length == 32 * (BEACON_STATE_FIELD_TREE_HEIGHT + BLOCK_ROOTS_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: blockHeaderProof has incorrect length");
        require(proofs.withdrawalProof.length == 32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT + WITHDRAWALS_TREE_HEIGHT + 1),
            "BeaconChainProofs.verifyWithdrawalProofs: withdrawalProof has incorrect length");
        require(proofs.executionPayloadProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT + BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: executionPayloadProof has incorrect length");
        require(proofs.slotProof.length == 32 * (BEACON_BLOCK_HEADER_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: slotProof has incorrect length");
        require(proofs.blockNumberProof.length == 32 * (EXECUTION_PAYLOAD_HEADER_FIELD_TREE_HEIGHT),
            "BeaconChainProofs.verifyWithdrawalProofs: blockNumberProof has incorrect length");


        /**
         * Computes the block_header_index relative to the beaconStateRoot.  It concatenates the indexes of all the
         * intermediate root indexes from the bottom of the sub trees (the block header container) to the top of the tree
         */
        uint256 blockHeaderIndex = BLOCK_ROOTS_INDEX << (BLOCK_ROOTS_TREE_HEIGHT)  | uint256(proofs.blockHeaderRootIndex);
        // Verify the blockHeaderRoot against the beaconStateRoot
        require(Merkle.verifyInclusionSha256(proofs.blockHeaderProof, beaconStateRoot, proofs.blockHeaderRoot, blockHeaderIndex),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid block header merkle proof");

        //Next we verify the slot against the blockHeaderRoot
        require(Merkle.verifyInclusionSha256(proofs.slotProof, proofs.blockHeaderRoot, proofs.slotRoot, SLOT_INDEX), "BeaconChainProofs.verifyWithdrawalProofs: Invalid slot merkle proof");

        // Next we verify the executionPayloadRoot against the blockHeaderRoot
        uint256 executionPayloadIndex = BODY_ROOT_INDEX << (BEACON_BLOCK_BODY_FIELD_TREE_HEIGHT)| EXECUTION_PAYLOAD_INDEX ;
        require(Merkle.verifyInclusionSha256(proofs.executionPayloadProof, proofs.blockHeaderRoot, proofs.executionPayloadRoot, executionPayloadIndex),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid executionPayload merkle proof");

        // Next we verify the blockNumberRoot against the executionPayload root
        require(Merkle.verifyInclusionSha256(proofs.blockNumberProof, proofs.executionPayloadRoot, proofs.blockNumberRoot, BLOCK_NUMBER_INDEX),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid blockNumber merkle proof");

        /**
         * Next we verify the withdrawal fields against the blockHeaderRoot:
         * First we compute the withdrawal_index relative to the blockHeaderRoot by concatenating the indexes of all the 
         * intermediate root indexes from the bottom of the sub trees (the withdrawal container) to the top, the blockHeaderRoot.
         * Then we calculate merkleize the withdrawalFields container to calculate the the withdrawalRoot.
         * Finally we verify the withdrawalRoot against the executionPayloadRoot.
         */
        uint256 withdrawalIndex = WITHDRAWALS_INDEX << (WITHDRAWALS_TREE_HEIGHT + 1) | uint256(proofs.withdrawalIndex);
        bytes32 withdrawalRoot = Merkle.merkleizeSha256(withdrawalFields);
        require(Merkle.verifyInclusionSha256(proofs.withdrawalProof, proofs.executionPayloadRoot, withdrawalRoot, withdrawalIndex),
            "BeaconChainProofs.verifyWithdrawalProofs: Invalid withdrawal merkle proof");
    }

}

File 7 of 24 : BytesLib.sol
// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;

library BytesLib {
    function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for { let cc := add(_postBytes, 0x20) } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } { mstore(mc, mload(cc)) }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(
                0x40,
                and(
                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                    not(31) // Round down to the nearest 32 bytes.
                )
            )
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } { sstore(sc, mload(mc)) }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                // solhint-disable-next-line no-unused-vars
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } { sstore(sc, mload(mc)) }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } { mstore(mc, mload(cc)) }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for { let cc := add(_postBytes, 0x20) }
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        // solhint-disable-next-line no-empty-blocks
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

File 8 of 24 : Endian.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

library Endian {
    /**
     * @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64
     * @param lenum little endian-formatted uint64 input, provided as 'bytes32' type
     * @return n The big endian-formatted uint64
     * @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits)
     * through a right-shift/shr operation.
     */
    function fromLittleEndianUint64(
        bytes32 lenum
    ) internal pure returns (uint64 n) {
        // the number needs to be stored in little-endian encoding (ie in bytes 0-8)
        n = uint64(uint256(lenum >> 192));
        return
            (n >> 56) |
            ((0x00FF000000000000 & n) >> 40) |
            ((0x0000FF0000000000 & n) >> 24) |
            ((0x000000FF00000000 & n) >> 8) |
            ((0x00000000FF000000 & n) << 8) |
            ((0x0000000000FF0000 & n) << 24) |
            ((0x000000000000FF00 & n) << 40) |
            ((0x00000000000000FF & n) << 56);
    }
}

File 9 of 24 : IETHPOSDeposit.sol
// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
// ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
// ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
// ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
// ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
// ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// SPDX-License-Identifier: CC0-1.0

pragma solidity =0.8.12;

// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IETHPOSDeposit {
    /// @notice A processed deposit event.
    event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index);

    /// @notice Submit a Phase 0 DepositData object.
    /// @param pubkey A BLS12-381 public key.
    /// @param withdrawal_credentials Commitment to a public key for withdrawals.
    /// @param signature A BLS12-381 signature.
    /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
    /// Used as a protection against malformed input.
    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) external payable;

    /// @notice Query the current deposit root hash.
    /// @return The deposit root hash.
    function get_deposit_root() external view returns (bytes32);

    /// @notice Query the current deposit count.
    /// @return The deposit count encoded as a little endian 64-bit number.
    function get_deposit_count() external view returns (bytes memory);
}

File 10 of 24 : IEigenPodManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "./IStrategyManager.sol";
import "./IEigenPod.sol";
import "./IBeaconChainOracle.sol";
import "./IPausable.sol";

/**
 * @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */

interface IEigenPodManager is IPausable {
    /**
     * @notice Creates an EigenPod for the sender.
     * @dev Function will revert if the `msg.sender` already has an EigenPod.
     */
    function createPod() external;

    /**
     * @notice Stakes for a new beacon chain validator on the sender's EigenPod. 
     * Also creates an EigenPod for the sender if they don't have one already.
     * @param pubkey The 48 bytes public key of the beacon chain validator.
     * @param signature The validator's signature of the deposit data.
     * @param depositDataRoot The root/hash of the deposit data for the validator's deposit.
     */
    function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;

    /**
     * @notice Deposits/Restakes beacon chain ETH in EigenLayer on behalf of the owner of an EigenPod.
     * @param podOwner The owner of the pod whose balance must be deposited.
     * @param amount The amount of ETH to 'deposit' (i.e. be credited to the podOwner).
     * @dev Callable only by the podOwner's EigenPod contract.
     */
    function restakeBeaconChainETH(address podOwner, uint256 amount) external;

    /**
     * @notice Removes beacon chain ETH from EigenLayer on behalf of the owner of an EigenPod, when the
     *         balance of a validator is lower than how much stake they have committed to EigenLayer
     * @param podOwner The owner of the pod whose balance must be removed.
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to 
     *                                    the StrategyManager in case it must be removed from the list of the podOwner's strategies
     * @param amount The amount of ETH to remove.
     * @dev Callable only by the podOwner's EigenPod contract.
     */
    function recordOvercommittedBeaconChainETH(address podOwner, uint256 beaconChainETHStrategyIndex, uint256 amount) external;
    
    /**
     * @notice Withdraws ETH from an EigenPod. The ETH must have first been withdrawn from the beacon chain.
     * @param podOwner The owner of the pod whose balance must be withdrawn.
     * @param recipient The recipient of the withdrawn ETH.
     * @param amount The amount of ETH to withdraw.
     * @dev Callable only by the StrategyManager contract.
     */
    function withdrawRestakedBeaconChainETH(address podOwner, address recipient, uint256 amount) external;

    /**
     * @notice Updates the oracle contract that provides the beacon chain state root
     * @param newBeaconChainOracle is the new oracle contract being pointed to
     * @dev Callable only by the owner of this contract (i.e. governance)
     */
    function updateBeaconChainOracle(IBeaconChainOracle newBeaconChainOracle) external;

    /// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed.
    function ownerToPod(address podOwner) external view returns(IEigenPod);

    /// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not).
    function getPod(address podOwner) external view returns(IEigenPod);

    /// @notice Oracle contract that provides updates to the beacon chain's state
    function beaconChainOracle() external view returns(IBeaconChainOracle);    

    /// @notice Returns the Beacon Chain state root at `blockNumber`. Reverts if the Beacon Chain state root at `blockNumber` has not yet been finalized.
    function getBeaconChainStateRoot(uint64 blockNumber) external view returns(bytes32);

    /// @notice EigenLayer's StrategyManager contract
    function strategyManager() external view returns(IStrategyManager);

    /// @notice EigenLayer's Slasher contract
    function slasher() external view returns(ISlasher);

    function hasPod(address podOwner) external view returns (bool);
}

File 11 of 24 : IEigenPod.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "../libraries/BeaconChainProofs.sol";
import "./IEigenPodManager.sol";
import "./IBeaconChainOracle.sol";

/**
 * @title The implementation contract used for restaking beacon chain ETH on EigenLayer 
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice The main functionalities are:
 * - creating new ETH validators with their withdrawal credentials pointed to this contract
 * - proving from beacon chain state roots that withdrawal credentials are pointed to this contract
 * - proving from beacon chain state roots the balances of ETH validators with their withdrawal credentials
 *   pointed to this contract
 * - updating aggregate balances in the EigenPodManager
 * - withdrawing eth when withdrawals are initiated
 * @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
 *   to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
 */
interface IEigenPod {
    enum VALIDATOR_STATUS {
        INACTIVE, // doesnt exist
        ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod
        OVERCOMMITTED, // proven to be overcommitted to EigenLayer
        WITHDRAWN // withdrawn from the Beacon Chain
    }

    // this struct keeps track of PartialWithdrawalClaims
    struct PartialWithdrawalClaim {
        PARTIAL_WITHDRAWAL_CLAIM_STATUS status;
        // block at which the PartialWithdrawalClaim was created
        uint32 creationBlockNumber;
        // last block (inclusive) in which the PartialWithdrawalClaim can be fraudproofed
        uint32 fraudproofPeriodEndBlockNumber;
        // amount of ETH -- in Gwei -- to be withdrawn until completion of this claim
        uint64 partialWithdrawalAmountGwei;
    }

    enum PARTIAL_WITHDRAWAL_CLAIM_STATUS {
        REDEEMED,
        PENDING,
        FAILED
    }

    /// @notice The amount of eth, in gwei, that is restaked per validator
    function REQUIRED_BALANCE_GWEI() external view returns(uint64);

    /// @notice The amount of eth, in wei, that is restaked per validator
    function REQUIRED_BALANCE_WEI() external view returns(uint256);

    /// @notice this is a mapping of validator indices to a Validator struct containing pertinent info about the validator
    function validatorStatus(uint40 validatorIndex) external view returns(VALIDATOR_STATUS);

    /// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from beaconchain but not EigenLayer), 
    function restakedExecutionLayerGwei() external view returns(uint64);

    /// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager
    function initialize(address owner) external;

    /// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
    function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;

    /**
     * @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address
     * @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain.
     * @dev Called during withdrawal or slashing.
     * @dev Note that this function is marked as non-reentrant to prevent the recipient calling back into it
     */
    function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external;

    /// @notice The single EigenPodManager for EigenLayer
    function eigenPodManager() external view returns (IEigenPodManager);

    /// @notice The owner of this EigenPod
    function podOwner() external view returns (address);

    /// @notice an indicator of whether or not the podOwner has ever "fully restaked" by successfully calling `verifyCorrectWithdrawalCredentials`.
    function hasRestaked() external view returns (bool);

    /// @notice block number of the most recent withdrawal
    function mostRecentWithdrawalBlockNumber() external view returns (uint64);


    ///@notice mapping that tracks proven partial withdrawals
    function provenPartialWithdrawal(uint40 validatorIndex, uint64 slot) external view returns (bool);

    /**
     * @notice This function verifies that the withdrawal credentials of the podOwner are pointed to
     * this contract. It also verifies the current (not effective) balance  of the validator.  It verifies the provided proof of the ETH validator against the beacon chain state
     * root, marks the validator as 'active' in EigenLayer, and credits the restaked ETH in Eigenlayer.
     * @param oracleBlockNumber is the Beacon Chain blockNumber whose state root the `proof` will be proven against.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs 
     * @param proofs is the bytes that prove the ETH validator's balance and withdrawal credentials against a beacon chain state root
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs 
     * for details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyWithdrawalCredentialsAndBalance(
        uint64 oracleBlockNumber,
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs memory proofs,
        bytes32[] calldata validatorFields
    ) external;
    
    /**
     * @notice This function records an overcommitment of stake to EigenLayer on behalf of a certain ETH validator.
     *         If successful, the overcommitted balance is penalized (available for withdrawal whenever the pod's balance allows).
     *         The ETH validator's shares in the enshrined beaconChainETH strategy are also removed from the StrategyManager and undelegated.
     * @param oracleBlockNumber The oracleBlockNumber whose state root the `proof` will be proven against.
     *        Must be within `VERIFY_OVERCOMMITTED_WINDOW_BLOCKS` of the current block.
     * @param validatorIndex is the index of the validator being proven, refer to consensus specs 
     * @param proofs is the proof of the validator's balance and validatorFields in the balance tree and the balanceRoot to prove for
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to 
     *                                    the StrategyManager in case it must be removed from the list of the podOwners strategies
     * @param validatorFields are the fields of the "Validator Container", refer to consensus specs
     * @dev For more details on the Beacon Chain spec, see: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
     */
    function verifyOvercommittedStake(
        uint40 validatorIndex,
        BeaconChainProofs.ValidatorFieldsAndBalanceProofs calldata proofs,
        bytes32[] calldata validatorFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    ) external;

    /**
     * @notice This function records a full withdrawal on behalf of one of the Ethereum validators for this EigenPod
     * @param withdrawalProofs is the information needed to check the veracity of the block number and withdrawal being proven
     * @param validatorFieldsProof is the proof of the validator's fields in the validator tree
     * @param withdrawalFields are the fields of the withdrawal being proven
     * @param validatorFields are the fields of the validator being proven
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy for the pod owner for the callback to 
     *        the EigenPodManager to the StrategyManager in case it must be removed from the podOwner's list of strategies
     */
    function verifyAndProcessWithdrawal(
        BeaconChainProofs.WithdrawalProofs calldata withdrawalProofs, 
        bytes calldata validatorFieldsProof,
        bytes32[] calldata validatorFields,
        bytes32[] calldata withdrawalFields,
        uint256 beaconChainETHStrategyIndex,
        uint64 oracleBlockNumber
    ) external;

    /// @notice Called by the pod owner to withdraw the balance of the pod when `hasRestaked` is set to false
    function withdrawBeforeRestaking() external;
}

File 12 of 24 : IDelayedWithdrawalRouter.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

interface IDelayedWithdrawalRouter {
    // struct used to pack data into a single storage slot
    struct DelayedWithdrawal {
        uint224 amount;
        uint32 blockCreated;
    }

    // struct used to store a single users delayedWithdrawal data
    struct UserDelayedWithdrawals {
        uint256 delayedWithdrawalsCompleted;
        DelayedWithdrawal[] delayedWithdrawals;
    }

    /** 
     * @notice Creates an delayed withdrawal for `msg.value` to the `recipient`.
     * @dev Only callable by the `podOwner`'s EigenPod contract.
     */
    function createDelayedWithdrawal(address podOwner, address recipient) external payable;

    /**
     * @notice Called in order to withdraw delayed withdrawals made to the `recipient` that have passed the `withdrawalDelayBlocks` period.
     * @param recipient The address to claim delayedWithdrawals for.
     * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming.
     */
    function claimDelayedWithdrawals(address recipient, uint256 maxNumberOfWithdrawalsToClaim) external;

    /**
     * @notice Called in order to withdraw delayed withdrawals made to the caller that have passed the `withdrawalDelayBlocks` period.
     * @param maxNumberOfWithdrawalsToClaim Used to limit the maximum number of withdrawals to loop through claiming.
     */
    function claimDelayedWithdrawals(uint256 maxNumberOfWithdrawalsToClaim) external;

    /// @notice Owner-only function for modifying the value of the `withdrawalDelayBlocks` variable.
    function setWithdrawalDelayBlocks(uint256 newValue) external;

    /// @notice Getter function for the mapping `_userWithdrawals`
    function userWithdrawals(address user) external view returns (UserDelayedWithdrawals memory);

    /// @notice Getter function to get all delayedWithdrawals of the `user`
    function getUserDelayedWithdrawals(address user) external view returns (DelayedWithdrawal[] memory);

    /// @notice Getter function to get all delayedWithdrawals that are currently claimable by the `user`
    function getClaimableUserDelayedWithdrawals(address user) external view returns (DelayedWithdrawal[] memory);
    
    /// @notice Getter function for fetching the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array
    function userDelayedWithdrawalByIndex(address user, uint256 index) external view returns (DelayedWithdrawal memory);

    /// @notice Getter function for fetching the length of the delayedWithdrawals array of a specific user
    function userWithdrawalsLength(address user) external view returns (uint256);

    /// @notice Convenience function for checking whether or not the delayedWithdrawal at the `index`th entry from the `_userWithdrawals[user].delayedWithdrawals` array is currently claimable
    function canClaimDelayedWithdrawal(address user, uint256 index) external view returns (bool);

    /**
     * @notice Delay enforced by this contract for completing any delayedWithdrawal. Measured in blocks, and adjustable by this contract's owner,
     * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced).
     */
    function withdrawalDelayBlocks() external view returns (uint256);
}

File 13 of 24 : IPausable.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "../interfaces/IPauserRegistry.sol";

/**
 * @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
 * These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
 * @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
 * Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
 * For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
 * you can only flip (any number of) switches to off/0 (aka "paused").
 * If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
 * 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
 * 2) update the paused state to this new value
 * @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
 * indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
 */

interface IPausable {
    /// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
    function pauserRegistry() external view returns (IPauserRegistry); 

    /**
     * @notice This function is used to pause an EigenLayer contract's functionality.
     * It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
     * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
     * @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
     */
    function pause(uint256 newPausedStatus) external;

    /**
     * @notice Alias for `pause(type(uint256).max)`.
     */
    function pauseAll() external;

    /**
     * @notice This function is used to unpause an EigenLayer contract's functionality.
     * It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
     * @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
     * @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
     */
    function unpause(uint256 newPausedStatus) external;

    /// @notice Returns the current paused status as a uint256.
    function paused() external view returns (uint256);

    /// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
    function paused(uint8 index) external view returns (bool);

    /// @notice Allows the unpauser to set a new pauser registry
    function setPauserRegistry(IPauserRegistry newPauserRegistry) external;
}

File 14 of 24 : EigenPodPausingConstants.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

/**
 * @title Constants shared between 'EigenPod' and 'EigenPodManager' contracts.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
abstract contract EigenPodPausingConstants {
    /// @notice Index for flag that pauses creation of new EigenPods when set. See EigenPodManager code for details.
    uint8 internal constant PAUSED_NEW_EIGENPODS = 0;
    /// @notice Index for flag that pauses the `withdrawRestakedBeaconChainETH` function *of the EigenPodManager* when set. See EigenPodManager code for details.
    uint8 internal constant PAUSED_WITHDRAW_RESTAKED_ETH = 1;

    /// @notice Index for flag that pauses the `verifyCorrectWithdrawalCredentials` function *of the EigenPods* when set. see EigenPod code for details.
    uint8 internal constant PAUSED_EIGENPODS_VERIFY_CREDENTIALS = 2;
    /// @notice Index for flag that pauses the `verifyOvercommittedStake` function *of the EigenPods* when set. see EigenPod code for details.
    uint8 internal constant PAUSED_EIGENPODS_VERIFY_OVERCOMMITTED = 3;
    /// @notice Index for flag that pauses the `verifyBeaconChainFullWithdrawal` function *of the EigenPods* when set. see EigenPod code for details.
    uint8 internal constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4;
}

File 15 of 24 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 16 of 24 : Merkle.sol
// SPDX-License-Identifier: BUSL-1.1
// Adapted from OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)

pragma solidity =0.8.12;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates merkle trees that are safe
 * against this attack out of the box.
 */
library Merkle {
    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is 
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     * 
     * Note this is for a Merkle tree using the keccak/sha3 hash function
     */
    function verifyInclusionKeccak(
        bytes memory proof,
        bytes32 root,
        bytes32 leaf,
        uint256 index
    ) internal pure returns (bool) {
        return processInclusionProofKeccak(proof, leaf, index) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is 
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     * 
     * _Available since v4.4._
     * 
     * Note this is for a Merkle tree using the keccak/sha3 hash function
     */
    function processInclusionProofKeccak(bytes memory proof, bytes32 leaf, uint256 index) internal pure returns (bytes32) {
        require(proof.length != 0 && proof.length % 32 == 0, "Merkle.processInclusionProofKeccak: proof length should be a non-zero multiple of 32");
        bytes32 computedHash = leaf;
        for (uint256 i = 32; i <= proof.length; i+=32) {
            if(index % 2 == 0) {
                // if ith bit of index is 0, then computedHash is a left sibling
                assembly {
                    mstore(0x00, computedHash)
                    mstore(0x20, mload(add(proof, i)))
                    computedHash := keccak256(0x00, 0x40)
                    index := div(index, 2)
                }
            } else {
                // if ith bit of index is 1, then computedHash is a right sibling
                assembly {
                    mstore(0x00, mload(add(proof, i)))
                    mstore(0x20, computedHash)
                    computedHash := keccak256(0x00, 0x40)
                    index := div(index, 2)
                }            
            }
        }
        return computedHash;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is 
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     * 
     * Note this is for a Merkle tree using the sha256 hash function
     */
    function verifyInclusionSha256(
        bytes memory proof,
        bytes32 root,
        bytes32 leaf,
        uint256 index
    ) internal view returns (bool) {
        return processInclusionProofSha256(proof, leaf, index) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. The tree is built assuming `leaf` is 
     * the 0 indexed `index`'th leaf from the bottom left of the tree.
     *
     * _Available since v4.4._
     * 
     * Note this is for a Merkle tree using the sha256 hash function
     */
    function processInclusionProofSha256(bytes memory proof, bytes32 leaf, uint256 index) internal view returns (bytes32) {
        require(proof.length != 0 && proof.length % 32 == 0, "Merkle.processInclusionProofSha256: proof length should be a non-zero multiple of 32");
        bytes32[1] memory computedHash = [leaf];
        for (uint256 i = 32; i <= proof.length; i+=32) {
            if(index % 2 == 0) {
                // if ith bit of index is 0, then computedHash is a left sibling
                assembly {
                    mstore(0x00, mload(computedHash))
                    mstore(0x20, mload(add(proof, i)))
                    if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) {revert(0, 0)}
                    index := div(index, 2)
                }
            } else {
                // if ith bit of index is 1, then computedHash is a right sibling
                assembly {
                    mstore(0x00, mload(add(proof, i)))
                    mstore(0x20, mload(computedHash))
                    if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) {revert(0, 0)}
                    index := div(index, 2)
                }            
            }
        }
        return computedHash[0];
    }

    /**
     @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function
     @param leaves the leaves of the merkle tree
     @return The computed Merkle root of the tree.
     @dev A pre-condition to this function is that leaves.length is a power of two.  If not, the function will merkleize the inputs incorrectly.
     */ 
    function merkleizeSha256(
        bytes32[] memory leaves
    ) internal pure returns (bytes32) {
        //there are half as many nodes in the layer above the leaves
        uint256 numNodesInLayer = leaves.length / 2;
        //create a layer to store the internal nodes
        bytes32[] memory layer = new bytes32[](numNodesInLayer);
        //fill the layer with the pairwise hashes of the leaves
        for (uint i = 0; i < numNodesInLayer; i++) {
            layer[i] = sha256(abi.encodePacked(leaves[2*i], leaves[2*i+1]));
        }
        //the next layer above has half as many nodes
        numNodesInLayer /= 2;
        //while we haven't computed the root
        while (numNodesInLayer != 0) {
            //overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
            for (uint i = 0; i < numNodesInLayer; i++) {
                layer[i] = sha256(abi.encodePacked(layer[2*i], layer[2*i+1]));
            }
            //the next layer above has half as many nodes
            numNodesInLayer /= 2;
        }
        //the first node in the layer is the root
        return layer[0];
    }
}

File 17 of 24 : IStrategyManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "./IStrategy.sol";
import "./ISlasher.sol";
import "./IDelegationManager.sol";

/**
 * @title Interface for the primary entrypoint for funds into EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice See the `StrategyManager` contract itself for implementation details.
 */
interface IStrategyManager {
    // packed struct for queued withdrawals; helps deal with stack-too-deep errors
    struct WithdrawerAndNonce {
        address withdrawer;
        uint96 nonce;
    }

    /**
     * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored.
     * In functions that operate on existing queued withdrawals -- e.g. `startQueuedWithdrawalWaitingPeriod` or `completeQueuedWithdrawal`,
     * the data is resubmitted and the hash of the submitted data is computed by `calculateWithdrawalRoot` and checked against the
     * stored hash in order to confirm the integrity of the submitted data.
     */
    struct QueuedWithdrawal {
        IStrategy[] strategies;
        uint256[] shares;
        address depositor;
        WithdrawerAndNonce withdrawerAndNonce;
        uint32 withdrawalStartBlock;
        address delegatedAddress;
    }

    /**
     * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender`
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the depositor
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen).
     * 
     * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy.
     */
    function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount)
        external
        returns (uint256 shares);


    /**
     * @notice Deposits `amount` of beaconchain ETH into this contract on behalf of `staker`
     * @param staker is the entity that is restaking in eigenlayer,
     * @param amount is the amount of beaconchain ETH being restaked,
     * @dev Only callable by EigenPodManager.
     */
    function depositBeaconChainETH(address staker, uint256 amount) external;

    /**
     * @notice Records an overcommitment event on behalf of a staker. The staker's beaconChainETH shares are decremented by `amount`.
     * @param overcommittedPodOwner is the pod owner to be slashed
     * @param beaconChainETHStrategyIndex is the index of the beaconChainETHStrategy in case it must be removed,
     * @param amount is the amount to decrement the slashedAddress's beaconChainETHStrategy shares
     * @dev Only callable by EigenPodManager.
     */
    function recordOvercommittedBeaconChainETH(address overcommittedPodOwner, uint256 beaconChainETHStrategyIndex, uint256 amount)
        external;

    /**
     * @notice Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`,
     * who must sign off on the action.
     * Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed 
     * purely to help one address deposit 'for' another.
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the depositor
     * @param staker the staker that the deposited assets will be credited to
     * @param expiry the timestamp at which the signature expires
     * @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward
     * following EIP-1271 if the `staker` is a contract
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those
     * targeting stakers who may be attempting to undelegate.
     * @dev Cannot be called on behalf of a staker that is 'frozen' (this function will revert if the `staker` is frozen).
     * 
     *  WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy
     */
    function depositIntoStrategyWithSignature(
        IStrategy strategy,
        IERC20 token,
        uint256 amount,
        address staker,
        uint256 expiry,
        bytes memory signature
    )
        external
        returns (uint256 shares);

    /// @notice Returns the current shares of `user` in `strategy`
    function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares);

    /**
     * @notice Get all details on the depositor's deposits and corresponding shares
     * @return (depositor's strategies, shares in these strategies)
     */
    function getDeposits(address depositor) external view returns (IStrategy[] memory, uint256[] memory);

    /// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
    function stakerStrategyListLength(address staker) external view returns (uint256);

    /**
     * @notice Called by a staker to queue a withdrawal of the given amount of `shares` from each of the respective given `strategies`.
     * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function.
     * User shares are decreased in this function, but the total number of shares in each strategy remains the same.
     * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where
     * the funds are actually sent to the user through use of the strategies' 'withdrawal' function. This ensures
     * that the value per share reported by each strategy will remain consistent, and that the shares will continue
     * to accrue gains during the enforced withdrawal waiting period.
     * @param strategyIndexes is a list of the indices in `stakerStrategyList[msg.sender]` that correspond to the strategies
     * for which `msg.sender` is withdrawing 100% of their shares
     * @param strategies The Strategies to withdraw from
     * @param shares The amount of shares to withdraw from each of the respective Strategies in the `strategies` array
     * @param withdrawer The address that can complete the withdrawal and will receive any withdrawn funds or shares upon completing the withdrawal
     * @param undelegateIfPossible If this param is marked as 'true' *and the withdrawal will result in `msg.sender` having no shares in any Strategy,*
     * then this function will also make an internal call to `undelegate(msg.sender)` to undelegate the `msg.sender`.
     * @return The 'withdrawalRoot' of the newly created Queued Withdrawal
     * @dev Strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, then
     * popping off the last entry in `stakerStrategyList`. The simplest way to calculate the correct `strategyIndexes` to input
     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in
     * `stakerStrategyList` to lowest index
     * @dev Note that if the withdrawal includes shares in the enshrined 'beaconChainETH' strategy, then it must *only* include shares in this strategy, and
     * `withdrawer` must match the caller's address. The first condition is because slashing of queued withdrawals cannot be guaranteed 
     * for Beacon Chain ETH (since we cannot trigger a withdrawal from the beacon chain through a smart contract) and the second condition is because shares in
     * the enshrined 'beaconChainETH' strategy technically represent non-fungible positions (deposits to the Beacon Chain, each pointed at a specific EigenPod).
     */
    function queueWithdrawal(
        uint256[] calldata strategyIndexes,
        IStrategy[] calldata strategies,
        uint256[] calldata shares,
        address withdrawer,
        bool undelegateIfPossible
    )
        external returns(bytes32);
        
    /**
     * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match `queuedWithdrawal.withdrawer`
     * @param queuedWithdrawal The QueuedWithdrawal to complete.
     * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies` array
     * of the `queuedWithdrawal`. This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused)
     * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array
     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves
     * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies
     * will simply be transferred to the caller directly.
     * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
     */
    function completeQueuedWithdrawal(
        QueuedWithdrawal calldata queuedWithdrawal,
        IERC20[] calldata tokens,
        uint256 middlewareTimesIndex,
        bool receiveAsTokens
    )
        external;
    
    /**
     * @notice Used to complete the specified `queuedWithdrawals`. The function caller must match `queuedWithdrawals[...].withdrawer`
     * @param queuedWithdrawals The QueuedWithdrawals to complete.
     * @param tokens Array of tokens for each QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
     * @param middlewareTimesIndexes One index to reference per QueuedWithdrawal. See `completeQueuedWithdrawal` for the usage of a single index.
     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves
     * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies
     * will simply be transferred to the caller directly.
     * @dev Array-ified version of `completeQueuedWithdrawal`
     * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
     */
    function completeQueuedWithdrawals(
        QueuedWithdrawal[] calldata queuedWithdrawals,
        IERC20[][] calldata tokens,
        uint256[] calldata middlewareTimesIndexes,
        bool[] calldata receiveAsTokens
    )
        external;

    /**
     * @notice Slashes the shares of a 'frozen' operator (or a staker delegated to one)
     * @param slashedAddress is the frozen address that is having its shares slashed
     * @param recipient is the address that will receive the slashed funds, which could e.g. be a harmed party themself,
     * or a MerkleDistributor-type contract that further sub-divides the slashed funds.
     * @param strategies Strategies to slash
     * @param shareAmounts The amount of shares to slash in each of the provided `strategies`
     * @param tokens The tokens to use as input to the `withdraw` function of each of the provided `strategies`
     * @param strategyIndexes is a list of the indices in `stakerStrategyList[msg.sender]` that correspond to the strategies
     * for which `msg.sender` is withdrawing 100% of their shares
     * @param recipient The slashed funds are withdrawn as tokens to this address.
     * @dev strategies are removed from `stakerStrategyList` by swapping the last entry with the entry to be removed, then
     * popping off the last entry in `stakerStrategyList`. The simplest way to calculate the correct `strategyIndexes` to input
     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in
     * `stakerStrategyList` to lowest index
     */
    function slashShares(
        address slashedAddress,
        address recipient,
        IStrategy[] calldata strategies,
        IERC20[] calldata tokens,
        uint256[] calldata strategyIndexes,
        uint256[] calldata shareAmounts
    )
        external;

    /**
     * @notice Slashes an existing queued withdrawal that was created by a 'frozen' operator (or a staker delegated to one)
     * @param recipient The funds in the slashed withdrawal are withdrawn as tokens to this address.
     * @param queuedWithdrawal The previously queued withdrawal to be slashed
     * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `strategies`
     * array of the `queuedWithdrawal`.
     * @param indicesToSkip Optional input parameter -- indices in the `strategies` array to skip (i.e. not call the 'withdraw' function on). This input exists
     * so that, e.g., if the slashed QueuedWithdrawal contains a malicious strategy in the `strategies` array which always reverts on calls to its 'withdraw' function,
     * then the malicious strategy can be skipped (with the shares in effect "burned"), while the non-malicious strategies are still called as normal.
     */
    function slashQueuedWithdrawal(address recipient, QueuedWithdrawal calldata queuedWithdrawal, IERC20[] calldata tokens, uint256[] calldata indicesToSkip)
        external;

    /// @notice Returns the keccak256 hash of `queuedWithdrawal`.
    function calculateWithdrawalRoot(
        QueuedWithdrawal memory queuedWithdrawal
    )
        external
        pure
        returns (bytes32);

    /**
     * @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
    */
    function addStrategiesToDepositWhitelist(IStrategy[] calldata strategiesToWhitelist) external;

    /**
     * @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
    */
    function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;

    /// @notice Returns the single, central Delegation contract of EigenLayer
    function delegation() external view returns (IDelegationManager);

    /// @notice Returns the single, central Slasher contract of EigenLayer
    function slasher() external view returns (ISlasher);

    /// @notice returns the enshrined, virtual 'beaconChainETH' Strategy
    function beaconChainETHStrategy() external view returns (IStrategy);

    /// @notice Returns the number of blocks that must pass between the time a withdrawal is queued and the time it can be completed
    function withdrawalDelayBlocks() external view returns (uint256);
}

File 18 of 24 : IBeaconChainOracle.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

/**
 * @title Interface for the BeaconStateOracle contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
interface IBeaconChainOracle {
    /// @notice Largest blockNumber that has been confirmed by the oracle.
    function latestConfirmedOracleBlockNumber() external view returns(uint64);
    /// @notice Mapping: Beacon Chain blockNumber => the Beacon Chain state root at the specified blockNumber.
    /// @dev This will return `bytes32(0)` if the state root at the specified blockNumber is not yet confirmed.
    function beaconStateRootAtBlockNumber(uint64 blockNumber) external view returns(bytes32);

    /// @notice Mapping: address => whether or not the address is in the set of oracle signers.
    function isOracleSigner(address _oracleSigner) external view returns(bool);

    /// @notice Mapping: Beacon Chain blockNumber => oracle signer address => whether or not the oracle signer has voted on the state root at the blockNumber.
    function hasVoted(uint64 blockNumber, address oracleSigner) external view returns(bool);

    /// @notice Mapping: Beacon Chain blockNumber => state root => total number of oracle signer votes for the state root at the blockNumber. 
    function stateRootVotes(uint64 blockNumber, bytes32 stateRoot) external view returns(uint256);

    /// @notice Total number of members of the set of oracle signers.
    function totalOracleSigners() external view returns(uint256);

    /**
     * @notice Number of oracle signers that must vote for a state root in order for the state root to be confirmed.
     * Adjustable by this contract's owner through use of the `setThreshold` function.
     * @dev We note that there is an edge case -- when the threshold is adjusted downward, if a state root already has enough votes to meet the *new* threshold,
     * the state root must still receive one additional vote from an oracle signer to be confirmed. This behavior is intended, to minimize unexpected root confirmations.
     */
    function threshold() external view returns(uint256);

    /**
     * @notice Owner-only function used to modify the value of the `threshold` variable.
     * @param _threshold Desired new value for the `threshold` variable. Function will revert if this is set to zero.
     */
    function setThreshold(uint256 _threshold) external;

    /**
     * @notice Owner-only function used to add a signer to the set of oracle signers.
     * @param _oracleSigners Array of address to be added to the set.
     * @dev Function will have no effect on the i-th input address if `_oracleSigners[i]`is already in the set of oracle signers.
     */
    function addOracleSigners(address[] memory _oracleSigners) external;

    /**
     * @notice Owner-only function used to remove a signer from the set of oracle signers.
     * @param _oracleSigners Array of address to be removed from the set.
     * @dev Function will have no effect on the i-th input address if `_oracleSigners[i]`is already not in the set of oracle signers.
     */
    function removeOracleSigners(address[] memory _oracleSigners) external;

    /**
     * @notice Called by a member of the set of oracle signers to assert that the Beacon Chain state root is `stateRoot` at `blockNumber`.
     * @dev The state root will be finalized once the total number of votes *for this exact state root at this exact blockNumber* meets the `threshold` value.
     * @param blockNumber The Beacon Chain blockNumber of interest.
     * @param stateRoot The Beacon Chain state root that the caller asserts was the correct root, at the specified `blockNumber`.
     */
    function voteForBeaconChainStateRoot(uint64 blockNumber, bytes32 stateRoot) external;
}

File 19 of 24 : IPauserRegistry.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

/**
 * @title Interface for the `PauserRegistry` contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
interface IPauserRegistry {
    /// @notice Mapping of addresses to whether they hold the pauser role.
    function isPauser(address pauser) external view returns (bool);

    /// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses.
    function unpauser() external view returns (address);
}

File 20 of 24 : IStrategy.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Minimal interface for an `Strategy` contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Custom `Strategy` implementations may expand extensively on this interface.
 */
interface IStrategy {
    /**
     * @notice Used to deposit tokens into this Strategy
     * @param token is the ERC20 token being deposited
     * @param amount is the amount of token being deposited
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
     * @return newShares is the number of new shares issued at the current exchange ratio.
     */
    function deposit(IERC20 token, uint256 amount) external returns (uint256);

    /**
     * @notice Used to withdraw tokens from this Strategy, to the `depositor`'s address
     * @param depositor is the address to receive the withdrawn funds
     * @param token is the ERC20 token being transferred out
     * @param amountShares is the amount of shares being withdrawn
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * other functions, and individual share balances are recorded in the strategyManager as well.
     */
    function withdraw(address depositor, IERC20 token, uint256 amountShares) external;

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlying(uint256 amountShares) external returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToShares(uint256 amountUnderlying) external returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
     */
    function userUnderlying(address user) external returns (uint256);

     /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
     */
    function userUnderlyingView(address user) external view returns (uint256);

    /// @notice The underlying token for shares in this Strategy
    function underlyingToken() external view returns (IERC20);

    /// @notice The total number of extant shares in this Strategy
    function totalShares() external view returns (uint256);

    /// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
    function explanation() external view returns (string memory);
}

File 21 of 24 : ISlasher.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

/**
 * @title Interface for the primary 'slashing' contract for EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice See the `Slasher` contract itself for implementation details.
 */
interface ISlasher {
    // struct used to store information about the current state of an operator's obligations to middlewares they are serving
    struct MiddlewareTimes {
        // The update block for the middleware whose most recent update was earliest, i.e. the 'stalest' update out of all middlewares the operator is serving
        uint32 stalestUpdateBlock;
        // The latest 'serveUntilBlock' from all of the middleware that the operator is serving
        uint32 latestServeUntilBlock;
    }

    // struct used to store details relevant to a single middleware that an operator has opted-in to serving
    struct MiddlewareDetails {
        // the block before which the contract is allowed to slash the user
        uint32 contractCanSlashOperatorUntilBlock;
        // the block at which the middleware's view of the operator's stake was most recently updated
        uint32 latestUpdateBlock;
    }

    /**
     * @notice Gives the `contractAddress` permission to slash the funds of the caller.
     * @dev Typically, this function must be called prior to registering for a middleware.
     */
    function optIntoSlashing(address contractAddress) external;

    /**
     * @notice Used for 'slashing' a certain operator.
     * @param toBeFrozen The operator to be frozen.
     * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop.
     * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `optIntoSlashing`.
     */
    function freezeOperator(address toBeFrozen) external;
    
    /**
     * @notice Removes the 'frozen' status from each of the `frozenAddresses`
     * @dev Callable only by the contract owner (i.e. governance).
     */
    function resetFrozenStatus(address[] calldata frozenAddresses) external;

    /**
     * @notice this function is a called by middlewares during an operator's registration to make sure the operator's stake at registration 
     *         is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at the current block is slashable
     * @dev adds the middleware's slashing contract to the operator's linked list
     */
    function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external;

    /**
     * @notice this function is a called by middlewares during a stake update for an operator (perhaps to free pending withdrawals)
     *         to make sure the operator's stake at updateBlock is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param updateBlock the block for which the stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at updateBlock is slashable
     * @param insertAfter the element of the operators linked list that the currently updating middleware should be inserted after
     * @dev insertAfter should be calculated offchain before making the transaction that calls this. this is subject to race conditions, 
     *      but it is anticipated to be rare and not detrimental.
     */
    function recordStakeUpdate(address operator, uint32 updateBlock, uint32 serveUntilBlock, uint256 insertAfter) external;

    /**
     * @notice this function is a called by middlewares during an operator's deregistration to make sure the operator's stake at deregistration 
     *         is slashable until serveUntil
     * @param operator the operator whose stake update is being recorded
     * @param serveUntilBlock the block until which the operator's stake at the current block is slashable
     * @dev removes the middleware's slashing contract to the operator's linked list and revokes the middleware's (i.e. caller's) ability to
     * slash `operator` once `serveUntil` is reached
     */
    function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external;

    /**
     * @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially subject to
     * slashing of their funds, and cannot cannot deposit or withdraw from the strategyManager until the slashing process is completed
     * and the staker's status is reset (to 'unfrozen').
     * @param staker The staker of interest.
     * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated
     * to an operator who has their status set to frozen. Otherwise returns 'false'.
     */
    function isFrozen(address staker) external view returns (bool);

    /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`.
    function canSlash(address toBeSlashed, address slashingContract) external view returns (bool);

    /// @notice Returns the block until which `serviceContract` is allowed to slash the `operator`.
    function contractCanSlashOperatorUntilBlock(address operator, address serviceContract) external view returns (uint32);

    /// @notice Returns the block at which the `serviceContract` last updated its view of the `operator`'s stake
    function latestUpdateBlock(address operator, address serviceContract) external view returns (uint32);

    /// @notice A search routine for finding the correct input value of `insertAfter` to `recordStakeUpdate` / `_updateMiddlewareList`.
    function getCorrectValueForInsertAfter(address operator, uint32 updateBlock) external view returns (uint256);

    /**
     * @notice Returns 'true' if `operator` can currently complete a withdrawal started at the `withdrawalStartBlock`, with `middlewareTimesIndex` used
     * to specify the index of a `MiddlewareTimes` struct in the operator's list (i.e. an index in `operatorToMiddlewareTimes[operator]`). The specified
     * struct is consulted as proof of the `operator`'s ability (or lack thereof) to complete the withdrawal.
     * This function will return 'false' if the operator cannot currently complete a withdrawal started at the `withdrawalStartBlock`, *or* in the event
     * that an incorrect `middlewareTimesIndex` is supplied, even if one or more correct inputs exist.
     * @param operator Either the operator who queued the withdrawal themselves, or if the withdrawing party is a staker who delegated to an operator,
     * this address is the operator *who the staker was delegated to* at the time of the `withdrawalStartBlock`.
     * @param withdrawalStartBlock The block number at which the withdrawal was initiated.
     * @param middlewareTimesIndex Indicates an index in `operatorToMiddlewareTimes[operator]` to consult as proof of the `operator`'s ability to withdraw
     * @dev The correct `middlewareTimesIndex` input should be computable off-chain.
     */
    function canWithdraw(address operator, uint32 withdrawalStartBlock, uint256 middlewareTimesIndex) external returns(bool);

    /**
     * operator => 
     *  [
     *      (
     *          the least recent update block of all of the middlewares it's serving/served, 
     *          latest time that the stake bonded at that update needed to serve until
     *      )
     *  ]
     */
    function operatorToMiddlewareTimes(address operator, uint256 arrayIndex) external view returns (MiddlewareTimes memory);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator].length`
    function middlewareTimesLength(address operator) external view returns (uint256);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].stalestUpdateBlock`.
    function getMiddlewareTimesIndexBlock(address operator, uint32 index) external view returns(uint32);

    /// @notice Getter function for fetching `operatorToMiddlewareTimes[operator][index].latestServeUntil`.
    function getMiddlewareTimesIndexServeUntilBlock(address operator, uint32 index) external view returns(uint32);

    /// @notice Getter function for fetching `_operatorToWhitelistedContractsByUpdate[operator].size`.
    function operatorWhitelistedContractsLinkedListSize(address operator) external view returns (uint256);

    /// @notice Getter function for fetching a single node in the operator's linked list (`_operatorToWhitelistedContractsByUpdate[operator]`).
    function operatorWhitelistedContractsLinkedListEntry(address operator, address node) external view returns (bool, uint256, uint256);
}

File 22 of 24 : IDelegationManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "./IDelegationTerms.sol";

/**
 * @title The interface for the primary delegation contract for EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice  This is the contract for delegation in EigenLayer. The main functionalities of this contract are
 * - enabling anyone to register as an operator in EigenLayer
 * - allowing new operators to provide a DelegationTerms-type contract, which may mediate their interactions with stakers who delegate to them
 * - enabling any staker to delegate its stake to the operator of its choice
 * - enabling a staker to undelegate its assets from an operator (performed as part of the withdrawal process, initiated through the StrategyManager)
 */
interface IDelegationManager {

    /**
     * @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.
     * @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.
     * @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments
     * in a more 'trustful' manner.
     * @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.
     */
    function registerAsOperator(IDelegationTerms dt) external;

    /**
     *  @notice This will be called by a staker to delegate its assets to some operator.
     *  @param operator is the operator to whom staker (msg.sender) is delegating its assets
     */
    function delegateTo(address operator) external;

    /**
     * @notice Delegates from `staker` to `operator`.
     * @dev requires that:
     * 1) if `staker` is an EOA, then `signature` is valid ECDSA signature from `staker`, indicating their intention for this action
     * 2) if `staker` is a contract, then `signature` must will be checked according to EIP-1271
     */
    function delegateToBySignature(address staker, address operator, uint256 expiry, bytes memory signature) external;

    /**
     * @notice Undelegates `staker` from the operator who they are delegated to.
     * @notice Callable only by the StrategyManager
     * @dev Should only ever be called in the event that the `staker` has no active deposits in EigenLayer.
     */
    function undelegate(address staker) external;

    /// @notice returns the address of the operator that `staker` is delegated to.
    function delegatedTo(address staker) external view returns (address);

    /// @notice returns the DelegationTerms of the `operator`, which may mediate their interactions with stakers who delegate to them.
    function delegationTerms(address operator) external view returns (IDelegationTerms);

    /// @notice returns the total number of shares in `strategy` that are delegated to `operator`.
    function operatorShares(address operator, IStrategy strategy) external view returns (uint256);

    /**
     * @notice Increases the `staker`'s delegated shares in `strategy` by `shares, typically called when the staker has further deposits into EigenLayer
     * @dev Callable only by the StrategyManager
     */
    function increaseDelegatedShares(address staker, IStrategy strategy, uint256 shares) external;

    /**
     * @notice Decreases the `staker`'s delegated shares in each entry of `strategies` by its respective `shares[i]`, typically called when the staker withdraws from EigenLayer
     * @dev Callable only by the StrategyManager
     */
    function decreaseDelegatedShares(
        address staker,
        IStrategy[] calldata strategies,
        uint256[] calldata shares
    ) external;

    /// @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
    function isDelegated(address staker) external view returns (bool);

    /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise.
    function isNotDelegated(address staker) external view returns (bool);

    /// @notice Returns if an operator can be delegated to, i.e. it has called `registerAsOperator`.
    function isOperator(address operator) external view returns (bool);
}

File 23 of 24 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 24 of 24 : IDelegationTerms.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "./IStrategy.sol";

/**
 * @title Abstract interface for a contract that helps structure the delegation relationship.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice The gas budget provided to this contract in calls from EigenLayer contracts is limited.
 */
interface IDelegationTerms {
    function payForService(IERC20 token, uint256 amount) external payable;

    function onDelegationWithdrawn(
        address delegator,
        IStrategy[] memory stakerStrategyList,
        uint256[] memory stakerShares
    ) external returns(bytes memory);

    function onDelegationReceived(
        address delegator,
        IStrategy[] memory stakerStrategyList,
        uint256[] memory stakerShares
    ) external returns(bytes memory);
}

Settings
{
  "remappings": [
    "@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "ds-test/=lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IETHPOSDeposit","name":"_ethPOS","type":"address"},{"internalType":"contract IDelayedWithdrawalRouter","name":"_delayedWithdrawalRouter","type":"address"},{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"},{"internalType":"uint256","name":"_REQUIRED_BALANCE_WEI","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"EigenPodStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"validatorIndex","type":"uint40"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint64","name":"withdrawalAmountGwei","type":"uint64"}],"name":"FullWithdrawalRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"validatorIndex","type":"uint40"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint64","name":"partialWithdrawalAmountGwei","type":"uint64"}],"name":"PartialWithdrawalRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RestakedBeaconChainETHWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"validatorIndex","type":"uint40"}],"name":"ValidatorOvercommitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint40","name":"validatorIndex","type":"uint40"}],"name":"ValidatorRestaked","type":"event"},{"inputs":[],"name":"REQUIRED_BALANCE_GWEI","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUIRED_BALANCE_WEI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delayedWithdrawalRouter","outputs":[{"internalType":"contract IDelayedWithdrawalRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethPOS","outputs":[{"internalType":"contract IETHPOSDeposit","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasRestaked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_podOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mostRecentWithdrawalBlockNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"podOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint40","name":"","type":"uint40"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"provenPartialWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"restakedExecutionLayerGwei","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint40","name":"","type":"uint40"}],"name":"validatorStatus","outputs":[{"internalType":"enum IEigenPod.VALIDATOR_STATUS","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"blockHeaderProof","type":"bytes"},{"internalType":"bytes","name":"withdrawalProof","type":"bytes"},{"internalType":"bytes","name":"slotProof","type":"bytes"},{"internalType":"bytes","name":"executionPayloadProof","type":"bytes"},{"internalType":"bytes","name":"blockNumberProof","type":"bytes"},{"internalType":"uint64","name":"blockHeaderRootIndex","type":"uint64"},{"internalType":"uint64","name":"withdrawalIndex","type":"uint64"},{"internalType":"bytes32","name":"blockHeaderRoot","type":"bytes32"},{"internalType":"bytes32","name":"blockBodyRoot","type":"bytes32"},{"internalType":"bytes32","name":"slotRoot","type":"bytes32"},{"internalType":"bytes32","name":"blockNumberRoot","type":"bytes32"},{"internalType":"bytes32","name":"executionPayloadRoot","type":"bytes32"}],"internalType":"struct BeaconChainProofs.WithdrawalProofs","name":"withdrawalProofs","type":"tuple"},{"internalType":"bytes","name":"validatorFieldsProof","type":"bytes"},{"internalType":"bytes32[]","name":"validatorFields","type":"bytes32[]"},{"internalType":"bytes32[]","name":"withdrawalFields","type":"bytes32[]"},{"internalType":"uint256","name":"beaconChainETHStrategyIndex","type":"uint256"},{"internalType":"uint64","name":"oracleBlockNumber","type":"uint64"}],"name":"verifyAndProcessWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"validatorIndex","type":"uint40"},{"components":[{"internalType":"bytes","name":"validatorFieldsProof","type":"bytes"},{"internalType":"bytes","name":"validatorBalanceProof","type":"bytes"},{"internalType":"bytes32","name":"balanceRoot","type":"bytes32"}],"internalType":"struct BeaconChainProofs.ValidatorFieldsAndBalanceProofs","name":"proofs","type":"tuple"},{"internalType":"bytes32[]","name":"validatorFields","type":"bytes32[]"},{"internalType":"uint256","name":"beaconChainETHStrategyIndex","type":"uint256"},{"internalType":"uint64","name":"oracleBlockNumber","type":"uint64"}],"name":"verifyOvercommittedStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"oracleBlockNumber","type":"uint64"},{"internalType":"uint40","name":"validatorIndex","type":"uint40"},{"components":[{"internalType":"bytes","name":"validatorFieldsProof","type":"bytes"},{"internalType":"bytes","name":"validatorBalanceProof","type":"bytes"},{"internalType":"bytes32","name":"balanceRoot","type":"bytes32"}],"internalType":"struct BeaconChainProofs.ValidatorFieldsAndBalanceProofs","name":"proofs","type":"tuple"},{"internalType":"bytes32[]","name":"validatorFields","type":"bytes32[]"}],"name":"verifyWithdrawalCredentialsAndBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBeforeRestaking","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"}],"name":"withdrawRestakedBeaconChainETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101206040523480156200001257600080fd5b5060405162003fdf38038062003fdf8339810160408190526200003591620001f6565b6001600160a01b0380851660805283811660a052821660c05261010081905262000064633b9aca008262000266565b6001600160401b031660e05262000080633b9aca00826200027d565b156200010a5760405162461bcd60e51b815260206004820152604860248201527f456967656e506f642e636f6e74727563746f723a205f52455155495245445f4260448201527f414c414e43455f574549206973206e6f7420612077686f6c65206e756d626572606482015267206f66206777656960c01b608482015260a4015b60405180910390fd5b620001146200011e565b5050505062000294565b600054610100900460ff1615620001885760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840162000101565b60005460ff9081161015620001db576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b0381168114620001f357600080fd5b50565b600080600080608085870312156200020d57600080fd5b84516200021a81620001dd565b60208601519094506200022d81620001dd565b60408601519093506200024081620001dd565b6060959095015193969295505050565b634e487b7160e01b600052601260045260246000fd5b60008262000278576200027862000250565b500490565b6000826200028f576200028f62000250565b500690565b60805160a05160c05160e05161010051613c426200039d600039600081816101fa01528181610dd2015281816114a9015261278701526000818161029201528181610b5f015281816111e601528181612465015281816124a6015281816124e7015281816125ca01528181612689015281816126ca015261270b01526000818161023c01528181610447015281816104e201528181610789015281816108fe01528181610c8301528181610df801528181610e6d01528181611028015281816112d4015281816114cf0152818161162701528181612595015281816127ad015261282301526000818161015d0152612d490152600081816102e60152610f380152613c426000f3fe6080604052600436106101095760003560e01c806374cdd79811610095578063baa7145a11610064578063baa7145a14610378578063c49074421461038d578063c4d66de8146103ad578063ddf4639a146103cd578063ef8015711461040857600080fd5b806374cdd798146102d45780639b4e463414610308578063b08b41981461031b578063b18a69f61461033b57600080fd5b806332b58cd7116100dc57806332b58cd7146101e85780634665bcda1461022a578063507fa7f61461025e578063517355dd1461028057806351f07208146102b457600080fd5b80630b18ff661461010e5780631a5057be1461014b5780631e4158631461017f5780633106ab53146101b7575b600080fd5b34801561011a57600080fd5b5060335461012e906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015757600080fd5b5061012e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561018b57600080fd5b5060345461019f906001600160401b031681565b6040516001600160401b039091168152602001610142565b3480156101c357600080fd5b506034546101d890600160401b900460ff1681565b6040519015158152602001610142565b3480156101f457600080fd5b5061021c7f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610142565b34801561023657600080fd5b5061012e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561026a57600080fd5b5061027e61027936600461327f565b61042f565b005b34801561028c57600080fd5b5061019f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102c057600080fd5b5061027e6102cf36600461337c565b6108e5565b3480156102e057600080fd5b5061012e7f000000000000000000000000000000000000000000000000000000000000000081565b61027e610316366004613407565b610e62565b34801561032757600080fd5b5061027e61033636600461347a565b61100f565b34801561034757600080fd5b5061036b61035636600461350c565b60356020526000908152604090205460ff1681565b6040516101429190613544565b34801561038457600080fd5b5061027e611500565b34801561039957600080fd5b5061027e6103a8366004613584565b61161c565b3480156103b957600080fd5b5061027e6103c83660046135b0565b611702565b3480156103d957600080fd5b506101d86103e83660046135cd565b603660209081526000928352604080842090915290825290205460ff1681565b34801561041457600080fd5b5060335461019f90600160a01b90046001600160401b031681565b604051635ac86ab760e01b81526004808201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610496573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ba9190613600565b156104e05760405162461bcd60e51b81526004016104d790613622565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b13442716040518163ffffffff1660e01b8152600401602060405180830381865afa15801561053e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610562919061367f565b6033546040516372c1cc1b60e11b81526001600160a01b03918216600482015291169063e583983690602401602060405180830381865afa1580156105ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cf9190613600565b156106305760405162461bcd60e51b815260206004820152602b60248201527f456967656e506f642e6f6e6c794e6f7446726f7a656e3a20706f64206f776e6560448201526a391034b990333937bd32b760a91b60648201526084016104d7565b61063e8a6101400135611899565b6033546001600160401b03600160a01b9091048116908216116106735760405162461bcd60e51b81526004016104d79061369c565b60006106978787600181811061068b5761068b61373e565b90506020020135611899565b9050600064ffffffffff821660009081526035602052604090205460ff1660038111156106c6576106c661352e565b14156107685760405162461bcd60e51b81526020600482015260716024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206e657665722070726f76656e20746f2068617660648201527f65207769746864726177616c2063726564656e7469616c7320706f696e746564608482015270081d1bc81d1a1a5cc818dbdb9d1c9858dd607a1b60a482015260c4016104d7565b604051636c2d846360e11b81526001600160401b03851660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d85b08c690602401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190613754565b905061080a818e8a8a611900565b61081882828e8e8e8e612230565b60006108308989600381811061068b5761068b61373e565b905060006108428f6101200135611899565b905061085860206001600160401b038316613799565b61086e8d8d600781811061068b5761068b61373e565b6001600160401b0316116108b95760335464ffffffffff85166000908152603560205260409020546108b491849187918c916001600160a01b039091169060ff16612447565b6108d4565b6033546108d4908290849087906001600160a01b03166129d6565b505050505050505050505050505050565b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa15801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190613600565b1561098e5760405162461bcd60e51b81526004016104d790613622565b60335486906001600160401b03600160a01b9091048116908216116109c55760405162461bcd60e51b81526004016104d79061369c565b64ffffffffff861660009081526035602052604081205460ff1660038111156109f0576109f061352e565b14610a995760405162461bcd60e51b815260206004820152606760248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a2056616c696461746f72206d757374206265206960648201527f6e61637469766520746f2070726f7665207769746864726177616c2063726564608482015266656e7469616c7360c81b60a482015260c4016104d7565b610aa1612b3d565b610aaa906137ad565b84846001818110610abd57610abd61373e565b9050602002013514610b4b5760405162461bcd60e51b815260206004820152604b60248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a2050726f6f66206973206e6f7420666f7220746860648201526a1a5cc8115a59d95b941bd960aa1b608482015260a4016104d7565b6000610b5b878760400135612b82565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160401b0316816001600160401b03161015610c625760405162461bcd60e51b815260206004820152608860248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a204554482076616c696461746f7227732062616c60648201527f616e6365206d7573742062652067726561746572207468616e206f722065717560848201527f616c20746f207468652072657374616b65642062616c616e636520706572207660a48201526730b634b230ba37b960c11b60c482015260e4016104d7565b604051636c2d846360e11b81526001600160401b03891660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d85b08c690602401602060405180830381865afa158015610cd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf69190613754565b9050610d0e8882610d078a806137d1565b8a8a612230565b610d2a8882610d2060208b018b6137d1565b8b60400135612bbe565b64ffffffffff88166000908152603560205260409020805460ff1916600117905560345460ff600160401b90910416610d76576034805468ff00000000000000001916600160401b1790555b60405164ffffffffff891681527f2d0800bbc377ea54a08c5db6a87aafff5e3e9c8fead0eda110e40e0c104414499060200160405180910390a160335460405163103ebac760e01b81526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000000000000000000000060248201527f00000000000000000000000000000000000000000000000000000000000000009091169063103ebac7906044015b600060405180830381600087803b158015610e3f57600080fd5b505af1158015610e53573d6000803e3d6000fd5b50505050505050505050505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610eaa5760405162461bcd60e51b81526004016104d790613817565b346801bc16d674ec80000014610f365760405162461bcd60e51b8152602060048201526044602482018190527f456967656e506f642e7374616b653a206d75737420696e697469616c6c792073908201527f74616b6520666f7220616e792076616c696461746f72207769746820333220656064820152633a3432b960e11b608482015260a4016104d7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008787610f79612b3d565b8888886040518863ffffffff1660e01b8152600401610f9d969594939291906138bd565b6000604051808303818588803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b50505050507f606865b7934a25d4aed43f6cdb426403353fa4b3009c4d228407474581b01e238585604051611000929190613925565b60405180910390a15050505050565b604051635ac86ab760e01b8152600360048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109b9190613600565b156110b85760405162461bcd60e51b81526004016104d790613622565b436110ce61c4e06001600160401b038516613941565b10156111445760405162461bcd60e51b815260206004820152604b6024820152600080516020613bad83398151915260448201527f653a2073706563696669656420626c6f636b4e756d62657220697320746f6f2060648201526a19985c881a5b881c185cdd60aa1b608482015260a4016104d7565b600164ffffffffff881660009081526035602052604090205460ff1660038111156111715761117161352e565b146111d25760405162461bcd60e51b81526020600482015260376024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206e6f742061637469766500000000000000000060648201526084016104d7565b60006111e2888860400135612b82565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160401b0316816001600160401b0316106112b35760405162461bcd60e51b815260206004820152606b6024820152600080516020613bad83398151915260448201527f653a2076616c696461746f7227732062616c616e6365206d757374206265206c60648201527f657373207468616e207468652072657374616b65642062616c616e636520706560848201526a39103b30b634b230ba37b960a91b60a482015260c4016104d7565b604051636c2d846360e11b81526001600160401b03841660048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d85b08c690602401602060405180830381865afa158015611323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113479190613754565b90506001600160401b03821661140f57600061136f8888600381811061068b5761068b61373e565b9050806001600160401b03166001146113f75760405162461bcd60e51b81526020600482015260506024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206d75737420626520736c617368656420746f2060648201526f1899481bdd995c98dbdb5b5a5d1d195960821b608482015260a4016104d7565b61140d8a836114068c806137d1565b8c8c612230565b505b61142b898261142160208c018c6137d1565b8c60400135612bbe565b64ffffffffff8916600081815260356020908152604091829020805460ff1916600217905590519182527f39436dbc3ba65889c15d38b42ce4be0e2da99723fdebaf0e12df341b5e6e5fd5910160405180910390a16033546040516331f657db60e11b81526001600160a01b039182166004820152602481018790527f000000000000000000000000000000000000000000000000000000000000000060448201527f0000000000000000000000000000000000000000000000000000000000000000909116906363ecafb690606401610e25565b6033546001600160a01b0316331461156b5760405162461bcd60e51b815260206004820152602860248201527f456967656e506f642e6f6e6c79456967656e506f644f776e65723a206e6f74206044820152673837b227bbb732b960c11b60648201526084016104d7565b603454600160401b900460ff16156115dd5760405162461bcd60e51b815260206004820152602f60248201527f456967656e506f642e6861734e6576657252657374616b65643a20726573746160448201526e1ada5b99c81a5cc8195b98589b1959608a1b60648201526084016104d7565b60338054600160a01b63ffffffff43160267ffffffffffffffff60a01b198216811790925561161a916001600160a01b0390811691161747612d1f565b565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116645760405162461bcd60e51b81526004016104d790613817565b611672633b9aca0082613799565b6034805460009061168d9084906001600160401b0316613959565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550816001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e826040516116ec91815260200190565b60405180910390a26116fe8282612d1f565b5050565b600054610100900460ff16158080156117225750600054600160ff909116105b8061173c5750303b15801561173c575060005460ff166001145b61179f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104d7565b6000805460ff1916600117905580156117c2576000805461ff0019166101001790555b6001600160a01b0382166118355760405162461bcd60e51b815260206004820152603460248201527f456967656e506f642e696e697469616c697a653a20706f644f776e65722063616044820152736e6e6f74206265207a65726f206164647265737360601b60648201526084016104d7565b603380546001600160a01b0319166001600160a01b03841617905580156116fe576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b61190b600280613a65565b81146119855760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c4669656c647320686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b611991600d6002613a65565b6119a160c0850160a08601613a71565b6001600160401b031610611a195760405162461bcd60e51b81526020600482015260456024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b526f6f74496e64657820697320746f6f206064820152646c6172676560d81b608482015260a4016104d7565b611a2560046002613a65565b611a3560e0850160c08601613a71565b6001600160401b031610611aae5760405162461bcd60e51b81526020600482015260466024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c496e64657820697320746f6f606482015265206c6172676560d01b608482015260a4016104d7565b611aba600d6005613941565b611ac5906020613a8c565b611acf84806137d1565b905014611b4a5760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b48656164657250726f6f6620686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b611b55600480613941565b611b60906001613941565b611b6b906020613a8c565b611b7860208501856137d1565b905014611bf25760405162461bcd60e51b815260206004820152604e6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c50726f6f662068617320696e60648201526d0c6dee4e4cac6e840d8cadccee8d60931b608482015260a4016104d7565b611bfe60046003613941565b611c09906020613a8c565b611c1660608501856137d1565b905014611c965760405162461bcd60e51b81526020600482015260546024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20657865637574696f6e5061796c6f616450726f6f66206064820152730d0c2e640d2dcc6dee4e4cac6e840d8cadccee8d60631b608482015260a4016104d7565b611ca260036020613a8c565b611caf60408501856137d1565b905014611d235760405162461bcd60e51b81526020600482015260486024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20736c6f7450726f6f662068617320696e636f727265636064820152670e840d8cadccee8d60c31b608482015260a4016104d7565b611d2f60046020613a8c565b611d3c60808501856137d1565b905014611db75760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b4e756d62657250726f6f6620686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b6000611dc960c0850160a08601613a71565b6001600160401b031661a000179050611e26611de585806137d1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250899250505060e087013584612dad565b611e9a5760405162461bcd60e51b815260206004820152604b6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420626c6f636b20686561646572206d60648201526a32b935b63290383937b7b360a91b608482015260a4016104d7565b611ef0611eaa60408601866137d1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060e08a013593506101208a013592509050612dad565b611f5c5760405162461bcd60e51b81526020600482015260436024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420736c6f74206d65726b6c6520707260648201526237b7b360e91b608482015260a4016104d7565b6049611fb3611f6e60608701876137d1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060e087013561016088013584612dad565b61202b5760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420657865637574696f6e5061796c6f60648201526e30b21036b2b935b63290383937b7b360891b608482015260a4016104d7565b61208261203b60808701876137d1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101608701356101408801356006612dad565b6120f55760405162461bcd60e51b815260206004820152604a6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420626c6f636b4e756d626572206d656064820152693935b63290383937b7b360b11b608482015260a4016104d7565b600061210760e0870160c08801613a71565b6001600160401b031661211c60046001613941565b600e901b1790506000612161868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612dc592505050565b90506121b461217360208901896137d1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101608901358385612dad565b6122265760405162461bcd60e51b81526020600482015260496024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c6964207769746864726177616c206d657260648201526835b63290383937b7b360b91b608482015260a4016104d7565b5050505050505050565b61223c60036002613a65565b81146122b55760405162461bcd60e51b815260206004820152604e6024820152600080516020613bcd83398151915260448201527f724669656c64733a2056616c696461746f72206669656c64732068617320696e60648201526d0c6dee4e4cac6e840d8cadccee8d60931b608482015260a4016104d7565b60056122c360286001613941565b6122cd9190613941565b6122d8906020613a8c565b83146123465760405162461bcd60e51b81526020600482015260436024820152600080516020613bcd83398151915260448201527f724669656c64733a2050726f6f662068617320696e636f7272656374206c656e6064820152620cee8d60eb1b608482015260a4016104d7565b600064ffffffffff871661235c60286001613941565b600b901b17905060006123a1848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612dc592505050565b90506123e786868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b9250859150869050612dad565b6122265760405162461bcd60e51b815260206004820152603d6024820152600080516020613bcd83398151915260448201527f724669656c64733a20496e76616c6964206d65726b6c652070726f6f6600000060648201526084016104d7565b6000600182600381111561245d5761245d61352e565b141561266d577f00000000000000000000000000000000000000000000000000000000000000006001600160401b0316866001600160401b03161061254757633b9aca006124cb7f000000000000000000000000000000000000000000000000000000000000000088613959565b6001600160401b03166124de9190613a8c565b603480549192507f00000000000000000000000000000000000000000000000000000000000000009160009061251e9084906001600160401b0316613aab565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550612950565b603480548791906000906125659084906001600160401b0316613aab565b82546001600160401b039182166101009390930a9283029190920219909116179055506033546001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116916363ecafb6911686633b9aca006125ee8b7f0000000000000000000000000000000000000000000000000000000000000000613959565b6001600160401b03166126019190613a8c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064015b600060405180830381600087803b15801561265057600080fd5b505af1158015612664573d6000803e3d6000fd5b50505050612950565b60028260038111156126815761268161352e565b14156128b0577f00000000000000000000000000000000000000000000000000000000000000006001600160401b0316866001600160401b0316106127df57633b9aca006126ef7f000000000000000000000000000000000000000000000000000000000000000088613959565b6001600160401b03166127029190613a8c565b603480549192507f0000000000000000000000000000000000000000000000000000000000000000916000906127429084906001600160401b0316613aab565b82546001600160401b039182166101009390930a92830291909202199091161790555060335460405163103ebac760e01b81526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000000000000000000000060248201527f0000000000000000000000000000000000000000000000000000000000000000919091169063103ebac790604401612636565b603480548791906000906127fd9084906001600160401b0316613aab565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663103ebac7603360009054906101000a90046001600160a01b0316633b9aca00896001600160401b031661287f9190613a8c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401612636565b60405162461bcd60e51b815260206004820152606360248201527f456967656e506f642e766572696679426561636f6e436861696e46756c6c576960448201527f746864726177616c3a2056414c494441544f525f53544154555320697320574960648201527f5448445241574e206f7220696e76616c69642056414c494441544f525f53544160848201526254555360e81b60a482015260c4016104d7565b64ffffffffff8516600081815260356020908152604091829020805460ff1916600317905581519283526001600160401b038916908301526001600160a01b038516917f7341859cc78ba6561939cd5245350631bfaddbc9a16ade2aa7d698c16e8f1d94910160405180910390a280156129ce576129ce8382612d1f565b505050505050565b64ffffffffff821660009081526036602090815260408083206001600160401b038816845290915290205460ff1615612a9d5760405162461bcd60e51b815260206004820152605c60248201527f456967656e506f642e5f70726f636573735061727469616c576974686472617760448201527f616c3a207061727469616c207769746864726177616c2068617320616c72656160648201527f6479206265656e2070726f76656e20666f72207468697320736c6f7400000000608482015260a4016104d7565b64ffffffffff821660008181526036602090815260408083206001600160401b03898116855290835292819020805460ff191660011790558051938452918616908301526001600160a01b038316917f56d746a6c4b72294c7b70b592e8e37d22c732ebd3f9fe9c8539d704b43a950b9910160405180910390a2612b3781612b32633b9aca006001600160401b038716613a8c565b612d1f565b50505050565b60408051600160f81b60208201526000602182015230606090811b6bffffffffffffffffffffffff1916602c8301529101604051602081830303815290604052905090565b600080612b90600485613ad6565b612b9b906040613afa565b64ffffffffff16905082811b6000612bb282611899565b93505050505b92915050565b6005612bcc60266001613941565b612bd69190613941565b612be1906020613a8c565b8214612c515760405162461bcd60e51b815260206004820152604460248201819052600080516020613bcd833981519152908201527f7242616c616e63653a2050726f6f662068617320696e636f7272656374206c656064820152630dccee8d60e31b608482015260a4016104d7565b6000612c5e600487613b27565b64ffffffffff16905080612c7460266001613941565b600c901b179050612cbf84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250899250869150859050612dad565b6129ce5760405162461bcd60e51b815260206004820152603e6024820152600080516020613bcd83398151915260448201527f7242616c616e63653a20496e76616c6964206d65726b6c652070726f6f66000060648201526084016104d7565b603354604051633036cd5360e21b81526001600160a01b03918216600482015283821660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063c0db354c9083906044016000604051808303818588803b158015612d9057600080fd5b505af1158015612da4573d6000803e3d6000fd5b50505050505050565b600083612dbb868585613072565b1495945050505050565b60008060028351612dd69190613799565b90506000816001600160401b03811115612df257612df2613b4b565b604051908082528060200260200182016040528015612e1b578160200160208202803683370190505b50905060005b82811015612f2257600285612e368383613a8c565b81518110612e4657612e4661373e565b602002602001015186836002612e5c9190613a8c565b612e67906001613941565b81518110612e7757612e7761373e565b6020026020010151604051602001612e99929190918252602082015260400190565b60408051601f1981840301815290829052612eb391613b61565b602060405180830381855afa158015612ed0573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612ef39190613754565b828281518110612f0557612f0561373e565b602090810291909101015280612f1a81613b7d565b915050612e21565b50612f2e600283613799565b91505b811561304e5760005b8281101561303b57600282612f4f8383613a8c565b81518110612f5f57612f5f61373e565b602002602001015183836002612f759190613a8c565b612f80906001613941565b81518110612f9057612f9061373e565b6020026020010151604051602001612fb2929190918252602082015260400190565b60408051601f1981840301815290829052612fcc91613b61565b602060405180830381855afa158015612fe9573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061300c9190613754565b82828151811061301e5761301e61373e565b60209081029190910101528061303381613b7d565b915050612f3a565b50613047600283613799565b9150612f31565b806000815181106130615761306161373e565b602002602001015192505050919050565b6000835160001415801561309157506020845161308f9190613b98565b155b6131205760405162461bcd60e51b815260206004820152605460248201527f4d65726b6c652e70726f63657373496e636c7573696f6e50726f6f665368613260448201527f35363a2070726f6f66206c656e6774682073686f756c642062652061206e6f6e60648201527316bd32b9379036bab63a34b836329037b310199960611b608482015260a4016104d7565b604080516020808201909252848152905b855181116131b457613144600285613b98565b613177578151600052808601516020526020826040600060026107d05a03fa61316c57600080fd5b6002840493506131a2565b8086015160005281516020526020826040600060026107d05a03fa61319b57600080fd5b6002840493505b6131ad602082613941565b9050613131565b5051949350505050565b600061018082840312156131d157600080fd5b50919050565b60008083601f8401126131e957600080fd5b5081356001600160401b0381111561320057600080fd5b60208301915083602082850101111561321857600080fd5b9250929050565b60008083601f84011261323157600080fd5b5081356001600160401b0381111561324857600080fd5b6020830191508360208260051b850101111561321857600080fd5b80356001600160401b038116811461327a57600080fd5b919050565b600080600080600080600080600060c08a8c03121561329d57600080fd5b89356001600160401b03808211156132b457600080fd5b6132c08d838e016131be565b9a5060208c01359150808211156132d657600080fd5b6132e28d838e016131d7565b909a50985060408c01359150808211156132fb57600080fd5b6133078d838e0161321f565b909850965060608c013591508082111561332057600080fd5b5061332d8c828d0161321f565b90955093505060808a0135915061334660a08b01613263565b90509295985092959850929598565b803564ffffffffff8116811461327a57600080fd5b6000606082840312156131d157600080fd5b60008060008060006080868803121561339457600080fd5b61339d86613263565b94506133ab60208701613355565b935060408601356001600160401b03808211156133c757600080fd5b6133d389838a0161336a565b945060608801359150808211156133e957600080fd5b506133f68882890161321f565b969995985093965092949392505050565b60008060008060006060868803121561341f57600080fd5b85356001600160401b038082111561343657600080fd5b61344289838a016131d7565b9097509550602088013591508082111561345b57600080fd5b50613468888289016131d7565b96999598509660400135949350505050565b60008060008060008060a0878903121561349357600080fd5b61349c87613355565b955060208701356001600160401b03808211156134b857600080fd5b6134c48a838b0161336a565b965060408901359150808211156134da57600080fd5b506134e789828a0161321f565b9095509350506060870135915061350060808801613263565b90509295509295509295565b60006020828403121561351e57600080fd5b61352782613355565b9392505050565b634e487b7160e01b600052602160045260246000fd5b602081016004831061356657634e487b7160e01b600052602160045260246000fd5b91905290565b6001600160a01b038116811461358157600080fd5b50565b6000806040838503121561359757600080fd5b82356135a28161356c565b946020939093013593505050565b6000602082840312156135c257600080fd5b81356135278161356c565b600080604083850312156135e057600080fd5b6135e983613355565b91506135f760208401613263565b90509250929050565b60006020828403121561361257600080fd5b8151801515811461352757600080fd5b6020808252603e908201527f456967656e506f642e6f6e6c795768656e4e6f745061757365643a20696e646560408201527f782069732070617573656420696e20456967656e506f644d616e616765720000606082015260800190565b60006020828403121561369157600080fd5b81516135278161356c565b60208082526076908201527f456967656e506f642e70726f6f664973466f7256616c6964426c6f636b4e756d60408201527f6265723a20626561636f6e20636861696e2070726f6f66206d7573742062652060608201527f666f7220626c6f636b206e756d626572206166746572206d6f7374526563656e6080820152753a2bb4ba34323930bbb0b6213637b1b5a73ab6b132b960511b60a082015260c00190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561376657600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000826137a8576137a861376d565b500490565b805160208083015191908110156131d15760001960209190910360031b1b16919050565b6000808335601e198436030181126137e857600080fd5b8301803591506001600160401b0382111561380257600080fd5b60200191503681900382131561321857600080fd5b60208082526031908201527f456967656e506f642e6f6e6c79456967656e506f644d616e616765723a206e6f6040820152703a1032b4b3b2b72837b226b0b730b3b2b960791b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60005b838110156138ac578181015183820152602001613894565b83811115612b375750506000910152565b6080815260006138d160808301888a613868565b828103602084015286518082526138ef816020840160208b01613891565b601f01601f191601828103602090810160408501526139119082018688613868565b915050826060830152979650505050505050565b602081526000613939602083018486613868565b949350505050565b6000821982111561395457613954613783565b500190565b60006001600160401b038381169083168181101561397957613979613783565b039392505050565b600181815b808511156139bc5781600019048211156139a2576139a2613783565b808516156139af57918102915b93841c9390800290613986565b509250929050565b6000826139d357506001612bb8565b816139e057506000612bb8565b81600181146139f65760028114613a0057613a1c565b6001915050612bb8565b60ff841115613a1157613a11613783565b50506001821b612bb8565b5060208310610133831016604e8410600b8410161715613a3f575081810a612bb8565b613a498383613981565b8060001904821115613a5d57613a5d613783565b029392505050565b600061352783836139c4565b600060208284031215613a8357600080fd5b61352782613263565b6000816000190483118215151615613aa657613aa6613783565b500290565b60006001600160401b03808316818516808303821115613acd57613acd613783565b01949350505050565b600064ffffffffff80841680613aee57613aee61376d565b92169190910692915050565b600064ffffffffff80831681851681830481118215151615613b1e57613b1e613783565b02949350505050565b600064ffffffffff80841680613b3f57613b3f61376d565b92169190910492915050565b634e487b7160e01b600052604160045260246000fd5b60008251613b73818460208701613891565b9190910192915050565b6000600019821415613b9157613b91613783565b5060010190565b600082613ba757613ba761376d565b50069056fe456967656e506f642e7665726966794f766572636f6d6d69747465645374616b426561636f6e436861696e50726f6f66732e76657269667956616c696461746f426561636f6e436861696e50726f6f66732e7665726966795769746864726177a26469706673582212201397755f24799e785bd5e07c1bec261405d0433e4478c74efc15395b8ad83a0164736f6c634300080c003300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000007fe7e9cc0f274d2435ad5d56d5fa73e47f6a23d800000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338000000000000000000000000000000000000000000000001ae361fc1451c0000

Deployed Bytecode

0x6080604052600436106101095760003560e01c806374cdd79811610095578063baa7145a11610064578063baa7145a14610378578063c49074421461038d578063c4d66de8146103ad578063ddf4639a146103cd578063ef8015711461040857600080fd5b806374cdd798146102d45780639b4e463414610308578063b08b41981461031b578063b18a69f61461033b57600080fd5b806332b58cd7116100dc57806332b58cd7146101e85780634665bcda1461022a578063507fa7f61461025e578063517355dd1461028057806351f07208146102b457600080fd5b80630b18ff661461010e5780631a5057be1461014b5780631e4158631461017f5780633106ab53146101b7575b600080fd5b34801561011a57600080fd5b5060335461012e906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015757600080fd5b5061012e7f0000000000000000000000007fe7e9cc0f274d2435ad5d56d5fa73e47f6a23d881565b34801561018b57600080fd5b5060345461019f906001600160401b031681565b6040516001600160401b039091168152602001610142565b3480156101c357600080fd5b506034546101d890600160401b900460ff1681565b6040519015158152602001610142565b3480156101f457600080fd5b5061021c7f000000000000000000000000000000000000000000000001ae361fc1451c000081565b604051908152602001610142565b34801561023657600080fd5b5061012e7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33881565b34801561026a57600080fd5b5061027e61027936600461327f565b61042f565b005b34801561028c57600080fd5b5061019f7f0000000000000000000000000000000000000000000000000000000737be760081565b3480156102c057600080fd5b5061027e6102cf36600461337c565b6108e5565b3480156102e057600080fd5b5061012e7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa81565b61027e610316366004613407565b610e62565b34801561032757600080fd5b5061027e61033636600461347a565b61100f565b34801561034757600080fd5b5061036b61035636600461350c565b60356020526000908152604090205460ff1681565b6040516101429190613544565b34801561038457600080fd5b5061027e611500565b34801561039957600080fd5b5061027e6103a8366004613584565b61161c565b3480156103b957600080fd5b5061027e6103c83660046135b0565b611702565b3480156103d957600080fd5b506101d86103e83660046135cd565b603660209081526000928352604080842090915290825290205460ff1681565b34801561041457600080fd5b5060335461019f90600160a01b90046001600160401b031681565b604051635ac86ab760e01b81526004808201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015610496573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ba9190613600565b156104e05760405162461bcd60e51b81526004016104d790613622565b60405180910390fd5b7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031663b13442716040518163ffffffff1660e01b8152600401602060405180830381865afa15801561053e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610562919061367f565b6033546040516372c1cc1b60e11b81526001600160a01b03918216600482015291169063e583983690602401602060405180830381865afa1580156105ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cf9190613600565b156106305760405162461bcd60e51b815260206004820152602b60248201527f456967656e506f642e6f6e6c794e6f7446726f7a656e3a20706f64206f776e6560448201526a391034b990333937bd32b760a91b60648201526084016104d7565b61063e8a6101400135611899565b6033546001600160401b03600160a01b9091048116908216116106735760405162461bcd60e51b81526004016104d79061369c565b60006106978787600181811061068b5761068b61373e565b90506020020135611899565b9050600064ffffffffff821660009081526035602052604090205460ff1660038111156106c6576106c661352e565b14156107685760405162461bcd60e51b81526020600482015260716024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206e657665722070726f76656e20746f2068617660648201527f65207769746864726177616c2063726564656e7469616c7320706f696e746564608482015270081d1bc81d1a1a5cc818dbdb9d1c9858dd607a1b60a482015260c4016104d7565b604051636c2d846360e11b81526001600160401b03851660048201526000907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b03169063d85b08c690602401602060405180830381865afa1580156107d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fc9190613754565b905061080a818e8a8a611900565b61081882828e8e8e8e612230565b60006108308989600381811061068b5761068b61373e565b905060006108428f6101200135611899565b905061085860206001600160401b038316613799565b61086e8d8d600781811061068b5761068b61373e565b6001600160401b0316116108b95760335464ffffffffff85166000908152603560205260409020546108b491849187918c916001600160a01b039091169060ff16612447565b6108d4565b6033546108d4908290849087906001600160a01b03166129d6565b505050505050505050505050505050565b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa15801561094d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109719190613600565b1561098e5760405162461bcd60e51b81526004016104d790613622565b60335486906001600160401b03600160a01b9091048116908216116109c55760405162461bcd60e51b81526004016104d79061369c565b64ffffffffff861660009081526035602052604081205460ff1660038111156109f0576109f061352e565b14610a995760405162461bcd60e51b815260206004820152606760248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a2056616c696461746f72206d757374206265206960648201527f6e61637469766520746f2070726f7665207769746864726177616c2063726564608482015266656e7469616c7360c81b60a482015260c4016104d7565b610aa1612b3d565b610aaa906137ad565b84846001818110610abd57610abd61373e565b9050602002013514610b4b5760405162461bcd60e51b815260206004820152604b60248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a2050726f6f66206973206e6f7420666f7220746860648201526a1a5cc8115a59d95b941bd960aa1b608482015260a4016104d7565b6000610b5b878760400135612b82565b90507f0000000000000000000000000000000000000000000000000000000737be76006001600160401b0316816001600160401b03161015610c625760405162461bcd60e51b815260206004820152608860248201527f456967656e506f642e766572696679436f72726563745769746864726177616c60448201527f43726564656e7469616c733a204554482076616c696461746f7227732062616c60648201527f616e6365206d7573742062652067726561746572207468616e206f722065717560848201527f616c20746f207468652072657374616b65642062616c616e636520706572207660a48201526730b634b230ba37b960c11b60c482015260e4016104d7565b604051636c2d846360e11b81526001600160401b03891660048201526000907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b03169063d85b08c690602401602060405180830381865afa158015610cd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf69190613754565b9050610d0e8882610d078a806137d1565b8a8a612230565b610d2a8882610d2060208b018b6137d1565b8b60400135612bbe565b64ffffffffff88166000908152603560205260409020805460ff1916600117905560345460ff600160401b90910416610d76576034805468ff00000000000000001916600160401b1790555b60405164ffffffffff891681527f2d0800bbc377ea54a08c5db6a87aafff5e3e9c8fead0eda110e40e0c104414499060200160405180910390a160335460405163103ebac760e01b81526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000001ae361fc1451c000060248201527f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3389091169063103ebac7906044015b600060405180830381600087803b158015610e3f57600080fd5b505af1158015610e53573d6000803e3d6000fd5b50505050505050505050505050565b336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3381614610eaa5760405162461bcd60e51b81526004016104d790613817565b346801bc16d674ec80000014610f365760405162461bcd60e51b8152602060048201526044602482018190527f456967656e506f642e7374616b653a206d75737420696e697469616c6c792073908201527f74616b6520666f7220616e792076616c696461746f72207769746820333220656064820152633a3432b960e11b608482015260a4016104d7565b7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa6001600160a01b031663228951186801bc16d674ec8000008787610f79612b3d565b8888886040518863ffffffff1660e01b8152600401610f9d969594939291906138bd565b6000604051808303818588803b158015610fb657600080fd5b505af1158015610fca573d6000803e3d6000fd5b50505050507f606865b7934a25d4aed43f6cdb426403353fa4b3009c4d228407474581b01e238585604051611000929190613925565b60405180910390a15050505050565b604051635ac86ab760e01b8152600360048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015611077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109b9190613600565b156110b85760405162461bcd60e51b81526004016104d790613622565b436110ce61c4e06001600160401b038516613941565b10156111445760405162461bcd60e51b815260206004820152604b6024820152600080516020613bad83398151915260448201527f653a2073706563696669656420626c6f636b4e756d62657220697320746f6f2060648201526a19985c881a5b881c185cdd60aa1b608482015260a4016104d7565b600164ffffffffff881660009081526035602052604090205460ff1660038111156111715761117161352e565b146111d25760405162461bcd60e51b81526020600482015260376024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206e6f742061637469766500000000000000000060648201526084016104d7565b60006111e2888860400135612b82565b90507f0000000000000000000000000000000000000000000000000000000737be76006001600160401b0316816001600160401b0316106112b35760405162461bcd60e51b815260206004820152606b6024820152600080516020613bad83398151915260448201527f653a2076616c696461746f7227732062616c616e6365206d757374206265206c60648201527f657373207468616e207468652072657374616b65642062616c616e636520706560848201526a39103b30b634b230ba37b960a91b60a482015260c4016104d7565b604051636c2d846360e11b81526001600160401b03841660048201526000907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b03169063d85b08c690602401602060405180830381865afa158015611323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113479190613754565b90506001600160401b03821661140f57600061136f8888600381811061068b5761068b61373e565b9050806001600160401b03166001146113f75760405162461bcd60e51b81526020600482015260506024820152600080516020613bad83398151915260448201527f653a2056616c696461746f72206d75737420626520736c617368656420746f2060648201526f1899481bdd995c98dbdb5b5a5d1d195960821b608482015260a4016104d7565b61140d8a836114068c806137d1565b8c8c612230565b505b61142b898261142160208c018c6137d1565b8c60400135612bbe565b64ffffffffff8916600081815260356020908152604091829020805460ff1916600217905590519182527f39436dbc3ba65889c15d38b42ce4be0e2da99723fdebaf0e12df341b5e6e5fd5910160405180910390a16033546040516331f657db60e11b81526001600160a01b039182166004820152602481018790527f000000000000000000000000000000000000000000000001ae361fc1451c000060448201527f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338909116906363ecafb690606401610e25565b6033546001600160a01b0316331461156b5760405162461bcd60e51b815260206004820152602860248201527f456967656e506f642e6f6e6c79456967656e506f644f776e65723a206e6f74206044820152673837b227bbb732b960c11b60648201526084016104d7565b603454600160401b900460ff16156115dd5760405162461bcd60e51b815260206004820152602f60248201527f456967656e506f642e6861734e6576657252657374616b65643a20726573746160448201526e1ada5b99c81a5cc8195b98589b1959608a1b60648201526084016104d7565b60338054600160a01b63ffffffff43160267ffffffffffffffff60a01b198216811790925561161a916001600160a01b0390811691161747612d1f565b565b336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33816146116645760405162461bcd60e51b81526004016104d790613817565b611672633b9aca0082613799565b6034805460009061168d9084906001600160401b0316613959565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550816001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e826040516116ec91815260200190565b60405180910390a26116fe8282612d1f565b5050565b600054610100900460ff16158080156117225750600054600160ff909116105b8061173c5750303b15801561173c575060005460ff166001145b61179f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104d7565b6000805460ff1916600117905580156117c2576000805461ff0019166101001790555b6001600160a01b0382166118355760405162461bcd60e51b815260206004820152603460248201527f456967656e506f642e696e697469616c697a653a20706f644f776e65722063616044820152736e6e6f74206265207a65726f206164647265737360601b60648201526084016104d7565b603380546001600160a01b0319166001600160a01b03841617905580156116fe576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b61190b600280613a65565b81146119855760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c4669656c647320686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b611991600d6002613a65565b6119a160c0850160a08601613a71565b6001600160401b031610611a195760405162461bcd60e51b81526020600482015260456024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b526f6f74496e64657820697320746f6f206064820152646c6172676560d81b608482015260a4016104d7565b611a2560046002613a65565b611a3560e0850160c08601613a71565b6001600160401b031610611aae5760405162461bcd60e51b81526020600482015260466024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c496e64657820697320746f6f606482015265206c6172676560d01b608482015260a4016104d7565b611aba600d6005613941565b611ac5906020613a8c565b611acf84806137d1565b905014611b4a5760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b48656164657250726f6f6620686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b611b55600480613941565b611b60906001613941565b611b6b906020613a8c565b611b7860208501856137d1565b905014611bf25760405162461bcd60e51b815260206004820152604e6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a207769746864726177616c50726f6f662068617320696e60648201526d0c6dee4e4cac6e840d8cadccee8d60931b608482015260a4016104d7565b611bfe60046003613941565b611c09906020613a8c565b611c1660608501856137d1565b905014611c965760405162461bcd60e51b81526020600482015260546024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20657865637574696f6e5061796c6f616450726f6f66206064820152730d0c2e640d2dcc6dee4e4cac6e840d8cadccee8d60631b608482015260a4016104d7565b611ca260036020613a8c565b611caf60408501856137d1565b905014611d235760405162461bcd60e51b81526020600482015260486024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20736c6f7450726f6f662068617320696e636f727265636064820152670e840d8cadccee8d60c31b608482015260a4016104d7565b611d2f60046020613a8c565b611d3c60808501856137d1565b905014611db75760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20626c6f636b4e756d62657250726f6f6620686173206960648201526e0dcc6dee4e4cac6e840d8cadccee8d608b1b608482015260a4016104d7565b6000611dc960c0850160a08601613a71565b6001600160401b031661a000179050611e26611de585806137d1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250899250505060e087013584612dad565b611e9a5760405162461bcd60e51b815260206004820152604b6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420626c6f636b20686561646572206d60648201526a32b935b63290383937b7b360a91b608482015260a4016104d7565b611ef0611eaa60408601866137d1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060e08a013593506101208a013592509050612dad565b611f5c5760405162461bcd60e51b81526020600482015260436024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420736c6f74206d65726b6c6520707260648201526237b7b360e91b608482015260a4016104d7565b6049611fb3611f6e60608701876137d1565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060e087013561016088013584612dad565b61202b5760405162461bcd60e51b815260206004820152604f6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420657865637574696f6e5061796c6f60648201526e30b21036b2b935b63290383937b7b360891b608482015260a4016104d7565b61208261203b60808701876137d1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101608701356101408801356006612dad565b6120f55760405162461bcd60e51b815260206004820152604a6024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c696420626c6f636b4e756d626572206d656064820152693935b63290383937b7b360b11b608482015260a4016104d7565b600061210760e0870160c08801613a71565b6001600160401b031661211c60046001613941565b600e901b1790506000612161868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612dc592505050565b90506121b461217360208901896137d1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050506101608901358385612dad565b6122265760405162461bcd60e51b81526020600482015260496024820152600080516020613bed83398151915260448201527f616c50726f6f66733a20496e76616c6964207769746864726177616c206d657260648201526835b63290383937b7b360b91b608482015260a4016104d7565b5050505050505050565b61223c60036002613a65565b81146122b55760405162461bcd60e51b815260206004820152604e6024820152600080516020613bcd83398151915260448201527f724669656c64733a2056616c696461746f72206669656c64732068617320696e60648201526d0c6dee4e4cac6e840d8cadccee8d60931b608482015260a4016104d7565b60056122c360286001613941565b6122cd9190613941565b6122d8906020613a8c565b83146123465760405162461bcd60e51b81526020600482015260436024820152600080516020613bcd83398151915260448201527f724669656c64733a2050726f6f662068617320696e636f7272656374206c656e6064820152620cee8d60eb1b608482015260a4016104d7565b600064ffffffffff871661235c60286001613941565b600b901b17905060006123a1848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612dc592505050565b90506123e786868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b9250859150869050612dad565b6122265760405162461bcd60e51b815260206004820152603d6024820152600080516020613bcd83398151915260448201527f724669656c64733a20496e76616c6964206d65726b6c652070726f6f6600000060648201526084016104d7565b6000600182600381111561245d5761245d61352e565b141561266d577f0000000000000000000000000000000000000000000000000000000737be76006001600160401b0316866001600160401b03161061254757633b9aca006124cb7f0000000000000000000000000000000000000000000000000000000737be760088613959565b6001600160401b03166124de9190613a8c565b603480549192507f0000000000000000000000000000000000000000000000000000000737be76009160009061251e9084906001600160401b0316613aab565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550612950565b603480548791906000906125659084906001600160401b0316613aab565b82546001600160401b039182166101009390930a9283029190920219909116179055506033546001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3388116916363ecafb6911686633b9aca006125ee8b7f0000000000000000000000000000000000000000000000000000000737be7600613959565b6001600160401b03166126019190613a8c565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915260448201526064015b600060405180830381600087803b15801561265057600080fd5b505af1158015612664573d6000803e3d6000fd5b50505050612950565b60028260038111156126815761268161352e565b14156128b0577f0000000000000000000000000000000000000000000000000000000737be76006001600160401b0316866001600160401b0316106127df57633b9aca006126ef7f0000000000000000000000000000000000000000000000000000000737be760088613959565b6001600160401b03166127029190613a8c565b603480549192507f0000000000000000000000000000000000000000000000000000000737be7600916000906127429084906001600160401b0316613aab565b82546001600160401b039182166101009390930a92830291909202199091161790555060335460405163103ebac760e01b81526001600160a01b0391821660048201527f000000000000000000000000000000000000000000000001ae361fc1451c000060248201527f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338919091169063103ebac790604401612636565b603480548791906000906127fd9084906001600160401b0316613aab565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031663103ebac7603360009054906101000a90046001600160a01b0316633b9aca00896001600160401b031661287f9190613a8c565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401612636565b60405162461bcd60e51b815260206004820152606360248201527f456967656e506f642e766572696679426561636f6e436861696e46756c6c576960448201527f746864726177616c3a2056414c494441544f525f53544154555320697320574960648201527f5448445241574e206f7220696e76616c69642056414c494441544f525f53544160848201526254555360e81b60a482015260c4016104d7565b64ffffffffff8516600081815260356020908152604091829020805460ff1916600317905581519283526001600160401b038916908301526001600160a01b038516917f7341859cc78ba6561939cd5245350631bfaddbc9a16ade2aa7d698c16e8f1d94910160405180910390a280156129ce576129ce8382612d1f565b505050505050565b64ffffffffff821660009081526036602090815260408083206001600160401b038816845290915290205460ff1615612a9d5760405162461bcd60e51b815260206004820152605c60248201527f456967656e506f642e5f70726f636573735061727469616c576974686472617760448201527f616c3a207061727469616c207769746864726177616c2068617320616c72656160648201527f6479206265656e2070726f76656e20666f72207468697320736c6f7400000000608482015260a4016104d7565b64ffffffffff821660008181526036602090815260408083206001600160401b03898116855290835292819020805460ff191660011790558051938452918616908301526001600160a01b038316917f56d746a6c4b72294c7b70b592e8e37d22c732ebd3f9fe9c8539d704b43a950b9910160405180910390a2612b3781612b32633b9aca006001600160401b038716613a8c565b612d1f565b50505050565b60408051600160f81b60208201526000602182015230606090811b6bffffffffffffffffffffffff1916602c8301529101604051602081830303815290604052905090565b600080612b90600485613ad6565b612b9b906040613afa565b64ffffffffff16905082811b6000612bb282611899565b93505050505b92915050565b6005612bcc60266001613941565b612bd69190613941565b612be1906020613a8c565b8214612c515760405162461bcd60e51b815260206004820152604460248201819052600080516020613bcd833981519152908201527f7242616c616e63653a2050726f6f662068617320696e636f7272656374206c656064820152630dccee8d60e31b608482015260a4016104d7565b6000612c5e600487613b27565b64ffffffffff16905080612c7460266001613941565b600c901b179050612cbf84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250899250869150859050612dad565b6129ce5760405162461bcd60e51b815260206004820152603e6024820152600080516020613bcd83398151915260448201527f7242616c616e63653a20496e76616c6964206d65726b6c652070726f6f66000060648201526084016104d7565b603354604051633036cd5360e21b81526001600160a01b03918216600482015283821660248201527f0000000000000000000000007fe7e9cc0f274d2435ad5d56d5fa73e47f6a23d89091169063c0db354c9083906044016000604051808303818588803b158015612d9057600080fd5b505af1158015612da4573d6000803e3d6000fd5b50505050505050565b600083612dbb868585613072565b1495945050505050565b60008060028351612dd69190613799565b90506000816001600160401b03811115612df257612df2613b4b565b604051908082528060200260200182016040528015612e1b578160200160208202803683370190505b50905060005b82811015612f2257600285612e368383613a8c565b81518110612e4657612e4661373e565b602002602001015186836002612e5c9190613a8c565b612e67906001613941565b81518110612e7757612e7761373e565b6020026020010151604051602001612e99929190918252602082015260400190565b60408051601f1981840301815290829052612eb391613b61565b602060405180830381855afa158015612ed0573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190612ef39190613754565b828281518110612f0557612f0561373e565b602090810291909101015280612f1a81613b7d565b915050612e21565b50612f2e600283613799565b91505b811561304e5760005b8281101561303b57600282612f4f8383613a8c565b81518110612f5f57612f5f61373e565b602002602001015183836002612f759190613a8c565b612f80906001613941565b81518110612f9057612f9061373e565b6020026020010151604051602001612fb2929190918252602082015260400190565b60408051601f1981840301815290829052612fcc91613b61565b602060405180830381855afa158015612fe9573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061300c9190613754565b82828151811061301e5761301e61373e565b60209081029190910101528061303381613b7d565b915050612f3a565b50613047600283613799565b9150612f31565b806000815181106130615761306161373e565b602002602001015192505050919050565b6000835160001415801561309157506020845161308f9190613b98565b155b6131205760405162461bcd60e51b815260206004820152605460248201527f4d65726b6c652e70726f63657373496e636c7573696f6e50726f6f665368613260448201527f35363a2070726f6f66206c656e6774682073686f756c642062652061206e6f6e60648201527316bd32b9379036bab63a34b836329037b310199960611b608482015260a4016104d7565b604080516020808201909252848152905b855181116131b457613144600285613b98565b613177578151600052808601516020526020826040600060026107d05a03fa61316c57600080fd5b6002840493506131a2565b8086015160005281516020526020826040600060026107d05a03fa61319b57600080fd5b6002840493505b6131ad602082613941565b9050613131565b5051949350505050565b600061018082840312156131d157600080fd5b50919050565b60008083601f8401126131e957600080fd5b5081356001600160401b0381111561320057600080fd5b60208301915083602082850101111561321857600080fd5b9250929050565b60008083601f84011261323157600080fd5b5081356001600160401b0381111561324857600080fd5b6020830191508360208260051b850101111561321857600080fd5b80356001600160401b038116811461327a57600080fd5b919050565b600080600080600080600080600060c08a8c03121561329d57600080fd5b89356001600160401b03808211156132b457600080fd5b6132c08d838e016131be565b9a5060208c01359150808211156132d657600080fd5b6132e28d838e016131d7565b909a50985060408c01359150808211156132fb57600080fd5b6133078d838e0161321f565b909850965060608c013591508082111561332057600080fd5b5061332d8c828d0161321f565b90955093505060808a0135915061334660a08b01613263565b90509295985092959850929598565b803564ffffffffff8116811461327a57600080fd5b6000606082840312156131d157600080fd5b60008060008060006080868803121561339457600080fd5b61339d86613263565b94506133ab60208701613355565b935060408601356001600160401b03808211156133c757600080fd5b6133d389838a0161336a565b945060608801359150808211156133e957600080fd5b506133f68882890161321f565b969995985093965092949392505050565b60008060008060006060868803121561341f57600080fd5b85356001600160401b038082111561343657600080fd5b61344289838a016131d7565b9097509550602088013591508082111561345b57600080fd5b50613468888289016131d7565b96999598509660400135949350505050565b60008060008060008060a0878903121561349357600080fd5b61349c87613355565b955060208701356001600160401b03808211156134b857600080fd5b6134c48a838b0161336a565b965060408901359150808211156134da57600080fd5b506134e789828a0161321f565b9095509350506060870135915061350060808801613263565b90509295509295509295565b60006020828403121561351e57600080fd5b61352782613355565b9392505050565b634e487b7160e01b600052602160045260246000fd5b602081016004831061356657634e487b7160e01b600052602160045260246000fd5b91905290565b6001600160a01b038116811461358157600080fd5b50565b6000806040838503121561359757600080fd5b82356135a28161356c565b946020939093013593505050565b6000602082840312156135c257600080fd5b81356135278161356c565b600080604083850312156135e057600080fd5b6135e983613355565b91506135f760208401613263565b90509250929050565b60006020828403121561361257600080fd5b8151801515811461352757600080fd5b6020808252603e908201527f456967656e506f642e6f6e6c795768656e4e6f745061757365643a20696e646560408201527f782069732070617573656420696e20456967656e506f644d616e616765720000606082015260800190565b60006020828403121561369157600080fd5b81516135278161356c565b60208082526076908201527f456967656e506f642e70726f6f664973466f7256616c6964426c6f636b4e756d60408201527f6265723a20626561636f6e20636861696e2070726f6f66206d7573742062652060608201527f666f7220626c6f636b206e756d626572206166746572206d6f7374526563656e6080820152753a2bb4ba34323930bbb0b6213637b1b5a73ab6b132b960511b60a082015260c00190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561376657600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000826137a8576137a861376d565b500490565b805160208083015191908110156131d15760001960209190910360031b1b16919050565b6000808335601e198436030181126137e857600080fd5b8301803591506001600160401b0382111561380257600080fd5b60200191503681900382131561321857600080fd5b60208082526031908201527f456967656e506f642e6f6e6c79456967656e506f644d616e616765723a206e6f6040820152703a1032b4b3b2b72837b226b0b730b3b2b960791b606082015260800190565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60005b838110156138ac578181015183820152602001613894565b83811115612b375750506000910152565b6080815260006138d160808301888a613868565b828103602084015286518082526138ef816020840160208b01613891565b601f01601f191601828103602090810160408501526139119082018688613868565b915050826060830152979650505050505050565b602081526000613939602083018486613868565b949350505050565b6000821982111561395457613954613783565b500190565b60006001600160401b038381169083168181101561397957613979613783565b039392505050565b600181815b808511156139bc5781600019048211156139a2576139a2613783565b808516156139af57918102915b93841c9390800290613986565b509250929050565b6000826139d357506001612bb8565b816139e057506000612bb8565b81600181146139f65760028114613a0057613a1c565b6001915050612bb8565b60ff841115613a1157613a11613783565b50506001821b612bb8565b5060208310610133831016604e8410600b8410161715613a3f575081810a612bb8565b613a498383613981565b8060001904821115613a5d57613a5d613783565b029392505050565b600061352783836139c4565b600060208284031215613a8357600080fd5b61352782613263565b6000816000190483118215151615613aa657613aa6613783565b500290565b60006001600160401b03808316818516808303821115613acd57613acd613783565b01949350505050565b600064ffffffffff80841680613aee57613aee61376d565b92169190910692915050565b600064ffffffffff80831681851681830481118215151615613b1e57613b1e613783565b02949350505050565b600064ffffffffff80841680613b3f57613b3f61376d565b92169190910492915050565b634e487b7160e01b600052604160045260246000fd5b60008251613b73818460208701613891565b9190910192915050565b6000600019821415613b9157613b91613783565b5060010190565b600082613ba757613ba761376d565b50069056fe456967656e506f642e7665726966794f766572636f6d6d69747465645374616b426561636f6e436861696e50726f6f66732e76657269667956616c696461746f426561636f6e436861696e50726f6f66732e7665726966795769746864726177a26469706673582212201397755f24799e785bd5e07c1bec261405d0433e4478c74efc15395b8ad83a0164736f6c634300080c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000007fe7e9cc0f274d2435ad5d56d5fa73e47f6a23d800000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338000000000000000000000000000000000000000000000001ae361fc1451c0000

-----Decoded View---------------
Arg [0] : _ethPOS (address): 0x00000000219ab540356cBB839Cbe05303d7705Fa
Arg [1] : _delayedWithdrawalRouter (address): 0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8
Arg [2] : _eigenPodManager (address): 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338
Arg [3] : _REQUIRED_BALANCE_WEI (uint256): 31000000000000000000

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Arg [1] : 0000000000000000000000007fe7e9cc0f274d2435ad5d56d5fa73e47f6a23d8
Arg [2] : 00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338
Arg [3] : 000000000000000000000000000000000000000000000001ae361fc1451c0000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.