Hoodi Testnet

Contract

0x5ff3782820Fc06cdF5a9ded897a778a6f0840b85
Source Code Source Code

Overview

ETH Balance

0.24381566788754529 ETH

More Info

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Amount
Transfer16944602025-11-25 16:18:2454 days ago1764087504IN
0x5ff37828...6f0840b85
0.01239337 ETH0.000021181.0056847
Transfer16489552025-11-18 22:15:1261 days ago1763504112IN
0x5ff37828...6f0840b85
0.01067539 ETH0.000021641.02754533
Transfer16423892025-11-17 22:34:1262 days ago1763418852IN
0x5ff37828...6f0840b85
0.0055548 ETH0.000022131.05088577
Transfer16078902025-11-12 19:46:3667 days ago1762976796IN
0x5ff37828...6f0840b85
0.00937099 ETH0.000021261.00979912
Transfer15899992025-11-10 3:38:0069 days ago1762745880IN
0x5ff37828...6f0840b85
0.00280212 ETH0.000022681.07684964
Transfer15379402025-11-02 7:30:2477 days ago1762068624IN
0x5ff37828...6f0840b85
0.01619779 ETH0.00001990.94506108
Transfer15369502025-11-02 4:04:3677 days ago1762056276IN
0x5ff37828...6f0840b85
0.03708501 ETH0.000021541.02292578
Transfer15310892025-11-01 7:24:2478 days ago1761981864IN
0x5ff37828...6f0840b85
0.06173309 ETH0.000019320.91763912
Transfer15296752025-11-01 2:27:3678 days ago1761964056IN
0x5ff37828...6f0840b85
0.0522916 ETH0.000022821.08373612

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Amount
Beacon Chain Dep...20577502026-01-18 17:13:365 hrs ago1768756416
0x5ff37828...6f0840b85
0 ETH
Beacon Chain Dep...20577452026-01-18 17:12:365 hrs ago1768756356
0x5ff37828...6f0840b85
0 ETH
Beacon Chain Dep...20577392026-01-18 17:11:125 hrs ago1768756272
0x5ff37828...6f0840b85
0 ETH
Beacon Chain Dep...20577312026-01-18 17:09:125 hrs ago1768756152
0x5ff37828...6f0840b85
0 ETH
Transfer20540602026-01-18 3:46:0019 hrs ago1768707960
0x5ff37828...6f0840b85
0.00379491 ETH
Transfer20515432026-01-17 18:35:1228 hrs ago1768674912
0x5ff37828...6f0840b85
0.00642036 ETH
Transfer20493782026-01-17 10:39:2436 hrs ago1768646364
0x5ff37828...6f0840b85
0.00399363 ETH
Transfer20463542026-01-16 23:35:2447 hrs ago1768606524
0x5ff37828...6f0840b85
0.00985999 ETH
Beacon Chain Dep...20439532026-01-16 14:53:002 days ago1768575180
0x5ff37828...6f0840b85
0 ETH
Withdraw20439532026-01-16 14:53:002 days ago1768575180
0x5ff37828...6f0840b85
0 ETH
Transfer20332532026-01-14 23:51:123 days ago1768434672
0x5ff37828...6f0840b85
0.00321853 ETH
Transfer20318752026-01-14 18:53:124 days ago1768416792
0x5ff37828...6f0840b85
0.01014675 ETH
Transfer20204472026-01-13 1:50:125 days ago1768269012
0x5ff37828...6f0840b85
0.02552148 ETH
Transfer20108232026-01-11 15:30:247 days ago1768145424
0x5ff37828...6f0840b85
0.02942315 ETH
Transfer20062502026-01-10 23:13:127 days ago1768086792
0x5ff37828...6f0840b85
0.02203672 ETH
Fund20043602026-01-10 16:30:128 days ago1768062612
0x5ff37828...6f0840b85
31 ETH
Fund20043402026-01-10 16:26:128 days ago1768062372
0x5ff37828...6f0840b85
1 ETH
Accept Ownership20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Owner20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Depositor20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Is Ossified20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Pending Owner20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Transfer Ownersh...20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
Fund20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
1 ETH
Initialize20043142026-01-10 16:20:488 days ago1768062048
0x5ff37828...6f0840b85
0 ETH
View All Internal Transactions
Loading...
Loading
Produced Blocks

 Latest 2 blocks produced

Block Transaction Difficulty Gas Used Reward
15789832025-11-08 10:38:2471 days ago1762598304430.00 TH58,021,509 (96.70%)
0.003584685698731239 ETH
15261042025-10-31 13:53:2479 days ago1761918804540.00 TH59,367,048 (98.95%)
0.032126798433897141 ETH

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StakingVault

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// See contracts/COMPILERS.md
pragma solidity 0.8.25;

import {OwnableUpgradeable} from "contracts/openzeppelin/5.2/upgradeable/access/OwnableUpgradeable.sol";
import {Ownable2StepUpgradeable} from "contracts/openzeppelin/5.2/upgradeable/access/Ownable2StepUpgradeable.sol";
import {TriggerableWithdrawals} from "contracts/common/lib/TriggerableWithdrawals.sol";
import {IDepositContract} from "contracts/common/interfaces/IDepositContract.sol";

import {PinnedBeaconUtils} from "./lib/PinnedBeaconUtils.sol";
import {IStakingVault} from "./interfaces/IStakingVault.sol";

/**
 * @title StakingVault
 * @author Lido
 * @notice
 *
 * StakingVault is a contract which is designed to be used as withdrawal credentials
 * to stake ETH with a designated node operator, while being able to mint stETH.
 *
 * The StakingVault can be used as a backing for minting new stETH through integration with the VaultHub.
 * When minting stETH backed by the StakingVault, the VaultHub designates a portion of the StakingVault's
 * total value as locked, which cannot be withdrawn by the owner. This locked portion represents the
 * collateral for the minted stETH.
 *
 * PinnedBeaconProxy
 * The contract is designed as an extended beacon proxy implementation, allowing individual StakingVault instances
 * to be ossified (pinned) to prevent future upgrades. The implementation is petrified (non-initializable)
 * and contains immutable references to the beacon chain deposit contract.
 */
contract StakingVault is IStakingVault, Ownable2StepUpgradeable {
    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            CONSTANTS                         │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Version of the contract on the implementation
     *         The implementation is petrified to this version
     */
    uint64 private constant _VERSION = 1;

    /**
     * @notice The type of withdrawal credentials for the validators deposited from this `StakingVault`.
     */
    uint256 private constant WC_0X02_PREFIX = 0x02 << 248;

    /**
     * @notice The length of the public key in bytes
     */
    uint256 private constant PUBLIC_KEY_LENGTH = 48;

    /**
     * @notice Storage offset slot for ERC-7201 namespace
     *         The storage namespace is used to prevent upgrade collisions
     *         `keccak256(abi.encode(uint256(keccak256("Lido.Vaults.StakingVault")) - 1)) & ~bytes32(uint256(0xff))`
     */
    bytes32 private constant ERC7201_SLOT = 0x2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b100;

    /**
     * @notice Address of `BeaconChainDepositContract`
     *         Set immutably in the constructor to avoid storage costs
     */
    IDepositContract public immutable DEPOSIT_CONTRACT;

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            STATE                             │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @dev ERC-7201: Namespaced Storage Layout
     */
    struct Storage {
        address nodeOperator;
        address depositor;
        bool beaconChainDepositsPaused;
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            INITIALIZATION                    │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @dev Fixes the deposit contract address. Disables reinitialization of the implementation.
     */
    constructor(address _beaconChainDepositContract) {
        if (_beaconChainDepositContract == address(0)) revert ZeroArgument("_beaconChainDepositContract");
        DEPOSIT_CONTRACT = IDepositContract(_beaconChainDepositContract);
        _disableInitializers();
    }

    /**
     * @notice Initializes `StakingVault` with an owner, node operator, and depositor
     * @param _owner Address of the owner
     * @param _nodeOperator Address of the node operator
     * @param _depositor Address of the depositor
     */
    function initialize(address _owner, address _nodeOperator, address _depositor) external initializer {
        if (_nodeOperator == address(0)) revert ZeroArgument("_nodeOperator");

        __Ownable_init(_owner);
        __Ownable2Step_init();
        _setDepositor(_depositor);
        _storage().nodeOperator = _nodeOperator;

        emit NodeOperatorSet(_nodeOperator);
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            VIEW FUNCTIONS                    │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Returns the highest version that has been initialized as uint64
     */
    function getInitializedVersion() external view returns (uint64) {
        return _getInitializedVersion();
    }

    /**
     * @notice Returns the version of the contract as uint64
     */
    function version() external pure returns (uint64) {
        return _VERSION;
    }

    /**
     * @notice Returns owner of the contract
     * @dev Fixes solidity interface inference
     */
    function owner() public view override(IStakingVault, OwnableUpgradeable) returns (address) {
        return OwnableUpgradeable.owner();
    }

    /**
     * @notice Returns the pending owner of the contract
     * @dev Fixes solidity interface inference
     */
    function pendingOwner() public view override(IStakingVault, Ownable2StepUpgradeable) returns (address) {
        return Ownable2StepUpgradeable.pendingOwner();
    }

    /**
     * @notice Returns the node operator address
     * @return Address of the node operator
     */
    function nodeOperator() public view returns (address) {
        return _storage().nodeOperator;
    }

    /**
     * @notice Returns the depositor address
     * @return Address of the depositor
     */
    function depositor() public view returns (address) {
        return _storage().depositor;
    }

    /**
     * @notice Returns whether the vault is ossified
     * @return True if the vault is ossified, false otherwise
     */
    function isOssified() public view returns (bool) {
        return PinnedBeaconUtils.ossified();
    }

    /**
     * @notice Returns the 0x02-type withdrawal credentials for the validators deposited from this `StakingVault`
     *         All consensus layer rewards are sent to this contract. Only 0x02-type withdrawal credentials are supported
     * @return Bytes32 value of the withdrawal credentials
     */
    function withdrawalCredentials() public view returns (bytes32) {
        return bytes32(WC_0X02_PREFIX | uint160(address(this)));
    }

    /**
     * @notice Calculates the total fee required for EIP-7002 withdrawals for a given number of validator keys
     * @param _numberOfKeys Number of validators' public keys
     * @return Total fee amount to pass as `msg.value` (wei)
     * @dev    The fee may change from block to block
     */
    function calculateValidatorWithdrawalFee(uint256 _numberOfKeys) external view returns (uint256) {
        return _numberOfKeys * TriggerableWithdrawals.getWithdrawalRequestFee();
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            BALANCE OPERATIONS                │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @dev Transfers ether directly to the `StakingVault`
     */
    receive() external payable {}

    /**
     * @notice Funds the `StakingVault` with ether
     */
    function fund() external payable onlyOwner {
        if (msg.value == 0) revert ZeroArgument("msg.value");

        emit EtherFunded(msg.value);
    }

    /**
     * @notice Withdraws ether from the vault
     * @param _recipient Address to send the ether to
     * @param _ether Amount of ether to withdraw
     */
    function withdraw(address _recipient, uint256 _ether) external onlyOwner {
        if (_recipient == address(0)) revert ZeroArgument("_recipient");
        if (_ether == 0) revert ZeroArgument("_ether");
        if (_ether > address(this).balance) revert InsufficientBalance(address(this).balance, _ether);

        (bool success, ) = _recipient.call{value: _ether}("");
        if (!success) revert TransferFailed(_recipient, _ether);

        emit EtherWithdrawn(_recipient, _ether);
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            BEACON CHAIN DEPOSITS             │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Returns whether the beacon chain deposits are paused
     */
    function beaconChainDepositsPaused() external view returns (bool) {
        return _storage().beaconChainDepositsPaused;
    }

    /**
     * @notice Pauses deposits to beacon chain
     */
    function pauseBeaconChainDeposits() external onlyOwner {
        Storage storage $ = _storage();
        if ($.beaconChainDepositsPaused) revert BeaconChainDepositsAlreadyPaused();

        $.beaconChainDepositsPaused = true;

        emit BeaconChainDepositsPaused();
    }

    /**
     * @notice Resumes deposits to beacon chain
     */
    function resumeBeaconChainDeposits() external onlyOwner {
        Storage storage $ = _storage();
        if (!$.beaconChainDepositsPaused) revert BeaconChainDepositsAlreadyResumed();

        $.beaconChainDepositsPaused = false;

        emit BeaconChainDepositsResumed();
    }

    /**
     * @notice Performs deposits to the beacon chain
     * @param _deposits Array of validator deposits
     */
    function depositToBeaconChain(Deposit[] calldata _deposits) external {
        if (_deposits.length == 0) revert ZeroArgument("_deposits");
        Storage storage $ = _storage();
        if ($.beaconChainDepositsPaused) revert BeaconChainDepositsOnPause();
        if (msg.sender != $.depositor) revert SenderNotDepositor();

        uint256 numberOfDeposits = _deposits.length;

        uint256 totalAmount;
        for (uint256 i = 0; i < numberOfDeposits; i++) {
            totalAmount += _deposits[i].amount;
        }

        if (totalAmount > address(this).balance) revert InsufficientBalance(address(this).balance, totalAmount);

        bytes memory withdrawalCredentials_ = bytes.concat(withdrawalCredentials());

        for (uint256 i = 0; i < numberOfDeposits; i++) {
            Deposit calldata deposit = _deposits[i];

            DEPOSIT_CONTRACT.deposit{value: deposit.amount}(
                deposit.pubkey,
                withdrawalCredentials_,
                deposit.signature,
                deposit.depositDataRoot
            );
        }

        emit DepositedToBeaconChain(numberOfDeposits, totalAmount);
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │          BEACON CHAIN WITHDRAWALS            │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Requests node operator to exit validators from the beacon chain
     *         It does not directly trigger exits - node operators must monitor for these events and handle the exits
     * @param _pubkeys Concatenated validator public keys, each 48 bytes long
     */
    function requestValidatorExit(bytes calldata _pubkeys) external onlyOwner {
        if (_pubkeys.length == 0) revert ZeroArgument("_pubkeys");
        if (_pubkeys.length % PUBLIC_KEY_LENGTH != 0) {
            revert InvalidPubkeysLength();
        }

        uint256 keysCount = _pubkeys.length / PUBLIC_KEY_LENGTH;
        for (uint256 i = 0; i < keysCount; i++) {
            bytes memory pubkey = _pubkeys[i * PUBLIC_KEY_LENGTH:(i + 1) * PUBLIC_KEY_LENGTH];
            emit ValidatorExitRequested(/* indexed */ pubkey, pubkey);
        }
    }

    /**
     * @notice Triggers validator withdrawals from the beacon chain using EIP-7002 triggerable withdrawals.
     *         A general-purpose function for withdrawing ether from the beacon chain by the owner.
     *         If the amount of ether to withdraw is not specified, the full balance of the validator is withdrawn.
     * @param _pubkeys Concatenated validators public keys, each 48 bytes long
     * @param _amounts Amounts of ether to withdraw. If array is empty or amount value is zero, triggers full withdrawals.
     * @param _excessRefundRecipient Address to receive any excess withdrawal fee
     * @dev    The caller must provide sufficient fee via msg.value to cover the withdrawal request costs
     * @dev    You can use `calculateValidatorWithdrawalFee` to calculate the fee but it's accurate only for the block
     *         it's called. The fee may change from block to block, so it's recommended to send fee with some surplus.
     *         The excess amount will be refunded.
     */
    function triggerValidatorWithdrawals(
        bytes calldata _pubkeys,
        uint64[] calldata _amounts,
        address _excessRefundRecipient
    ) external payable onlyOwner {
        if (msg.value == 0) revert ZeroArgument("msg.value");
        if (_pubkeys.length == 0) revert ZeroArgument("_pubkeys");
        if (_pubkeys.length % PUBLIC_KEY_LENGTH != 0) revert InvalidPubkeysLength();

        // If amounts array is not empty, validate its length matches pubkeys
        if (_amounts.length > 0 && _pubkeys.length / PUBLIC_KEY_LENGTH != _amounts.length) {
            revert PubkeyLengthDoesNotMatchAmountLength();
        }

        // If the refund recipient is not set, use the sender as the refund recipient
        if (_excessRefundRecipient == address(0)) _excessRefundRecipient = msg.sender;

        uint256 feePerRequest = TriggerableWithdrawals.getWithdrawalRequestFee();
        uint256 totalFee = (_pubkeys.length / PUBLIC_KEY_LENGTH) * feePerRequest;
        if (msg.value < totalFee) revert InsufficientValidatorWithdrawalFee(msg.value, totalFee);

        // If amounts array is empty, trigger full withdrawals, otherwise use amount-driven withdrawal types
        if (_amounts.length == 0) {
            TriggerableWithdrawals.addFullWithdrawalRequests(_pubkeys, feePerRequest);
        } else {
            TriggerableWithdrawals.addWithdrawalRequests(_pubkeys, _amounts, feePerRequest);
        }

        uint256 excess = msg.value - totalFee;
        if (excess > 0) {
            (bool success, ) = _excessRefundRecipient.call{value: excess}("");
            if (!success) revert TransferFailed(_excessRefundRecipient, excess);
        }

        emit ValidatorWithdrawalsTriggered(_pubkeys, _amounts, excess, _excessRefundRecipient);
    }

    /**
     * @notice Triggers EIP-7002 validator exits by the node operator.
     *         Because the node operator cannot ensure that all the associated validators are under control,
     *         the node operator has the ability to forcefully eject validators.
     * @param _pubkeys Concatenated validators public keys, each 48 bytes long
     * @param _refundRecipient Address to receive the fee refund, if zero, refunds go to msg.sender
     * @dev    The caller must provide sufficient fee via msg.value to cover the withdrawal request costs
     * @dev    Use `calculateValidatorWithdrawalFee` to calculate the fee
     */
    function ejectValidators(bytes calldata _pubkeys, address _refundRecipient) external payable {
        if (msg.value == 0) revert ZeroArgument("msg.value");
        if (_pubkeys.length == 0) revert ZeroArgument("_pubkeys");
        if (_pubkeys.length % PUBLIC_KEY_LENGTH != 0) revert InvalidPubkeysLength();
        if (msg.sender != _storage().nodeOperator) revert SenderNotNodeOperator();

        // If the refund recipient is not set, use the sender as the refund recipient
        if (_refundRecipient == address(0)) _refundRecipient = msg.sender;

        uint256 feePerRequest = TriggerableWithdrawals.getWithdrawalRequestFee();
        uint256 totalFee = (_pubkeys.length / PUBLIC_KEY_LENGTH) * feePerRequest;
        if (msg.value < totalFee) revert InsufficientValidatorWithdrawalFee(msg.value, totalFee);

        TriggerableWithdrawals.addFullWithdrawalRequests(_pubkeys, feePerRequest);

        uint256 excess = msg.value - totalFee;
        if (excess > 0) {
            (bool success, ) = _refundRecipient.call{value: excess}("");
            if (!success) revert TransferFailed(_refundRecipient, excess);
        }

        emit ValidatorEjectionsTriggered(_pubkeys, excess, _refundRecipient);
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │           ADMINISTRATIVE FUNCTIONS           │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Accepts the pending owner
     * @dev Fixes solidity interface inference
     * @dev Can only be called by the pending owner
     */
    function acceptOwnership() public override(IStakingVault, Ownable2StepUpgradeable) {
        Ownable2StepUpgradeable.acceptOwnership();
    }

    /**
     * @notice Transfers the ownership of the contract to a new owner
     * @param _newOwner Address of the new owner
     * @dev Fixes solidity interface inference
     * @dev Can only be called by the owner
     */
    function transferOwnership(address _newOwner) public override(IStakingVault, Ownable2StepUpgradeable) {
        Ownable2StepUpgradeable.transferOwnership(_newOwner);
    }

    /**
     * @notice Sets the depositor address
     * @param _depositor Address of the new depositor
     */
    function setDepositor(address _depositor) external onlyOwner {
        _setDepositor(_depositor);
    }

    /**
     * @notice Ossifies the current implementation. WARNING: This operation is irreversible.
     * @dev vault can't be connected to the hub after ossification
     */
    function ossify() external onlyOwner {
        if (isOssified()) revert VaultOssified();

        PinnedBeaconUtils.ossify();
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │            INTERNAL FUNCTIONS                │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @dev Returns the storage struct for the ERC-7201 namespace
     * @return $ storage struct for the ERC-7201 namespace
     */
    function _storage() private pure returns (Storage storage $) {
        assembly {
            $.slot := ERC7201_SLOT
        }
    }

    /**
     * @dev Sets the depositor address in the `StakingVault`
     * @param _depositor Address of the new depositor
     */
    function _setDepositor(address _depositor) internal {
        if (_depositor == address(0)) revert ZeroArgument("_depositor");
        if (_depositor == _storage().depositor) revert NewDepositorSameAsPrevious();
        address previousDepositor = _storage().depositor;
        _storage().depositor = _depositor;
        emit DepositorSet(previousDepositor, _depositor);
    }

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │                EVENTS                        │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Emitted when ether is funded to the `StakingVault`
     * @param amount Amount of ether funded
     */
    event EtherFunded(uint256 amount);

    /**
     * @notice Emitted when ether is withdrawn from the `StakingVault`
     * @param recipient Address that received the ether
     * @param amount Amount of ether withdrawn
     */
    event EtherWithdrawn(address indexed recipient, uint256 amount);

    /**
     * @notice Emitted when the node operator is set in the `StakingVault`
     * @param nodeOperator Address of the node operator
     */
    event NodeOperatorSet(address indexed nodeOperator);

    /**
     * @notice Emitted when the depositor is set in the `StakingVault`
     * @param previousDepositor Previous depositor
     * @param newDepositor New depositor
     */
    event DepositorSet(address indexed previousDepositor, address indexed newDepositor);

    /**
     * @notice Emitted when the beacon chain deposits are paused
     */
    event BeaconChainDepositsPaused();

    /**
     * @notice Emitted when the beacon chain deposits are resumed
     */
    event BeaconChainDepositsResumed();

    /**
     * @notice Emitted when ether is deposited to `DepositContract`.
     * @param _deposits Number of validator deposits made.
     * @param _totalAmount Total amount of ether deposited.
     */
    event DepositedToBeaconChain(uint256 _deposits, uint256 _totalAmount);

    /**
     * @notice Emitted when vault owner requests node operator to exit validators from the beacon chain
     * @param pubkey Indexed public key of the validator to exit
     * @param pubkeyRaw Raw public key of the validator to exit
     * @dev    Signals to node operators that they should exit this validator from the beacon chain
     */
    event ValidatorExitRequested(bytes indexed pubkey, bytes pubkeyRaw);

    /**
     * @notice Emitted when validator withdrawals are requested via EIP-7002
     * @param pubkeys Concatenated public keys of the validators to withdraw
     * @param amounts Amounts of ether to withdraw per validator
     * @param refundRecipient Address to receive any excess withdrawal fee
     * @param excess Amount of excess fee refunded to recipient
     */
    event ValidatorWithdrawalsTriggered(
        bytes pubkeys,
        uint64[] amounts,
        uint256 excess,
        address indexed refundRecipient
    );

    /**
     * @notice Emitted when validator ejections are triggered
     * @param pubkeys Concatenated public keys of the validators to eject
     * @param excess Amount of excess fee refunded to recipient
     * @param refundRecipient Address to receive any excess withdrawal fee
     */
    event ValidatorEjectionsTriggered(
        bytes pubkeys,
        uint256 excess,
        address indexed refundRecipient
    );

    /*
     * ╔══════════════════════════════════════════════════╗
     * ║ ┌──────────────────────────────────────────────┐ ║
     * ║ │                ERRORS                        │ ║
     * ║ └──────────────────────────────────────────────┘ ║
     * ╚══════════════════════════════════════════════════╝
     */

    /**
     * @notice Thrown when an invalid zero value is passed
     * @param name Name of the argument that was zero
     */
    error ZeroArgument(string name);

    /**
     * @notice Thrown when the balance of the vault is insufficient
     * @param _balance Balance of the vault
     * @param _required Amount of ether required
     */
    error InsufficientBalance(uint256 _balance, uint256 _required);

    /**
     * @notice Thrown when the transfer of ether to a recipient fails
     * @param recipient Address that was supposed to receive the transfer
     * @param amount Amount that failed to transfer
     */
    error TransferFailed(address recipient, uint256 amount);

    /**
     * @notice Thrown when the new depositor is the same as the previous depositor
     */
    error NewDepositorSameAsPrevious();

    /**
     * @notice Thrown when the beacon chain deposits are already paused
     */
    error BeaconChainDepositsAlreadyPaused();

    /**
     * @notice Thrown when the beacon chain deposits are already resumed
     */
    error BeaconChainDepositsAlreadyResumed();

    /**
     * @notice Thrown when the beacon chain deposits are on pause
     */
    error BeaconChainDepositsOnPause();

    /**
     * @notice Thrown when the sender is not set as the depositor
     */
    error SenderNotDepositor();

    /**
     * @notice Thrown when the sender is not the node operator
     */
    error SenderNotNodeOperator();

    /**
     * @notice Thrown when the length of the validator public keys is invalid
     */
    error InvalidPubkeysLength();

    /**
     * @notice Thrown when the validator withdrawal fee is insufficient
     * @param _passed Amount of ether passed to the function
     * @param _required Amount of ether required to cover the fee
     */
    error InsufficientValidatorWithdrawalFee(uint256 _passed, uint256 _required);

    /**
     * @notice Thrown when the vault is already ossified
     */
    error VaultOssified();

    /**
     * @notice Thrown when the length of the validator public keys does not match the length of the amounts
     */
    error PubkeyLengthDoesNotMatchAmountLength();
}

File 2 of 15 : IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)

pragma solidity ^0.8.20;

/**
 * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
 */
interface IERC1967 {
    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Emitted when the beacon is changed.
     */
    event BeaconUpgraded(address indexed beacon);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {UpgradeableBeacon} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/ERC1967/ERC1967Utils.sol)

pragma solidity ^0.8.22;

import {IBeacon} from "../beacon/IBeacon.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";

/**
 * @dev This library provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots.
 */
library ERC1967Utils {
    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev The `implementation` of the proxy is invalid.
     */
    error ERC1967InvalidImplementation(address implementation);

    /**
     * @dev The `admin` of the proxy is invalid.
     */
    error ERC1967InvalidAdmin(address admin);

    /**
     * @dev The `beacon` of the proxy is invalid.
     */
    error ERC1967InvalidBeacon(address beacon);

    /**
     * @dev An upgrade function sees `msg.value > 0` that may be lost.
     */
    error ERC1967NonPayable();

    /**
     * @dev Returns the current implementation address.
     */
    function getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the ERC-1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        if (newImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(newImplementation);
        }
        StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Performs implementation upgrade with additional setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-Upgraded} event.
     */
    function upgradeToAndCall(address newImplementation, bytes memory data) internal {
        _setImplementation(newImplementation);
        emit IERC1967.Upgraded(newImplementation);

        if (data.length > 0) {
            Address.functionDelegateCall(newImplementation, data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Returns the current admin.
     *
     * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using
     * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
     */
    function getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the ERC-1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        if (newAdmin == address(0)) {
            revert ERC1967InvalidAdmin(address(0));
        }
        StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {IERC1967-AdminChanged} event.
     */
    function changeAdmin(address newAdmin) internal {
        emit IERC1967.AdminChanged(getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
     */
    // solhint-disable-next-line private-vars-leading-underscore
    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Returns the current beacon.
     */
    function getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the ERC-1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        if (newBeacon.code.length == 0) {
            revert ERC1967InvalidBeacon(newBeacon);
        }

        StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;

        address beaconImplementation = IBeacon(newBeacon).implementation();
        if (beaconImplementation.code.length == 0) {
            revert ERC1967InvalidImplementation(beaconImplementation);
        }
    }

    /**
     * @dev Change the beacon and trigger a setup call if data is nonempty.
     * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
     * to avoid stuck value in the contract.
     *
     * Emits an {IERC1967-BeaconUpgraded} event.
     *
     * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
     * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
     * efficiency.
     */
    function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
        _setBeacon(newBeacon);
        emit IERC1967.BeaconUpgraded(newBeacon);

        if (data.length > 0) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        } else {
            _checkNonPayable();
        }
    }

    /**
     * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
     * if an upgrade doesn't perform an initialization call.
     */
    function _checkNonPayable() private {
        if (msg.value > 0) {
            revert ERC1967NonPayable();
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, bytes memory returndata) = recipient.call{value: amount}("");
        if (!success) {
            _revert(returndata);
        }
    }

    /**
     * @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 or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * 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.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @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`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // 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
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

File 6 of 15 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// See contracts/COMPILERS.md
// solhint-disable-next-line lido/fixed-compiler-version
pragma solidity >=0.8.0;

import {IDepositContract} from "contracts/common/interfaces/IDepositContract.sol";

/**
 * @title IStakingVault
 * @author Lido
 * @notice Interface for the `StakingVault` contract
 */
interface IStakingVault {
    /**
     * @notice validator deposit from the `StakingVault` to the beacon chain
     * @dev withdrawal credentials are provided by the vault
     * @custom:pubkey The validator's BLS public key (48 bytes)
     * @custom:signature BLS signature of the deposit data (96 bytes)
     * @custom:amount Amount of ETH to deposit in wei (must be a multiple of 1 ETH)
     * @custom:depositDataRoot The root hash of the deposit data per ETH beacon spec
     */
    struct Deposit {
        bytes pubkey;
        bytes signature;
        uint256 amount;
        bytes32 depositDataRoot;
    }

    function DEPOSIT_CONTRACT() external view returns (IDepositContract);
    function initialize(address _owner, address _nodeOperator, address _depositor) external;
    function version() external pure returns (uint64);
    function getInitializedVersion() external view returns (uint64);
    function withdrawalCredentials() external view returns (bytes32);

    function owner() external view returns (address);
    function pendingOwner() external view returns (address);
    function acceptOwnership() external;
    function transferOwnership(address _newOwner) external;

    function nodeOperator() external view returns (address);
    function depositor() external view returns (address);
    function isOssified() external view returns (bool);
    function calculateValidatorWithdrawalFee(uint256 _keysCount) external view returns (uint256);
    function fund() external payable;
    function withdraw(address _recipient, uint256 _ether) external;

    function beaconChainDepositsPaused() external view returns (bool);
    function pauseBeaconChainDeposits() external;
    function resumeBeaconChainDeposits() external;
    function depositToBeaconChain(Deposit[] calldata _deposits) external;

    function requestValidatorExit(bytes calldata _pubkeys) external;
    function triggerValidatorWithdrawals(bytes calldata _pubkeys, uint64[] calldata _amounts, address _refundRecipient) external payable;
    function ejectValidators(bytes calldata _pubkeys, address _refundRecipient) external payable;
    function setDepositor(address _depositor) external;
    function ossify() external;
}

// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// See contracts/COMPILERS.md
pragma solidity 0.8.25;

import {StorageSlot} from "@openzeppelin/contracts-v5.2/utils/StorageSlot.sol";
import {IBeacon} from "@openzeppelin/contracts-v5.2/proxy/beacon/IBeacon.sol";
import {ERC1967Utils} from "@openzeppelin/contracts-v5.2/proxy/ERC1967/ERC1967Utils.sol";

library PinnedBeaconUtils {
    /**
     * @dev Storage slot with the address of the last implementation.
     * PINNED_BEACON_STORAGE_SLOT = bytes32(uint256(keccak256("stakingVault.proxy.pinnedBeacon")) - 1)
     */
    bytes32 internal constant PINNED_BEACON_STORAGE_SLOT = 0x8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f5;

    function getPinnedImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(PINNED_BEACON_STORAGE_SLOT).value;
    }

    /**
     * @notice Ossifies the beacon by pinning the current implementation
     */
    function ossify() internal {
        if (ossified()) revert AlreadyOssified();
        address currentImplementation = IBeacon(ERC1967Utils.getBeacon()).implementation();
        StorageSlot.getAddressSlot(PINNED_BEACON_STORAGE_SLOT).value = currentImplementation;
        emit PinnedImplementationUpdated(currentImplementation);
    }

    /**
     * @notice Returns true if the proxy is ossified
     * @return True if the proxy is ossified, false otherwise
     */
    function ossified() internal view returns(bool) {
        return getPinnedImplementation() != address(0);
    }

    /**
     * @notice Emitted when the pinned implementation is updated
     * @param implementation The address of the new pinned implementation
     */
    event PinnedImplementationUpdated(address indexed implementation);

    /**
     * @notice Thrown when trying to ossify the proxy while it is already ossified
     */
    error AlreadyOssified();
}

// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

// See contracts/COMPILERS.md
// solhint-disable-next-line lido/fixed-compiler-version
pragma solidity >=0.5.0;

interface IDepositContract {
    function get_deposit_root() external view returns (bytes32 rootHash);

    function deposit(
        bytes calldata pubkey, // 48 bytes
        bytes calldata withdrawal_credentials, // 32 bytes
        bytes calldata signature, // 96 bytes
        bytes32 deposit_data_root
    ) external payable;
}

// SPDX-FileCopyrightText: 2025 Lido <[email protected]>
// SPDX-License-Identifier: GPL-3.0

/* See contracts/COMPILERS.md */
// solhint-disable-next-line lido/fixed-compiler-version
pragma solidity >=0.8.9 <0.9.0;

/**
 * @title A lib for EIP-7002: Execution layer triggerable withdrawals.
 * Allow validators to trigger withdrawals and exits from their execution layer (0x01) withdrawal credentials.
 */
library TriggerableWithdrawals {
    address constant WITHDRAWAL_REQUEST = 0x00000961Ef480Eb55e80D19ad83579A64c007002;

    uint256 internal constant PUBLIC_KEY_LENGTH = 48;
    uint256 internal constant WITHDRAWAL_AMOUNT_LENGTH = 8;
    uint256 internal constant WITHDRAWAL_REQUEST_CALLDATA_LENGTH = 56;

    error WithdrawalFeeReadFailed();
    error WithdrawalFeeInvalidData();
    error WithdrawalRequestAdditionFailed(bytes callData);

    error NoWithdrawalRequests();
    error MalformedPubkeysArray();
    error PartialWithdrawalRequired(uint256 index);
    error MismatchedArrayLengths(uint256 keysCount, uint256 amountsCount);

    /**
     * @dev Send EIP-7002 full withdrawal requests for the specified public keys.
     *      Each request instructs a validator to fully withdraw its stake and exit its duties as a validator.
     *
     * @param pubkeys A tightly packed array of 48-byte public keys corresponding to validators requesting full withdrawals.
     *      | ----- public key (48 bytes) ----- || ----- public key (48 bytes) ----- | ...
     *
     * @param feePerRequest The withdrawal fee for each withdrawal request.
     *        - Must be greater than or equal to the current minimal withdrawal fee.
     *
     * @notice Reverts if:
     *         - Validation of the public keys fails.
     *         - The provided fee per request is insufficient.
     *         - The contract has an insufficient balance to cover the total fees.
     */
    function addFullWithdrawalRequests(bytes calldata pubkeys, uint256 feePerRequest) internal {
        uint256 keysCount = _validateAndCountPubkeys(pubkeys);

        bytes memory callData = new bytes(56);

        for (uint256 i = 0; i < keysCount; i++) {
            _copyPubkeyToMemory(pubkeys, callData, i);

            (bool success, ) = WITHDRAWAL_REQUEST.call{value: feePerRequest}(callData);

            if (!success) {
                revert WithdrawalRequestAdditionFailed(callData);
            }
        }
    }

    /**
     * @dev Send EIP-7002 partial withdrawal requests for the specified public keys with corresponding amounts.
     *      Each request instructs a validator to partially withdraw its stake.
     *      A partial withdrawal is any withdrawal where the amount is greater than zero,
     *      allows withdrawal of any balance exceeding 32 ETH (e.g., if a validator has 35 ETH, up to 3 ETH can be withdrawn),
     *      the protocol enforces a minimum balance of 32 ETH per validator, even if a higher amount is requested.
     *
     * @param pubkeys A tightly packed array of 48-byte public keys corresponding to validators requesting full withdrawals.
     *      | ----- public key (48 bytes) ----- || ----- public key (48 bytes) ----- | ...
     *
     * @param amounts An array of corresponding partial withdrawal amounts for each public key.
     *
     * @param feePerRequest The withdrawal fee for each withdrawal request.
     *        - Must be greater than or equal to the current minimal withdrawal fee.
     *
     * @notice Reverts if:
     *         - Validation of the public keys fails.
     *         - The pubkeys and amounts length mismatch.
     *         - Full withdrawal requested for any pubkeys (withdrawal amount = 0).
     *         - The provided fee per request is insufficient.
     *         - The contract has an insufficient balance to cover the total fees.
     */
    function addPartialWithdrawalRequests(
        bytes calldata pubkeys,
        uint64[] calldata amounts,
        uint256 feePerRequest
    ) internal {
        for (uint256 i = 0; i < amounts.length; i++) {
            if (amounts[i] == 0) {
                revert PartialWithdrawalRequired(i);
            }
        }

        addWithdrawalRequests(pubkeys, amounts, feePerRequest);
    }

    /**
     * @dev Send EIP-7002 partial or full withdrawal requests for the specified public keys with corresponding amounts.
     *      Each request instructs a validator to partially or fully withdraw its stake.

     *      1. A partial withdrawal is any withdrawal where the amount is greater than zero,
     *      allows withdrawal of any balance exceeding 32 ETH (e.g., if a validator has 35 ETH, up to 3 ETH can be withdrawn),
     *      the protocol enforces a minimum balance of 32 ETH per validator, even if a higher amount is requested.
     *
     *      2. A full withdrawal is a withdrawal where the amount is equal to zero,
     *      allows to fully withdraw validator stake and exit its duties as a validator.
     *
     * @param pubkeys A tightly packed array of 48-byte public keys corresponding to validators requesting full withdrawals.
     *      | ----- public key (48 bytes) ----- || ----- public key (48 bytes) ----- | ...
     *
     * @param amounts An array of corresponding partial withdrawal amounts for each public key.
     *
     * @param feePerRequest The withdrawal fee for each withdrawal request.
     *        - Must be greater than or equal to the current minimal withdrawal fee.
     *
     * @notice Reverts if:
     *         - Validation of the public keys fails.
     *         - The pubkeys and amounts length mismatch.
     *         - The provided fee per request is insufficient.
     *         - The contract has an insufficient balance to cover the total fees.
     */
    function addWithdrawalRequests(bytes calldata pubkeys, uint64[] calldata amounts, uint256 feePerRequest) internal {
        uint256 keysCount = _validateAndCountPubkeys(pubkeys);

        if (keysCount != amounts.length) {
            revert MismatchedArrayLengths(keysCount, amounts.length);
        }

        bytes memory callData = new bytes(56);
        for (uint256 i = 0; i < keysCount; i++) {
            _copyPubkeyToMemory(pubkeys, callData, i);
            _copyAmountToMemory(callData, amounts[i]);

            (bool success, ) = WITHDRAWAL_REQUEST.call{value: feePerRequest}(callData);

            if (!success) {
                revert WithdrawalRequestAdditionFailed(callData);
            }
        }
    }

    /**
     * @dev Retrieves the current EIP-7002 withdrawal fee.
     * @return The minimum fee required per withdrawal request.
     */
    function getWithdrawalRequestFee() internal view returns (uint256) {
        (bool success, bytes memory feeData) = WITHDRAWAL_REQUEST.staticcall("");

        if (!success) {
            revert WithdrawalFeeReadFailed();
        }

        if (feeData.length != 32) {
            revert WithdrawalFeeInvalidData();
        }

        return abi.decode(feeData, (uint256));
    }

    function _copyPubkeyToMemory(bytes calldata pubkeys, bytes memory target, uint256 keyIndex) private pure {
        assembly {
            calldatacopy(add(target, 32), add(pubkeys.offset, mul(keyIndex, PUBLIC_KEY_LENGTH)), PUBLIC_KEY_LENGTH)
        }
    }

    function _copyAmountToMemory(bytes memory target, uint64 amount) private pure {
        assembly {
            mstore(add(target, 80), shl(192, amount))
        }
    }

    function _validateAndCountPubkeys(bytes calldata pubkeys) private pure returns (uint256) {
        if (pubkeys.length % PUBLIC_KEY_LENGTH != 0) {
            revert MalformedPubkeysArray();
        }

        uint256 keysCount = pubkeys.length / PUBLIC_KEY_LENGTH;
        if (keysCount == 0) {
            revert NoWithdrawalRequests();
        }

        return keysCount;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "./OwnableUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This extension of the {Ownable} contract includes a two-step mechanism to transfer
 * ownership, where the new owner must call {acceptOwnership} in order to replace the
 * old one. This can help prevent common mistakes, such as transfers of ownership to
 * incorrect accounts, or to contracts that are unable to interact with the
 * permission system.
 *
 * The initial owner is specified at deployment time in the constructor for `Ownable`. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step
    struct Ownable2StepStorage {
        address _pendingOwner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;

    function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {
        assembly {
            $.slot := Ownable2StepStorageLocation
        }
    }

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

    function __Ownable2Step_init() internal onlyInitializing {
    }

    function __Ownable2Step_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        return $._pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     *
     * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        $._pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        Ownable2StepStorage storage $ = _getOwnable2StepStorage();
        delete $._pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert OwnableUnauthorizedAccount(sender);
        }
        _transferOwnership(sender);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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 {
    /// @custom:storage-location erc7201:openzeppelin.storage.Ownable
    struct OwnableStorage {
        address _owner;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant OwnableStorageLocation =
        0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;

    function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
        assembly {
            $.slot := OwnableStorageLocation
        }
    }

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

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

    function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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) {
        OwnableStorage storage $ = _getOwnableStorage();
        return $._owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @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]
 * ```solidity
 * 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 Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 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.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._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.
     *
     * 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.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * 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.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._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() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @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.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": true,
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_beaconChainDepositContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyOssified","type":"error"},{"inputs":[],"name":"BeaconChainDepositsAlreadyPaused","type":"error"},{"inputs":[],"name":"BeaconChainDepositsAlreadyResumed","type":"error"},{"inputs":[],"name":"BeaconChainDepositsOnPause","type":"error"},{"inputs":[{"internalType":"uint256","name":"_balance","type":"uint256"},{"internalType":"uint256","name":"_required","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_passed","type":"uint256"},{"internalType":"uint256","name":"_required","type":"uint256"}],"name":"InsufficientValidatorWithdrawalFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidPubkeysLength","type":"error"},{"inputs":[],"name":"MalformedPubkeysArray","type":"error"},{"inputs":[{"internalType":"uint256","name":"keysCount","type":"uint256"},{"internalType":"uint256","name":"amountsCount","type":"uint256"}],"name":"MismatchedArrayLengths","type":"error"},{"inputs":[],"name":"NewDepositorSameAsPrevious","type":"error"},{"inputs":[],"name":"NoWithdrawalRequests","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PubkeyLengthDoesNotMatchAmountLength","type":"error"},{"inputs":[],"name":"SenderNotDepositor","type":"error"},{"inputs":[],"name":"SenderNotNodeOperator","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"VaultOssified","type":"error"},{"inputs":[],"name":"WithdrawalFeeInvalidData","type":"error"},{"inputs":[],"name":"WithdrawalFeeReadFailed","type":"error"},{"inputs":[{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"WithdrawalRequestAdditionFailed","type":"error"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"ZeroArgument","type":"error"},{"anonymous":false,"inputs":[],"name":"BeaconChainDepositsPaused","type":"event"},{"anonymous":false,"inputs":[],"name":"BeaconChainDepositsResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_deposits","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalAmount","type":"uint256"}],"name":"DepositedToBeaconChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousDepositor","type":"address"},{"indexed":true,"internalType":"address","name":"newDepositor","type":"address"}],"name":"DepositorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EtherWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeOperator","type":"address"}],"name":"NodeOperatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"PinnedImplementationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"pubkeys","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"excess","type":"uint256"},{"indexed":true,"internalType":"address","name":"refundRecipient","type":"address"}],"name":"ValidatorEjectionsTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"pubkey","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"pubkeyRaw","type":"bytes"}],"name":"ValidatorExitRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"pubkeys","type":"bytes"},{"indexed":false,"internalType":"uint64[]","name":"amounts","type":"uint64[]"},{"indexed":false,"internalType":"uint256","name":"excess","type":"uint256"},{"indexed":true,"internalType":"address","name":"refundRecipient","type":"address"}],"name":"ValidatorWithdrawalsTriggered","type":"event"},{"inputs":[],"name":"DEPOSIT_CONTRACT","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"beaconChainDepositsPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numberOfKeys","type":"uint256"}],"name":"calculateValidatorWithdrawalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"internalType":"struct IStakingVault.Deposit[]","name":"_deposits","type":"tuple[]"}],"name":"depositToBeaconChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkeys","type":"bytes"},{"internalType":"address","name":"_refundRecipient","type":"address"}],"name":"ejectValidators","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fund","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getInitializedVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_nodeOperator","type":"address"},{"internalType":"address","name":"_depositor","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isOssified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ossify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseBeaconChainDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkeys","type":"bytes"}],"name":"requestValidatorExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resumeBeaconChainDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_depositor","type":"address"}],"name":"setDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_pubkeys","type":"bytes"},{"internalType":"uint64[]","name":"_amounts","type":"uint64[]"},{"internalType":"address","name":"_excessRefundRecipient","type":"address"}],"name":"triggerValidatorWithdrawals","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_ether","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCredentials","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a03461015157601f611c2738819003918201601f19168301926001600160401b039290918385118386101761015557816020928492604097885283398101031261015157516001600160a01b0381169081900361015157801561010c576080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff82851c166100fb5780808316036100b7575b8351611abd908161016a823960805181818161081c01526109c80152f35b6001600160401b0319909116811790915581519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f8080610099565b835163f92ee8a960e01b8152600490fd5b82516356e4289360e01b815260206004820152601b60248201527f5f626561636f6e436861696e4465706f736974436f6e747261637400000000006044820152606490fd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c8063023c5b08146101a957806310741552146101a457806313e40efb1461019f5780632cbf918f1461019a5780634cd79e0a146101955780634f0a765f1461019057806354fd4d501461018b57806362b2f4b0146101865780636b96736b146101815780636d3718941461017c578063715018a6146101775780637271518a1461017257806379ba50971461016d5780638da5cb5b1461016857806395631105146101635780639a23d8511461015e578063b3c6501514610159578063b60d428814610154578063bddf300c1461014f578063c0c53b8b1461014a578063c7c4ff4614610145578063e30c397814610140578063f2c098b71461013b578063f2fde38b146101365763f3fef3a30361000e576110a8565b611020565b610ff3565b610fbf565b610f8b565b610e3d565b610dc3565b610d64565b610d32565b610d01565b610c8c565b610c58565b610c07565b610abd565b610a40565b6109f7565b6109b3565b610791565b610776565b6105ad565b61058c565b61055e565b61036d565b610230565b6101bc565b5f9103126101b857565b5f80fd5b346101b8575f3660031901126101b8577f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b100546040516001600160a01b039091168152602090f35b9181601f840112156101b8578235916001600160401b0383116101b857602083818601950101116101b857565b346101b85760203660031901126101b8576004356001600160401b0381116101b857610260903690600401610203565b90610269611646565b811561030e57603082066102fc5760308204905f5b82811061028757005b806102b96102b2610299600194611217565b6102aa6102a585611245565b611217565b908887611260565b36916112e0565b7f05b0196730e2e8bc442ab62c49ca0d3a71da677a0b1723ec2294f3f46a19f2ea6102f36102e683611316565b9260405191829182611356565b0390a20161027e565b6040516349b7ed0560e11b8152600490fd5b6040516356e4289360e01b815280610328600482016111e0565b0390fd5b9181601f840112156101b8578235916001600160401b0383116101b8576020808501948460051b0101116101b857565b6001600160a01b038116036101b857565b60603660031901126101b85760046001600160401b0381358181116101b8576103999036908401610203565b9290916024359081116101b8576103b3903690830161032c565b60443592916103c18461035c565b6103c9611646565b8395341561054557801561052c576030810661051b57821580158061050e575b6104fd576001600160a01b03958616156104f5575b610406611666565b6104138160308504611232565b918234106104d057610437929190156104be5761043190848a6117e3565b3461138e565b938461047c575b50917fc96e90b5c207d52ad68c8d1ce870aa2861a35bf9b1f94a5b3daa6a3552979a1595969391610477936040519687961698866113fb565b0390a2005b5f808080888c5af161048c61139b565b5061043e5760408051630e21dcbb60e11b81526001600160a01b038a1692810192835260208301879052918291010390fd5b6104cb908686868c611714565b610431565b6040805163e546602560e01b815234818a019081526020810186905290918291010390fd5b3397506103fe565b604051630d28c48160e11b81528590fd5b50836030830414156103e9565b6040516349b7ed0560e11b81528490fd5b6040516356e4289360e01b8152806103288187016111e0565b6040516356e4289360e01b81528061032881870161136a565b346101b85760203660031901126101b857602061058461057c611666565b600435611232565b604051908152f35b346101b8575f3660031901126101b857604051600160f91b30178152602090f35b6040806003193601126101b857600480356001600160401b0381116101b8576105d99036908301610203565b9091602435916105e88361035c565b8294341561075f5781156107485760308206610739577f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b1005461063a906001600160a01b03165b6001600160a01b031690565b330361072a576001600160a01b0393841615610722575b610659611666565b6106668160308504611232565b908134106106fc579061043161067d9285896117e3565b92836106ba575b5091610477917f055e588165a70cfccaefb20f408c65da0a57e4846e0d6213fb423e7fb20eb49d95969351948594169684611467565b5f808080878b5af16106ca61139b565b50610684579051630e21dcbb60e11b81526001600160a01b038716918101918252602082018490529081906040010390fd5b50815163e546602560e01b81523481860190815260208101929092529081906040010390fd5b339550610651565b516309adda0960e01b81529050fd5b516349b7ed0560e11b81529050fd5b516356e4289360e01b8152806103288185016111e0565b516356e4289360e01b81528061032881850161136a565b346101b8575f3660031901126101b857602060405160018152f35b346101b8576020806003193601126101b857600480356001600160401b0381116101b8576107c2903690830161032c565b90918115610979575f80516020611a08833981519152549060ff8260a01c1661096a576001600160a01b03918216330361095b575f935f5b84811061093857504785116109135791610819600160f91b30176114bf565b907f0000000000000000000000000000000000000000000000000000000000000000165f5b85811061087f5760408051878152602081018990527f3f12c34a6e19535fc60ef8188232863b8834209bd12986d10abc21dac813045691819081015b0390a1005b61088a818787611498565b9060409161089881806114e8565b90916108a68c8201826114e8565b929095873b156101b8575f946108d88b8b9684519a8b98899788966304512a2360e31b885260608b013595880161151a565b03920135875af191821561090e576001926108f5575b500161083e565b806109026109089261128c565b806101ae565b5f6108ee565b611557565b6040805163cf47918160e01b8152478185019081526020810188905290918291010390fd5b94610954600191604061094c898987611498565b013590611253565b95016107fa565b604051630f6e792560e31b8152fd5b604051638f5a323160e01b8152fd5b610328906040519182916356e4289360e01b835282016060906020815260096020820152685f6465706f7369747360b81b60408201520190565b346101b8575f3660031901126101b8576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101b8575f3660031901126101b8577f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f5546040516001600160a01b0390911615158152602090f35b346101b8575f3660031901126101b857610a58611646565b5f80516020611a6883398151915280546001600160a01b03199081169091555f80516020611a28833981519152805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101b8575f3660031901126101b857610ad5611646565b7f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f5546001600160a01b03908116610bf5577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5054600490602090610b429084166001600160a01b031661062e565b604051635c60da1b60e01b815292839182905afa90811561090e575f91610bc6575b507f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f580546001600160a01b0319166001600160a01b038316179055167f948a0b52be7a2928784f372bdcaa858365110f82b72b8acc5341cb70ad6c516b5f80a2005b610be8915060203d602011610bee575b610be081836112a4565b8101906118d8565b5f610b64565b503d610bd6565b60405163603245d760e11b8152600490fd5b346101b8575f3660031901126101b8575f80516020611a6883398151915254336001600160a01b0390911603610c40576100183361186d565b60405163118cdaa760e01b8152336004820152602490fd5b346101b8575f3660031901126101b8575f80516020611a28833981519152546040516001600160a01b039091168152602090f35b346101b8575f3660031901126101b857610ca4611646565b5f80516020611a08833981519152805460ff8160a01c1615610cef5760ff60a01b191690557f27a55085732907412de31b5518e3722e1d43962cead04fee6c02a358732f65ed5f80a1005b604051630238123160e51b8152600490fd5b346101b8575f3660031901126101b857602060ff5f80516020611a088339815191525460a01c166040519015158152f35b346101b8575f3660031901126101b85760206001600160401b035f80516020611a488339815191525416604051908152f35b5f3660031901126101b857610d77611646565b3415610da9577f4d0a0f381b6ff1c2de8626566279f8cf649198694a36b4e0276b5ad82d8374156020604051348152a1005b6040516356e4289360e01b8152806103286004820161136a565b346101b8575f3660031901126101b857610ddb611646565b5f80516020611a08833981519152805460ff8160a01c16610e2b5760ff60a01b1916600160a01b1790557f1b0c9f2dbf20ce090cc310b3480b4dc96cbc2dd2806563f379cb4750e47d1aeb5f80a1005b60405163403b743b60e01b8152600490fd5b346101b85760603660031901126101b857600435610e5a8161035c565b60243590610e678261035c565b604435610e738161035c565b5f80516020611a4883398151915254926001600160401b0360ff8560401c1615941680159081610f83575b6001149081610f79575b159081610f70575b50610f5e575f80516020611a48833981519152805467ffffffffffffffff19166001179055610ee39284610f3557611562565b610ee957005b5f80516020611a48833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290806020810161087a565b5f80516020611a48833981519152805460ff60401b191668010000000000000000179055611562565b60405163f92ee8a960e01b8152600490fd5b9050155f610eb0565b303b159150610ea8565b859150610e9e565b346101b8575f3660031901126101b8575f80516020611a08833981519152546040516001600160a01b039091168152602090f35b346101b8575f3660031901126101b8575f80516020611a68833981519152546040516001600160a01b039091168152602090f35b346101b85760203660031901126101b8576100186004356110138161035c565b61101b611646565b6118ed565b346101b85760203660031901126101b85760043561103d8161035c565b611045611646565b5f80516020611a6883398151915280546001600160a01b0319166001600160a01b039283169081179091555f80516020611a28833981519152549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346101b8576040806003193601126101b857600435906110c78261035c565b602435906110d3611646565b6001600160a01b0383169283156111ae57821561118057478311611161575f80808086855af161110161139b565b50156111385750519081527f06097061aeda806b5e9cb4133d9899f332ff0913956567fc0f7ea15e3d19947c908060208101610477565b9051630e21dcbb60e11b81526001600160a01b0390911660048201526024810191909152604490fd5b505163cf47918160e01b81524760048201526024810191909152604490fd5b50516356e4289360e01b81526020600482015260066024820152652fb2ba3432b960d11b6044820152606490fd5b50516356e4289360e01b815260206004820152600a60248201526917dc9958da5c1a595b9d60b21b6044820152606490fd5b6060906020815260086020820152675f7075626b65797360c01b60408201520190565b634e487b7160e01b5f52601160045260245ffd5b9060308202918083046030149015171561122d57565b611203565b8181029291811591840414171561122d57565b906001820180921161122d57565b9190820180921161122d57565b909392938483116101b85784116101b8578101920390565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161129f57604052565b611278565b90601f801991011681019081106001600160401b0382111761129f57604052565b6001600160401b03811161129f57601f01601f191660200190565b9291926112ec826112c5565b916112fa60405193846112a4565b8294818452818301116101b8578281602093845f960137010152565b602090604051918183925191829101835e81015f815203902090565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906020611367928181520190611332565b90565b6060906020815260096020820152686d73672e76616c756560b81b60408201520190565b9190820391821161122d57565b3d156113c5573d906113ac826112c5565b916113ba60405193846112a4565b82523d5f602084013e565b606090565b908060209392818452848401375f828201840152601f01601f1916010190565b6001600160401b038116036101b857565b959493929190611413916060885260608801916113ca565b9160208093878103828901528281520191925f5b82811061143a5750505060409150930152565b90919282806001926001600160401b038835611455816113ea565b16815201950191019392919093611427565b93929160209161147f916040875260408701916113ca565b930152565b634e487b7160e01b5f52603260045260245ffd5b91908110156114ba5760051b81013590607e19813603018212156101b8570190565b611484565b9060405191602083015260208252604082018281106001600160401b0382111761129f57604052565b903590601e19813603018212156101b857018035906001600160401b0382116101b8576020019181360383136101b857565b9695949061147f9361153b611549926060979560808c5260808c01916113ca565b9089820360208b0152611332565b9187830360408901526113ca565b6040513d5f823e3d90fd5b6001600160a01b0391821692909183156116105761157e6119d9565b6115866119d9565b8216156115f8576115996115a19261186d565b61101b6119d9565b7f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b10080546001600160a01b031916821790557f57d209fa057c282ad4b54dc6ad1a002b01d20bf16299f62ff8040943a692b8d35f80a2565b604051631e4fbdf760e01b81525f6004820152602490fd5b6040516356e4289360e01b815260206004820152600d60248201526c2fb737b232a7b832b930ba37b960991b6044820152606490fd5b5f80516020611a28833981519152546001600160a01b03163303610c4057565b5f808080710961ef480eb55e80d19ad83579a64c0070025afa61168761139b565b90156116bc5760208151036116aa576020818051810103126101b8576020015190565b604051631dc5371160e31b8152600490fd5b6040516322daa69760e21b8152600490fd5b60405190606082018281106001600160401b0382111761129f5760405260388252604082602036910137565b91908110156114ba5760051b0190565b35611367816113ea565b9294939061172190611993565b8581036117c257926117316116ce565b9260208401915f5b86811061174b57505050505050509050565b6117568187846119cc565b61177661176c611767838c876116fa565b61170a565b60c01b6050880152565b5f8087518688710961ef480eb55e80d19ad83579a64c0070025af161179961139b565b50156117a757600101611739565b604051638751976f60e01b8152806103288860048301611356565b604051633adf150f60e21b8152600481019190915260248101869052604490fd5b9291906117ef90611993565b6117f76116ce565b916020908184015f5b848110611811575050505050509050565b6030808202890183375f8087518486710961ef480eb55e80d19ad83579a64c0070025af161183d61139b565b501561184b57600101611800565b604051638751976f60e01b815260048101859052806103286024820189611332565b5f80516020611a6883398151915280546001600160a01b03199081169091555f80516020611a2883398151915280549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b908160209103126101b857516113678161035c565b6001600160a01b03908116908115611960575f80516020611a0883398151915280549182169182841461194e576001600160a01b031916831790557f4720a1f119ade4c12ca0c8d93b91d69ca0bf693770c9dacaab0806d1f63cc81b5f80a3565b6040516335abdfdf60e01b8152600490fd5b6040516356e4289360e01b815260206004820152600a6024820152692fb232b837b9b4ba37b960b11b6044820152606490fd5b603081066119ba576030900480156119a85790565b604051639106113760e01b8152600490fd5b604051630726fa7960e31b8152600490fd5b6030928302019060200137565b60ff5f80516020611a488339815191525460401c16156119f557565b604051631afcd79f60e31b8152600490fdfe2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b1019016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00a26469706673582212208084a17de5858e45b60184f6f8c050327cb7d5899cb216c71bbba22a5083340264736f6c6343000819003300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa

Deployed Bytecode

0x6080604052600436101561001a575b3615610018575f80fd5b005b5f3560e01c8063023c5b08146101a957806310741552146101a457806313e40efb1461019f5780632cbf918f1461019a5780634cd79e0a146101955780634f0a765f1461019057806354fd4d501461018b57806362b2f4b0146101865780636b96736b146101815780636d3718941461017c578063715018a6146101775780637271518a1461017257806379ba50971461016d5780638da5cb5b1461016857806395631105146101635780639a23d8511461015e578063b3c6501514610159578063b60d428814610154578063bddf300c1461014f578063c0c53b8b1461014a578063c7c4ff4614610145578063e30c397814610140578063f2c098b71461013b578063f2fde38b146101365763f3fef3a30361000e576110a8565b611020565b610ff3565b610fbf565b610f8b565b610e3d565b610dc3565b610d64565b610d32565b610d01565b610c8c565b610c58565b610c07565b610abd565b610a40565b6109f7565b6109b3565b610791565b610776565b6105ad565b61058c565b61055e565b61036d565b610230565b6101bc565b5f9103126101b857565b5f80fd5b346101b8575f3660031901126101b8577f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b100546040516001600160a01b039091168152602090f35b9181601f840112156101b8578235916001600160401b0383116101b857602083818601950101116101b857565b346101b85760203660031901126101b8576004356001600160401b0381116101b857610260903690600401610203565b90610269611646565b811561030e57603082066102fc5760308204905f5b82811061028757005b806102b96102b2610299600194611217565b6102aa6102a585611245565b611217565b908887611260565b36916112e0565b7f05b0196730e2e8bc442ab62c49ca0d3a71da677a0b1723ec2294f3f46a19f2ea6102f36102e683611316565b9260405191829182611356565b0390a20161027e565b6040516349b7ed0560e11b8152600490fd5b6040516356e4289360e01b815280610328600482016111e0565b0390fd5b9181601f840112156101b8578235916001600160401b0383116101b8576020808501948460051b0101116101b857565b6001600160a01b038116036101b857565b60603660031901126101b85760046001600160401b0381358181116101b8576103999036908401610203565b9290916024359081116101b8576103b3903690830161032c565b60443592916103c18461035c565b6103c9611646565b8395341561054557801561052c576030810661051b57821580158061050e575b6104fd576001600160a01b03958616156104f5575b610406611666565b6104138160308504611232565b918234106104d057610437929190156104be5761043190848a6117e3565b3461138e565b938461047c575b50917fc96e90b5c207d52ad68c8d1ce870aa2861a35bf9b1f94a5b3daa6a3552979a1595969391610477936040519687961698866113fb565b0390a2005b5f808080888c5af161048c61139b565b5061043e5760408051630e21dcbb60e11b81526001600160a01b038a1692810192835260208301879052918291010390fd5b6104cb908686868c611714565b610431565b6040805163e546602560e01b815234818a019081526020810186905290918291010390fd5b3397506103fe565b604051630d28c48160e11b81528590fd5b50836030830414156103e9565b6040516349b7ed0560e11b81528490fd5b6040516356e4289360e01b8152806103288187016111e0565b6040516356e4289360e01b81528061032881870161136a565b346101b85760203660031901126101b857602061058461057c611666565b600435611232565b604051908152f35b346101b8575f3660031901126101b857604051600160f91b30178152602090f35b6040806003193601126101b857600480356001600160401b0381116101b8576105d99036908301610203565b9091602435916105e88361035c565b8294341561075f5781156107485760308206610739577f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b1005461063a906001600160a01b03165b6001600160a01b031690565b330361072a576001600160a01b0393841615610722575b610659611666565b6106668160308504611232565b908134106106fc579061043161067d9285896117e3565b92836106ba575b5091610477917f055e588165a70cfccaefb20f408c65da0a57e4846e0d6213fb423e7fb20eb49d95969351948594169684611467565b5f808080878b5af16106ca61139b565b50610684579051630e21dcbb60e11b81526001600160a01b038716918101918252602082018490529081906040010390fd5b50815163e546602560e01b81523481860190815260208101929092529081906040010390fd5b339550610651565b516309adda0960e01b81529050fd5b516349b7ed0560e11b81529050fd5b516356e4289360e01b8152806103288185016111e0565b516356e4289360e01b81528061032881850161136a565b346101b8575f3660031901126101b857602060405160018152f35b346101b8576020806003193601126101b857600480356001600160401b0381116101b8576107c2903690830161032c565b90918115610979575f80516020611a08833981519152549060ff8260a01c1661096a576001600160a01b03918216330361095b575f935f5b84811061093857504785116109135791610819600160f91b30176114bf565b907f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa165f5b85811061087f5760408051878152602081018990527f3f12c34a6e19535fc60ef8188232863b8834209bd12986d10abc21dac813045691819081015b0390a1005b61088a818787611498565b9060409161089881806114e8565b90916108a68c8201826114e8565b929095873b156101b8575f946108d88b8b9684519a8b98899788966304512a2360e31b885260608b013595880161151a565b03920135875af191821561090e576001926108f5575b500161083e565b806109026109089261128c565b806101ae565b5f6108ee565b611557565b6040805163cf47918160e01b8152478185019081526020810188905290918291010390fd5b94610954600191604061094c898987611498565b013590611253565b95016107fa565b604051630f6e792560e31b8152fd5b604051638f5a323160e01b8152fd5b610328906040519182916356e4289360e01b835282016060906020815260096020820152685f6465706f7369747360b81b60408201520190565b346101b8575f3660031901126101b8576040517f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa6001600160a01b03168152602090f35b346101b8575f3660031901126101b8577f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f5546040516001600160a01b0390911615158152602090f35b346101b8575f3660031901126101b857610a58611646565b5f80516020611a6883398151915280546001600160a01b03199081169091555f80516020611a28833981519152805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101b8575f3660031901126101b857610ad5611646565b7f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f5546001600160a01b03908116610bf5577fa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d5054600490602090610b429084166001600160a01b031661062e565b604051635c60da1b60e01b815292839182905afa90811561090e575f91610bc6575b507f8d75cfa6c9a3cd2fb8b6d445eafb32adc5497a45b333009f9000379f7024f9f580546001600160a01b0319166001600160a01b038316179055167f948a0b52be7a2928784f372bdcaa858365110f82b72b8acc5341cb70ad6c516b5f80a2005b610be8915060203d602011610bee575b610be081836112a4565b8101906118d8565b5f610b64565b503d610bd6565b60405163603245d760e11b8152600490fd5b346101b8575f3660031901126101b8575f80516020611a6883398151915254336001600160a01b0390911603610c40576100183361186d565b60405163118cdaa760e01b8152336004820152602490fd5b346101b8575f3660031901126101b8575f80516020611a28833981519152546040516001600160a01b039091168152602090f35b346101b8575f3660031901126101b857610ca4611646565b5f80516020611a08833981519152805460ff8160a01c1615610cef5760ff60a01b191690557f27a55085732907412de31b5518e3722e1d43962cead04fee6c02a358732f65ed5f80a1005b604051630238123160e51b8152600490fd5b346101b8575f3660031901126101b857602060ff5f80516020611a088339815191525460a01c166040519015158152f35b346101b8575f3660031901126101b85760206001600160401b035f80516020611a488339815191525416604051908152f35b5f3660031901126101b857610d77611646565b3415610da9577f4d0a0f381b6ff1c2de8626566279f8cf649198694a36b4e0276b5ad82d8374156020604051348152a1005b6040516356e4289360e01b8152806103286004820161136a565b346101b8575f3660031901126101b857610ddb611646565b5f80516020611a08833981519152805460ff8160a01c16610e2b5760ff60a01b1916600160a01b1790557f1b0c9f2dbf20ce090cc310b3480b4dc96cbc2dd2806563f379cb4750e47d1aeb5f80a1005b60405163403b743b60e01b8152600490fd5b346101b85760603660031901126101b857600435610e5a8161035c565b60243590610e678261035c565b604435610e738161035c565b5f80516020611a4883398151915254926001600160401b0360ff8560401c1615941680159081610f83575b6001149081610f79575b159081610f70575b50610f5e575f80516020611a48833981519152805467ffffffffffffffff19166001179055610ee39284610f3557611562565b610ee957005b5f80516020611a48833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290806020810161087a565b5f80516020611a48833981519152805460ff60401b191668010000000000000000179055611562565b60405163f92ee8a960e01b8152600490fd5b9050155f610eb0565b303b159150610ea8565b859150610e9e565b346101b8575f3660031901126101b8575f80516020611a08833981519152546040516001600160a01b039091168152602090f35b346101b8575f3660031901126101b8575f80516020611a68833981519152546040516001600160a01b039091168152602090f35b346101b85760203660031901126101b8576100186004356110138161035c565b61101b611646565b6118ed565b346101b85760203660031901126101b85760043561103d8161035c565b611045611646565b5f80516020611a6883398151915280546001600160a01b0319166001600160a01b039283169081179091555f80516020611a28833981519152549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346101b8576040806003193601126101b857600435906110c78261035c565b602435906110d3611646565b6001600160a01b0383169283156111ae57821561118057478311611161575f80808086855af161110161139b565b50156111385750519081527f06097061aeda806b5e9cb4133d9899f332ff0913956567fc0f7ea15e3d19947c908060208101610477565b9051630e21dcbb60e11b81526001600160a01b0390911660048201526024810191909152604490fd5b505163cf47918160e01b81524760048201526024810191909152604490fd5b50516356e4289360e01b81526020600482015260066024820152652fb2ba3432b960d11b6044820152606490fd5b50516356e4289360e01b815260206004820152600a60248201526917dc9958da5c1a595b9d60b21b6044820152606490fd5b6060906020815260086020820152675f7075626b65797360c01b60408201520190565b634e487b7160e01b5f52601160045260245ffd5b9060308202918083046030149015171561122d57565b611203565b8181029291811591840414171561122d57565b906001820180921161122d57565b9190820180921161122d57565b909392938483116101b85784116101b8578101920390565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b03811161129f57604052565b611278565b90601f801991011681019081106001600160401b0382111761129f57604052565b6001600160401b03811161129f57601f01601f191660200190565b9291926112ec826112c5565b916112fa60405193846112a4565b8294818452818301116101b8578281602093845f960137010152565b602090604051918183925191829101835e81015f815203902090565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906020611367928181520190611332565b90565b6060906020815260096020820152686d73672e76616c756560b81b60408201520190565b9190820391821161122d57565b3d156113c5573d906113ac826112c5565b916113ba60405193846112a4565b82523d5f602084013e565b606090565b908060209392818452848401375f828201840152601f01601f1916010190565b6001600160401b038116036101b857565b959493929190611413916060885260608801916113ca565b9160208093878103828901528281520191925f5b82811061143a5750505060409150930152565b90919282806001926001600160401b038835611455816113ea565b16815201950191019392919093611427565b93929160209161147f916040875260408701916113ca565b930152565b634e487b7160e01b5f52603260045260245ffd5b91908110156114ba5760051b81013590607e19813603018212156101b8570190565b611484565b9060405191602083015260208252604082018281106001600160401b0382111761129f57604052565b903590601e19813603018212156101b857018035906001600160401b0382116101b8576020019181360383136101b857565b9695949061147f9361153b611549926060979560808c5260808c01916113ca565b9089820360208b0152611332565b9187830360408901526113ca565b6040513d5f823e3d90fd5b6001600160a01b0391821692909183156116105761157e6119d9565b6115866119d9565b8216156115f8576115996115a19261186d565b61101b6119d9565b7f2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b10080546001600160a01b031916821790557f57d209fa057c282ad4b54dc6ad1a002b01d20bf16299f62ff8040943a692b8d35f80a2565b604051631e4fbdf760e01b81525f6004820152602490fd5b6040516356e4289360e01b815260206004820152600d60248201526c2fb737b232a7b832b930ba37b960991b6044820152606490fd5b5f80516020611a28833981519152546001600160a01b03163303610c4057565b5f808080710961ef480eb55e80d19ad83579a64c0070025afa61168761139b565b90156116bc5760208151036116aa576020818051810103126101b8576020015190565b604051631dc5371160e31b8152600490fd5b6040516322daa69760e21b8152600490fd5b60405190606082018281106001600160401b0382111761129f5760405260388252604082602036910137565b91908110156114ba5760051b0190565b35611367816113ea565b9294939061172190611993565b8581036117c257926117316116ce565b9260208401915f5b86811061174b57505050505050509050565b6117568187846119cc565b61177661176c611767838c876116fa565b61170a565b60c01b6050880152565b5f8087518688710961ef480eb55e80d19ad83579a64c0070025af161179961139b565b50156117a757600101611739565b604051638751976f60e01b8152806103288860048301611356565b604051633adf150f60e21b8152600481019190915260248101869052604490fd5b9291906117ef90611993565b6117f76116ce565b916020908184015f5b848110611811575050505050509050565b6030808202890183375f8087518486710961ef480eb55e80d19ad83579a64c0070025af161183d61139b565b501561184b57600101611800565b604051638751976f60e01b815260048101859052806103286024820189611332565b5f80516020611a6883398151915280546001600160a01b03199081169091555f80516020611a2883398151915280549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b908160209103126101b857516113678161035c565b6001600160a01b03908116908115611960575f80516020611a0883398151915280549182169182841461194e576001600160a01b031916831790557f4720a1f119ade4c12ca0c8d93b91d69ca0bf693770c9dacaab0806d1f63cc81b5f80a3565b6040516335abdfdf60e01b8152600490fd5b6040516356e4289360e01b815260206004820152600a6024820152692fb232b837b9b4ba37b960b11b6044820152606490fd5b603081066119ba576030900480156119a85790565b604051639106113760e01b8152600490fd5b604051630726fa7960e31b8152600490fd5b6030928302019060200137565b60ff5f80516020611a488339815191525460401c16156119f557565b604051631afcd79f60e31b8152600490fdfe2ec50241a851d8d3fea472e7057288d4603f7a7f78e6d18a9c12cad84552b1019016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00a26469706673582212208084a17de5858e45b60184f6f8c050327cb7d5899cb216c71bbba22a5083340264736f6c63430008190033

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

00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa

-----Decoded View---------------
Arg [0] : _beaconChainDepositContract (address): 0x00000000219ab540356cBB839Cbe05303d7705Fa

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
0x5ff3782820Fc06cdF5a9ded897a778a6f0840b85
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]
[ 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.