Source Code
Overview
ETH Balance
0.24381566788754529 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 9 from a total of 9 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer | 1694460 | 54 days ago | IN | 0.01239337 ETH | 0.00002118 | ||||
| Transfer | 1648955 | 61 days ago | IN | 0.01067539 ETH | 0.00002164 | ||||
| Transfer | 1642389 | 62 days ago | IN | 0.0055548 ETH | 0.00002213 | ||||
| Transfer | 1607890 | 67 days ago | IN | 0.00937099 ETH | 0.00002126 | ||||
| Transfer | 1589999 | 69 days ago | IN | 0.00280212 ETH | 0.00002268 | ||||
| Transfer | 1537940 | 77 days ago | IN | 0.01619779 ETH | 0.0000199 | ||||
| Transfer | 1536950 | 77 days ago | IN | 0.03708501 ETH | 0.00002154 | ||||
| Transfer | 1531089 | 78 days ago | IN | 0.06173309 ETH | 0.00001932 | ||||
| Transfer | 1529675 | 78 days ago | IN | 0.0522916 ETH | 0.00002282 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| Beacon Chain Dep... | 2057750 | 5 hrs ago | 0 ETH | ||||
| Beacon Chain Dep... | 2057745 | 5 hrs ago | 0 ETH | ||||
| Beacon Chain Dep... | 2057739 | 5 hrs ago | 0 ETH | ||||
| Beacon Chain Dep... | 2057731 | 5 hrs ago | 0 ETH | ||||
| Transfer | 2054060 | 19 hrs ago | 0.00379491 ETH | ||||
| Transfer | 2051543 | 28 hrs ago | 0.00642036 ETH | ||||
| Transfer | 2049378 | 36 hrs ago | 0.00399363 ETH | ||||
| Transfer | 2046354 | 47 hrs ago | 0.00985999 ETH | ||||
| Beacon Chain Dep... | 2043953 | 2 days ago | 0 ETH | ||||
| Withdraw | 2043953 | 2 days ago | 0 ETH | ||||
| Transfer | 2033253 | 3 days ago | 0.00321853 ETH | ||||
| Transfer | 2031875 | 4 days ago | 0.01014675 ETH | ||||
| Transfer | 2020447 | 5 days ago | 0.02552148 ETH | ||||
| Transfer | 2010823 | 7 days ago | 0.02942315 ETH | ||||
| Transfer | 2006250 | 7 days ago | 0.02203672 ETH | ||||
| Fund | 2004360 | 8 days ago | 31 ETH | ||||
| Fund | 2004340 | 8 days ago | 1 ETH | ||||
| Accept Ownership | 2004314 | 8 days ago | 0 ETH | ||||
| Owner | 2004314 | 8 days ago | 0 ETH | ||||
| Depositor | 2004314 | 8 days ago | 0 ETH | ||||
| Is Ossified | 2004314 | 8 days ago | 0 ETH | ||||
| Pending Owner | 2004314 | 8 days ago | 0 ETH | ||||
| Transfer Ownersh... | 2004314 | 8 days ago | 0 ETH | ||||
| Fund | 2004314 | 8 days ago | 1 ETH | ||||
| Initialize | 2004314 | 8 days ago | 0 ETH |
Loading...
Loading
Produced Blocks
Loading...
Loading
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(); }
// 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();
}
}
}// 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;
}
}{
"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"}]Contract Creation Code
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
Loading...
Loading
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.