Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
EigenPod
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../libraries/BeaconChainProofs.sol";
import "../mixins/SemVerMixin.sol";
import "../interfaces/IETHPOSDeposit.sol";
import "../interfaces/IEigenPodManager.sol";
import "../interfaces/IPausable.sol";
import "./EigenPodPausingConstants.sol";
import "./EigenPodStorage.sol";
/**
* @title The implementation contract used for restaking beacon chain ETH on EigenLayer
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This EigenPod Beacon Proxy implementation adheres to the current Deneb consensus specs
* @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
* to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
*/
contract EigenPod is
Initializable,
ReentrancyGuardUpgradeable,
EigenPodPausingConstants,
EigenPodStorage,
SemVerMixin
{
using SafeERC20 for IERC20;
using BeaconChainProofs for *;
/**
*
* CONSTANTS / IMMUTABLES
*
*/
/// @notice The beacon chain stores balances in Gwei, rather than wei. This value is used to convert between the two
uint256 internal constant GWEI_TO_WEI = 1e9;
/// @notice The address of the EIP-4788 beacon block root oracle
/// (See https://eips.ethereum.org/EIPS/eip-4788)
address internal constant BEACON_ROOTS_ADDRESS = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02;
/// @notice The address of the EIP-7002 withdrawal request predeploy
/// (See https://eips.ethereum.org/EIPS/eip-7002)
address internal constant WITHDRAWAL_REQUEST_ADDRESS = 0x00000961Ef480Eb55e80D19ad83579A64c007002;
/// @notice The address of the EIP-7251 consolidation request predeploy
/// (See https://eips.ethereum.org/EIPS/eip-7251)
address internal constant CONSOLIDATION_REQUEST_ADDRESS = 0x0000BBdDc7CE488642fb579F8B00f3a590007251;
/// @notice The length of the EIP-4788 beacon block root ring buffer
uint256 internal constant BEACON_ROOTS_HISTORY_BUFFER_LENGTH = 8191;
/// @notice The beacon chain deposit contract
IETHPOSDeposit public immutable ethPOS;
/// @notice The single EigenPodManager for EigenLayer
IEigenPodManager public immutable eigenPodManager;
/**
*
* MODIFIERS
*
*/
/// @notice Callable only by the EigenPodManager
modifier onlyEigenPodManager() {
require(msg.sender == address(eigenPodManager), OnlyEigenPodManager());
_;
}
/// @notice Callable only by the pod's owner
modifier onlyEigenPodOwner() {
require(msg.sender == podOwner, OnlyEigenPodOwner());
_;
}
/// @notice Callable only by the pod's owner or proof submitter
modifier onlyOwnerOrProofSubmitter() {
require(msg.sender == podOwner || msg.sender == proofSubmitter, OnlyEigenPodOwnerOrProofSubmitter());
_;
}
/**
* @notice Based on 'Pausable' code, but uses the storage of the EigenPodManager instead of this contract. This construction
* is necessary for enabling pausing all EigenPods at the same time (due to EigenPods being Beacon Proxies).
* Modifier throws if the `indexed`th bit of `_paused` in the EigenPodManager is 1, i.e. if the `index`th pause switch is flipped.
*/
modifier onlyWhenNotPaused(
uint8 index
) {
require(!IPausable(address(eigenPodManager)).paused(index), CurrentlyPaused());
_;
}
/**
*
* CONSTRUCTOR / INIT
*
*/
constructor(
IETHPOSDeposit _ethPOS,
IEigenPodManager _eigenPodManager,
string memory _version
) SemVerMixin(_version) {
ethPOS = _ethPOS;
eigenPodManager = _eigenPodManager;
_disableInitializers();
}
/// @inheritdoc IEigenPod
function initialize(
address _podOwner
) external initializer {
require(_podOwner != address(0), InputAddressZero());
podOwner = _podOwner;
}
/**
*
* EXTERNAL METHODS
*
*/
/// @notice payable fallback function used to receive ETH sent directly to the pod
receive() external payable {
emit NonBeaconChainETHReceived(msg.value);
}
/// @inheritdoc IEigenPod
function startCheckpoint(
bool revertIfNoBalance
) external onlyOwnerOrProofSubmitter onlyWhenNotPaused(PAUSED_START_CHECKPOINT) {
_startCheckpoint(revertIfNoBalance);
}
/// @inheritdoc IEigenPod
function verifyCheckpointProofs(
BeaconChainProofs.BalanceContainerProof calldata balanceContainerProof,
BeaconChainProofs.BalanceProof[] calldata proofs
) external onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS) {
uint64 checkpointTimestamp = currentCheckpointTimestamp;
require(checkpointTimestamp != 0, NoActiveCheckpoint());
Checkpoint memory checkpoint = _currentCheckpoint;
// Verify `balanceContainerProof` against `beaconBlockRoot`
BeaconChainProofs.verifyBalanceContainer({
proofVersion: _getProofVersion(checkpointTimestamp),
beaconBlockRoot: checkpoint.beaconBlockRoot,
proof: balanceContainerProof
});
// Process each checkpoint proof submitted
uint64 exitedBalancesGwei;
for (uint256 i = 0; i < proofs.length; i++) {
BeaconChainProofs.BalanceProof calldata proof = proofs[i];
ValidatorInfo memory validatorInfo = _validatorPubkeyHashToInfo[proof.pubkeyHash];
// Validator must be in the ACTIVE state to be provable during a checkpoint.
// Validators become ACTIVE when initially proven via verifyWithdrawalCredentials
// Validators become WITHDRAWN when a checkpoint proof shows they have 0 balance
if (validatorInfo.status != VALIDATOR_STATUS.ACTIVE) {
continue;
}
// Ensure we aren't proving a validator twice for the same checkpoint. This will fail if:
// - validator submitted twice during this checkpoint
// - validator withdrawal credentials verified after checkpoint starts, then submitted
// as a checkpoint proof
if (validatorInfo.lastCheckpointedAt >= checkpointTimestamp) {
continue;
}
// Process a checkpoint proof for a validator and update its balance.
//
// If the proof shows the validator has a balance of 0, they are marked `WITHDRAWN`.
// The assumption is that if this is the case, any withdrawn ETH was already in
// the pod when `startCheckpoint` was originally called.
(uint64 prevBalanceGwei, int64 balanceDeltaGwei, uint64 exitedBalanceGwei) = _verifyCheckpointProof({
validatorInfo: validatorInfo,
checkpointTimestamp: checkpointTimestamp,
balanceContainerRoot: balanceContainerProof.balanceContainerRoot,
proof: proof
});
checkpoint.proofsRemaining--;
checkpoint.prevBeaconBalanceGwei += prevBalanceGwei;
checkpoint.balanceDeltasGwei += balanceDeltaGwei;
exitedBalancesGwei += exitedBalanceGwei;
// Record the updated validator in state
_validatorPubkeyHashToInfo[proof.pubkeyHash] = validatorInfo;
emit ValidatorCheckpointed(checkpointTimestamp, proof.pubkeyHash);
}
// Update the checkpoint and the total amount attributed to exited validators
checkpointBalanceExitedGwei[checkpointTimestamp] += exitedBalancesGwei;
_updateCheckpoint(checkpoint);
}
/// @inheritdoc IEigenPod
function verifyWithdrawalCredentials(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
uint40[] calldata validatorIndices,
bytes[] calldata validatorFieldsProofs,
bytes32[][] calldata validatorFields
) external onlyOwnerOrProofSubmitter onlyWhenNotPaused(PAUSED_EIGENPODS_VERIFY_CREDENTIALS) {
require(
(validatorIndices.length == validatorFieldsProofs.length)
&& (validatorFieldsProofs.length == validatorFields.length),
InputArrayLengthMismatch()
);
// Calling this method using a `beaconTimestamp` <= `currentCheckpointTimestamp` would allow
// a newly-verified validator to be submitted to `verifyCheckpointProofs`, making progress
// on an existing checkpoint.
require(beaconTimestamp > currentCheckpointTimestamp, BeaconTimestampTooFarInPast());
// For sanity, we want to ensure that a newly-verified validator cannot be proven against state
// that has already been checkpointed. This check makes the state transitions easier to reason about.
require(beaconTimestamp > lastCheckpointTimestamp, BeaconTimestampBeforeLatestCheckpoint());
// Verify passed-in `beaconStateRoot` against the beacon block root
// forgefmt: disable-next-item
BeaconChainProofs.verifyStateRoot({
beaconBlockRoot: getParentBlockRoot(beaconTimestamp),
proof: stateRootProof
});
uint256 totalAmountToBeRestakedWei;
for (uint256 i = 0; i < validatorIndices.length; i++) {
// forgefmt: disable-next-item
totalAmountToBeRestakedWei += _verifyWithdrawalCredentials(
beaconTimestamp,
stateRootProof.beaconStateRoot,
validatorIndices[i],
validatorFieldsProofs[i],
validatorFields[i]
);
}
// Update the EigenPodManager on this pod's new balance
eigenPodManager.recordBeaconChainETHBalanceUpdate({
podOwner: podOwner,
prevRestakedBalanceWei: 0, // only used for checkpoint balance updates
balanceDeltaWei: int256(totalAmountToBeRestakedWei)
});
}
/// @inheritdoc IEigenPod
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external onlyWhenNotPaused(PAUSED_START_CHECKPOINT) onlyWhenNotPaused(PAUSED_VERIFY_STALE_BALANCE) {
bytes32 validatorPubkey = proof.validatorFields.getPubkeyHash();
ValidatorInfo memory validatorInfo = _validatorPubkeyHashToInfo[validatorPubkey];
// Validator must be eligible for a staleness proof. Generally, this condition
// ensures that the staleness proof is newer than the last time we got an update
// on this validator.
//
// Note: It is possible for `validatorInfo.lastCheckpointedAt` to be 0 if
// a validator's withdrawal credentials are verified when no checkpoint has
// ever been completed in this pod. Technically, this would mean that `beaconTimestamp`
// can be any valid EIP-4788 timestamp - because any nonzero value satisfies the
// require below.
//
// However, in practice, if the only update we've seen from a validator is their
// `verifyWithdrawalCredentials` proof, any valid `verifyStaleBalance` proof is
// necessarily newer. This is because when a validator is initially slashed, their
// exit epoch is set. And because `verifyWithdrawalCredentials` rejects validators
// that have initiated exits, we know that if we're seeing a proof where the validator
// is slashed that it MUST be newer than the `verifyWithdrawalCredentials` proof
// (regardless of the relationship between `beaconTimestamp` and `lastCheckpointedAt`).
require(beaconTimestamp > validatorInfo.lastCheckpointedAt, BeaconTimestampTooFarInPast());
// Validator must be checkpoint-able
require(validatorInfo.status == VALIDATOR_STATUS.ACTIVE, ValidatorNotActiveInPod());
// Validator must be slashed on the beacon chain
require(proof.validatorFields.isValidatorSlashed(), ValidatorNotSlashedOnBeaconChain());
// Verify passed-in `beaconStateRoot` against the beacon block root
// forgefmt: disable-next-item
BeaconChainProofs.verifyStateRoot({
beaconBlockRoot: getParentBlockRoot(beaconTimestamp),
proof: stateRootProof
});
// Verify Validator container proof against `beaconStateRoot`
BeaconChainProofs.verifyValidatorFields({
proofVersion: _getProofVersion(beaconTimestamp),
beaconStateRoot: stateRootProof.beaconStateRoot,
validatorFields: proof.validatorFields,
validatorFieldsProof: proof.proof,
validatorIndex: uint40(validatorInfo.validatorIndex)
});
// Validator verified to be stale - start a checkpoint
_startCheckpoint(false);
}
/// @inheritdoc IEigenPod
function requestConsolidation(
ConsolidationRequest[] calldata requests
) external payable onlyWhenNotPaused(PAUSED_CONSOLIDATIONS) onlyOwnerOrProofSubmitter {
uint256 fee = getConsolidationRequestFee();
uint256 totalFee = fee * requests.length;
require(msg.value >= totalFee, InsufficientFunds());
uint256 remainder = msg.value - totalFee;
for (uint256 i = 0; i < requests.length; i++) {
ConsolidationRequest calldata request = requests[i];
// Ensure target has verified withdrawal credentials pointed at this pod
bytes32 sourcePubkeyHash = _calcPubkeyHash(request.srcPubkey);
bytes32 targetPubkeyHash = _calcPubkeyHash(request.targetPubkey);
require(validatorStatus(targetPubkeyHash) == VALIDATOR_STATUS.ACTIVE, ValidatorNotActiveInPod());
// Call the predeploy
bytes memory callData = bytes.concat(request.srcPubkey, request.targetPubkey);
(bool ok,) = CONSOLIDATION_REQUEST_ADDRESS.call{value: fee}(callData);
require(ok, PredeployFailed());
// Emit event depending on whether this is a switch to 0x02, or a regular consolidation
if (sourcePubkeyHash == targetPubkeyHash) emit SwitchToCompoundingRequested(sourcePubkeyHash);
else emit ConsolidationRequested(sourcePubkeyHash, targetPubkeyHash);
}
// Refund remainder of msg.value
if (remainder > 0) {
Address.sendValue(payable(msg.sender), remainder);
}
}
/// @inheritdoc IEigenPod
function requestWithdrawal(
WithdrawalRequest[] calldata requests
) external payable onlyWhenNotPaused(PAUSED_WITHDRAWAL_REQUESTS) onlyOwnerOrProofSubmitter {
uint256 fee = getWithdrawalRequestFee();
uint256 totalFee = fee * requests.length;
require(msg.value >= totalFee, InsufficientFunds());
uint256 remainder = msg.value - totalFee;
for (uint256 i = 0; i < requests.length; i++) {
WithdrawalRequest calldata request = requests[i];
bytes32 pubkeyHash = _calcPubkeyHash(request.pubkey);
// Ensure validator has verified withdrawal credentials pointed at this pod
require(validatorStatus(pubkeyHash) == VALIDATOR_STATUS.ACTIVE, ValidatorNotActiveInPod());
// Call the predeploy
bytes memory callData = abi.encodePacked(request.pubkey, request.amountGwei);
(bool ok,) = WITHDRAWAL_REQUEST_ADDRESS.call{value: fee}(callData);
require(ok, PredeployFailed());
// Emit event depending on whether the request is a full exit or a partial withdrawal
if (request.amountGwei == 0) emit ExitRequested(pubkeyHash);
else emit WithdrawalRequested(pubkeyHash, request.amountGwei);
}
// Refund remainder of msg.value
if (remainder > 0) {
Address.sendValue(payable(msg.sender), remainder);
}
}
/// @inheritdoc IEigenPod
function recoverTokens(
IERC20[] memory tokenList,
uint256[] memory amountsToWithdraw,
address recipient
) external onlyEigenPodOwner onlyWhenNotPaused(PAUSED_NON_PROOF_WITHDRAWALS) {
require(tokenList.length == amountsToWithdraw.length, InputArrayLengthMismatch());
for (uint256 i = 0; i < tokenList.length; i++) {
tokenList[i].safeTransfer(recipient, amountsToWithdraw[i]);
}
}
/// @inheritdoc IEigenPod
function setProofSubmitter(
address newProofSubmitter
) external onlyEigenPodOwner {
emit ProofSubmitterUpdated(proofSubmitter, newProofSubmitter);
proofSubmitter = newProofSubmitter;
}
/// @inheritdoc IEigenPod
function stake(
bytes calldata pubkey,
bytes calldata signature,
bytes32 depositDataRoot
) external payable onlyEigenPodManager {
// stake on ethpos
require(msg.value == 32 ether, MsgValueNot32ETH());
ethPOS.deposit{value: 32 ether}(pubkey, _podWithdrawalCredentials(), signature, depositDataRoot);
emit EigenPodStaked(_calcPubkeyHash(pubkey));
}
/// @inheritdoc IEigenPod
function withdrawRestakedBeaconChainETH(address recipient, uint256 amountWei) external onlyEigenPodManager {
uint64 amountGwei = uint64(amountWei / GWEI_TO_WEI);
amountWei = amountGwei * GWEI_TO_WEI;
require(amountGwei <= restakedExecutionLayerGwei, InsufficientWithdrawableBalance());
restakedExecutionLayerGwei -= amountGwei;
emit RestakedBeaconChainETHWithdrawn(recipient, amountWei);
// transfer ETH from pod to `recipient` directly
Address.sendValue(payable(recipient), amountWei);
}
/**
*
* INTERNAL FUNCTIONS
*
*/
/**
* @notice internal function that proves an individual validator's withdrawal credentials
* @param validatorIndex is the index of the validator being proven
* @param validatorFieldsProof is the bytes that prove the ETH validator's withdrawal credentials against a beacon chain state root
* @param validatorFields are the fields of the "Validator Container", refer to consensus specs
*/
function _verifyWithdrawalCredentials(
uint64 beaconTimestamp,
bytes32 beaconStateRoot,
uint40 validatorIndex,
bytes calldata validatorFieldsProof,
bytes32[] calldata validatorFields
) internal returns (uint256) {
bytes32 pubkeyHash = validatorFields.getPubkeyHash();
ValidatorInfo memory validatorInfo = _validatorPubkeyHashToInfo[pubkeyHash];
// Withdrawal credential proofs should only be processed for "INACTIVE" validators
require(validatorInfo.status == VALIDATOR_STATUS.INACTIVE, CredentialsAlreadyVerified());
// Validator should be active on the beacon chain, or in the process of activating.
// This implies the validator has reached the minimum effective balance required
// to become active on the beacon chain.
//
// This check is important because the Pectra upgrade will move any validators that
// do NOT have an activation epoch to a "pending deposit queue," temporarily resetting
// their current and effective balances to 0. This balance can be restored if a deposit
// is made to bring the validator's balance above the minimum activation balance.
// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/fork.md#upgrading-the-state)
//
// In the context of EigenLayer slashing, this temporary reset would allow pod shares
// to temporarily decrease, then be restored later. This would effectively prevent these
// shares from being slashable on EigenLayer for a short period of time.
require(
validatorFields.getActivationEpoch() != BeaconChainProofs.FAR_FUTURE_EPOCH, ValidatorInactiveOnBeaconChain()
);
// Validator should not already be in the process of exiting. This is an important property
// this method needs to enforce to ensure a validator cannot be already-exited by the time
// its withdrawal credentials are verified.
//
// Note that when a validator initiates an exit, two values are set:
// - exit_epoch
// - withdrawable_epoch
//
// The latter of these two values describes an epoch after which the validator's ETH MIGHT
// have been exited to the EigenPod, depending on the state of the beacon chain withdrawal
// queue.
//
// Requiring that a validator has not initiated exit by the time the EigenPod sees their
// withdrawal credentials guarantees that the validator has not fully exited at this point.
//
// This is because:
// - the earliest beacon chain slot allowed for withdrawal credential proofs is the earliest
// slot available in the EIP-4788 oracle, which keeps the last 8192 slots.
// - when initiating an exit, a validator's earliest possible withdrawable_epoch is equal to
// 1 + MAX_SEED_LOOKAHEAD + MIN_VALIDATOR_WITHDRAWABILITY_DELAY == 261 epochs (8352 slots).
//
// (See https://eth2book.info/capella/part3/helper/mutators/#initiate_validator_exit)
require(validatorFields.getExitEpoch() == BeaconChainProofs.FAR_FUTURE_EPOCH, ValidatorIsExitingBeaconChain());
// Ensure the validator's withdrawal credentials are pointed at this pod
require(
validatorFields.getWithdrawalCredentials() == bytes32(_podWithdrawalCredentials())
|| validatorFields.getWithdrawalCredentials() == bytes32(_podCompoundingWithdrawalCredentials()),
WithdrawalCredentialsNotForEigenPod()
);
// Get the validator's effective balance. Note that this method uses effective balance, while
// `verifyCheckpointProofs` uses current balance. Effective balance is updated per-epoch - so it's
// less accurate, but is good enough for verifying withdrawal credentials.
uint64 restakedBalanceGwei = validatorFields.getEffectiveBalanceGwei();
// Verify passed-in validatorFields against verified beaconStateRoot:
BeaconChainProofs.verifyValidatorFields({
proofVersion: _getProofVersion(beaconTimestamp),
beaconStateRoot: beaconStateRoot,
validatorFields: validatorFields,
validatorFieldsProof: validatorFieldsProof,
validatorIndex: validatorIndex
});
// Account for validator in future checkpoints. Note that if this pod has never started a
// checkpoint before, `lastCheckpointedAt` will be zero here. This is fine because the main
// purpose of `lastCheckpointedAt` is to enforce that newly-verified validators are not
// eligible to progress already-existing checkpoints - however in this case, no checkpoints exist.
activeValidatorCount++;
uint64 lastCheckpointedAt =
currentCheckpointTimestamp == 0 ? lastCheckpointTimestamp : currentCheckpointTimestamp;
// Proofs complete - create the validator in state
_validatorPubkeyHashToInfo[pubkeyHash] = ValidatorInfo({
validatorIndex: validatorIndex,
restakedBalanceGwei: restakedBalanceGwei,
lastCheckpointedAt: lastCheckpointedAt,
status: VALIDATOR_STATUS.ACTIVE
});
// Add the validator's balance to the checkpoint's previous beacon balance
// Note that even if this checkpoint is not active, the next one will include
// the validator's restaked balance during the checkpoint process
_currentCheckpoint.prevBeaconBalanceGwei += restakedBalanceGwei;
emit ValidatorRestaked(pubkeyHash);
emit ValidatorBalanceUpdated(pubkeyHash, lastCheckpointedAt, restakedBalanceGwei);
return restakedBalanceGwei * GWEI_TO_WEI;
}
function _verifyCheckpointProof(
ValidatorInfo memory validatorInfo,
uint64 checkpointTimestamp,
bytes32 balanceContainerRoot,
BeaconChainProofs.BalanceProof calldata proof
) internal returns (uint64 prevBalanceGwei, int64 balanceDeltaGwei, uint64 exitedBalanceGwei) {
// Verify validator balance against `balanceContainerRoot`
prevBalanceGwei = validatorInfo.restakedBalanceGwei;
uint64 newBalanceGwei = BeaconChainProofs.verifyValidatorBalance({
balanceContainerRoot: balanceContainerRoot,
validatorIndex: uint40(validatorInfo.validatorIndex),
proof: proof
});
// Calculate change in the validator's balance since the last proof
if (newBalanceGwei != prevBalanceGwei) {
balanceDeltaGwei = int64(newBalanceGwei) - int64(prevBalanceGwei);
emit ValidatorBalanceUpdated(proof.pubkeyHash, checkpointTimestamp, newBalanceGwei);
}
validatorInfo.restakedBalanceGwei = newBalanceGwei;
validatorInfo.lastCheckpointedAt = checkpointTimestamp;
// If the validator's new balance is 0, mark them withdrawn
if (newBalanceGwei == 0) {
activeValidatorCount--;
validatorInfo.status = VALIDATOR_STATUS.WITHDRAWN;
// If we reach this point, `balanceDeltaGwei` should always be negative,
// so this should be a safe conversion
exitedBalanceGwei = uint64(-balanceDeltaGwei);
emit ValidatorWithdrawn(checkpointTimestamp, proof.pubkeyHash);
}
return (prevBalanceGwei, balanceDeltaGwei, exitedBalanceGwei);
}
/**
* @dev Initiate a checkpoint proof by snapshotting both the pod's ETH balance and the
* current block's parent block root. After providing a checkpoint proof for each of the
* pod's ACTIVE validators, the pod's ETH balance is awarded shares and can be withdrawn.
* @dev ACTIVE validators are validators with verified withdrawal credentials (See
* `verifyWithdrawalCredentials` for details)
* @dev If the pod does not have any ACTIVE validators, the checkpoint is automatically
* finalized.
* @dev Once started, a checkpoint MUST be completed! It is not possible to start a
* checkpoint if the existing one is incomplete.
* @param revertIfNoBalance If the available ETH balance for checkpointing is 0 and this is
* true, this method will revert
*/
function _startCheckpoint(
bool revertIfNoBalance
) internal {
require(currentCheckpointTimestamp == 0, CheckpointAlreadyActive());
// Prevent a checkpoint being completable twice in the same block. This prevents an edge case
// where the second checkpoint would not be completable.
//
// This is because the validators checkpointed in the first checkpoint would have a `lastCheckpointedAt`
// value equal to the second checkpoint, causing their proofs to get skipped in `verifyCheckpointProofs`
require(lastCheckpointTimestamp != uint64(block.timestamp), CannotCheckpointTwiceInSingleBlock());
// Snapshot pod balance at the start of the checkpoint, subtracting pod balance that has
// previously been credited with shares. Once the checkpoint is finalized, `podBalanceGwei`
// will be added to the total validator balance delta and credited as shares.
//
// Note: On finalization, `podBalanceGwei` is added to `restakedExecutionLayerGwei`
// to denote that it has been credited with shares. Because this value is denominated in gwei,
// `podBalanceGwei` is also converted to a gwei amount here. This means that any sub-gwei amounts
// sent to the pod are not credited with shares and are therefore not withdrawable.
// This can be addressed by topping up a pod's balance to a value divisible by 1 gwei.
uint64 podBalanceGwei = uint64(address(this).balance / GWEI_TO_WEI) - restakedExecutionLayerGwei;
// If the caller doesn't want a "0 balance" checkpoint, revert
if (revertIfNoBalance && podBalanceGwei == 0) {
revert NoBalanceToCheckpoint();
}
// Create checkpoint using the previous block's root for proofs, and the current
// `activeValidatorCount` as the number of checkpoint proofs needed to finalize
// the checkpoint.
Checkpoint memory checkpoint = Checkpoint({
beaconBlockRoot: getParentBlockRoot(uint64(block.timestamp)),
proofsRemaining: uint24(activeValidatorCount),
podBalanceGwei: podBalanceGwei,
balanceDeltasGwei: 0,
prevBeaconBalanceGwei: 0
});
// Place checkpoint in storage. If `proofsRemaining` is 0, the checkpoint
// is automatically finalized.
currentCheckpointTimestamp = uint64(block.timestamp);
_updateCheckpoint(checkpoint);
emit CheckpointCreated(uint64(block.timestamp), checkpoint.beaconBlockRoot, checkpoint.proofsRemaining);
}
/**
* @dev Finish progress on a checkpoint and store it in state.
* @dev If the checkpoint has no proofs remaining, it is finalized:
* - a share delta is calculated and sent to the `EigenPodManager`
* - the checkpointed `podBalanceGwei` is added to `restakedExecutionLayerGwei`
* - `lastCheckpointTimestamp` is updated
* - `currentCheckpointTimestamp` is set to zero
*/
function _updateCheckpoint(
Checkpoint memory checkpoint
) internal {
_currentCheckpoint = checkpoint;
if (checkpoint.proofsRemaining != 0) {
return;
}
// Calculate the previous total restaked balance and change in restaked balance
// Note: due to how these values are calculated, a negative `balanceDeltaGwei`
// should NEVER be greater in magnitude than `prevRestakedBalanceGwei`
uint64 prevRestakedBalanceGwei = restakedExecutionLayerGwei + checkpoint.prevBeaconBalanceGwei;
int64 balanceDeltaGwei = int64(checkpoint.podBalanceGwei) + checkpoint.balanceDeltasGwei;
// And native ETH when the checkpoint was started is now considered restaked.
// Add it to `restakedExecutionLayerGwei`, which allows it to be withdrawn via
// the `DelegationManager` withdrawal queue.
restakedExecutionLayerGwei += checkpoint.podBalanceGwei;
// Finalize the checkpoint by resetting `currentCheckpointTimestamp`.
lastCheckpointTimestamp = currentCheckpointTimestamp;
delete currentCheckpointTimestamp;
// Convert shares and delta to wei
uint256 prevRestakedBalanceWei = prevRestakedBalanceGwei * GWEI_TO_WEI;
int256 balanceDeltaWei = balanceDeltaGwei * int256(GWEI_TO_WEI);
// Update pod owner's shares
emit CheckpointFinalized(lastCheckpointTimestamp, balanceDeltaWei);
eigenPodManager.recordBeaconChainETHBalanceUpdate({
podOwner: podOwner,
prevRestakedBalanceWei: prevRestakedBalanceWei,
balanceDeltaWei: balanceDeltaWei
});
}
function _podWithdrawalCredentials() internal view returns (bytes memory) {
return abi.encodePacked(bytes1(uint8(1)), bytes11(0), address(this));
}
function _podCompoundingWithdrawalCredentials() internal view returns (bytes memory) {
return abi.encodePacked(bytes1(uint8(2)), bytes11(0), address(this));
}
///@notice Calculates the pubkey hash of a validator's pubkey as per SSZ spec
function _calcPubkeyHash(
bytes memory validatorPubkey
) internal pure returns (bytes32) {
require(validatorPubkey.length == 48, InvalidPubKeyLength());
return sha256(abi.encodePacked(validatorPubkey, bytes16(0)));
}
/// @dev Returns the current fee required to query either the EIP-7002 or EIP-7251 predeploy
function _getFee(
address predeploy
) internal view returns (uint256) {
(bool success, bytes memory result) = predeploy.staticcall("");
require(success && result.length == 32, FeeQueryFailed());
return uint256(bytes32(result));
}
/// @notice Returns the PROOF_TYPE depending on the `proofTimestamp` in relation to the fork timestamp.
function _getProofVersion(
uint64 proofTimestamp
) internal view returns (BeaconChainProofs.ProofVersion) {
/// Get the timestamp of the Pectra fork, read from the `EigenPodManager`
/// This returns the timestamp of the first non-missed slot at or after the Pectra hard fork
uint64 forkTimestamp = eigenPodManager.pectraForkTimestamp();
require(forkTimestamp != 0, ForkTimestampZero());
/// We check if the proofTimestamp is <= pectraForkTimestamp because a `proofTimestamp` at the `pectraForkTimestamp`
/// is considered to be Pre-Pectra given the EIP-4788 oracle returns the parent block.
return proofTimestamp <= forkTimestamp
? BeaconChainProofs.ProofVersion.DENEB
: BeaconChainProofs.ProofVersion.PECTRA;
}
/**
*
* VIEW FUNCTIONS
*
*/
/// @inheritdoc IEigenPod
function withdrawableRestakedExecutionLayerGwei() external view returns (uint64) {
return restakedExecutionLayerGwei;
}
/// @inheritdoc IEigenPod
function validatorPubkeyHashToInfo(
bytes32 validatorPubkeyHash
) public view returns (ValidatorInfo memory) {
return _validatorPubkeyHashToInfo[validatorPubkeyHash];
}
/// @inheritdoc IEigenPod
function validatorPubkeyToInfo(
bytes calldata validatorPubkey
) public view returns (ValidatorInfo memory) {
return _validatorPubkeyHashToInfo[_calcPubkeyHash(validatorPubkey)];
}
/// @inheritdoc IEigenPod
function validatorStatus(
bytes32 pubkeyHash
) public view returns (VALIDATOR_STATUS) {
return _validatorPubkeyHashToInfo[pubkeyHash].status;
}
/// @inheritdoc IEigenPod
function validatorStatus(
bytes calldata validatorPubkey
) external view returns (VALIDATOR_STATUS) {
bytes32 validatorPubkeyHash = _calcPubkeyHash(validatorPubkey);
return _validatorPubkeyHashToInfo[validatorPubkeyHash].status;
}
/// @inheritdoc IEigenPod
function currentCheckpoint() public view returns (Checkpoint memory) {
return _currentCheckpoint;
}
/// @inheritdoc IEigenPod
function getParentBlockRoot(
uint64 timestamp
) public view returns (bytes32) {
require(block.timestamp - timestamp < BEACON_ROOTS_HISTORY_BUFFER_LENGTH * 12, TimestampOutOfRange());
(bool success, bytes memory result) = BEACON_ROOTS_ADDRESS.staticcall(abi.encode(timestamp));
require(success && result.length > 0, InvalidEIP4788Response());
return abi.decode(result, (bytes32));
}
/// @inheritdoc IEigenPod
function getConsolidationRequestFee() public view returns (uint256) {
return _getFee(CONSOLIDATION_REQUEST_ADDRESS);
}
/// @inheritdoc IEigenPod
function getWithdrawalRequestFee() public view returns (uint256) {
return _getFee(WITHDRAWAL_REQUEST_ADDRESS);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* 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 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
* 0 before setting it to a non-zero value.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Merkle.sol";
import "../libraries/Endian.sol";
//Utility library for parsing and PHASE0 beacon chain block headers
//SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization
//BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
//BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate
library BeaconChainProofs {
/// @dev Thrown when a proof is invalid.
error InvalidProof();
/// @dev Thrown when a proof with an invalid length is provided.
error InvalidProofLength();
/// @dev Thrown when a validator fields length is invalid.
error InvalidValidatorFieldsLength();
/// @notice Heights of various merkle trees in the beacon chain
/// beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// beaconStateRoot
/// / \ HEIGHT: BEACON_STATE_TREE_HEIGHT
/// validatorContainerRoot, balanceContainerRoot
/// | | HEIGHT: BALANCE_TREE_HEIGHT
/// | individual balances
/// | HEIGHT: VALIDATOR_TREE_HEIGHT
/// individual validators
uint256 internal constant BEACON_BLOCK_HEADER_TREE_HEIGHT = 3;
uint256 internal constant DENEB_BEACON_STATE_TREE_HEIGHT = 5;
uint256 internal constant PECTRA_BEACON_STATE_TREE_HEIGHT = 6;
uint256 internal constant BALANCE_TREE_HEIGHT = 38;
uint256 internal constant VALIDATOR_TREE_HEIGHT = 40;
/// @notice Index of the beaconStateRoot in the `BeaconBlockHeader` container
///
/// BeaconBlockHeader = [..., state_root, ...]
/// 0... 3
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader)
uint256 internal constant STATE_ROOT_INDEX = 3;
/// @notice Indices for fields in the `BeaconState` container
///
/// BeaconState = [..., validators, balances, ...]
/// 0... 11 12
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconstate)
uint256 internal constant VALIDATOR_CONTAINER_INDEX = 11;
uint256 internal constant BALANCE_CONTAINER_INDEX = 12;
/// @notice Number of fields in the `Validator` container
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator)
uint256 internal constant VALIDATOR_FIELDS_LENGTH = 8;
/// @notice Indices for fields in the `Validator` container
uint256 internal constant VALIDATOR_PUBKEY_INDEX = 0;
uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1;
uint256 internal constant VALIDATOR_BALANCE_INDEX = 2;
uint256 internal constant VALIDATOR_SLASHED_INDEX = 3;
uint256 internal constant VALIDATOR_ACTIVATION_EPOCH_INDEX = 5;
uint256 internal constant VALIDATOR_EXIT_EPOCH_INDEX = 6;
/// @notice Slot/Epoch timings
uint64 internal constant SECONDS_PER_SLOT = 12;
uint64 internal constant SLOTS_PER_EPOCH = 32;
uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT;
/// @notice `FAR_FUTURE_EPOCH` is used as the default value for certain `Validator`
/// fields when a `Validator` is first created on the beacon chain
uint64 internal constant FAR_FUTURE_EPOCH = type(uint64).max;
bytes8 internal constant UINT64_MASK = 0xffffffffffffffff;
/// @notice The beacon chain version to validate against
enum ProofVersion {
DENEB,
PECTRA
}
/// @notice Contains a beacon state root and a merkle proof verifying its inclusion under a beacon block root
struct StateRootProof {
bytes32 beaconStateRoot;
bytes proof;
}
/// @notice Contains a validator's fields and a merkle proof of their inclusion under a beacon state root
struct ValidatorProof {
bytes32[] validatorFields;
bytes proof;
}
/// @notice Contains a beacon balance container root and a proof of this root under a beacon block root
struct BalanceContainerProof {
bytes32 balanceContainerRoot;
bytes proof;
}
/// @notice Contains a validator balance root and a proof of its inclusion under a balance container root
struct BalanceProof {
bytes32 pubkeyHash;
bytes32 balanceRoot;
bytes proof;
}
/**
*
* VALIDATOR FIELDS -> BEACON STATE ROOT -> BEACON BLOCK ROOT
*
*/
/// @notice Verify a merkle proof of the beacon state root against a beacon block root
/// @param beaconBlockRoot merkle root of the beacon block
/// @param proof the beacon state root and merkle proof of its inclusion under `beaconBlockRoot`
function verifyStateRoot(bytes32 beaconBlockRoot, StateRootProof calldata proof) internal view {
require(proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT), InvalidProofLength());
/// This merkle proof verifies the `beaconStateRoot` under the `beaconBlockRoot`
/// - beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// -- beaconStateRoot
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: beaconBlockRoot,
leaf: proof.beaconStateRoot,
index: STATE_ROOT_INDEX
}),
InvalidProof()
);
}
/// @notice Verify a merkle proof of a validator container against a `beaconStateRoot`
/// @dev This proof starts at a validator's container root, proves through the validator container root,
/// and continues proving to the root of the `BeaconState`
/// @dev See https://eth2book.info/capella/part3/containers/dependencies/#validator for info on `Validator` containers
/// @dev See https://eth2book.info/capella/part3/containers/state/#beaconstate for info on `BeaconState` containers
/// @param beaconStateRoot merkle root of the `BeaconState` container
/// @param validatorFields an individual validator's fields. These are merklized to form a `validatorRoot`,
/// which is used as the leaf to prove against `beaconStateRoot`
/// @param validatorFieldsProof a merkle proof of inclusion of `validatorFields` under `beaconStateRoot`
/// @param validatorIndex the validator's unique index
function verifyValidatorFields(
ProofVersion proofVersion,
bytes32 beaconStateRoot,
bytes32[] calldata validatorFields,
bytes calldata validatorFieldsProof,
uint40 validatorIndex
) internal view {
require(validatorFields.length == VALIDATOR_FIELDS_LENGTH, InvalidValidatorFieldsLength());
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofVersion);
/// Note: the reason we use `VALIDATOR_TREE_HEIGHT + 1` here is because the merklization process for
/// this container includes hashing the root of the validator tree with the length of the validator list
require(
validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + beaconStateTreeHeight),
InvalidProofLength()
);
// Merkleize `validatorFields` to get the leaf to prove
bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields);
/// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees:
/// - beaconStateRoot
/// | HEIGHT: BEACON_STATE_TREE_HEIGHT
/// -- validatorContainerRoot
/// | HEIGHT: VALIDATOR_TREE_HEIGHT + 1
/// ---- validatorRoot
uint256 index = (VALIDATOR_CONTAINER_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex);
require(
Merkle.verifyInclusionSha256({
proof: validatorFieldsProof,
root: beaconStateRoot,
leaf: validatorRoot,
index: index
}),
InvalidProof()
);
}
/**
*
* VALIDATOR BALANCE -> BALANCE CONTAINER ROOT -> BEACON BLOCK ROOT
*
*/
/// @notice Verify a merkle proof of the beacon state's balances container against the beacon block root
/// @dev This proof starts at the balance container root, proves through the beacon state root, and
/// continues proving through the beacon block root. As a result, this proof will contain elements
/// of a `StateRootProof` under the same block root, with the addition of proving the balances field
/// within the beacon state.
/// @dev This is used to make checkpoint proofs more efficient, as a checkpoint will verify multiple balances
/// against the same balance container root.
/// @param beaconBlockRoot merkle root of the beacon block
/// @param proof a beacon balance container root and merkle proof of its inclusion under `beaconBlockRoot`
function verifyBalanceContainer(
ProofVersion proofVersion,
bytes32 beaconBlockRoot,
BalanceContainerProof calldata proof
) internal view {
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofVersion);
require(
proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + beaconStateTreeHeight), InvalidProofLength()
);
/// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees:
/// - beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// -- beaconStateRoot
/// | HEIGHT: BEACON_STATE_TREE_HEIGHT
/// ---- balancesContainerRoot
uint256 index = (STATE_ROOT_INDEX << (beaconStateTreeHeight)) | BALANCE_CONTAINER_INDEX;
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: beaconBlockRoot,
leaf: proof.balanceContainerRoot,
index: index
}),
InvalidProof()
);
}
/// @notice Verify a merkle proof of a validator's balance against the beacon state's `balanceContainerRoot`
/// @param balanceContainerRoot the merkle root of all validators' current balances
/// @param validatorIndex the index of the validator whose balance we are proving
/// @param proof the validator's associated balance root and a merkle proof of inclusion under `balanceContainerRoot`
/// @return validatorBalanceGwei the validator's current balance (in gwei)
function verifyValidatorBalance(
bytes32 balanceContainerRoot,
uint40 validatorIndex,
BalanceProof calldata proof
) internal view returns (uint64 validatorBalanceGwei) {
/// Note: the reason we use `BALANCE_TREE_HEIGHT + 1` here is because the merklization process for
/// this container includes hashing the root of the balances tree with the length of the balances list
require(proof.proof.length == 32 * (BALANCE_TREE_HEIGHT + 1), InvalidProofLength());
/// When merkleized, beacon chain balances are combined into groups of 4 called a `balanceRoot`. The merkle
/// proof here verifies that this validator's `balanceRoot` is included in the `balanceContainerRoot`
/// - balanceContainerRoot
/// | HEIGHT: BALANCE_TREE_HEIGHT
/// -- balanceRoot
uint256 balanceIndex = uint256(validatorIndex / 4);
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: balanceContainerRoot,
leaf: proof.balanceRoot,
index: balanceIndex
}),
InvalidProof()
);
/// Extract the individual validator's balance from the `balanceRoot`
return getBalanceAtIndex(proof.balanceRoot, validatorIndex);
}
/**
* @notice Parses a balanceRoot to get the uint64 balance of a validator.
* @dev During merkleization of the beacon state balance tree, four uint64 values are treated as a single
* leaf in the merkle tree. We use validatorIndex % 4 to determine which of the four uint64 values to
* extract from the balanceRoot.
* @param balanceRoot is the combination of 4 validator balances being proven for
* @param validatorIndex is the index of the validator being proven for
* @return The validator's balance, in Gwei
*/
function getBalanceAtIndex(bytes32 balanceRoot, uint40 validatorIndex) internal pure returns (uint64) {
uint256 bitShiftAmount = (validatorIndex % 4) * 64;
return Endian.fromLittleEndianUint64(bytes32((uint256(balanceRoot) << bitShiftAmount)));
}
/// @notice Indices for fields in the `Validator` container:
/// 0: pubkey
/// 1: withdrawal credentials
/// 2: effective balance
/// 3: slashed?
/// 4: activation eligibility epoch
/// 5: activation epoch
/// 6: exit epoch
/// 7: withdrawable epoch
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator)
/// @dev Retrieves a validator's pubkey hash
function getPubkeyHash(
bytes32[] memory validatorFields
) internal pure returns (bytes32) {
return validatorFields[VALIDATOR_PUBKEY_INDEX];
}
/// @dev Retrieves a validator's withdrawal credentials
function getWithdrawalCredentials(
bytes32[] memory validatorFields
) internal pure returns (bytes32) {
return validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX];
}
/// @dev Retrieves a validator's effective balance (in gwei)
function getEffectiveBalanceGwei(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_BALANCE_INDEX]);
}
/// @dev Retrieves a validator's activation epoch
function getActivationEpoch(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_ACTIVATION_EPOCH_INDEX]);
}
/// @dev Retrieves true IFF a validator is marked slashed
function isValidatorSlashed(
bytes32[] memory validatorFields
) internal pure returns (bool) {
return validatorFields[VALIDATOR_SLASHED_INDEX] != 0;
}
/// @dev Retrieves a validator's exit epoch
function getExitEpoch(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_EXIT_EPOCH_INDEX]);
}
/// @dev We check if the proofTimestamp is <= pectraForkTimestamp because a `proofTimestamp` at the `pectraForkTimestamp`
/// is considered to be Pre-Pectra given the EIP-4788 oracle returns the parent block.
function getBeaconStateTreeHeight(
ProofVersion proofVersion
) internal pure returns (uint256) {
return proofVersion == ProofVersion.DENEB ? DENEB_BEACON_STATE_TREE_HEIGHT : PECTRA_BEACON_STATE_TREE_HEIGHT;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../interfaces/ISemVerMixin.sol";
import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol";
/// @title SemVerMixin
/// @notice A mixin contract that provides semantic versioning functionality.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/).
abstract contract SemVerMixin is ISemVerMixin {
using ShortStringsUpgradeable for *;
/// @notice The semantic version string for this contract, stored as a ShortString for gas efficiency.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/).
ShortString internal immutable _VERSION;
/// @notice Initializes the contract with a semantic version string.
/// @param _version The SemVer-formatted version string (e.g., "1.2.3")
/// @dev Version should follow SemVer 2.0.0 format: MAJOR.MINOR.PATCH
constructor(
string memory _version
) {
_VERSION = _version.toShortString();
}
/// @inheritdoc ISemVerMixin
function version() public view virtual returns (string memory) {
return _VERSION.toString();
}
/// @notice Returns the major version of the contract.
/// @dev Supports single digit major versions (e.g., "1" for version "1.2.3")
/// @return The major version string (e.g., "1" for version "1.2.3")
function _majorVersion() internal view returns (string memory) {
bytes memory v = bytes(_VERSION.toString());
return string(abi.encodePacked(v[0]));
}
}// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
// ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
// ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
// ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
// ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
// ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.5.0;
// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IETHPOSDeposit {
/// @notice A processed deposit event.
event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(
bytes calldata pubkey,
bytes calldata withdrawal_credentials,
bytes calldata signature,
bytes32 deposit_data_root
) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import "./IETHPOSDeposit.sol";
import "./IStrategyManager.sol";
import "./IEigenPod.sol";
import "./IShareManager.sol";
import "./IPausable.sol";
import "./IStrategy.sol";
import "./ISemVerMixin.sol";
interface IEigenPodManagerErrors {
/// @dev Thrown when caller is not a EigenPod.
error OnlyEigenPod();
/// @dev Thrown when caller is not DelegationManager.
error OnlyDelegationManager();
/// @dev Thrown when caller already has an EigenPod.
error EigenPodAlreadyExists();
/// @dev Thrown when shares is not a multiple of gwei.
error SharesNotMultipleOfGwei();
/// @dev Thrown when shares would result in a negative integer.
error SharesNegative();
/// @dev Thrown when the strategy is not the beaconChainETH strategy.
error InvalidStrategy();
/// @dev Thrown when the pods shares are negative and a beacon chain balance update is attempted.
/// The podOwner should complete legacy withdrawal first.
error LegacyWithdrawalsNotCompleted();
/// @dev Thrown when caller is not the proof timestamp setter
error OnlyProofTimestampSetter();
}
interface IEigenPodManagerEvents {
/// @notice Emitted to notify the deployment of an EigenPod
event PodDeployed(address indexed eigenPod, address indexed podOwner);
/// @notice Emitted to notify a deposit of beacon chain ETH recorded in the strategy manager
event BeaconChainETHDeposited(address indexed podOwner, uint256 amount);
/// @notice Emitted when the balance of an EigenPod is updated
event PodSharesUpdated(address indexed podOwner, int256 sharesDelta);
/// @notice Emitted every time the total shares of a pod are updated
event NewTotalShares(address indexed podOwner, int256 newTotalShares);
/// @notice Emitted when a withdrawal of beacon chain ETH is completed
event BeaconChainETHWithdrawalCompleted(
address indexed podOwner,
uint256 shares,
uint96 nonce,
address delegatedAddress,
address withdrawer,
bytes32 withdrawalRoot
);
/// @notice Emitted when a staker's beaconChainSlashingFactor is updated
event BeaconChainSlashingFactorDecreased(
address staker, uint64 prevBeaconChainSlashingFactor, uint64 newBeaconChainSlashingFactor
);
/// @notice Emitted when an operator is slashed and shares to be burned are increased
event BurnableETHSharesIncreased(uint256 shares);
/// @notice Emitted when the Pectra fork timestamp is updated
event PectraForkTimestampSet(uint64 newPectraForkTimestamp);
/// @notice Emitted when the proof timestamp setter is updated
event ProofTimestampSetterSet(address newProofTimestampSetter);
}
interface IEigenPodManagerTypes {
/**
* @notice The amount of beacon chain slashing experienced by a pod owner as a proportion of WAD
* @param isSet whether the slashingFactor has ever been updated. Used to distinguish between
* a value of "0" and an uninitialized value.
* @param slashingFactor the proportion of the pod owner's balance that has been decreased due to
* slashing or other beacon chain balance decreases.
* @dev NOTE: if !isSet, `slashingFactor` should be treated as WAD. `slashingFactor` is monotonically
* decreasing and can hit 0 if fully slashed.
*/
struct BeaconChainSlashingFactor {
bool isSet;
uint64 slashingFactor;
}
}
/**
* @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface IEigenPodManager is
IEigenPodManagerErrors,
IEigenPodManagerEvents,
IEigenPodManagerTypes,
IShareManager,
IPausable,
ISemVerMixin
{
/**
* @notice Creates an EigenPod for the sender.
* @dev Function will revert if the `msg.sender` already has an EigenPod.
* @dev Returns EigenPod address
*/
function createPod() external returns (address);
/**
* @notice Stakes for a new beacon chain validator on the sender's EigenPod.
* Also creates an EigenPod for the sender if they don't have one already.
* @param pubkey The 48 bytes public key of the beacon chain validator.
* @param signature The validator's signature of the deposit data.
* @param depositDataRoot The root/hash of the deposit data for the validator's deposit.
*/
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;
/**
* @notice Adds any positive share delta to the pod owner's deposit shares, and delegates them to the pod
* owner's operator (if applicable). A negative share delta does NOT impact the pod owner's deposit shares,
* but will reduce their beacon chain slashing factor and delegated shares accordingly.
* @param podOwner is the pod owner whose balance is being updated.
* @param prevRestakedBalanceWei is the total amount restaked through the pod before the balance update, including
* any amount currently in the withdrawal queue.
* @param balanceDeltaWei is the amount the balance changed
* @dev Callable only by the podOwner's EigenPod contract.
* @dev Reverts if `sharesDelta` is not a whole Gwei amount
*/
function recordBeaconChainETHBalanceUpdate(
address podOwner,
uint256 prevRestakedBalanceWei,
int256 balanceDeltaWei
) external;
/// @notice Sets the address that can set proof timestamps
function setProofTimestampSetter(
address newProofTimestampSetter
) external;
/// @notice Sets the Pectra fork timestamp, only callable by `proofTimestampSetter`
function setPectraForkTimestamp(
uint64 timestamp
) external;
/// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed.
function ownerToPod(
address podOwner
) external view returns (IEigenPod);
/// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not).
function getPod(
address podOwner
) external view returns (IEigenPod);
/// @notice The ETH2 Deposit Contract
function ethPOS() external view returns (IETHPOSDeposit);
/// @notice Beacon proxy to which the EigenPods point
function eigenPodBeacon() external view returns (IBeacon);
/// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise.
function hasPod(
address podOwner
) external view returns (bool);
/// @notice Returns the number of EigenPods that have been created
function numPods() external view returns (uint256);
/**
* @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy.
* @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can
* decrease between the pod owner queuing and completing a withdrawal.
* When the pod owner's shares would otherwise increase, this "deficit" is decreased first _instead_.
* Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We can think of this
* as the withdrawal "paying off the deficit".
*/
function podOwnerDepositShares(
address podOwner
) external view returns (int256);
/// @notice returns canonical, virtual beaconChainETH strategy
function beaconChainETHStrategy() external view returns (IStrategy);
/**
* @notice Returns the historical sum of proportional balance decreases a pod owner has experienced when
* updating their pod's balance.
*/
function beaconChainSlashingFactor(
address staker
) external view returns (uint64);
/// @notice Returns the accumulated amount of beacon chain ETH Strategy shares
function burnableETHShares() external view returns (uint256);
/// @notice Returns the timestamp of the Pectra hard fork
/// @dev Specifically, this returns the timestamp of the first non-missed slot at or after the Pectra hard fork
function pectraForkTimestamp() external view returns (uint64);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "../interfaces/IPauserRegistry.sol";
/**
* @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
* These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
* @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
* Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
* For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
* you can only flip (any number of) switches to off/0 (aka "paused").
* If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
* 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
* 2) update the paused state to this new value
* @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
* indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
*/
interface IPausable {
/// @dev Thrown when caller is not pauser.
error OnlyPauser();
/// @dev Thrown when caller is not unpauser.
error OnlyUnpauser();
/// @dev Thrown when currently paused.
error CurrentlyPaused();
/// @dev Thrown when invalid `newPausedStatus` is provided.
error InvalidNewPausedStatus();
/// @dev Thrown when a null address input is provided.
error InputAddressZero();
/// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`.
event Paused(address indexed account, uint256 newPausedStatus);
/// @notice Emitted when the pause is lifted by `account`, and changed to `newPausedStatus`.
event Unpaused(address indexed account, uint256 newPausedStatus);
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
function pauserRegistry() external view returns (IPauserRegistry);
/**
* @notice This function is used to pause an EigenLayer contract's functionality.
* It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
*/
function pause(
uint256 newPausedStatus
) external;
/**
* @notice Alias for `pause(type(uint256).max)`.
*/
function pauseAll() external;
/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(
uint256 newPausedStatus
) external;
/// @notice Returns the current paused status as a uint256.
function paused() external view returns (uint256);
/// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
function paused(
uint8 index
) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/**
* @title Constants shared between 'EigenPod' and 'EigenPodManager' contracts.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
abstract contract EigenPodPausingConstants {
/// @notice Index for flag that pauses creation of new EigenPods when set. See EigenPodManager code for details.
uint8 internal constant PAUSED_NEW_EIGENPODS = 0;
// Deprecated
// uint8 internal constant PAUSED_WITHDRAW_RESTAKED_ETH = 1;
/// @notice Index for flag that pauses the deposit related functions *of the EigenPods* when set. see EigenPod code for details.
uint8 internal constant PAUSED_EIGENPODS_VERIFY_CREDENTIALS = 2;
// Deprecated
// uint8 internal constant PAUSED_EIGENPODS_VERIFY_BALANCE_UPDATE = 3;
// Deprecated
// uint8 internal constant PAUSED_EIGENPODS_VERIFY_WITHDRAWAL = 4;
/// @notice Pausability for EigenPod's "accidental transfer" withdrawal methods
uint8 internal constant PAUSED_NON_PROOF_WITHDRAWALS = 5;
uint8 internal constant PAUSED_START_CHECKPOINT = 6;
/// @notice Index for flag that pauses the `verifyCheckpointProofs` function *of the EigenPods* when set. see EigenPod code for details.
uint8 internal constant PAUSED_EIGENPODS_VERIFY_CHECKPOINT_PROOFS = 7;
uint8 internal constant PAUSED_VERIFY_STALE_BALANCE = 8;
uint8 internal constant PAUSED_CONSOLIDATIONS = 9;
uint8 internal constant PAUSED_WITHDRAWAL_REQUESTS = 10;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "../interfaces/IEigenPod.sol";
abstract contract EigenPodStorage is IEigenPod {
/// @notice The owner of this EigenPod
address public podOwner;
/// @notice DEPRECATED: previously used to track the time when restaking was activated
uint64 internal __deprecated_mostRecentWithdrawalTimestamp;
/// @notice the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from the Beacon Chain but not from EigenLayer),
uint64 internal restakedExecutionLayerGwei;
/// @notice DEPRECATED: previously used to track whether a pod had activated restaking
bool internal __deprecated_hasRestaked;
/// @notice DEPRECATED: previously tracked withdrawals proven per validator
mapping(bytes32 => mapping(uint64 => bool)) internal __deprecated_provenWithdrawal;
/// @notice This is a mapping that tracks a validator's information by their pubkey hash
mapping(bytes32 => ValidatorInfo) internal _validatorPubkeyHashToInfo;
/// @notice DEPRECATED: previously used to track ETH sent to the fallback function
uint256 internal __deprecated_nonBeaconChainETHBalanceWei;
/// @notice DEPRECATED: previously used to track claimed partial withdrawals
uint64 __deprecated_sumOfPartialWithdrawalsClaimedGwei;
/// @notice Number of validators with proven withdrawal credentials, who do not have proven full withdrawals
uint256 public activeValidatorCount;
/// @notice The timestamp of the last checkpoint finalized
uint64 public lastCheckpointTimestamp;
/// @notice The timestamp of the currently-active checkpoint. Will be 0 if there is not active checkpoint
uint64 public currentCheckpointTimestamp;
/// @notice For each checkpoint, the total balance attributed to exited validators, in gwei
///
/// NOTE that the values added to this mapping are NOT guaranteed to capture the entirety of a validator's
/// exit - rather, they capture the total change in a validator's balance when a checkpoint shows their
/// balance change from nonzero to zero. While a change from nonzero to zero DOES guarantee that a validator
/// has been fully exited, it is possible that the magnitude of this change does not capture what is
/// typically thought of as a "full exit."
///
///
/// Example A: (deposits)
/// 1. Consider a validator was last checkpointed at 32 ETH before exiting. Once the exit has been processed,
/// it is expected that the validator's exited balance is calculated to be `32 ETH`.
/// 2. However, before `startCheckpoint` is called, a deposit is made to the validator for 1 ETH. The beacon
/// chain will automatically withdraw this ETH, but not until the withdrawal sweep passes over the validator
/// again. Until this occurs, the validator's current balance (used for checkpointing) is 1 ETH.
/// 3. If `startCheckpoint` is called at this point, the balance delta calculated for this validator will be
/// `-31 ETH`, and because the validator has a nonzero balance, it is not marked WITHDRAWN.
/// 4. After the exit is processed by the beacon chain, a subsequent `startCheckpoint` and checkpoint proof
/// will calculate a balance delta of `-1 ETH` and attribute a 1 ETH exit to the validator.
///
/// Example B: (consolidation)
/// 1. Consider 2 validators (a and b), each last checkpointed at 32 ETH.
/// 2. EigenPod.requestConsolidation is called, requesting a consolidation of b -> a
/// 3. When the beacon chain processes this consolidation, b's entire balance is transferred to a, and
/// b is left with 0 balance.
/// 4. Post-consolidation, start+completeCheckpoint will show validator a now has 64 ETH, and validator b has 0 ETH.
/// b's state is set to WITHDRAWN, and `checkpointBalanceExitedGwei` will show 32 ETH, even though this balance
/// did not exit the beacon chain.
///
/// Unfortunately, these edge cases can't be fully accounted for within an EigenPod. Please keep in mind that this
/// mapping is intended to be an approximation, and ensure your offchain tooling can account for these edge cases
/// before relying on the value for important operations.
///
/// Additional edge cases this mapping does not cover:
/// - If a validator is slashed, their balance exited will reflect their original balance rather than the slashed amount
/// - The final partial withdrawal for an exited validator will be likely be included in this mapping.
/// i.e. if a validator was last checkpointed at 32.1 ETH before exiting, the next checkpoint will calculate their
/// "exited" amount to be 32.1 ETH rather than 32 ETH.
mapping(uint64 => uint64) public checkpointBalanceExitedGwei;
/// @notice The current checkpoint, if there is one active
Checkpoint internal _currentCheckpoint;
/// @notice An address with permissions to call `startCheckpoint` and `verifyWithdrawalCredentials`, set
/// by the podOwner. This role exists to allow a podOwner to designate a hot wallet that can call
/// these methods, allowing the podOwner to remain a cold wallet that is only used to manage funds.
/// @dev If this address is NOT set, only the podOwner can call `startCheckpoint` and `verifyWithdrawalCredentials`
address public proofSubmitter;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[35] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// Adapted from OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library Merkle {
error InvalidProofLength();
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. The tree is built assuming `leaf` is
* the 0 indexed `index`'th leaf from the bottom left of the tree.
*
* Note this is for a Merkle tree using the keccak/sha3 hash function
*/
function verifyInclusionKeccak(
bytes memory proof,
bytes32 root,
bytes32 leaf,
uint256 index
) internal pure returns (bool) {
return processInclusionProofKeccak(proof, leaf, index) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. The tree is built assuming `leaf` is
* the 0 indexed `index`'th leaf from the bottom left of the tree.
* @dev If the proof length is 0 then the leaf hash is returned.
*
* _Available since v4.4._
*
* Note this is for a Merkle tree using the keccak/sha3 hash function
*/
function processInclusionProofKeccak(
bytes memory proof,
bytes32 leaf,
uint256 index
) internal pure returns (bytes32) {
require(proof.length % 32 == 0, InvalidProofLength());
bytes32 computedHash = leaf;
for (uint256 i = 32; i <= proof.length; i += 32) {
if (index % 2 == 0) {
// if ith bit of index is 0, then computedHash is a left sibling
assembly {
mstore(0x00, computedHash)
mstore(0x20, mload(add(proof, i)))
computedHash := keccak256(0x00, 0x40)
index := div(index, 2)
}
} else {
// if ith bit of index is 1, then computedHash is a right sibling
assembly {
mstore(0x00, mload(add(proof, i)))
mstore(0x20, computedHash)
computedHash := keccak256(0x00, 0x40)
index := div(index, 2)
}
}
}
return computedHash;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. The tree is built assuming `leaf` is
* the 0 indexed `index`'th leaf from the bottom left of the tree.
*
* Note this is for a Merkle tree using the sha256 hash function
*/
function verifyInclusionSha256(
bytes memory proof,
bytes32 root,
bytes32 leaf,
uint256 index
) internal view returns (bool) {
return processInclusionProofSha256(proof, leaf, index) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. The tree is built assuming `leaf` is
* the 0 indexed `index`'th leaf from the bottom left of the tree.
*
* _Available since v4.4._
*
* Note this is for a Merkle tree using the sha256 hash function
*/
function processInclusionProofSha256(
bytes memory proof,
bytes32 leaf,
uint256 index
) internal view returns (bytes32) {
require(proof.length != 0 && proof.length % 32 == 0, InvalidProofLength());
bytes32[1] memory computedHash = [leaf];
for (uint256 i = 32; i <= proof.length; i += 32) {
if (index % 2 == 0) {
// if ith bit of index is 0, then computedHash is a left sibling
assembly {
mstore(0x00, mload(computedHash))
mstore(0x20, mload(add(proof, i)))
if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) }
index := div(index, 2)
}
} else {
// if ith bit of index is 1, then computedHash is a right sibling
assembly {
mstore(0x00, mload(add(proof, i)))
mstore(0x20, mload(computedHash))
if iszero(staticcall(sub(gas(), 2000), 2, 0x00, 0x40, computedHash, 0x20)) { revert(0, 0) }
index := div(index, 2)
}
}
}
return computedHash[0];
}
/**
* @notice this function returns the merkle root of a tree created from a set of leaves using sha256 as its hash function
* @param leaves the leaves of the merkle tree
* @return The computed Merkle root of the tree.
* @dev A pre-condition to this function is that leaves.length is a power of two. If not, the function will merkleize the inputs incorrectly.
*/
function merkleizeSha256(
bytes32[] memory leaves
) internal pure returns (bytes32) {
//there are half as many nodes in the layer above the leaves
uint256 numNodesInLayer = leaves.length / 2;
//create a layer to store the internal nodes
bytes32[] memory layer = new bytes32[](numNodesInLayer);
//fill the layer with the pairwise hashes of the leaves
for (uint256 i = 0; i < numNodesInLayer; i++) {
layer[i] = sha256(abi.encodePacked(leaves[2 * i], leaves[2 * i + 1]));
}
//the next layer above has half as many nodes
numNodesInLayer /= 2;
//while we haven't computed the root
while (numNodesInLayer != 0) {
//overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < numNodesInLayer; i++) {
layer[i] = sha256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
}
//the next layer above has half as many nodes
numNodesInLayer /= 2;
}
//the first node in the layer is the root
return layer[0];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
library Endian {
/**
* @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64
* @param lenum little endian-formatted uint64 input, provided as 'bytes32' type
* @return n The big endian-formatted uint64
* @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits)
* through a right-shift/shr operation.
*/
function fromLittleEndianUint64(
bytes32 lenum
) internal pure returns (uint64 n) {
// the number needs to be stored in little-endian encoding (ie in bytes 0-8)
n = uint64(uint256(lenum >> 192));
// forgefmt: disable-next-item
return (n >> 56) |
((0x00FF000000000000 & n) >> 40) |
((0x0000FF0000000000 & n) >> 24) |
((0x000000FF00000000 & n) >> 8) |
((0x00000000FF000000 & n) << 8) |
((0x0000000000FF0000 & n) << 24) |
((0x000000000000FF00 & n) << 40) |
((0x00000000000000FF & n) << 56);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
/// @title ISemVerMixin
/// @notice A mixin interface that provides semantic versioning functionality.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/)
interface ISemVerMixin {
/// @notice Returns the semantic version string of the contract.
/// @return The version string in SemVer format (e.g., "1.1.1")
function version() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlotUpgradeable.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStringsUpgradeable {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlotUpgradeable.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @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.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./IStrategy.sol";
import "./IShareManager.sol";
import "./IDelegationManager.sol";
import "./IEigenPodManager.sol";
import "./ISemVerMixin.sol";
interface IStrategyManagerErrors {
/// @dev Thrown when total strategies deployed exceeds max.
error MaxStrategiesExceeded();
/// @dev Thrown when call attempted from address that's not delegation manager.
error OnlyDelegationManager();
/// @dev Thrown when call attempted from address that's not strategy whitelister.
error OnlyStrategyWhitelister();
/// @dev Thrown when provided `shares` amount is too high.
error SharesAmountTooHigh();
/// @dev Thrown when provided `shares` amount is zero.
error SharesAmountZero();
/// @dev Thrown when provided `staker` address is null.
error StakerAddressZero();
/// @dev Thrown when provided `strategy` not found.
error StrategyNotFound();
/// @dev Thrown when attempting to deposit to a non-whitelisted strategy.
error StrategyNotWhitelisted();
/// @dev Thrown when attempting to add a strategy that is already in the operator set's burn or redistributable shares.
error StrategyAlreadyInSlash();
}
interface IStrategyManagerEvents {
/**
* @notice Emitted when a new deposit occurs on behalf of `staker`.
* @param staker Is the staker who is depositing funds into EigenLayer.
* @param strategy Is the strategy that `staker` has deposited into.
* @param shares Is the number of new shares `staker` has been granted in `strategy`.
*/
event Deposit(address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted when the `strategyWhitelister` is changed
event StrategyWhitelisterChanged(address previousAddress, address newAddress);
/// @notice Emitted when a strategy is added to the approved list of strategies for deposit
event StrategyAddedToDepositWhitelist(IStrategy strategy);
/// @notice Emitted when a strategy is removed from the approved list of strategies for deposit
event StrategyRemovedFromDepositWhitelist(IStrategy strategy);
/// @notice Emitted when an operator is slashed and shares to be burned or redistributed are increased
event BurnOrRedistributableSharesIncreased(
OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
);
/// @notice Emitted when shares marked for burning or redistribution are decreased and transferred to the operator set's redistribution recipient
event BurnOrRedistributableSharesDecreased(
OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
);
/// @notice Emitted when shares are burnt
/// @dev This event is only emitted in the pre-redistribution slash path
event BurnableSharesDecreased(IStrategy strategy, uint256 shares);
}
/**
* @title Interface for the primary entrypoint for funds into EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice See the `StrategyManager` contract itself for implementation details.
*/
interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IShareManager, ISemVerMixin {
/**
* @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set),
* and transfers contract ownership to the specified `initialOwner`.
* @param initialOwner Ownership of this contract is transferred to this address.
* @param initialStrategyWhitelister The initial value of `strategyWhitelister` to set.
* @param initialPausedStatus The initial value of `_paused` to set.
*/
function initialize(
address initialOwner,
address initialStrategyWhitelister,
uint256 initialPausedStatus
) external;
/**
* @notice Deposits `amount` of `token` into the specified `strategy` and credits shares to the caller
* @param strategy the strategy that handles `token`
* @param token the token from which the `amount` will be transferred
* @param amount the number of tokens to deposit
* @return depositShares the number of deposit shares credited to the caller
* @dev The caller must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
*
* WARNING: Be extremely cautious when depositing tokens that do not strictly adhere to ERC20 standards.
* Tokens that diverge significantly from ERC20 norms can cause unexpected behavior in token balances for
* that strategy, e.g. ERC-777 tokens allowing cross-contract reentrancy.
*/
function depositIntoStrategy(
IStrategy strategy,
IERC20 token,
uint256 amount
) external returns (uint256 depositShares);
/**
* @notice Deposits `amount` of `token` into the specified `strategy` and credits shares to the `staker`
* Note tokens are transferred from `msg.sender`, NOT from `staker`. This method allows the caller, using a
* signature, to deposit their tokens to another staker's balance.
* @param strategy the strategy that handles `token`
* @param token the token from which the `amount` will be transferred
* @param amount the number of tokens to transfer from the caller to the strategy
* @param staker the staker that the deposited assets will be credited to
* @param expiry the timestamp at which the signature expires
* @param signature a valid ECDSA or EIP-1271 signature from `staker`
* @return depositShares the number of deposit shares credited to `staker`
* @dev The caller must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
*
* WARNING: Be extremely cautious when depositing tokens that do not strictly adhere to ERC20 standards.
* Tokens that diverge significantly from ERC20 norms can cause unexpected behavior in token balances for
* that strategy, e.g. ERC-777 tokens allowing cross-contract reentrancy.
*/
function depositIntoStrategyWithSignature(
IStrategy strategy,
IERC20 token,
uint256 amount,
address staker,
uint256 expiry,
bytes memory signature
) external returns (uint256 depositShares);
/**
* @notice Legacy burn strategy shares for the given strategy by calling into the strategy to transfer
* to the default burn address.
* @param strategy The strategy to burn shares in.
* @dev This function will be DEPRECATED in a release after redistribution
*/
function burnShares(
IStrategy strategy
) external;
/**
* @notice Removes burned shares from storage and transfers the underlying tokens for the slashId to the redistribution recipient.
* @dev Reentrancy is checked in the `clearBurnOrRedistributableSharesByStrategy` function.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash ID to burn shares in.
* @return The amounts of tokens transferred to the redistribution recipient for each strategy
*/
function clearBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId
) external returns (uint256[] memory);
/**
* @notice Removes a single strategy's shares from storage and transfers the underlying tokens for the slashId to the redistribution recipient.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash ID to burn shares in.
* @param strategy The strategy to burn shares in.
* @return The amount of tokens transferred to the redistribution recipient for the strategy.
*/
function clearBurnOrRedistributableSharesByStrategy(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy
) external returns (uint256);
/**
* @notice Returns the strategies and shares that have NOT been sent to the redistribution recipient for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @return The strategies and shares for the given slashId.
*/
function getBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId
) external view returns (IStrategy[] memory, uint256[] memory);
/**
* @notice Returns the shares for a given strategy for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @param strategy The strategy to get the shares for.
* @return The shares for the given strategy for the given slashId.
* @dev This function will return revert if the shares have already been sent to the redistribution recipient.
*/
function getBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy
) external view returns (uint256);
/**
* @notice Returns the number of strategies that have NOT been sent to the redistribution recipient for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @return The number of strategies for the given slashId.
*/
function getBurnOrRedistributableCount(
OperatorSet calldata operatorSet,
uint256 slashId
) external view returns (uint256);
/**
* @notice Owner-only function to change the `strategyWhitelister` address.
* @param newStrategyWhitelister new address for the `strategyWhitelister`.
*/
function setStrategyWhitelister(
address newStrategyWhitelister
) external;
/**
* @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
*/
function addStrategiesToDepositWhitelist(
IStrategy[] calldata strategiesToWhitelist
) external;
/**
* @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
*/
function removeStrategiesFromDepositWhitelist(
IStrategy[] calldata strategiesToRemoveFromWhitelist
) external;
/// @notice Returns bool for whether or not `strategy` is whitelisted for deposit
function strategyIsWhitelistedForDeposit(
IStrategy strategy
) external view returns (bool);
/**
* @notice Get all details on the staker's deposits and corresponding shares
* @return (staker's strategies, shares in these strategies)
*/
function getDeposits(
address staker
) external view returns (IStrategy[] memory, uint256[] memory);
function getStakerStrategyList(
address staker
) external view returns (IStrategy[] memory);
/// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
function stakerStrategyListLength(
address staker
) external view returns (uint256);
/// @notice Returns the current shares of `user` in `strategy`
function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 shares);
/// @notice Returns the single, central Delegation contract of EigenLayer
function delegation() external view returns (IDelegationManager);
/// @notice Returns the address of the `strategyWhitelister`
function strategyWhitelister() external view returns (address);
/// @notice Returns the burnable shares of a strategy
/// @dev This function will be deprecated in a release after redistribution
function getBurnableShares(
IStrategy strategy
) external view returns (uint256);
/**
* @notice Gets every strategy with burnable shares and the amount of burnable shares in each said strategy
*
* @dev This function will be deprecated in a release after redistribution
* WARNING: This operation can copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Users should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function getStrategiesWithBurnableShares() external view returns (address[] memory, uint256[] memory);
/**
* @param staker The address of the staker.
* @param strategy The strategy to deposit into.
* @param token The token to deposit.
* @param amount The amount of `token` to deposit.
* @param nonce The nonce of the staker.
* @param expiry The expiry of the signature.
* @return The EIP-712 signable digest hash.
*/
function calculateStrategyDepositDigestHash(
address staker,
IStrategy strategy,
IERC20 token,
uint256 amount,
uint256 nonce,
uint256 expiry
) external view returns (bytes32);
/**
* @notice Returns the operator sets that have pending burn or redistributable shares.
* @return The operator sets that have pending burn or redistributable shares.
*/
function getPendingOperatorSets() external view returns (OperatorSet[] memory);
/**
* @notice Returns the slash IDs that are pending to be burned or redistributed.
* @dev This function will return revert if the operator set has no pending burn or redistributable shares.
* @param operatorSet The operator set to get the pending slash IDs for.
* @return The slash IDs that are pending to be burned or redistributed.
*/
function getPendingSlashIds(
OperatorSet calldata operatorSet
) external view returns (uint256[] memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/BeaconChainProofs.sol";
import "./ISemVerMixin.sol";
import "./IEigenPodManager.sol";
interface IEigenPodErrors {
/// @dev Thrown when msg.sender is not the EPM.
error OnlyEigenPodManager();
/// @dev Thrown when msg.sender is not the pod owner.
error OnlyEigenPodOwner();
/// @dev Thrown when msg.sender is not owner or the proof submitter.
error OnlyEigenPodOwnerOrProofSubmitter();
/// @dev Thrown when attempting an action that is currently paused.
error CurrentlyPaused();
/// Invalid Inputs
/// @dev Thrown when an address of zero is provided.
error InputAddressZero();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when `validatorPubKey` length is not equal to 48-bytes.
error InvalidPubKeyLength();
/// @dev Thrown when provided timestamp is out of range.
error TimestampOutOfRange();
/// Checkpoints
/// @dev Thrown when no active checkpoints are found.
error NoActiveCheckpoint();
/// @dev Thrown if an uncompleted checkpoint exists.
error CheckpointAlreadyActive();
/// @dev Thrown if there's not a balance available to checkpoint.
error NoBalanceToCheckpoint();
/// @dev Thrown when attempting to create a checkpoint twice within a given block.
error CannotCheckpointTwiceInSingleBlock();
/// Withdrawing
/// @dev Thrown when amount exceeds `restakedExecutionLayerGwei`.
error InsufficientWithdrawableBalance();
/// Validator Status
/// @dev Thrown when a validator's withdrawal credentials have already been verified.
error CredentialsAlreadyVerified();
/// @dev Thrown if the provided proof is not valid for this EigenPod.
error WithdrawalCredentialsNotForEigenPod();
/// @dev Thrown when a validator is not in the ACTIVE status in the pod.
error ValidatorNotActiveInPod();
/// @dev Thrown when validator is not active yet on the beacon chain.
error ValidatorInactiveOnBeaconChain();
/// @dev Thrown if a validator is exiting the beacon chain.
error ValidatorIsExitingBeaconChain();
/// @dev Thrown when a validator has not been slashed on the beacon chain.
error ValidatorNotSlashedOnBeaconChain();
/// Consolidation and Withdrawal Requests
/// @dev Thrown when a predeploy request is initiated with insufficient msg.value
error InsufficientFunds();
/// @dev Thrown when calling the predeploy fails
error PredeployFailed();
/// @dev Thrown when querying a predeploy for its current fee fails
error FeeQueryFailed();
/// Misc
/// @dev Thrown when an invalid block root is returned by the EIP-4788 oracle.
error InvalidEIP4788Response();
/// @dev Thrown when attempting to send an invalid amount to the beacon deposit contract.
error MsgValueNot32ETH();
/// @dev Thrown when provided `beaconTimestamp` is too far in the past.
error BeaconTimestampTooFarInPast();
/// @dev Thrown when provided `beaconTimestamp` is before the last checkpoint
error BeaconTimestampBeforeLatestCheckpoint();
/// @dev Thrown when the pectraForkTimestamp returned from the EigenPodManager is zero
error ForkTimestampZero();
}
interface IEigenPodTypes {
enum VALIDATOR_STATUS {
INACTIVE, // doesnt exist
ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod
WITHDRAWN // withdrawn from the Beacon Chain
}
/**
* @param validatorIndex index of the validator on the beacon chain
* @param restakedBalanceGwei amount of beacon chain ETH restaked on EigenLayer in gwei
* @param lastCheckpointedAt timestamp of the validator's most recent balance update
* @param status last recorded status of the validator
*/
struct ValidatorInfo {
uint64 validatorIndex;
uint64 restakedBalanceGwei;
uint64 lastCheckpointedAt;
VALIDATOR_STATUS status;
}
struct Checkpoint {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int64 balanceDeltasGwei;
uint64 prevBeaconBalanceGwei;
}
/**
* @param srcPubkey the pubkey of the source validator for the consolidation
* @param targetPubkey the pubkey of the target validator for the consolidation
* @dev Note that if srcPubkey == targetPubkey, this is a "switch request," and will
* change the validator's withdrawal credential type from 0x01 to 0x02.
* For more notes on usage, see `requestConsolidation`
*/
struct ConsolidationRequest {
bytes srcPubkey;
bytes targetPubkey;
}
/**
* @param pubkey the pubkey of the validator to withdraw from
* @param amountGwei the amount (in gwei) to withdraw from the beacon chain to the pod
* @dev Note that if amountGwei == 0, this is a "full exit request," and will fully exit
* the validator to the pod.
* For more notes on usage, see `requestWithdrawal`
*/
struct WithdrawalRequest {
bytes pubkey;
uint64 amountGwei;
}
}
interface IEigenPodEvents is IEigenPodTypes {
/// @notice Emitted when an ETH validator stakes via this eigenPod
event EigenPodStaked(bytes32 pubkeyHash);
/// @notice Emitted when a pod owner updates the proof submitter address
event ProofSubmitterUpdated(address prevProofSubmitter, address newProofSubmitter);
/// @notice Emitted when an ETH validator's withdrawal credentials are successfully verified to be pointed to this eigenPod
event ValidatorRestaked(bytes32 pubkeyHash);
/// @notice Emitted when an ETH validator's balance is proven to be updated. Here newValidatorBalanceGwei
// is the validator's balance that is credited on EigenLayer.
event ValidatorBalanceUpdated(bytes32 pubkeyHash, uint64 balanceTimestamp, uint64 newValidatorBalanceGwei);
/// @notice Emitted when restaked beacon chain ETH is withdrawn from the eigenPod.
event RestakedBeaconChainETHWithdrawn(address indexed recipient, uint256 amount);
/// @notice Emitted when ETH is received via the `receive` fallback
event NonBeaconChainETHReceived(uint256 amountReceived);
/// @notice Emitted when a checkpoint is created
event CheckpointCreated(
uint64 indexed checkpointTimestamp, bytes32 indexed beaconBlockRoot, uint256 validatorCount
);
/// @notice Emitted when a checkpoint is finalized
event CheckpointFinalized(uint64 indexed checkpointTimestamp, int256 totalShareDeltaWei);
/// @notice Emitted when a validator is proven for a given checkpoint
event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, bytes32 indexed pubkeyHash);
/// @notice Emitted when a validator is proven to have 0 balance at a given checkpoint
event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, bytes32 indexed pubkeyHash);
/// @notice Emitted when a consolidation request is initiated where source == target
event SwitchToCompoundingRequested(bytes32 indexed validatorPubkeyHash);
/// @notice Emitted when a standard consolidation request is initiated
event ConsolidationRequested(bytes32 indexed sourcePubkeyHash, bytes32 indexed targetPubkeyHash);
/// @notice Emitted when a withdrawal request is initiated where request.amountGwei == 0
event ExitRequested(bytes32 indexed validatorPubkeyHash);
/// @notice Emitted when a partial withdrawal request is initiated
event WithdrawalRequested(bytes32 indexed validatorPubkeyHash, uint64 withdrawalAmountGwei);
}
/**
* @title The implementation contract used for restaking beacon chain ETH on EigenLayer
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
* to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
*/
interface IEigenPod is IEigenPodErrors, IEigenPodEvents, ISemVerMixin {
/// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager
function initialize(
address owner
) external;
/// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
/// @dev This function only supports staking to a 0x01 validator. For compounding validators, please interact directly with the deposit contract.
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;
/**
* @notice Transfers `amountWei` from this contract to the `recipient`. Only callable by the EigenPodManager as part
* of the DelegationManager's withdrawal flow.
* @dev `amountWei` is not required to be a whole Gwei amount. Amounts less than a Gwei multiple may be unrecoverable due to Gwei conversion.
*/
function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external;
/**
* @dev Create a checkpoint used to prove this pod's active validator set. Checkpoints are completed
* by submitting one checkpoint proof per ACTIVE validator. During the checkpoint process, the total
* change in ACTIVE validator balance is tracked, and any validators with 0 balance are marked `WITHDRAWN`.
* @dev Once finalized, the pod owner is awarded shares corresponding to:
* - the total change in their ACTIVE validator balances
* - any ETH in the pod not already awarded shares
* @dev A checkpoint cannot be created if the pod already has an outstanding checkpoint. If
* this is the case, the pod owner MUST complete the existing checkpoint before starting a new one.
* @param revertIfNoBalance Forces a revert if the pod ETH balance is 0. This allows the pod owner
* to prevent accidentally starting a checkpoint that will not increase their shares
*/
function startCheckpoint(
bool revertIfNoBalance
) external;
/**
* @dev Progress the current checkpoint towards completion by submitting one or more validator
* checkpoint proofs. Anyone can call this method to submit proofs towards the current checkpoint.
* For each validator proven, the current checkpoint's `proofsRemaining` decreases.
* @dev If the checkpoint's `proofsRemaining` reaches 0, the checkpoint is finalized.
* (see `_updateCheckpoint` for more details)
* @dev This method can only be called when there is a currently-active checkpoint.
* @param balanceContainerProof proves the beacon's current balance container root against a checkpoint's `beaconBlockRoot`
* @param proofs Proofs for one or more validator current balances against the `balanceContainerRoot`
*/
function verifyCheckpointProofs(
BeaconChainProofs.BalanceContainerProof calldata balanceContainerProof,
BeaconChainProofs.BalanceProof[] calldata proofs
) external;
/**
* @dev Verify one or more validators have their withdrawal credentials pointed at this EigenPod, and award
* shares based on their effective balance. Proven validators are marked `ACTIVE` within the EigenPod, and
* future checkpoint proofs will need to include them.
* @dev Withdrawal credential proofs MUST NOT be older than `currentCheckpointTimestamp`.
* @dev Validators proven via this method MUST NOT have an exit epoch set already.
* @param beaconTimestamp the beacon chain timestamp sent to the 4788 oracle contract. Corresponds
* to the parent beacon block root against which the proof is verified.
* @param stateRootProof proves a beacon state root against a beacon block root
* @param validatorIndices a list of validator indices being proven
* @param validatorFieldsProofs proofs of each validator's `validatorFields` against the beacon state root
* @param validatorFields the fields of the beacon chain "Validator" container. See consensus specs for
* details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
*/
function verifyWithdrawalCredentials(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
uint40[] calldata validatorIndices,
bytes[] calldata validatorFieldsProofs,
bytes32[][] calldata validatorFields
) external;
/**
* @dev Prove that one of this pod's active validators was slashed on the beacon chain. A successful
* staleness proof allows the caller to start a checkpoint.
*
* @dev Note that in order to start a checkpoint, any existing checkpoint must already be completed!
* (See `_startCheckpoint` for details)
*
* @dev Note that this method allows anyone to start a checkpoint as soon as a slashing occurs on the beacon
* chain. This is intended to make it easier to external watchers to keep a pod's balance up to date.
*
* @dev Note too that beacon chain slashings are not instant. There is a delay between the initial slashing event
* and the validator's final exit back to the execution layer. During this time, the validator's balance may or
* may not drop further due to a correlation penalty. This method allows proof of a slashed validator
* to initiate a checkpoint for as long as the validator remains on the beacon chain. Once the validator
* has exited and been checkpointed at 0 balance, they are no longer "checkpoint-able" and cannot be proven
* "stale" via this method.
* See https://eth2book.info/capella/part3/transition/epoch/#slashings for more info.
*
* @param beaconTimestamp the beacon chain timestamp sent to the 4788 oracle contract. Corresponds
* to the parent beacon block root against which the proof is verified.
* @param stateRootProof proves a beacon state root against a beacon block root
* @param proof the fields of the beacon chain "Validator" container, along with a merkle proof against
* the beacon state root. See the consensus specs for more details:
* https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
*
* @dev Staleness conditions:
* - Validator's last checkpoint is older than `beaconTimestamp`
* - Validator MUST be in `ACTIVE` status in the pod
* - Validator MUST be slashed on the beacon chain
*/
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
/// @notice Allows the owner or proof submitter to initiate one or more requests to
/// consolidate their validators on the beacon chain.
/// @param requests An array of requests consisting of the source and target pubkeys
/// of the validators to be consolidated
/// @dev The target validator MUST have ACTIVE (proven) withdrawal credentials pointed at
/// the pod. This prevents cross-pod consolidations.
/// @dev The consolidation request predeploy requires a fee is sent with each request;
/// this is pulled from msg.value. After submitting all requests, any remaining fee is
/// refunded to the caller by calling its fallback function.
/// @dev This contract exposes `getConsolidationRequestFee` to query the current fee for
/// a single request. If submitting multiple requests in a single block, the total fee
/// is equal to (fee * requests.length). This fee is updated at the end of each block.
///
/// (See https://eips.ethereum.org/EIPS/eip-7251#fee-calculation for details)
///
/// @dev Note on beacon chain behavior:
/// - If request.srcPubkey == request.targetPubkey, this is a "switch" consolidation. Once
/// processed on the beacon chain, the validator's withdrawal credentials will be changed
/// to compounding (0x02).
/// - The rest of the notes assume src != target.
/// - The target validator MUST already have 0x02 credentials. The source validator can have either.
/// - Consolidation sets the source validator's exit_epoch and withdrawable_epoch, similar to an exit.
/// When the exit epoch is reached, an epoch sweep will process the consolidation and transfer balance
/// from the source to the target validator.
/// - Consolidation transfers min(srcValidator.effective_balance, state.balance[srcIndex]) to the target.
/// This may not be the entirety of the source validator's balance; any remainder will be moved to the
/// pod when hit by a subsequent withdrawal sweep.
///
/// @dev Note that consolidation requests CAN FAIL for a variety of reasons. Failures occur when the request
/// is processed on the beacon chain, and are invisible to the pod. The pod and predeploy cannot guarantee
/// a request will succeed; it's up to the pod owner to determine this for themselves. If your request fails,
/// you can retry by initiating another request via this method.
///
/// Some requirements that are NOT checked by the pod:
/// - If request.srcPubkey == request.targetPubkey, the validator MUST have 0x01 credentials
/// - If request.srcPubkey != request.targetPubkey, the target validator MUST have 0x02 credentials
/// - Both the source and target validators MUST be active on the beacon chain and MUST NOT have
/// initiated exits
/// - The source validator MUST NOT have pending partial withdrawal requests (via `requestWithdrawal`)
/// - If the source validator is slashed after requesting consolidation (but before processing),
/// the consolidation will be skipped.
///
/// For further reference, see consolidation processing at block and epoch boundaries:
/// - Block: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_consolidation_request
/// - Epoch: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_pending_consolidations
function requestConsolidation(
ConsolidationRequest[] calldata requests
) external payable;
/// @notice Allows the owner or proof submitter to initiate one or more requests to
/// withdraw funds from validators on the beacon chain.
/// @param requests An array of requests consisting of the source validator and an
/// amount to withdraw
/// @dev The withdrawal request predeploy requires a fee is sent with each request;
/// this is pulled from msg.value. After submitting all requests, any remaining fee is
/// refunded to the caller by calling its fallback function.
/// @dev This contract exposes `getWithdrawalRequestFee` to query the current fee for
/// a single request. If submitting multiple requests in a single block, the total fee
/// is equal to (fee * requests.length). This fee is updated at the end of each block.
///
/// (See https://eips.ethereum.org/EIPS/eip-7002#fee-update-rule for details)
///
/// @dev Note on beacon chain behavior:
/// - Withdrawal requests have two types: full exit requests, and partial exit requests.
/// Partial exit requests will be skipped if the validator has 0x01 withdrawal credentials.
/// If you want your validators to have access to partial exits, use `requestConsolidation`
/// to change their withdrawal credentials to compounding (0x02).
/// - If request.amount == 0, this is a FULL exit request. A full exit request initiates a
/// standard validator exit.
/// - Other amounts are treated as PARTIAL exit requests. A partial exit request will NOT result
/// in a validator with less than 32 ETH balance. Any requested amount above this is ignored.
/// - The actual amount withdrawn for a partial exit is given by the formula:
/// min(request.amount, state.balances[vIdx] - 32 ETH - pending_balance_to_withdraw)
/// (where `pending_balance_to_withdraw` is the sum of any outstanding partial exit requests)
/// (Note that this means you may request more than is actually withdrawn!)
///
/// @dev Note that withdrawal requests CAN FAIL for a variety of reasons. Failures occur when the request
/// is processed on the beacon chain, and are invisible to the pod. The pod and predeploy cannot guarantee
/// a request will succeed; it's up to the pod owner to determine this for themselves. If your request fails,
/// you can retry by initiating another request via this method.
///
/// Some requirements that are NOT checked by the pod:
/// - request.pubkey MUST be a valid validator pubkey
/// - request.pubkey MUST belong to a validator whose withdrawal credentials are this pod
/// - If request.amount is for a partial exit, the validator MUST have 0x02 withdrawal credentials
/// - If request.amount is for a full exit, the validator MUST NOT have any pending partial exits
/// - The validator MUST be active and MUST NOT have initiated exit
///
/// For further reference: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_withdrawal_request
function requestWithdrawal(
WithdrawalRequest[] calldata requests
) external payable;
/// @notice called by owner of a pod to remove any ERC20s deposited in the pod
function recoverTokens(IERC20[] memory tokenList, uint256[] memory amountsToWithdraw, address recipient) external;
/// @notice Allows the owner of a pod to update the proof submitter, a permissioned
/// address that can call various EigenPod methods, but cannot trigger asset withdrawals
/// from the DelegationManager.
/// @dev Note that EITHER the podOwner OR proofSubmitter can access these methods,
/// so it's fine to set your proofSubmitter to 0 if you want the podOwner to be the
/// only address that can call these methods.
/// @param newProofSubmitter The new proof submitter address. If set to 0, only the
/// pod owner will be able to call EigenPod methods.
function setProofSubmitter(
address newProofSubmitter
) external;
/**
*
* VIEW METHODS
*
*/
/// @notice An address with permissions to call `startCheckpoint` and `verifyWithdrawalCredentials`, set
/// by the podOwner. This role exists to allow a podOwner to designate a hot wallet that can call
/// these methods, allowing the podOwner to remain a cold wallet that is only used to manage funds.
/// @dev If this address is NOT set, only the podOwner can call `startCheckpoint` and `verifyWithdrawalCredentials`
function proofSubmitter() external view returns (address);
/// @notice Native ETH in the pod that has been accounted for in a checkpoint (denominated in gwei).
/// This amount is withdrawable from the pod via the DelegationManager withdrawal flow.
function withdrawableRestakedExecutionLayerGwei() external view returns (uint64);
/// @notice The single EigenPodManager for EigenLayer
function eigenPodManager() external view returns (IEigenPodManager);
/// @notice The owner of this EigenPod
function podOwner() external view returns (address);
/// @notice Returns the validatorInfo struct for the provided pubkeyHash
function validatorPubkeyHashToInfo(
bytes32 validatorPubkeyHash
) external view returns (ValidatorInfo memory);
/// @notice Returns the validatorInfo struct for the provided pubkey
function validatorPubkeyToInfo(
bytes calldata validatorPubkey
) external view returns (ValidatorInfo memory);
/// @notice Returns the validator status for a given validator pubkey hash
function validatorStatus(
bytes32 pubkeyHash
) external view returns (VALIDATOR_STATUS);
/// @notice Returns the validator status for a given validator pubkey
function validatorStatus(
bytes calldata validatorPubkey
) external view returns (VALIDATOR_STATUS);
/// @notice Number of validators with proven withdrawal credentials, who do not have proven full withdrawals
function activeValidatorCount() external view returns (uint256);
/// @notice The timestamp of the last checkpoint finalized
function lastCheckpointTimestamp() external view returns (uint64);
/// @notice The timestamp of the currently-active checkpoint. Will be 0 if there is not active checkpoint
function currentCheckpointTimestamp() external view returns (uint64);
/// @notice Returns the currently-active checkpoint
/// If there's not an active checkpoint, this method returns the checkpoint that was last active.
function currentCheckpoint() external view returns (Checkpoint memory);
/// @notice For each checkpoint, the total balance attributed to exited validators, in gwei
///
/// NOTE that the values added to this mapping are NOT guaranteed to capture the entirety of a validator's
/// exit - rather, they capture the total change in a validator's balance when a checkpoint shows their
/// balance change from nonzero to zero. While a change from nonzero to zero DOES guarantee that a validator
/// has been fully exited, it is possible that the magnitude of this change does not capture what is
/// typically thought of as a "full exit."
///
/// For example:
/// 1. Consider a validator was last checkpointed at 32 ETH before exiting. Once the exit has been processed,
/// it is expected that the validator's exited balance is calculated to be `32 ETH`.
/// 2. However, before `startCheckpoint` is called, a deposit is made to the validator for 1 ETH. The beacon
/// chain will automatically withdraw this ETH, but not until the withdrawal sweep passes over the validator
/// again. Until this occurs, the validator's current balance (used for checkpointing) is 1 ETH.
/// 3. If `startCheckpoint` is called at this point, the balance delta calculated for this validator will be
/// `-31 ETH`, and because the validator has a nonzero balance, it is not marked WITHDRAWN.
/// 4. After the exit is processed by the beacon chain, a subsequent `startCheckpoint` and checkpoint proof
/// will calculate a balance delta of `-1 ETH` and attribute a 1 ETH exit to the validator.
///
/// If this edge case impacts your usecase, it should be possible to mitigate this by monitoring for deposits
/// to your exited validators, and waiting to call `startCheckpoint` until those deposits have been automatically
/// exited.
///
/// Additional edge cases this mapping does not cover:
/// - If a validator is slashed, their balance exited will reflect their original balance rather than the slashed amount
/// - The final partial withdrawal for an exited validator will be likely be included in this mapping.
/// i.e. if a validator was last checkpointed at 32.1 ETH before exiting, the next checkpoint will calculate their
/// "exited" amount to be 32.1 ETH rather than 32 ETH.
function checkpointBalanceExitedGwei(
uint64
) external view returns (uint64);
/// @notice Query the 4788 oracle to get the parent block root of the slot with the given `timestamp`
/// @param timestamp of the block for which the parent block root will be returned. MUST correspond
/// to an existing slot within the last 24 hours. If the slot at `timestamp` was skipped, this method
/// will revert.
function getParentBlockRoot(
uint64 timestamp
) external view returns (bytes32);
/// @notice Returns the fee required to add a consolidation request to the EIP-7251 predeploy this block.
/// @dev Note that the predeploy updates its fee every block according to https://eips.ethereum.org/EIPS/eip-7251#fee-calculation
/// Consider overestimating the amount sent to ensure the fee does not update before your transaction.
function getConsolidationRequestFee() external view returns (uint256);
/// @notice Returns the current fee required to add a withdrawal request to the EIP-7002 predeploy.
/// @dev Note that the predeploy updates its fee every block according to https://eips.ethereum.org/EIPS/eip-7002#fee-update-rule
/// Consider overestimating the amount sent to ensure the fee does not update before your transaction.
function getWithdrawalRequestFee() external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "../libraries/SlashingLib.sol";
import "./IStrategy.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/OperatorSetLib.sol";
/**
* @title Interface for a `IShareManager` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This contract is used by the DelegationManager as a unified interface to interact with the EigenPodManager and StrategyManager
*/
interface IShareManager {
/// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @return updatedShares the staker's deposit shares after decrement
function removeDepositShares(
address staker,
IStrategy strategy,
uint256 depositSharesToRemove
) external returns (uint256);
/// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @return existingDepositShares the shares the staker had before any were added
/// @return addedShares the new shares added to the staker's balance
function addShares(address staker, IStrategy strategy, uint256 shares) external returns (uint256, uint256);
/// @notice Used by the DelegationManager to convert deposit shares to tokens and send them to a staker
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @dev token is not validated when talking to the EigenPodManager
function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external;
/// @notice Returns the current shares of `user` in `strategy`
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @dev returns 0 if the user has negative shares
function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares);
/**
* @notice Increase the amount of burnable/redistributable shares for a given Strategy. This is called by the DelegationManager
* when an operator is slashed in EigenLayer.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash id to burn shares in.
* @param strategy The strategy to burn shares in.
* @param addedSharesToBurn The amount of added shares to burn.
* @dev This function is only called by the DelegationManager when an operator is slashed.
*/
function increaseBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy,
uint256 addedSharesToBurn
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/SlashingLib.sol";
import "./ISemVerMixin.sol";
interface IStrategyErrors {
/// @dev Thrown when called by an account that is not strategy manager.
error OnlyStrategyManager();
/// @dev Thrown when new shares value is zero.
error NewSharesZero();
/// @dev Thrown when total shares exceeds max.
error TotalSharesExceedsMax();
/// @dev Thrown when amount shares is greater than total shares.
error WithdrawalAmountExceedsTotalDeposits();
/// @dev Thrown when attempting an action with a token that is not accepted.
error OnlyUnderlyingToken();
/// StrategyBaseWithTVLLimits
/// @dev Thrown when `maxPerDeposit` exceeds max.
error MaxPerDepositExceedsMax();
/// @dev Thrown when balance exceeds max total deposits.
error BalanceExceedsMaxTotalDeposits();
}
interface IStrategyEvents {
/**
* @notice Used to emit an event for the exchange rate between 1 share and underlying token in a strategy contract
* @param rate is the exchange rate in wad 18 decimals
* @dev Tokens that do not have 18 decimals must have offchain services scale the exchange rate by the proper magnitude
*/
event ExchangeRateEmitted(uint256 rate);
/**
* Used to emit the underlying token and its decimals on strategy creation
* @notice token
* @param token is the ERC20 token of the strategy
* @param decimals are the decimals of the ERC20 token in the strategy
*/
event StrategyTokenSet(IERC20 token, uint8 decimals);
}
/**
* @title Minimal interface for an `Strategy` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Custom `Strategy` implementations may expand extensively on this interface.
*/
interface IStrategy is IStrategyErrors, IStrategyEvents, ISemVerMixin {
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount) external returns (uint256);
/**
* @notice Used to withdraw tokens from this Strategy, to the `recipient`'s address
* @param recipient is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
* @return amountOut is the amount of tokens being transferred out.
*/
function withdraw(address recipient, IERC20 token, uint256 amountShares) external returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(
uint256 amountShares
) external returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(
uint256 amountUnderlying
) external returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(
address user
) external returns (uint256);
/**
* @notice convenience function for fetching the current total shares of `user` in this strategy, by
* querying the `strategyManager` contract
*/
function shares(
address user
) external view returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(
uint256 amountShares
) external view returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(
uint256 amountUnderlying
) external view returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(
address user
) external view returns (uint256);
/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);
/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);
/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
/**
* @title Interface for the `PauserRegistry` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface IPauserRegistry {
error OnlyUnpauser();
error InputAddressZero();
event PauserStatusChanged(address pauser, bool canPause);
event UnpauserChanged(address previousUnpauser, address newUnpauser);
/// @notice Mapping of addresses to whether they hold the pauser role.
function isPauser(
address pauser
) external view returns (bool);
/// @notice Unique address that holds the unpauser role. Capable of changing *both* the pauser and unpauser addresses.
function unpauser() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @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 ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./IStrategy.sol";
import "./IPauserRegistry.sol";
import "./ISignatureUtilsMixin.sol";
import "../libraries/SlashingLib.sol";
import "../libraries/OperatorSetLib.sol";
interface IDelegationManagerErrors {
/// @dev Thrown when caller is neither the StrategyManager or EigenPodManager contract.
error OnlyStrategyManagerOrEigenPodManager();
/// @dev Thrown when msg.sender is not the EigenPodManager
error OnlyEigenPodManager();
/// @dev Throw when msg.sender is not the AllocationManager
error OnlyAllocationManager();
/// Delegation Status
/// @dev Thrown when an operator attempts to undelegate.
error OperatorsCannotUndelegate();
/// @dev Thrown when an account is actively delegated.
error ActivelyDelegated();
/// @dev Thrown when an account is not actively delegated.
error NotActivelyDelegated();
/// @dev Thrown when `operator` is not a registered operator.
error OperatorNotRegistered();
/// Invalid Inputs
/// @dev Thrown when attempting to execute an action that was not queued.
error WithdrawalNotQueued();
/// @dev Thrown when caller cannot undelegate on behalf of a staker.
error CallerCannotUndelegate();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when input arrays length is zero.
error InputArrayLengthZero();
/// Slashing
/// @dev Thrown when an operator has been fully slashed(maxMagnitude is 0) for a strategy.
/// or if the staker has had been natively slashed to the point of their beaconChainScalingFactor equalling 0.
error FullySlashed();
/// Signatures
/// @dev Thrown when attempting to spend a spent eip-712 salt.
error SaltSpent();
/// Withdrawal Processing
/// @dev Thrown when attempting to withdraw before delay has elapsed.
error WithdrawalDelayNotElapsed();
/// @dev Thrown when withdrawer is not the current caller.
error WithdrawerNotCaller();
}
interface IDelegationManagerTypes {
// @notice Struct used for storing information about a single operator who has registered with EigenLayer
struct OperatorDetails {
/// @notice DEPRECATED -- this field is no longer used, payments are handled in RewardsCoordinator.sol
address __deprecated_earningsReceiver;
/**
* @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling "forced undelegations".
* @dev Signature verification follows these rules:
* 1) If this address is left as address(0), then any staker will be free to delegate to the operator, i.e. no signature verification will be performed.
* 2) If this address is an EOA (i.e. it has no code), then we follow standard ECDSA signature verification for delegations to the operator.
* 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it returns the correct EIP-1271 "magic value".
*/
address delegationApprover;
/// @notice DEPRECATED -- this field is no longer used. An analogous field is the `allocationDelay` stored in the AllocationManager
uint32 __deprecated_stakerOptOutWindowBlocks;
}
/**
* @notice Abstract struct used in calculating an EIP712 signature for an operator's delegationApprover to approve that a specific staker delegate to the operator.
* @dev Used in computing the `DELEGATION_APPROVAL_TYPEHASH` and as a reference in the computation of the approverDigestHash in the `_delegate` function.
*/
struct DelegationApproval {
// the staker who is delegating
address staker;
// the operator being delegated to
address operator;
// the operator's provided salt
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/**
* @dev A struct representing an existing queued withdrawal. After the withdrawal delay has elapsed, this withdrawal can be completed via `completeQueuedWithdrawal`.
* A `Withdrawal` is created by the `DelegationManager` when `queueWithdrawals` is called. The `withdrawalRoots` hashes returned by `queueWithdrawals` can be used
* to fetch the corresponding `Withdrawal` from storage (via `getQueuedWithdrawal`).
*
* @param staker The address that queued the withdrawal
* @param delegatedTo The address that the staker was delegated to at the time the withdrawal was queued. Used to determine if additional slashing occurred before
* this withdrawal became completable.
* @param withdrawer The address that will call the contract to complete the withdrawal. Note that this will always equal `staker`; alternate withdrawers are not
* supported at this time.
* @param nonce The staker's `cumulativeWithdrawalsQueued` at time of queuing. Used to ensure withdrawals have unique hashes.
* @param startBlock The block number when the withdrawal was queued.
* @param strategies The strategies requested for withdrawal when the withdrawal was queued
* @param scaledShares The staker's deposit shares requested for withdrawal, scaled by the staker's `depositScalingFactor`. Upon completion, these will be
* scaled by the appropriate slashing factor as of the withdrawal's completable block. The result is what is actually withdrawable.
*/
struct Withdrawal {
address staker;
address delegatedTo;
address withdrawer;
uint256 nonce;
uint32 startBlock;
IStrategy[] strategies;
uint256[] scaledShares;
}
/**
* @param strategies The strategies to withdraw from
* @param depositShares For each strategy, the number of deposit shares to withdraw. Deposit shares can
* be queried via `getDepositedShares`.
* NOTE: The number of shares ultimately received when a withdrawal is completed may be lower depositShares
* if the staker or their delegated operator has experienced slashing.
* @param __deprecated_withdrawer This field is ignored. The only party that may complete a withdrawal
* is the staker that originally queued it. Alternate withdrawers are not supported.
*/
struct QueuedWithdrawalParams {
IStrategy[] strategies;
uint256[] depositShares;
address __deprecated_withdrawer;
}
}
interface IDelegationManagerEvents is IDelegationManagerTypes {
// @notice Emitted when a new operator registers in EigenLayer and provides their delegation approver.
event OperatorRegistered(address indexed operator, address delegationApprover);
/// @notice Emitted when an operator updates their delegation approver
event DelegationApproverUpdated(address indexed operator, address newDelegationApprover);
/**
* @notice Emitted when @param operator indicates that they are updating their MetadataURI string
* @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing
*/
event OperatorMetadataURIUpdated(address indexed operator, string metadataURI);
/// @notice Emitted whenever an operator's shares are increased for a given strategy. Note that shares is the delta in the operator's shares.
event OperatorSharesIncreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta in the operator's shares.
event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted when @param staker delegates to @param operator.
event StakerDelegated(address indexed staker, address indexed operator);
/// @notice Emitted when @param staker undelegates from @param operator.
event StakerUndelegated(address indexed staker, address indexed operator);
/// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself
event StakerForceUndelegated(address indexed staker, address indexed operator);
/// @notice Emitted when a staker's depositScalingFactor is updated
event DepositScalingFactorUpdated(address staker, IStrategy strategy, uint256 newDepositScalingFactor);
/**
* @notice Emitted when a new withdrawal is queued.
* @param withdrawalRoot Is the hash of the `withdrawal`.
* @param withdrawal Is the withdrawal itself.
* @param sharesToWithdraw Is an array of the expected shares that were queued for withdrawal corresponding to the strategies in the `withdrawal`.
*/
event SlashingWithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal, uint256[] sharesToWithdraw);
/// @notice Emitted when a queued withdrawal is completed
event SlashingWithdrawalCompleted(bytes32 withdrawalRoot);
/// @notice Emitted whenever an operator's shares are slashed for a given strategy
event OperatorSharesSlashed(address indexed operator, IStrategy strategy, uint256 totalSlashedShares);
}
/**
* @title DelegationManager
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are
* - enabling anyone to register as an operator in EigenLayer
* - allowing operators to specify parameters related to stakers who delegate to them
* - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time)
* - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager)
*/
interface IDelegationManager is ISignatureUtilsMixin, IDelegationManagerErrors, IDelegationManagerEvents {
/**
* @dev Initializes the initial owner and paused status.
*/
function initialize(
uint256 initialPausedStatus
) external;
/**
* @notice Registers the caller as an operator in EigenLayer.
* @param initDelegationApprover is an address that, if set, must provide a signature when stakers delegate
* to an operator.
* @param allocationDelay The delay before allocations take effect.
* @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator.
*
* @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself".
* @dev This function will revert if the caller is already delegated to an operator.
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
*/
function registerAsOperator(
address initDelegationApprover,
uint32 allocationDelay,
string calldata metadataURI
) external;
/**
* @notice Updates an operator's stored `delegationApprover`.
* @param operator is the operator to update the delegationApprover for
* @param newDelegationApprover is the new delegationApprover for the operator
*
* @dev The caller must have previously registered as an operator in EigenLayer.
*/
function modifyOperatorDetails(address operator, address newDelegationApprover) external;
/**
* @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated.
* @param operator The operator to update metadata for
* @param metadataURI The URI for metadata associated with an operator
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
*/
function updateOperatorMetadataURI(address operator, string calldata metadataURI) external;
/**
* @notice Caller delegates their stake to an operator.
* @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer.
* @param approverSignatureAndExpiry (optional) Verifies the operator approves of this delegation
* @param approverSalt (optional) A unique single use value tied to an individual signature.
* @dev The signature/salt are used ONLY if the operator has configured a delegationApprover.
* If they have not, these params can be left empty.
*/
function delegateTo(
address operator,
SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) external;
/**
* @notice Undelegates the staker from their operator and queues a withdrawal for all of their shares
* @param staker The account to be undelegated
* @return withdrawalRoots The roots of the newly queued withdrawals, if a withdrawal was queued. Returns
* an empty array if none was queued.
*
* @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves.
* @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover"
* @dev Reverts if the `staker` is not delegated to an operator
*/
function undelegate(
address staker
) external returns (bytes32[] memory withdrawalRoots);
/**
* @notice Undelegates the staker from their current operator, and redelegates to `newOperator`
* Queues a withdrawal for all of the staker's withdrawable shares. These shares will only be
* delegated to `newOperator` AFTER the withdrawal is completed.
* @dev This method acts like a call to `undelegate`, then `delegateTo`
* @param newOperator the new operator that will be delegated all assets
* @dev NOTE: the following 2 params are ONLY checked if `newOperator` has a `delegationApprover`.
* If not, they can be left empty.
* @param newOperatorApproverSig A signature from the operator's `delegationApprover`
* @param approverSalt A unique single use value tied to the approver's signature
*/
function redelegate(
address newOperator,
SignatureWithExpiry memory newOperatorApproverSig,
bytes32 approverSalt
) external returns (bytes32[] memory withdrawalRoots);
/**
* @notice Allows a staker to queue a withdrawal of their deposit shares. The withdrawal can be
* completed after the MIN_WITHDRAWAL_DELAY_BLOCKS via either of the completeQueuedWithdrawal methods.
*
* While in the queue, these shares are removed from the staker's balance, as well as from their operator's
* delegated share balance (if applicable). Note that while in the queue, deposit shares are still subject
* to slashing. If any slashing has occurred, the shares received may be less than the queued deposit shares.
*
* @dev To view all the staker's strategies/deposit shares that can be queued for withdrawal, see `getDepositedShares`
* @dev To view the current conversion between a staker's deposit shares and withdrawable shares, see `getWithdrawableShares`
*/
function queueWithdrawals(
QueuedWithdrawalParams[] calldata params
) external returns (bytes32[] memory);
/**
* @notice Used to complete a queued withdrawal
* @param withdrawal The withdrawal to complete
* @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array.
* @param tokens For each `withdrawal.strategies`, the underlying token of the strategy
* NOTE: if `receiveAsTokens` is false, the `tokens` array is unused and can be filled with default values. However, `tokens.length` MUST still be equal to `withdrawal.strategies.length`.
* NOTE: For the `beaconChainETHStrategy`, the corresponding `tokens` value is ignored (can be 0).
* @param receiveAsTokens If true, withdrawn shares will be converted to tokens and sent to the caller. If false, the caller receives shares that can be delegated to an operator.
* NOTE: if the caller receives shares and is currently delegated to an operator, the received shares are
* automatically delegated to the caller's current operator.
*/
function completeQueuedWithdrawal(
Withdrawal calldata withdrawal,
IERC20[] calldata tokens,
bool receiveAsTokens
) external;
/**
* @notice Used to complete multiple queued withdrawals
* @param withdrawals Array of Withdrawals to complete. See `completeQueuedWithdrawal` for the usage of a single Withdrawal.
* @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
* @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean.
* @dev See `completeQueuedWithdrawal` for relevant dev tags
*/
function completeQueuedWithdrawals(
Withdrawal[] calldata withdrawals,
IERC20[][] calldata tokens,
bool[] calldata receiveAsTokens
) external;
/**
* @notice Called by a share manager when a staker's deposit share balance in a strategy increases.
* This method delegates any new shares to an operator (if applicable), and updates the staker's
* deposit scaling factor regardless.
* @param staker The address whose deposit shares have increased
* @param strategy The strategy in which shares have been deposited
* @param prevDepositShares The number of deposit shares the staker had in the strategy prior to the increase
* @param addedShares The number of deposit shares added by the staker
*
* @dev Note that if the either the staker's current operator has been slashed 100% for `strategy`, OR the
* staker has been slashed 100% on the beacon chain such that the calculated slashing factor is 0, this
* method WILL REVERT.
*/
function increaseDelegatedShares(
address staker,
IStrategy strategy,
uint256 prevDepositShares,
uint256 addedShares
) external;
/**
* @notice If the staker is delegated, decreases its operator's shares in response to
* a decrease in balance in the beaconChainETHStrategy
* @param staker the staker whose operator's balance will be decreased
* @param curDepositShares the current deposit shares held by the staker
* @param beaconChainSlashingFactorDecrease the amount that the staker's beaconChainSlashingFactor has decreased by
* @dev Note: `beaconChainSlashingFactorDecrease` are assumed to ALWAYS be < 1 WAD.
* These invariants are maintained in the EigenPodManager.
*/
function decreaseDelegatedShares(
address staker,
uint256 curDepositShares,
uint64 beaconChainSlashingFactorDecrease
) external;
/**
* @notice Decreases the operator's shares in storage after a slash and increases the burnable shares by calling
* into either the StrategyManager or EigenPodManager (if the strategy is beaconChainETH).
* @param operator The operator to decrease shares for.
* @param operatorSet The operator set to decrease shares for.
* @param slashId The slash id to decrease shares for.
* @param strategy The strategy to decrease shares for.
* @param prevMaxMagnitude The previous maxMagnitude of the operator.
* @param newMaxMagnitude The new maxMagnitude of the operator.
* @dev Callable only by the AllocationManager.
* @dev Note: Assumes `prevMaxMagnitude <= newMaxMagnitude`. This invariant is maintained in
* the AllocationManager.
* @return totalDepositSharesToSlash The total deposit shares to burn or redistribute.
*/
function slashOperatorShares(
address operator,
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) external returns (uint256 totalDepositSharesToSlash);
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice returns the address of the operator that `staker` is delegated to.
* @notice Mapping: staker => operator whom the staker is currently delegated to.
* @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator.
*/
function delegatedTo(
address staker
) external view returns (address);
/**
* @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover.
* @dev Salts are used in the `delegateTo` function. Note that this function only processes the delegationApprover's
* signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`.
*/
function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool);
/// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated.
/// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes.
function cumulativeWithdrawalsQueued(
address staker
) external view returns (uint256);
/**
* @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
*/
function isDelegated(
address staker
) external view returns (bool);
/**
* @notice Returns true is an operator has previously registered for delegation.
*/
function isOperator(
address operator
) external view returns (bool);
/**
* @notice Returns the delegationApprover account for an operator
*/
function delegationApprover(
address operator
) external view returns (address);
/**
* @notice Returns the shares that an operator has delegated to them in a set of strategies
* @param operator the operator to get shares for
* @param strategies the strategies to get shares for
*/
function getOperatorShares(
address operator,
IStrategy[] memory strategies
) external view returns (uint256[] memory);
/**
* @notice Returns the shares that a set of operators have delegated to them in a set of strategies
* @param operators the operators to get shares for
* @param strategies the strategies to get shares for
*/
function getOperatorsShares(
address[] memory operators,
IStrategy[] memory strategies
) external view returns (uint256[][] memory);
/**
* @notice Returns amount of withdrawable shares from an operator for a strategy that is still in the queue
* and therefore slashable. Note that the *actual* slashable amount could be less than this value as this doesn't account
* for amounts that have already been slashed. This assumes that none of the shares have been slashed.
* @param operator the operator to get shares for
* @param strategy the strategy to get shares for
* @return the amount of shares that are slashable in the withdrawal queue for an operator and a strategy
*/
function getSlashableSharesInQueue(address operator, IStrategy strategy) external view returns (uint256);
/**
* @notice Given a staker and a set of strategies, return the shares they can queue for withdrawal and the
* corresponding depositShares.
* This value depends on which operator the staker is delegated to.
* The shares amount returned is the actual amount of Strategy shares the staker would receive (subject
* to each strategy's underlying shares to token ratio).
*/
function getWithdrawableShares(
address staker,
IStrategy[] memory strategies
) external view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares);
/**
* @notice Returns the number of shares in storage for a staker and all their strategies
*/
function getDepositedShares(
address staker
) external view returns (IStrategy[] memory, uint256[] memory);
/**
* @notice Returns the scaling factor applied to a staker's deposits for a given strategy
*/
function depositScalingFactor(address staker, IStrategy strategy) external view returns (uint256);
/**
* @notice Returns the Withdrawal associated with a `withdrawalRoot`.
* @param withdrawalRoot The hash identifying the queued withdrawal.
* @return withdrawal The withdrawal details.
*/
function queuedWithdrawals(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal);
/**
* @notice Returns the Withdrawal and corresponding shares associated with a `withdrawalRoot`
* @param withdrawalRoot The hash identifying the queued withdrawal
* @return withdrawal The withdrawal details
* @return shares Array of shares corresponding to each strategy in the withdrawal
* @dev The shares are what a user would receive from completing a queued withdrawal, assuming all slashings are applied
* @dev Withdrawals queued before the slashing release cannot be queried with this method
*/
function getQueuedWithdrawal(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal, uint256[] memory shares);
/**
* @notice Returns all queued withdrawals and their corresponding shares for a staker.
* @param staker The address of the staker to query withdrawals for.
* @return withdrawals Array of Withdrawal structs containing details about each queued withdrawal.
* @return shares 2D array of shares, where each inner array corresponds to the strategies in the withdrawal.
* @dev The shares are what a user would receive from completing a queued withdrawal, assuming all slashings are applied.
*/
function getQueuedWithdrawals(
address staker
) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares);
/// @notice Returns a list of queued withdrawal roots for the `staker`.
/// NOTE that this only returns withdrawals queued AFTER the slashing release.
function getQueuedWithdrawalRoots(
address staker
) external view returns (bytes32[] memory);
/**
* @notice Converts shares for a set of strategies to deposit shares, likely in order to input into `queueWithdrawals`.
* This function will revert from a division by 0 error if any of the staker's strategies have a slashing factor of 0.
* @param staker the staker to convert shares for
* @param strategies the strategies to convert shares for
* @param withdrawableShares the shares to convert
* @return the deposit shares
* @dev will be a few wei off due to rounding errors
*/
function convertToDepositShares(
address staker,
IStrategy[] memory strategies,
uint256[] memory withdrawableShares
) external view returns (uint256[] memory);
/// @notice Returns the keccak256 hash of `withdrawal`.
function calculateWithdrawalRoot(
Withdrawal memory withdrawal
) external pure returns (bytes32);
/**
* @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` function.
* @param staker The account delegating their stake
* @param operator The account receiving delegated stake
* @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general)
* @param approverSalt A unique and single use value associated with the approver signature.
* @param expiry Time after which the approver's signature becomes invalid
*/
function calculateDelegationApprovalDigestHash(
address staker,
address operator,
address _delegationApprover,
bytes32 approverSalt,
uint256 expiry
) external view returns (bytes32);
/// @notice return address of the beaconChainETHStrategy
function beaconChainETHStrategy() external view returns (IStrategy);
/**
* @notice Returns the minimum withdrawal delay in blocks to pass for withdrawals queued to be completable.
* Also applies to legacy withdrawals so any withdrawals not completed prior to the slashing upgrade will be subject
* to this longer delay.
* @dev Backwards-compatible interface to return the internal `MIN_WITHDRAWAL_DELAY_BLOCKS` value
* @dev Previous value in storage was deprecated. See `__deprecated_minWithdrawalDelayBlocks`
*/
function minWithdrawalDelayBlocks() external view returns (uint32);
/// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract
function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin-upgrades/contracts/utils/math/SafeCastUpgradeable.sol";
/// @dev All scaling factors have `1e18` as an initial/default value. This value is represented
/// by the constant `WAD`, which is used to preserve precision with uint256 math.
///
/// When applying scaling factors, they are typically multiplied/divided by `WAD`, allowing this
/// constant to act as a "1" in mathematical formulae.
uint64 constant WAD = 1e18;
/*
* There are 2 types of shares:
* 1. deposit shares
* - These can be converted to an amount of tokens given a strategy
* - by calling `sharesToUnderlying` on the strategy address (they're already tokens
* in the case of EigenPods)
* - These live in the storage of the EigenPodManager and individual StrategyManager strategies
* 2. withdrawable shares
* - For a staker, this is the amount of shares that they can withdraw
* - For an operator, the shares delegated to them are equal to the sum of their stakers'
* withdrawable shares
*
* Along with a slashing factor, the DepositScalingFactor is used to convert between the two share types.
*/
struct DepositScalingFactor {
uint256 _scalingFactor;
}
using SlashingLib for DepositScalingFactor global;
library SlashingLib {
using Math for uint256;
using SlashingLib for uint256;
using SafeCastUpgradeable for uint256;
/// @dev Thrown if an updated deposit scaling factor is 0 to avoid underflow.
error InvalidDepositScalingFactor();
// WAD MATH
function mulWad(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(y, WAD);
}
function divWad(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(WAD, y);
}
/**
* @notice Used explicitly for calculating slashed magnitude, we want to ensure even in the
* situation where an operator is slashed several times and precision has been lost over time,
* an incoming slashing request isn't rounded down to 0 and an operator is able to avoid slashing penalties.
*/
function mulWadRoundUp(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(y, WAD, Math.Rounding.Up);
}
// GETTERS
function scalingFactor(
DepositScalingFactor memory dsf
) internal pure returns (uint256) {
return dsf._scalingFactor == 0 ? WAD : dsf._scalingFactor;
}
function scaleForQueueWithdrawal(
DepositScalingFactor memory dsf,
uint256 depositSharesToWithdraw
) internal pure returns (uint256) {
return depositSharesToWithdraw.mulWad(dsf.scalingFactor());
}
function scaleForCompleteWithdrawal(uint256 scaledShares, uint256 slashingFactor) internal pure returns (uint256) {
return scaledShares.mulWad(slashingFactor);
}
/**
* @notice Scales shares according to the difference in an operator's magnitude before and
* after being slashed. This is used to calculate the number of slashable shares in the
* withdrawal queue.
* NOTE: max magnitude is guaranteed to only ever decrease.
*/
function scaleForBurning(
uint256 scaledShares,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) internal pure returns (uint256) {
return scaledShares.mulWad(prevMaxMagnitude - newMaxMagnitude);
}
function update(
DepositScalingFactor storage dsf,
uint256 prevDepositShares,
uint256 addedShares,
uint256 slashingFactor
) internal {
if (prevDepositShares == 0) {
// If this is the staker's first deposit or they are delegating to an operator,
// the slashing factor is inverted and applied to the existing DSF. This has the
// effect of "forgiving" prior slashing for any subsequent deposits.
dsf._scalingFactor = dsf.scalingFactor().divWad(slashingFactor);
return;
}
/**
* Base Equations:
* (1) newShares = currentShares + addedShares
* (2) newDepositShares = prevDepositShares + addedShares
* (3) newShares = newDepositShares * newDepositScalingFactor * slashingFactor
*
* Plugging (1) into (3):
* (4) newDepositShares * newDepositScalingFactor * slashingFactor = currentShares + addedShares
*
* Solving for newDepositScalingFactor
* (5) newDepositScalingFactor = (currentShares + addedShares) / (newDepositShares * slashingFactor)
*
* Plugging in (2) into (5):
* (7) newDepositScalingFactor = (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor)
* Note that magnitudes must be divided by WAD for precision. Thus,
*
* (8) newDepositScalingFactor = WAD * (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor / WAD)
* (9) newDepositScalingFactor = (currentShares + addedShares) * WAD / (prevDepositShares + addedShares) * WAD / slashingFactor
*/
// Step 1: Calculate Numerator
uint256 currentShares = dsf.calcWithdrawable(prevDepositShares, slashingFactor);
// Step 2: Compute currentShares + addedShares
uint256 newShares = currentShares + addedShares;
// Step 3: Calculate newDepositScalingFactor
/// forgefmt: disable-next-item
uint256 newDepositScalingFactor = newShares
.divWad(prevDepositShares + addedShares)
.divWad(slashingFactor);
dsf._scalingFactor = newDepositScalingFactor;
// Avoid potential underflow.
require(newDepositScalingFactor != 0, InvalidDepositScalingFactor());
}
/// @dev Reset the staker's DSF for a strategy by setting it to 0. This is the same
/// as setting it to WAD (see the `scalingFactor` getter above).
///
/// A DSF is reset when a staker reduces their deposit shares to 0, either by queueing
/// a withdrawal, or undelegating from their operator. This ensures that subsequent
/// delegations/deposits do not use a stale DSF (e.g. from a prior operator).
function reset(
DepositScalingFactor storage dsf
) internal {
dsf._scalingFactor = 0;
}
// CONVERSION
function calcWithdrawable(
DepositScalingFactor memory dsf,
uint256 depositShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return depositShares
.mulWad(dsf.scalingFactor())
.mulWad(slashingFactor);
}
function calcDepositShares(
DepositScalingFactor memory dsf,
uint256 withdrawableShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return withdrawableShares
.divWad(dsf.scalingFactor())
.divWad(slashingFactor);
}
function calcSlashedAmount(
uint256 operatorShares,
uint256 prevMaxMagnitude,
uint256 newMaxMagnitude
) internal pure returns (uint256) {
// round up mulDiv so we don't overslash
return operatorShares - operatorShares.mulDiv(newMaxMagnitude, prevMaxMagnitude, Math.Rounding.Up);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
using OperatorSetLib for OperatorSet global;
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
library OperatorSetLib {
function key(
OperatorSet memory os
) internal pure returns (bytes32) {
return bytes32(abi.encodePacked(os.avs, uint96(os.id)));
}
function decode(
bytes32 _key
) internal pure returns (OperatorSet memory) {
/// forgefmt: disable-next-item
return OperatorSet({
avs: address(uint160(uint256(_key) >> 96)),
id: uint32(uint256(_key) & type(uint96).max)
});
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ISemVerMixin.sol";
interface ISignatureUtilsMixinErrors {
/// @notice Thrown when a signature is invalid.
error InvalidSignature();
/// @notice Thrown when a signature has expired.
error SignatureExpired();
}
interface ISignatureUtilsMixinTypes {
/// @notice Struct that bundles together a signature and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithSaltAndExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the salt used to generate the signature
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
}
/**
* @title The interface for common signature utilities.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface ISignatureUtilsMixin is ISignatureUtilsMixinErrors, ISignatureUtilsMixinTypes, ISemVerMixin {
/// @notice Computes the EIP-712 domain separator used for signature validation.
/// @dev The domain separator is computed according to EIP-712 specification, using:
/// - The hardcoded name "EigenLayer"
/// - The contract's version string
/// - The current chain ID
/// - This contract's address
/// @return The 32-byte domain separator hash used in EIP-712 structured data signing.
/// @dev See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
function domainSeparator() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCastUpgradeable {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts-v4.9.0/",
"@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable-v4.9.0/",
"ds-test/=lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable-v4.9.0/lib/erc4626-tests/",
"openzeppelin-contracts-upgradeable-v4.9.0/=lib/openzeppelin-contracts-upgradeable-v4.9.0/",
"openzeppelin-contracts-v4.9.0/=lib/openzeppelin-contracts-v4.9.0/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/",
"zeus-templates/=lib/zeus-templates/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IETHPOSDeposit","name":"_ethPOS","type":"address"},{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"},{"internalType":"string","name":"_version","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BeaconTimestampBeforeLatestCheckpoint","type":"error"},{"inputs":[],"name":"BeaconTimestampTooFarInPast","type":"error"},{"inputs":[],"name":"CannotCheckpointTwiceInSingleBlock","type":"error"},{"inputs":[],"name":"CheckpointAlreadyActive","type":"error"},{"inputs":[],"name":"CredentialsAlreadyVerified","type":"error"},{"inputs":[],"name":"CurrentlyPaused","type":"error"},{"inputs":[],"name":"FeeQueryFailed","type":"error"},{"inputs":[],"name":"ForkTimestampZero","type":"error"},{"inputs":[],"name":"InputAddressZero","type":"error"},{"inputs":[],"name":"InputArrayLengthMismatch","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientWithdrawableBalance","type":"error"},{"inputs":[],"name":"InvalidEIP4788Response","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidProofLength","type":"error"},{"inputs":[],"name":"InvalidProofLength","type":"error"},{"inputs":[],"name":"InvalidPubKeyLength","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidValidatorFieldsLength","type":"error"},{"inputs":[],"name":"MsgValueNot32ETH","type":"error"},{"inputs":[],"name":"NoActiveCheckpoint","type":"error"},{"inputs":[],"name":"NoBalanceToCheckpoint","type":"error"},{"inputs":[],"name":"OnlyEigenPodManager","type":"error"},{"inputs":[],"name":"OnlyEigenPodOwner","type":"error"},{"inputs":[],"name":"OnlyEigenPodOwnerOrProofSubmitter","type":"error"},{"inputs":[],"name":"PredeployFailed","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TimestampOutOfRange","type":"error"},{"inputs":[],"name":"ValidatorInactiveOnBeaconChain","type":"error"},{"inputs":[],"name":"ValidatorIsExitingBeaconChain","type":"error"},{"inputs":[],"name":"ValidatorNotActiveInPod","type":"error"},{"inputs":[],"name":"ValidatorNotSlashedOnBeaconChain","type":"error"},{"inputs":[],"name":"WithdrawalCredentialsNotForEigenPod","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"checkpointTimestamp","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"beaconBlockRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"validatorCount","type":"uint256"}],"name":"CheckpointCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"checkpointTimestamp","type":"uint64"},{"indexed":false,"internalType":"int256","name":"totalShareDeltaWei","type":"int256"}],"name":"CheckpointFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"sourcePubkeyHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"targetPubkeyHash","type":"bytes32"}],"name":"ConsolidationRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"name":"EigenPodStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"validatorPubkeyHash","type":"bytes32"}],"name":"ExitRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"NonBeaconChainETHReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prevProofSubmitter","type":"address"},{"indexed":false,"internalType":"address","name":"newProofSubmitter","type":"address"}],"name":"ProofSubmitterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RestakedBeaconChainETHWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"validatorPubkeyHash","type":"bytes32"}],"name":"SwitchToCompoundingRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"balanceTimestamp","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newValidatorBalanceGwei","type":"uint64"}],"name":"ValidatorBalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"checkpointTimestamp","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"name":"ValidatorCheckpointed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"name":"ValidatorRestaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"checkpointTimestamp","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"name":"ValidatorWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"validatorPubkeyHash","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"withdrawalAmountGwei","type":"uint64"}],"name":"WithdrawalRequested","type":"event"},{"inputs":[],"name":"activeValidatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"checkpointBalanceExitedGwei","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCheckpoint","outputs":[{"components":[{"internalType":"bytes32","name":"beaconBlockRoot","type":"bytes32"},{"internalType":"uint24","name":"proofsRemaining","type":"uint24"},{"internalType":"uint64","name":"podBalanceGwei","type":"uint64"},{"internalType":"int64","name":"balanceDeltasGwei","type":"int64"},{"internalType":"uint64","name":"prevBeaconBalanceGwei","type":"uint64"}],"internalType":"struct IEigenPodTypes.Checkpoint","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentCheckpointTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethPOS","outputs":[{"internalType":"contract IETHPOSDeposit","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConsolidationRequestFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"timestamp","type":"uint64"}],"name":"getParentBlockRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawalRequestFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_podOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastCheckpointTimestamp","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"podOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofSubmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokenList","type":"address[]"},{"internalType":"uint256[]","name":"amountsToWithdraw","type":"uint256[]"},{"internalType":"address","name":"recipient","type":"address"}],"name":"recoverTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"srcPubkey","type":"bytes"},{"internalType":"bytes","name":"targetPubkey","type":"bytes"}],"internalType":"struct IEigenPodTypes.ConsolidationRequest[]","name":"requests","type":"tuple[]"}],"name":"requestConsolidation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"uint64","name":"amountGwei","type":"uint64"}],"internalType":"struct IEigenPodTypes.WithdrawalRequest[]","name":"requests","type":"tuple[]"}],"name":"requestWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newProofSubmitter","type":"address"}],"name":"setProofSubmitter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"pubkey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"}],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"revertIfNoBalance","type":"bool"}],"name":"startCheckpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"validatorPubkeyHash","type":"bytes32"}],"name":"validatorPubkeyHashToInfo","outputs":[{"components":[{"internalType":"uint64","name":"validatorIndex","type":"uint64"},{"internalType":"uint64","name":"restakedBalanceGwei","type":"uint64"},{"internalType":"uint64","name":"lastCheckpointedAt","type":"uint64"},{"internalType":"enum IEigenPodTypes.VALIDATOR_STATUS","name":"status","type":"uint8"}],"internalType":"struct IEigenPodTypes.ValidatorInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubkey","type":"bytes"}],"name":"validatorPubkeyToInfo","outputs":[{"components":[{"internalType":"uint64","name":"validatorIndex","type":"uint64"},{"internalType":"uint64","name":"restakedBalanceGwei","type":"uint64"},{"internalType":"uint64","name":"lastCheckpointedAt","type":"uint64"},{"internalType":"enum IEigenPodTypes.VALIDATOR_STATUS","name":"status","type":"uint8"}],"internalType":"struct IEigenPodTypes.ValidatorInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubkey","type":"bytes"}],"name":"validatorStatus","outputs":[{"internalType":"enum IEigenPodTypes.VALIDATOR_STATUS","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"}],"name":"validatorStatus","outputs":[{"internalType":"enum IEigenPodTypes.VALIDATOR_STATUS","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"balanceContainerRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.BalanceContainerProof","name":"balanceContainerProof","type":"tuple"},{"components":[{"internalType":"bytes32","name":"pubkeyHash","type":"bytes32"},{"internalType":"bytes32","name":"balanceRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.BalanceProof[]","name":"proofs","type":"tuple[]"}],"name":"verifyCheckpointProofs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"beaconTimestamp","type":"uint64"},{"components":[{"internalType":"bytes32","name":"beaconStateRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.StateRootProof","name":"stateRootProof","type":"tuple"},{"components":[{"internalType":"bytes32[]","name":"validatorFields","type":"bytes32[]"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.ValidatorProof","name":"proof","type":"tuple"}],"name":"verifyStaleBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"beaconTimestamp","type":"uint64"},{"components":[{"internalType":"bytes32","name":"beaconStateRoot","type":"bytes32"},{"internalType":"bytes","name":"proof","type":"bytes"}],"internalType":"struct BeaconChainProofs.StateRootProof","name":"stateRootProof","type":"tuple"},{"internalType":"uint40[]","name":"validatorIndices","type":"uint40[]"},{"internalType":"bytes[]","name":"validatorFieldsProofs","type":"bytes[]"},{"internalType":"bytes32[][]","name":"validatorFields","type":"bytes32[][]"}],"name":"verifyWithdrawalCredentials","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountWei","type":"uint256"}],"name":"withdrawRestakedBeaconChainETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawableRestakedExecutionLayerGwei","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e060405234801561000f575f5ffd5b506040516148c03803806148c083398101604081905261002e91610188565b806100388161005f565b608052506001600160a01b0380841660a052821660c0526100576100a5565b5050506102b9565b5f5f829050601f81511115610092578260405163305a27a960e01b8152600401610089919061025e565b60405180910390fd5b805161009d82610293565b179392505050565b5f54610100900460ff161561010c5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608401610089565b5f5460ff9081161461015b575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b0381168114610171575f5ffd5b50565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f6060848603121561019a575f5ffd5b83516101a58161015d565b60208501519093506101b68161015d565b60408501519092506001600160401b038111156101d1575f5ffd5b8401601f810186136101e1575f5ffd5b80516001600160401b038111156101fa576101fa610174565b604051601f8201601f19908116603f011681016001600160401b038111828210171561022857610228610174565b60405281815282820160200188101561023f575f5ffd5b8160208401602083015e5f602083830101528093505050509250925092565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b805160208083015191908110156102b3575f198160200360031b1b821691505b50919050565b60805160a05160c05161457b6103455f395f8181610329015281816106d40152818161077c01528181610a2a01528181610deb01528181610fe5015281816110f0015281816115f1015281816116980152818161192101528181611c6f01528181611da301528181612279015261318301525f818161057a015261170101525f611051015261457b5ff3fe6080604052600436106101bd575f3560e01c80636691954e116100f2578063b522538a11610092578063d06d558711610062578063d06d55871461063f578063dda3346c1461065e578063ee94d67c1461067d578063f074ba621461069c575f5ffd5b8063b522538a146105ce578063c44e30dc146105ed578063c490744214610601578063c4d66de814610620575f5ffd5b80637439841f116100cd5780637439841f1461053457806374cdd7981461056957806388676cad1461059c5780639b4e4634146105bb575f5ffd5b80636691954e146104d65780636c0d2d5a146104e95780636fcd0e5314610508575f5ffd5b806342ecff2a1161015d57806352396a591161013857806352396a591461043657806354fd4d501461046a578063587533571461048b57806358eaee79146104aa575f5ffd5b806342ecff2a146102f25780634665bcda1461031857806347d283721461034b575f5ffd5b80632340e8d3116101985780632340e8d31461027a5780633474aa161461028f5780633f5fa57a146102c05780633f65cf19146102d3575f5ffd5b8063039157d2146101fb5780630b18ff661461021c5780631e51553314610258575f5ffd5b366101f7576040513481527f6fdd3dbdb173299608c0aa9f368735857c8842b581f8389238bf05bd04b3bf499060200160405180910390a1005b5f5ffd5b348015610206575f5ffd5b5061021a610215366004613a22565b6106bb565b005b348015610227575f5ffd5b5060335461023b906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610263575f5ffd5b5061026c6109f0565b60405190815260200161024f565b348015610285575f5ffd5b5061026c60395481565b34801561029a575f5ffd5b506034546001600160401b03165b6040516001600160401b03909116815260200161024f565b61021a6102ce366004613add565b610a11565b3480156102de575f5ffd5b5061021a6102ed366004613b1b565b610d92565b3480156102fd575f5ffd5b50603a546102a890600160401b90046001600160401b031681565b348015610323575f5ffd5b5061023b7f000000000000000000000000000000000000000000000000000000000000000081565b348015610356575f5ffd5b506103db6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152506040805160a081018252603c548152603d5462ffffff811660208301526001600160401b0363010000008204811693830193909352600160581b810460070b6060830152600160981b9004909116608082015290565b60405161024f91905f60a0820190508251825262ffffff60208401511660208301526001600160401b036040840151166040830152606083015160070b60608301526001600160401b03608084015116608083015292915050565b348015610441575f5ffd5b506102a8610450366004613bf2565b603b6020525f90815260409020546001600160401b031681565b348015610475575f5ffd5b5061047e61104a565b60405161024f9190613c3b565b348015610496575f5ffd5b50603e5461023b906001600160a01b031681565b3480156104b5575f5ffd5b506104c96104c4366004613c8a565b611075565b60405161024f9190613cf0565b61021a6104e4366004613add565b6110d7565b3480156104f4575f5ffd5b5061026c610503366004613bf2565b6113df565b348015610513575f5ffd5b50610527610522366004613cfe565b6114ed565b60405161024f9190613d15565b34801561053f575f5ffd5b506104c961054e366004613cfe565b5f90815260366020526040902054600160c01b900460ff1690565b348015610574575f5ffd5b5061023b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105a7575f5ffd5b5061021a6105b6366004613d75565b611598565b61021a6105c9366004613d90565b61168d565b3480156105d9575f5ffd5b506105276105e8366004613c8a565b61180b565b3480156105f8575f5ffd5b5061026c6118fa565b34801561060c575f5ffd5b5061021a61061b366004613e25565b611916565b34801561062b575f5ffd5b5061021a61063a366004613e4f565b611a4d565b34801561064a575f5ffd5b5061021a610659366004613e4f565b611b97565b348015610669575f5ffd5b5061021a610678366004613f3a565b611c2b565b348015610688575f5ffd5b50603a546102a8906001600160401b031681565b3480156106a7575f5ffd5b5061021a6106b636600461400c565b611d8a565b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610721573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107459190614073565b156107635760405163840a48d560e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600860048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa1580156107c9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ed9190614073565b1561080b5760405163840a48d560e01b815260040160405180910390fd5b5f61084f610819858061408e565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061218692505050565b5f818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff1660028111156108bd576108bd613cbc565b60028111156108ce576108ce613cbc565b81525050905080604001516001600160401b0316876001600160401b03161161090a576040516337e07ffd60e01b815260040160405180910390fd5b60018160600151600281111561092257610922613cbc565b146109405760405163d49e19a760e01b815260040160405180910390fd5b61098361094d868061408e565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506121a892505050565b6109a05760405163161ce5ed60e31b815260040160405180910390fd5b6109b26109ac886113df565b876121d0565b6109de6109be88612275565b87356109ca888061408e565b6109d760208b018b6140d3565b875161234c565b6109e75f612480565b50505050505050565b5f610a0c71bbddc7ce488642fb579f8b00f3a590007251612600565b905090565b604051635ac86ab760e01b8152600a60048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610a77573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a9b9190614073565b15610ab95760405163840a48d560e01b815260040160405180910390fd5b6033546001600160a01b0316331480610adc5750603e546001600160a01b031633145b610af95760405163427a777960e01b815260040160405180910390fd5b5f610b026118fa565b90505f610b0f8483614129565b905080341015610b325760405163356680b760e01b815260040160405180910390fd5b5f610b3d8234614140565b90505f5b85811015610d795736878783818110610b5c57610b5c614153565b9050602002810190610b6e9190614167565b90505f610bb7610b7e83806140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b905060015f82815260366020526040902054600160c01b900460ff166002811115610be457610be4613cbc565b14610c025760405163d49e19a760e01b815260040160405180910390fd5b5f610c0d83806140d3565b610c1d6040860160208701613bf2565b604051602001610c2f93929190614185565b60405160208183030381529060405290505f710961ef480eb55e80d19ad83579a64c0070026001600160a01b03168883604051610c6c91906141bd565b5f6040518083038185875af1925050503d805f8114610ca6576040519150601f19603f3d011682016040523d82523d5f602084013e610cab565b606091505b5050905080610ccd5760405163fc52d48360e01b815260040160405180910390fd5b610cdd6040850160208601613bf2565b6001600160401b03165f03610d1b5760405183907f60d8ca014d4765a2b8b389e25714cb1cef83b574222911a01d90c1bd69d2d320905f90a2610d69565b827f8b2737bb64ab2f2dc09552dfa1c250399e6a42c7ea9f0e1c658f5d65d708ec05610d4d6040870160208801613bf2565b6040516001600160401b03909116815260200160405180910390a25b505060019092019150610b419050565b508015610d8a57610d8a3382612717565b505050505050565b6033546001600160a01b0316331480610db55750603e546001600160a01b031633145b610dd25760405163427a777960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015610e38573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5c9190614073565b15610e7a5760405163840a48d560e01b815260040160405180910390fd5b8584148015610e8857508382145b610ea5576040516343714afd60e01b815260040160405180910390fd5b603a546001600160401b03600160401b9091048116908a1611610edb576040516337e07ffd60e01b815260040160405180910390fd5b603a546001600160401b03908116908a1611610f0a576040516335e7f6b760e01b815260040160405180910390fd5b610f1c610f168a6113df565b896121d0565b5f805b87811015610fb557610fa18b8b358b8b85818110610f3f57610f3f614153565b9050602002016020810190610f5491906141c8565b8a8a86818110610f6657610f66614153565b9050602002810190610f7891906140d3565b8a8a88818110610f8a57610f8a614153565b9050602002810190610f9c919061408e565b61282c565b610fab90836141ec565b9150600101610f1f565b5060335460405163a1ca780b60e01b81526001600160a01b0391821660048201525f6024820152604481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063a1ca780b906064015f604051808303815f87803b158015611028575f5ffd5b505af115801561103a573d5f5f3e3d5ffd5b5050505050505050505050505050565b6060610a0c7f0000000000000000000000000000000000000000000000000000000000000000612d2d565b5f5f6110b584848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b5f90815260366020526040902054600160c01b900460ff169150505b92915050565b604051635ac86ab760e01b8152600960048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa15801561113d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111619190614073565b1561117f5760405163840a48d560e01b815260040160405180910390fd5b6033546001600160a01b03163314806111a25750603e546001600160a01b031633145b6111bf5760405163427a777960e01b815260040160405180910390fd5b5f6111c86109f0565b90505f6111d58483614129565b9050803410156111f85760405163356680b760e01b815260040160405180910390fd5b5f6112038234614140565b90505f5b85811015610d79573687878381811061122257611222614153565b90506020028101906112349190614167565b90505f611244610b7e83806140d3565b90505f611257610b7e60208501856140d3565b905060015f82815260366020526040902054600160c01b900460ff16600281111561128457611284613cbc565b146112a25760405163d49e19a760e01b815260040160405180910390fd5b5f6112ad84806140d3565b6112ba60208701876140d3565b6040516020016112cd94939291906141ff565b60405160208183030381529060405290505f71bbddc7ce488642fb579f8b00f3a5900072516001600160a01b0316898360405161130a91906141bd565b5f6040518083038185875af1925050503d805f8114611344576040519150601f19603f3d011682016040523d82523d5f602084013e611349565b606091505b505090508061136b5760405163fc52d48360e01b815260040160405180910390fd5b8284036113a15760405184907fc97b965b92ae7fd20095fe8eb7b99f81f95f8c4adffb22a19116d8eb2846b016905f90a26113ce565b604051839085907f42f9c9db2ca443e9ec62f4588bd0c9b241065c02c2a8001ac164ae1282dc7b94905f90a35b505060019093019250611207915050565b5f6113ed611fff600c614129565b6114006001600160401b03841642614140565b1061141e57604051637944e66d60e11b815260040160405180910390fd5b604080516001600160401b03841660208201525f918291720f3df6d732807ef1319fb7b8bb8522d0beac02910160408051601f1981840301815290829052611465916141bd565b5f60405180830381855afa9150503d805f811461149d576040519150601f19603f3d011682016040523d82523d5f602084013e6114a2565b606091505b50915091508180156114b457505f8151115b6114d15760405163558ad0a360e01b815260040160405180910390fd5b808060200190518101906114e5919061421e565b949350505050565b611514604080516080810182525f8082526020820181905291810182905290606082015290565b5f82815260366020908152604091829020825160808101845281546001600160401b038082168352600160401b8204811694830194909452600160801b810490931693810193909352906060830190600160c01b900460ff16600281111561157e5761157e613cbc565b600281111561158f5761158f613cbc565b90525092915050565b6033546001600160a01b03163314806115bb5750603e546001600160a01b031633145b6115d85760405163427a777960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa15801561163e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116629190614073565b156116805760405163840a48d560e01b815260040160405180910390fd5b61168982612480565b5050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146116d657604051633213a66160e21b815260040160405180910390fd5b346801bc16d674ec800000146116ff5760405163049696b360e31b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663228951186801bc16d674ec8000008787611742612d6a565b8888886040518863ffffffff1660e01b81526004016117669695949392919061425d565b5f604051808303818588803b15801561177d575f5ffd5b505af115801561178f573d5f5f3e3d5ffd5b50505050507fa01003766d3cd97cf2ade5429690bf5d206be7fb01ef9d3a0089ecf67bc112196117f386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b60405190815260200160405180910390a15050505050565b611832604080516080810182525f8082526020820181905291810182905290606082015290565b60365f61187385858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b815260208082019290925260409081015f20815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b81049094169281019290925290916060830190600160c01b900460ff1660028111156118df576118df613cbc565b60028111156118f0576118f0613cbc565b9052509392505050565b5f610a0c710961ef480eb55e80d19ad83579a64c007002612600565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461195f57604051633213a66160e21b815260040160405180910390fd5b5f61196e633b9aca00836142bf565b9050611987633b9aca006001600160401b038316614129565b6034549092506001600160401b0390811690821611156119ba576040516302c6f54760e21b815260040160405180910390fd5b603480548291905f906119d79084906001600160401b03166142d2565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e83604051611a3691815260200190565b60405180910390a2611a488383612717565b505050565b5f54610100900460ff1615808015611a6b57505f54600160ff909116105b80611a845750303b158015611a8457505f5460ff166001145b611aec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015611b0d575f805461ff0019166101001790555b6001600160a01b038216611b34576040516339b190bb60e11b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0384161790558015611689575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6033546001600160a01b03163314611bc25760405163719f370360e11b815260040160405180910390fd5b603e54604080516001600160a01b03928316815291831660208301527ffb8129080a19d34dceac04ba253fc50304dc86c729bd63cdca4a969ad19a5eac910160405180910390a1603e80546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b03163314611c565760405163719f370360e11b815260040160405180910390fd5b604051635ac86ab760e01b8152600560048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611cbc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce09190614073565b15611cfe5760405163840a48d560e01b815260040160405180910390fd5b8251845114611d20576040516343714afd60e01b815260040160405180910390fd5b5f5b8451811015611d8357611d7b83858381518110611d4157611d41614153565b6020026020010151878481518110611d5b57611d5b614153565b60200260200101516001600160a01b0316612d9a9092919063ffffffff16565b600101611d22565b5050505050565b604051635ac86ab760e01b8152600760048201819052907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635ac86ab790602401602060405180830381865afa158015611df0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e149190614073565b15611e325760405163840a48d560e01b815260040160405180910390fd5b603a54600160401b90046001600160401b03165f819003611e6657604051631a544f4960e01b815260040160405180910390fd5b6040805160a081018252603c548152603d5462ffffff811660208301526001600160401b0363010000008204811693830193909352600160581b810460070b6060830152600160981b90049091166080820152611ecd611ec583612275565b825188612dec565b5f805b8581101561212d5736878783818110611eeb57611eeb614153565b9050602002810190611efd91906142f1565b80355f908152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff166002811115611f6d57611f6d613cbc565b6002811115611f7e57611f7e613cbc565b9052509050600181606001516002811115611f9b57611f9b613cbc565b14611fa7575050612125565b856001600160401b031681604001516001600160401b031610611fcb575050612125565b5f8080611fdb848a8f3588612ead565b60208b0180519396509194509250611ff282614305565b62ffffff1690525060808801805184919061200e908390614322565b6001600160401b031690525060608801805183919061202e908390614341565b60070b90525061203e8188614322565b85355f908152603660209081526040918290208751815492890151938901516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b0319909516919092161792909217928316821781556060880151939a50879390929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b8360028111156120e2576120e2613cbc565b021790555050604051863591506001600160401b038b16907fe4866335761a51dcaff766448ab0af6064291ee5dc94e68492bb9cd757c1e350905f90a350505050505b600101611ed0565b506001600160401b038084165f908152603b602052604081208054849391929161215991859116614322565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506109e782612fc3565b5f815f8151811061219957612199614153565b60200260200101519050919050565b5f816003815181106121bc576121bc614153565b60200260200101515f5f1b14159050919050565b6121dc60036020614129565b6121e960208301836140d3565b905014612209576040516313717da960e21b815260040160405180910390fd5b61225861221960208301836140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250869250508435905060036131e3565b611689576040516309bde33960e01b815260040160405180910390fd5b5f5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632704351a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122d3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122f79190614370565b9050806001600160401b03165f03612322576040516341a02cc960e01b815260040160405180910390fd5b806001600160401b0316836001600160401b03161115612343576001612345565b5f5b9392505050565b6008841461236d5760405163200591bd60e01b815260040160405180910390fd5b5f612377886131fa565b905080612386602860016141ec565b61239091906141ec565b61239b906020614129565b83146123ba576040516313717da960e21b815260040160405180910390fd5b5f6123f68787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061322292505050565b90505f64ffffffffff841661240d602860016141ec565b600b901b17905061245786868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508d92508691508590506131e3565b612474576040516309bde33960e01b815260040160405180910390fd5b50505050505050505050565b603a54600160401b90046001600160401b0316156124b05760405162be9bc360e81b815260040160405180910390fd5b603a546001600160401b034281169116036124de576040516367db5b8b60e01b815260040160405180910390fd5b6034545f906001600160401b03166124fa633b9aca00476142bf565b61250491906142d2565b905081801561251a57506001600160401b038116155b15612538576040516332dea95960e21b815260040160405180910390fd5b5f6040518060a0016040528061254d426113df565b815260395462ffffff1660208201526001600160401b0380851660408301525f60608301819052608090920191909152603a805442909216600160401b026fffffffffffffffff00000000000000001990921691909117905590506125b181612fc3565b805160208083015160405162ffffff90911681526001600160401b034216917f575796133bbed337e5b39aa49a30dc2556a91e0c6c2af4b7b886ae77ebef1076910160405180910390a3505050565b5f5f5f836001600160a01b03166040515f60405180830381855afa9150503d805f8114612648576040519150601f19603f3d011682016040523d82523d5f602084013e61264d565b606091505b5091509150818015612660575080516020145b61267d5760405163c90158af60e01b815260040160405180910390fd5b6114e58161438b565b5f81516030146126a957604051634f88323960e11b815260040160405180910390fd5b6040516002906126bf9084905f906020016143ae565b60408051601f19818403018152908290526126d9916141bd565b602060405180830381855afa1580156126f4573d5f5f3e3d5ffd5b5050506040513d601f19601f820116820180604052508101906110d1919061421e565b804710156127675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611ae3565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146127b0576040519150601f19603f3d011682016040523d82523d5f602084013e6127b5565b606091505b5050905080611a485760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611ae3565b5f5f6128698484808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061218692505050565b5f818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff1660028111156128d7576128d7613cbc565b60028111156128e8576128e8613cbc565b90525090505f8160600151600281111561290457612904613cbc565b14612922576040516335e09e9d60e01b815260040160405180910390fd5b6001600160401b0380166129678686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134b292505050565b6001600160401b03160361298e57604051631958236d60e21b815260040160405180910390fd5b6001600160401b0380166129d38686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134d692505050565b6001600160401b0316146129fa57604051632eade63760e01b815260040160405180910390fd5b612a02612d6a565b612a0b9061438b565b612a468686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134ed92505050565b1480612a9b5750612a55613501565b612a5e9061438b565b612a998686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134ed92505050565b145b612ab857604051633772dd5360e11b815260040160405180910390fd5b5f612af48686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061351d92505050565b9050612b0d612b028c612275565b8b88888c8c8f61234c565b60398054905f612b1c836143d2565b9091555050603a545f90600160401b90046001600160401b031615612b5357603a54600160401b90046001600160401b0316612b60565b603a546001600160401b03165b6040805160808101825264ffffffffff8d1681526001600160401b03858116602083015283169181019190915290915060608101600190525f858152603660209081526040918290208351815492850151938501516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b031990951691909216179290921792831682178155606084015190929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b836002811115612c3557612c35613cbc565b021790555050603d8054849250601390612c60908490600160981b90046001600160401b0316614322565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507f101790c2993f6a4d962bd17c786126823ba1c4cf04ff4cccb2659d50fb20aee884604051612cb591815260200190565b60405180910390a1604080518581526001600160401b03838116602083015284168183015290517fcdae700d7241bc027168c53cf6f889763b0a2c88a65d77fc13a8a9fef0d8605f9181900360600190a1612d1d633b9aca006001600160401b038416614129565b9c9b505050505050505050505050565b60605f612d3983613534565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b604051606090612d8690600160f81b905f9030906020016143ea565b604051602081830303815290604052905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a4890849061355b565b5f612df6846131fa565b9050612e038160036141ec565b612e0e906020614129565b612e1b60208401846140d3565b905014612e3b576040516313717da960e21b815260040160405180910390fd5b6003811b600c17612e90612e5260208501856140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892505086359050846131e3565b611d83576040516309bde33960e01b815260040160405180910390fd5b5f5f5f866020015192505f612ec686895f01518761362e565b9050836001600160401b0316816001600160401b031614612f3a57612eeb8482614428565b60408051873581526001600160401b038a8116602083015284168183015290519194507fcdae700d7241bc027168c53cf6f889763b0a2c88a65d77fc13a8a9fef0d8605f919081900360600190a15b6001600160401b0380821660208a0181905290881660408a01525f03612fb85760398054905f612f6983614457565b909155505060026060890152612f7e8361446c565b6040519092508535906001600160401b038916907f5ce0aa04ae51d52da6e680fbe0336d2e2432f7c3dc2d4f3193204c57b9072107905f90a35b509450945094915050565b8051603c556020810151603d805460408401516060850151608086015162ffffff9095166affffffffffffffffffffff19909316831763010000006001600160401b0393841602176fffffffffffffffffffffffffffffffff60581b1916600160581b9183169190910267ffffffffffffffff60981b191617600160981b9190941602929092179055156130545750565b60808101516034545f91613070916001600160401b0316614322565b90505f826060015183604001516130879190614341565b60408401516034805492935090915f906130ab9084906001600160401b0316614322565b82546101009290920a6001600160401b03818102199093169183160217909155603a8054600160401b810483166001600160801b03199091161790555f91506130fb90633b9aca00908516614129565b90505f613110633b9aca00600785900b614491565b603a546040518281529192506001600160401b0316907f525408c201bc1576eb44116f6478f1c2a54775b19a043bcfdc708364f74f8e449060200160405180910390a260335460405163a1ca780b60e01b81526001600160a01b03918216600482015260248101849052604481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063a1ca780b906064015f604051808303815f87803b1580156131c6575f5ffd5b505af11580156131d8573d5f5f3e3d5ffd5b505050505050505050565b5f836131f086858561370c565b1495945050505050565b5f8082600181111561320e5761320e613cbc565b1461321a5760066110d1565b600592915050565b5f5f6002835161323291906142bf565b90505f816001600160401b0381111561324d5761324d613e6a565b604051908082528060200260200182016040528015613276578160200160208202803683370190505b5090505f5b82811015613370576002856132908383614129565b815181106132a0576132a0614153565b6020026020010151868360026132b69190614129565b6132c19060016141ec565b815181106132d1576132d1614153565b60200260200101516040516020016132f3929190918252602082015260400190565b60408051601f198184030181529082905261330d916141bd565b602060405180830381855afa158015613328573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061334b919061421e565b82828151811061335d5761335d614153565b602090810291909101015260010161327b565b5061337c6002836142bf565b91505b811561348f575f5b8281101561347c5760028261339c8383614129565b815181106133ac576133ac614153565b6020026020010151838360026133c29190614129565b6133cd9060016141ec565b815181106133dd576133dd614153565b60200260200101516040516020016133ff929190918252602082015260400190565b60408051601f1981840301815290829052613419916141bd565b602060405180830381855afa158015613434573d5f5f3e3d5ffd5b5050506040513d601f19601f82011682018060405250810190613457919061421e565b82828151811061346957613469614153565b6020908102919091010152600101613387565b506134886002836142bf565b915061337f565b805f815181106134a1576134a1614153565b602002602001015192505050919050565b5f6110d1826005815181106134c9576134c9614153565b60200260200101516137e0565b5f6110d1826006815181106134c9576134c9614153565b5f8160018151811061219957612199614153565b604051606090612d8690600160f91b905f9030906020016143ea565b5f6110d1826002815181106134c9576134c9614153565b5f60ff8216601f8111156110d157604051632cd44ac360e21b815260040160405180910390fd5b5f6135af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138479092919063ffffffff16565b905080515f14806135cf5750808060200190518101906135cf9190614073565b611a485760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611ae3565b5f61363b602660016141ec565b613646906020614129565b61365360408401846140d3565b905014613673576040516313717da960e21b815260040160405180910390fd5b5f61367f6004856144c0565b64ffffffffff1690506136d861369860408501856140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525089925050506020860135846131e3565b6136f5576040516309bde33960e01b815260040160405180910390fd5b613703836020013585613855565b95945050505050565b5f83515f1415801561372957506020845161372791906144e9565b155b613746576040516313717da960e21b815260040160405180910390fd5b604080516020808201909252848152905b855181116137d65761376a6002856144e9565b5f0361379c5781515f528086015160205260208260405f60026107d05a03fa613791575f5ffd5b6002840493506137c4565b808601515f52815160205260208260405f60026107d05a03fa6137bd575f5ffd5b6002840493505b6137cf6020826141ec565b9050613757565b5051949350505050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b60606114e584845f85613881565b5f806138626004846144fc565b61386d906040614525565b64ffffffffff1690506114e584821b6137e0565b6060824710156138e25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611ae3565b5f5f866001600160a01b031685876040516138fd91906141bd565b5f6040518083038185875af1925050503d805f8114613937576040519150601f19603f3d011682016040523d82523d5f602084013e61393c565b606091505b509150915061394d87838387613958565b979650505050505050565b606083156139c65782515f036139bf576001600160a01b0385163b6139bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ae3565b50816114e5565b6114e583838151156139db5781518083602001fd5b8060405162461bcd60e51b8152600401611ae39190613c3b565b6001600160401b0381168114613a09575f5ffd5b50565b5f60408284031215613a1c575f5ffd5b50919050565b5f5f5f60608486031215613a34575f5ffd5b8335613a3f816139f5565b925060208401356001600160401b03811115613a59575f5ffd5b613a6586828701613a0c565b92505060408401356001600160401b03811115613a80575f5ffd5b613a8c86828701613a0c565b9150509250925092565b5f5f83601f840112613aa6575f5ffd5b5081356001600160401b03811115613abc575f5ffd5b6020830191508360208260051b8501011115613ad6575f5ffd5b9250929050565b5f5f60208385031215613aee575f5ffd5b82356001600160401b03811115613b03575f5ffd5b613b0f85828601613a96565b90969095509350505050565b5f5f5f5f5f5f5f5f60a0898b031215613b32575f5ffd5b8835613b3d816139f5565b975060208901356001600160401b03811115613b57575f5ffd5b613b638b828c01613a0c565b97505060408901356001600160401b03811115613b7e575f5ffd5b613b8a8b828c01613a96565b90975095505060608901356001600160401b03811115613ba8575f5ffd5b613bb48b828c01613a96565b90955093505060808901356001600160401b03811115613bd2575f5ffd5b613bde8b828c01613a96565b999c989b5096995094979396929594505050565b5f60208284031215613c02575f5ffd5b8135612345816139f5565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6123456020830184613c0d565b5f5f83601f840112613c5d575f5ffd5b5081356001600160401b03811115613c73575f5ffd5b602083019150836020828501011115613ad6575f5ffd5b5f5f60208385031215613c9b575f5ffd5b82356001600160401b03811115613cb0575f5ffd5b613b0f85828601613c4d565b634e487b7160e01b5f52602160045260245ffd5b60038110613cec57634e487b7160e01b5f52602160045260245ffd5b9052565b602081016110d18284613cd0565b5f60208284031215613d0e575f5ffd5b5035919050565b5f6080820190506001600160401b0383511682526001600160401b0360208401511660208301526001600160401b0360408401511660408301526060830151613d616060840182613cd0565b5092915050565b8015158114613a09575f5ffd5b5f60208284031215613d85575f5ffd5b813561234581613d68565b5f5f5f5f5f60608688031215613da4575f5ffd5b85356001600160401b03811115613db9575f5ffd5b613dc588828901613c4d565b90965094505060208601356001600160401b03811115613de3575f5ffd5b613def88828901613c4d565b96999598509660400135949350505050565b6001600160a01b0381168114613a09575f5ffd5b8035613e2081613e01565b919050565b5f5f60408385031215613e36575f5ffd5b8235613e4181613e01565b946020939093013593505050565b5f60208284031215613e5f575f5ffd5b813561234581613e01565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613ea657613ea6613e6a565b604052919050565b5f6001600160401b03821115613ec657613ec6613e6a565b5060051b60200190565b5f82601f830112613edf575f5ffd5b8135613ef2613eed82613eae565b613e7e565b8082825260208201915060208360051b860101925085831115613f13575f5ffd5b602085015b83811015613f30578035835260209283019201613f18565b5095945050505050565b5f5f5f60608486031215613f4c575f5ffd5b83356001600160401b03811115613f61575f5ffd5b8401601f81018613613f71575f5ffd5b8035613f7f613eed82613eae565b8082825260208201915060208360051b850101925088831115613fa0575f5ffd5b6020840193505b82841015613fcb578335613fba81613e01565b825260209384019390910190613fa7565b955050505060208401356001600160401b03811115613fe8575f5ffd5b613ff486828701613ed0565b92505061400360408501613e15565b90509250925092565b5f5f5f6040848603121561401e575f5ffd5b83356001600160401b03811115614033575f5ffd5b61403f86828701613a0c565b93505060208401356001600160401b0381111561405a575f5ffd5b61406686828701613a96565b9497909650939450505050565b5f60208284031215614083575f5ffd5b815161234581613d68565b5f5f8335601e198436030181126140a3575f5ffd5b8301803591506001600160401b038211156140bc575f5ffd5b6020019150600581901b3603821315613ad6575f5ffd5b5f5f8335601e198436030181126140e8575f5ffd5b8301803591506001600160401b03821115614101575f5ffd5b602001915036819003821315613ad6575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176110d1576110d1614115565b818103818111156110d1576110d1614115565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e1983360301811261417b575f5ffd5b9190910192915050565b8284823760c09190911b6001600160c01b0319169101908152600801919050565b5f81518060208401855e5f93019283525090919050565b5f61234582846141a6565b5f602082840312156141d8575f5ffd5b813564ffffffffff81168114612345575f5ffd5b808201808211156110d1576110d1614115565b838582375f8482015f8152838582375f93019283525090949350505050565b5f6020828403121561422e575f5ffd5b5051919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b608081525f61427060808301888a614235565b82810360208401526142828188613c0d565b90508281036040840152614297818688614235565b915050826060830152979650505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f826142cd576142cd6142ab565b500490565b6001600160401b0382811682821603908111156110d1576110d1614115565b5f8235605e1983360301811261417b575f5ffd5b5f62ffffff82168061431957614319614115565b5f190192915050565b6001600160401b0381811683821601908111156110d1576110d1614115565b600781810b9083900b01677fffffffffffffff8113677fffffffffffffff19821217156110d1576110d1614115565b5f60208284031215614380575f5ffd5b8151612345816139f5565b80516020808301519190811015613a1c575f1960209190910360031b1b16919050565b5f6143b982856141a6565b6001600160801b03199390931683525050601001919050565b5f600182016143e3576143e3614115565b5060010190565b6001600160f81b03199390931683526001600160a81b031991909116600183015260601b6bffffffffffffffffffffffff1916600c82015260200190565b600782810b9082900b03677fffffffffffffff198112677fffffffffffffff821317156110d1576110d1614115565b5f8161446557614465614115565b505f190190565b5f8160070b677fffffffffffffff19810361448957614489614115565b5f0392915050565b8082025f8212600160ff1b841416156144ac576144ac614115565b81810583148215176110d1576110d1614115565b5f64ffffffffff8316806144d6576144d66142ab565b8064ffffffffff84160491505092915050565b5f826144f7576144f76142ab565b500690565b5f64ffffffffff831680614512576145126142ab565b8064ffffffffff84160691505092915050565b64ffffffffff8181168382160290811690818114613d6157613d6161411556fea2646970667358221220df25bf74091fccc75b585648f8457afd9f5b9a6239c2833d5cd58126b8bc989d64736f6c634300081b003300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000005312e362e31000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101bd575f3560e01c80636691954e116100f2578063b522538a11610092578063d06d558711610062578063d06d55871461063f578063dda3346c1461065e578063ee94d67c1461067d578063f074ba621461069c575f5ffd5b8063b522538a146105ce578063c44e30dc146105ed578063c490744214610601578063c4d66de814610620575f5ffd5b80637439841f116100cd5780637439841f1461053457806374cdd7981461056957806388676cad1461059c5780639b4e4634146105bb575f5ffd5b80636691954e146104d65780636c0d2d5a146104e95780636fcd0e5314610508575f5ffd5b806342ecff2a1161015d57806352396a591161013857806352396a591461043657806354fd4d501461046a578063587533571461048b57806358eaee79146104aa575f5ffd5b806342ecff2a146102f25780634665bcda1461031857806347d283721461034b575f5ffd5b80632340e8d3116101985780632340e8d31461027a5780633474aa161461028f5780633f5fa57a146102c05780633f65cf19146102d3575f5ffd5b8063039157d2146101fb5780630b18ff661461021c5780631e51553314610258575f5ffd5b366101f7576040513481527f6fdd3dbdb173299608c0aa9f368735857c8842b581f8389238bf05bd04b3bf499060200160405180910390a1005b5f5ffd5b348015610206575f5ffd5b5061021a610215366004613a22565b6106bb565b005b348015610227575f5ffd5b5060335461023b906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610263575f5ffd5b5061026c6109f0565b60405190815260200161024f565b348015610285575f5ffd5b5061026c60395481565b34801561029a575f5ffd5b506034546001600160401b03165b6040516001600160401b03909116815260200161024f565b61021a6102ce366004613add565b610a11565b3480156102de575f5ffd5b5061021a6102ed366004613b1b565b610d92565b3480156102fd575f5ffd5b50603a546102a890600160401b90046001600160401b031681565b348015610323575f5ffd5b5061023b7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33881565b348015610356575f5ffd5b506103db6040805160a0810182525f80825260208201819052918101829052606081018290526080810191909152506040805160a081018252603c548152603d5462ffffff811660208301526001600160401b0363010000008204811693830193909352600160581b810460070b6060830152600160981b9004909116608082015290565b60405161024f91905f60a0820190508251825262ffffff60208401511660208301526001600160401b036040840151166040830152606083015160070b60608301526001600160401b03608084015116608083015292915050565b348015610441575f5ffd5b506102a8610450366004613bf2565b603b6020525f90815260409020546001600160401b031681565b348015610475575f5ffd5b5061047e61104a565b60405161024f9190613c3b565b348015610496575f5ffd5b50603e5461023b906001600160a01b031681565b3480156104b5575f5ffd5b506104c96104c4366004613c8a565b611075565b60405161024f9190613cf0565b61021a6104e4366004613add565b6110d7565b3480156104f4575f5ffd5b5061026c610503366004613bf2565b6113df565b348015610513575f5ffd5b50610527610522366004613cfe565b6114ed565b60405161024f9190613d15565b34801561053f575f5ffd5b506104c961054e366004613cfe565b5f90815260366020526040902054600160c01b900460ff1690565b348015610574575f5ffd5b5061023b7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa81565b3480156105a7575f5ffd5b5061021a6105b6366004613d75565b611598565b61021a6105c9366004613d90565b61168d565b3480156105d9575f5ffd5b506105276105e8366004613c8a565b61180b565b3480156105f8575f5ffd5b5061026c6118fa565b34801561060c575f5ffd5b5061021a61061b366004613e25565b611916565b34801561062b575f5ffd5b5061021a61063a366004613e4f565b611a4d565b34801561064a575f5ffd5b5061021a610659366004613e4f565b611b97565b348015610669575f5ffd5b5061021a610678366004613f3a565b611c2b565b348015610688575f5ffd5b50603a546102a8906001600160401b031681565b3480156106a7575f5ffd5b5061021a6106b636600461400c565b611d8a565b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015610721573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107459190614073565b156107635760405163840a48d560e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600860048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa1580156107c9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ed9190614073565b1561080b5760405163840a48d560e01b815260040160405180910390fd5b5f61084f610819858061408e565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061218692505050565b5f818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff1660028111156108bd576108bd613cbc565b60028111156108ce576108ce613cbc565b81525050905080604001516001600160401b0316876001600160401b03161161090a576040516337e07ffd60e01b815260040160405180910390fd5b60018160600151600281111561092257610922613cbc565b146109405760405163d49e19a760e01b815260040160405180910390fd5b61098361094d868061408e565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506121a892505050565b6109a05760405163161ce5ed60e31b815260040160405180910390fd5b6109b26109ac886113df565b876121d0565b6109de6109be88612275565b87356109ca888061408e565b6109d760208b018b6140d3565b875161234c565b6109e75f612480565b50505050505050565b5f610a0c71bbddc7ce488642fb579f8b00f3a590007251612600565b905090565b604051635ac86ab760e01b8152600a60048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015610a77573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a9b9190614073565b15610ab95760405163840a48d560e01b815260040160405180910390fd5b6033546001600160a01b0316331480610adc5750603e546001600160a01b031633145b610af95760405163427a777960e01b815260040160405180910390fd5b5f610b026118fa565b90505f610b0f8483614129565b905080341015610b325760405163356680b760e01b815260040160405180910390fd5b5f610b3d8234614140565b90505f5b85811015610d795736878783818110610b5c57610b5c614153565b9050602002810190610b6e9190614167565b90505f610bb7610b7e83806140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b905060015f82815260366020526040902054600160c01b900460ff166002811115610be457610be4613cbc565b14610c025760405163d49e19a760e01b815260040160405180910390fd5b5f610c0d83806140d3565b610c1d6040860160208701613bf2565b604051602001610c2f93929190614185565b60405160208183030381529060405290505f710961ef480eb55e80d19ad83579a64c0070026001600160a01b03168883604051610c6c91906141bd565b5f6040518083038185875af1925050503d805f8114610ca6576040519150601f19603f3d011682016040523d82523d5f602084013e610cab565b606091505b5050905080610ccd5760405163fc52d48360e01b815260040160405180910390fd5b610cdd6040850160208601613bf2565b6001600160401b03165f03610d1b5760405183907f60d8ca014d4765a2b8b389e25714cb1cef83b574222911a01d90c1bd69d2d320905f90a2610d69565b827f8b2737bb64ab2f2dc09552dfa1c250399e6a42c7ea9f0e1c658f5d65d708ec05610d4d6040870160208801613bf2565b6040516001600160401b03909116815260200160405180910390a25b505060019092019150610b419050565b508015610d8a57610d8a3382612717565b505050505050565b6033546001600160a01b0316331480610db55750603e546001600160a01b031633145b610dd25760405163427a777960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600260048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015610e38573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e5c9190614073565b15610e7a5760405163840a48d560e01b815260040160405180910390fd5b8584148015610e8857508382145b610ea5576040516343714afd60e01b815260040160405180910390fd5b603a546001600160401b03600160401b9091048116908a1611610edb576040516337e07ffd60e01b815260040160405180910390fd5b603a546001600160401b03908116908a1611610f0a576040516335e7f6b760e01b815260040160405180910390fd5b610f1c610f168a6113df565b896121d0565b5f805b87811015610fb557610fa18b8b358b8b85818110610f3f57610f3f614153565b9050602002016020810190610f5491906141c8565b8a8a86818110610f6657610f66614153565b9050602002810190610f7891906140d3565b8a8a88818110610f8a57610f8a614153565b9050602002810190610f9c919061408e565b61282c565b610fab90836141ec565b9150600101610f1f565b5060335460405163a1ca780b60e01b81526001600160a01b0391821660048201525f6024820152604481018390527f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3389091169063a1ca780b906064015f604051808303815f87803b158015611028575f5ffd5b505af115801561103a573d5f5f3e3d5ffd5b5050505050505050505050505050565b6060610a0c7f312e362e31000000000000000000000000000000000000000000000000000005612d2d565b5f5f6110b584848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b5f90815260366020526040902054600160c01b900460ff169150505b92915050565b604051635ac86ab760e01b8152600960048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa15801561113d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111619190614073565b1561117f5760405163840a48d560e01b815260040160405180910390fd5b6033546001600160a01b03163314806111a25750603e546001600160a01b031633145b6111bf5760405163427a777960e01b815260040160405180910390fd5b5f6111c86109f0565b90505f6111d58483614129565b9050803410156111f85760405163356680b760e01b815260040160405180910390fd5b5f6112038234614140565b90505f5b85811015610d79573687878381811061122257611222614153565b90506020028101906112349190614167565b90505f611244610b7e83806140d3565b90505f611257610b7e60208501856140d3565b905060015f82815260366020526040902054600160c01b900460ff16600281111561128457611284613cbc565b146112a25760405163d49e19a760e01b815260040160405180910390fd5b5f6112ad84806140d3565b6112ba60208701876140d3565b6040516020016112cd94939291906141ff565b60405160208183030381529060405290505f71bbddc7ce488642fb579f8b00f3a5900072516001600160a01b0316898360405161130a91906141bd565b5f6040518083038185875af1925050503d805f8114611344576040519150601f19603f3d011682016040523d82523d5f602084013e611349565b606091505b505090508061136b5760405163fc52d48360e01b815260040160405180910390fd5b8284036113a15760405184907fc97b965b92ae7fd20095fe8eb7b99f81f95f8c4adffb22a19116d8eb2846b016905f90a26113ce565b604051839085907f42f9c9db2ca443e9ec62f4588bd0c9b241065c02c2a8001ac164ae1282dc7b94905f90a35b505060019093019250611207915050565b5f6113ed611fff600c614129565b6114006001600160401b03841642614140565b1061141e57604051637944e66d60e11b815260040160405180910390fd5b604080516001600160401b03841660208201525f918291720f3df6d732807ef1319fb7b8bb8522d0beac02910160408051601f1981840301815290829052611465916141bd565b5f60405180830381855afa9150503d805f811461149d576040519150601f19603f3d011682016040523d82523d5f602084013e6114a2565b606091505b50915091508180156114b457505f8151115b6114d15760405163558ad0a360e01b815260040160405180910390fd5b808060200190518101906114e5919061421e565b949350505050565b611514604080516080810182525f8082526020820181905291810182905290606082015290565b5f82815260366020908152604091829020825160808101845281546001600160401b038082168352600160401b8204811694830194909452600160801b810490931693810193909352906060830190600160c01b900460ff16600281111561157e5761157e613cbc565b600281111561158f5761158f613cbc565b90525092915050565b6033546001600160a01b03163314806115bb5750603e546001600160a01b031633145b6115d85760405163427a777960e01b815260040160405180910390fd5b604051635ac86ab760e01b8152600660048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa15801561163e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116629190614073565b156116805760405163840a48d560e01b815260040160405180910390fd5b61168982612480565b5050565b336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33816146116d657604051633213a66160e21b815260040160405180910390fd5b346801bc16d674ec800000146116ff5760405163049696b360e31b815260040160405180910390fd5b7f00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa6001600160a01b031663228951186801bc16d674ec8000008787611742612d6a565b8888886040518863ffffffff1660e01b81526004016117669695949392919061425d565b5f604051808303818588803b15801561177d575f5ffd5b505af115801561178f573d5f5f3e3d5ffd5b50505050507fa01003766d3cd97cf2ade5429690bf5d206be7fb01ef9d3a0089ecf67bc112196117f386868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b60405190815260200160405180910390a15050505050565b611832604080516080810182525f8082526020820181905291810182905290606082015290565b60365f61187385858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061268692505050565b815260208082019290925260409081015f20815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b81049094169281019290925290916060830190600160c01b900460ff1660028111156118df576118df613cbc565b60028111156118f0576118f0613cbc565b9052509392505050565b5f610a0c710961ef480eb55e80d19ad83579a64c007002612600565b336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338161461195f57604051633213a66160e21b815260040160405180910390fd5b5f61196e633b9aca00836142bf565b9050611987633b9aca006001600160401b038316614129565b6034549092506001600160401b0390811690821611156119ba576040516302c6f54760e21b815260040160405180910390fd5b603480548291905f906119d79084906001600160401b03166142d2565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550826001600160a01b03167f8947fd2ce07ef9cc302c4e8f0461015615d91ce851564839e91cc804c2f49d8e83604051611a3691815260200190565b60405180910390a2611a488383612717565b505050565b5f54610100900460ff1615808015611a6b57505f54600160ff909116105b80611a845750303b158015611a8457505f5460ff166001145b611aec5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015611b0d575f805461ff0019166101001790555b6001600160a01b038216611b34576040516339b190bb60e11b815260040160405180910390fd5b603380546001600160a01b0319166001600160a01b0384161790558015611689575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6033546001600160a01b03163314611bc25760405163719f370360e11b815260040160405180910390fd5b603e54604080516001600160a01b03928316815291831660208301527ffb8129080a19d34dceac04ba253fc50304dc86c729bd63cdca4a969ad19a5eac910160405180910390a1603e80546001600160a01b0319166001600160a01b0392909216919091179055565b6033546001600160a01b03163314611c565760405163719f370360e11b815260040160405180910390fd5b604051635ac86ab760e01b8152600560048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015611cbc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ce09190614073565b15611cfe5760405163840a48d560e01b815260040160405180910390fd5b8251845114611d20576040516343714afd60e01b815260040160405180910390fd5b5f5b8451811015611d8357611d7b83858381518110611d4157611d41614153565b6020026020010151878481518110611d5b57611d5b614153565b60200260200101516001600160a01b0316612d9a9092919063ffffffff16565b600101611d22565b5050505050565b604051635ac86ab760e01b8152600760048201819052907f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b031690635ac86ab790602401602060405180830381865afa158015611df0573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e149190614073565b15611e325760405163840a48d560e01b815260040160405180910390fd5b603a54600160401b90046001600160401b03165f819003611e6657604051631a544f4960e01b815260040160405180910390fd5b6040805160a081018252603c548152603d5462ffffff811660208301526001600160401b0363010000008204811693830193909352600160581b810460070b6060830152600160981b90049091166080820152611ecd611ec583612275565b825188612dec565b5f805b8581101561212d5736878783818110611eeb57611eeb614153565b9050602002810190611efd91906142f1565b80355f908152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff166002811115611f6d57611f6d613cbc565b6002811115611f7e57611f7e613cbc565b9052509050600181606001516002811115611f9b57611f9b613cbc565b14611fa7575050612125565b856001600160401b031681604001516001600160401b031610611fcb575050612125565b5f8080611fdb848a8f3588612ead565b60208b0180519396509194509250611ff282614305565b62ffffff1690525060808801805184919061200e908390614322565b6001600160401b031690525060608801805183919061202e908390614341565b60070b90525061203e8188614322565b85355f908152603660209081526040918290208751815492890151938901516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b0319909516919092161792909217928316821781556060880151939a50879390929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b8360028111156120e2576120e2613cbc565b021790555050604051863591506001600160401b038b16907fe4866335761a51dcaff766448ab0af6064291ee5dc94e68492bb9cd757c1e350905f90a350505050505b600101611ed0565b506001600160401b038084165f908152603b602052604081208054849391929161215991859116614322565b92506101000a8154816001600160401b0302191690836001600160401b031602179055506109e782612fc3565b5f815f8151811061219957612199614153565b60200260200101519050919050565b5f816003815181106121bc576121bc614153565b60200260200101515f5f1b14159050919050565b6121dc60036020614129565b6121e960208301836140d3565b905014612209576040516313717da960e21b815260040160405180910390fd5b61225861221960208301836140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250869250508435905060036131e3565b611689576040516309bde33960e01b815260040160405180910390fd5b5f5f7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3386001600160a01b0316632704351a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122d3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122f79190614370565b9050806001600160401b03165f03612322576040516341a02cc960e01b815260040160405180910390fd5b806001600160401b0316836001600160401b03161115612343576001612345565b5f5b9392505050565b6008841461236d5760405163200591bd60e01b815260040160405180910390fd5b5f612377886131fa565b905080612386602860016141ec565b61239091906141ec565b61239b906020614129565b83146123ba576040516313717da960e21b815260040160405180910390fd5b5f6123f68787808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061322292505050565b90505f64ffffffffff841661240d602860016141ec565b600b901b17905061245786868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508d92508691508590506131e3565b612474576040516309bde33960e01b815260040160405180910390fd5b50505050505050505050565b603a54600160401b90046001600160401b0316156124b05760405162be9bc360e81b815260040160405180910390fd5b603a546001600160401b034281169116036124de576040516367db5b8b60e01b815260040160405180910390fd5b6034545f906001600160401b03166124fa633b9aca00476142bf565b61250491906142d2565b905081801561251a57506001600160401b038116155b15612538576040516332dea95960e21b815260040160405180910390fd5b5f6040518060a0016040528061254d426113df565b815260395462ffffff1660208201526001600160401b0380851660408301525f60608301819052608090920191909152603a805442909216600160401b026fffffffffffffffff00000000000000001990921691909117905590506125b181612fc3565b805160208083015160405162ffffff90911681526001600160401b034216917f575796133bbed337e5b39aa49a30dc2556a91e0c6c2af4b7b886ae77ebef1076910160405180910390a3505050565b5f5f5f836001600160a01b03166040515f60405180830381855afa9150503d805f8114612648576040519150601f19603f3d011682016040523d82523d5f602084013e61264d565b606091505b5091509150818015612660575080516020145b61267d5760405163c90158af60e01b815260040160405180910390fd5b6114e58161438b565b5f81516030146126a957604051634f88323960e11b815260040160405180910390fd5b6040516002906126bf9084905f906020016143ae565b60408051601f19818403018152908290526126d9916141bd565b602060405180830381855afa1580156126f4573d5f5f3e3d5ffd5b5050506040513d601f19601f820116820180604052508101906110d1919061421e565b804710156127675760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401611ae3565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146127b0576040519150601f19603f3d011682016040523d82523d5f602084013e6127b5565b606091505b5050905080611a485760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401611ae3565b5f5f6128698484808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061218692505050565b5f818152603660209081526040808320815160808101835281546001600160401b038082168352600160401b8204811695830195909552600160801b8104909416928101929092529394509192906060830190600160c01b900460ff1660028111156128d7576128d7613cbc565b60028111156128e8576128e8613cbc565b90525090505f8160600151600281111561290457612904613cbc565b14612922576040516335e09e9d60e01b815260040160405180910390fd5b6001600160401b0380166129678686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134b292505050565b6001600160401b03160361298e57604051631958236d60e21b815260040160405180910390fd5b6001600160401b0380166129d38686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134d692505050565b6001600160401b0316146129fa57604051632eade63760e01b815260040160405180910390fd5b612a02612d6a565b612a0b9061438b565b612a468686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134ed92505050565b1480612a9b5750612a55613501565b612a5e9061438b565b612a998686808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152506134ed92505050565b145b612ab857604051633772dd5360e11b815260040160405180910390fd5b5f612af48686808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061351d92505050565b9050612b0d612b028c612275565b8b88888c8c8f61234c565b60398054905f612b1c836143d2565b9091555050603a545f90600160401b90046001600160401b031615612b5357603a54600160401b90046001600160401b0316612b60565b603a546001600160401b03165b6040805160808101825264ffffffffff8d1681526001600160401b03858116602083015283169181019190915290915060608101600190525f858152603660209081526040918290208351815492850151938501516001600160401b03908116600160801b0267ffffffffffffffff60801b19958216600160401b026001600160801b031990951691909216179290921792831682178155606084015190929091839160ff60c01b1990911668ffffffffffffffffff60801b1990911617600160c01b836002811115612c3557612c35613cbc565b021790555050603d8054849250601390612c60908490600160981b90046001600160401b0316614322565b92506101000a8154816001600160401b0302191690836001600160401b031602179055507f101790c2993f6a4d962bd17c786126823ba1c4cf04ff4cccb2659d50fb20aee884604051612cb591815260200190565b60405180910390a1604080518581526001600160401b03838116602083015284168183015290517fcdae700d7241bc027168c53cf6f889763b0a2c88a65d77fc13a8a9fef0d8605f9181900360600190a1612d1d633b9aca006001600160401b038416614129565b9c9b505050505050505050505050565b60605f612d3983613534565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b604051606090612d8690600160f81b905f9030906020016143ea565b604051602081830303815290604052905090565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a4890849061355b565b5f612df6846131fa565b9050612e038160036141ec565b612e0e906020614129565b612e1b60208401846140d3565b905014612e3b576040516313717da960e21b815260040160405180910390fd5b6003811b600c17612e90612e5260208501856140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892505086359050846131e3565b611d83576040516309bde33960e01b815260040160405180910390fd5b5f5f5f866020015192505f612ec686895f01518761362e565b9050836001600160401b0316816001600160401b031614612f3a57612eeb8482614428565b60408051873581526001600160401b038a8116602083015284168183015290519194507fcdae700d7241bc027168c53cf6f889763b0a2c88a65d77fc13a8a9fef0d8605f919081900360600190a15b6001600160401b0380821660208a0181905290881660408a01525f03612fb85760398054905f612f6983614457565b909155505060026060890152612f7e8361446c565b6040519092508535906001600160401b038916907f5ce0aa04ae51d52da6e680fbe0336d2e2432f7c3dc2d4f3193204c57b9072107905f90a35b509450945094915050565b8051603c556020810151603d805460408401516060850151608086015162ffffff9095166affffffffffffffffffffff19909316831763010000006001600160401b0393841602176fffffffffffffffffffffffffffffffff60581b1916600160581b9183169190910267ffffffffffffffff60981b191617600160981b9190941602929092179055156130545750565b60808101516034545f91613070916001600160401b0316614322565b90505f826060015183604001516130879190614341565b60408401516034805492935090915f906130ab9084906001600160401b0316614322565b82546101009290920a6001600160401b03818102199093169183160217909155603a8054600160401b810483166001600160801b03199091161790555f91506130fb90633b9aca00908516614129565b90505f613110633b9aca00600785900b614491565b603a546040518281529192506001600160401b0316907f525408c201bc1576eb44116f6478f1c2a54775b19a043bcfdc708364f74f8e449060200160405180910390a260335460405163a1ca780b60e01b81526001600160a01b03918216600482015260248101849052604481018390527f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3389091169063a1ca780b906064015f604051808303815f87803b1580156131c6575f5ffd5b505af11580156131d8573d5f5f3e3d5ffd5b505050505050505050565b5f836131f086858561370c565b1495945050505050565b5f8082600181111561320e5761320e613cbc565b1461321a5760066110d1565b600592915050565b5f5f6002835161323291906142bf565b90505f816001600160401b0381111561324d5761324d613e6a565b604051908082528060200260200182016040528015613276578160200160208202803683370190505b5090505f5b82811015613370576002856132908383614129565b815181106132a0576132a0614153565b6020026020010151868360026132b69190614129565b6132c19060016141ec565b815181106132d1576132d1614153565b60200260200101516040516020016132f3929190918252602082015260400190565b60408051601f198184030181529082905261330d916141bd565b602060405180830381855afa158015613328573d5f5f3e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061334b919061421e565b82828151811061335d5761335d614153565b602090810291909101015260010161327b565b5061337c6002836142bf565b91505b811561348f575f5b8281101561347c5760028261339c8383614129565b815181106133ac576133ac614153565b6020026020010151838360026133c29190614129565b6133cd9060016141ec565b815181106133dd576133dd614153565b60200260200101516040516020016133ff929190918252602082015260400190565b60408051601f1981840301815290829052613419916141bd565b602060405180830381855afa158015613434573d5f5f3e3d5ffd5b5050506040513d601f19601f82011682018060405250810190613457919061421e565b82828151811061346957613469614153565b6020908102919091010152600101613387565b506134886002836142bf565b915061337f565b805f815181106134a1576134a1614153565b602002602001015192505050919050565b5f6110d1826005815181106134c9576134c9614153565b60200260200101516137e0565b5f6110d1826006815181106134c9576134c9614153565b5f8160018151811061219957612199614153565b604051606090612d8690600160f91b905f9030906020016143ea565b5f6110d1826002815181106134c9576134c9614153565b5f60ff8216601f8111156110d157604051632cd44ac360e21b815260040160405180910390fd5b5f6135af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138479092919063ffffffff16565b905080515f14806135cf5750808060200190518101906135cf9190614073565b611a485760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611ae3565b5f61363b602660016141ec565b613646906020614129565b61365360408401846140d3565b905014613673576040516313717da960e21b815260040160405180910390fd5b5f61367f6004856144c0565b64ffffffffff1690506136d861369860408501856140d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525089925050506020860135846131e3565b6136f5576040516309bde33960e01b815260040160405180910390fd5b613703836020013585613855565b95945050505050565b5f83515f1415801561372957506020845161372791906144e9565b155b613746576040516313717da960e21b815260040160405180910390fd5b604080516020808201909252848152905b855181116137d65761376a6002856144e9565b5f0361379c5781515f528086015160205260208260405f60026107d05a03fa613791575f5ffd5b6002840493506137c4565b808601515f52815160205260208260405f60026107d05a03fa6137bd575f5ffd5b6002840493505b6137cf6020826141ec565b9050613757565b5051949350505050565b60f881901c60e882901c61ff00161760d882901c62ff0000161760c882901c63ff000000161764ff0000000060b883901c161765ff000000000060a883901c161766ff000000000000609883901c161767ff0000000000000060889290921c919091161790565b60606114e584845f85613881565b5f806138626004846144fc565b61386d906040614525565b64ffffffffff1690506114e584821b6137e0565b6060824710156138e25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611ae3565b5f5f866001600160a01b031685876040516138fd91906141bd565b5f6040518083038185875af1925050503d805f8114613937576040519150601f19603f3d011682016040523d82523d5f602084013e61393c565b606091505b509150915061394d87838387613958565b979650505050505050565b606083156139c65782515f036139bf576001600160a01b0385163b6139bf5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ae3565b50816114e5565b6114e583838151156139db5781518083602001fd5b8060405162461bcd60e51b8152600401611ae39190613c3b565b6001600160401b0381168114613a09575f5ffd5b50565b5f60408284031215613a1c575f5ffd5b50919050565b5f5f5f60608486031215613a34575f5ffd5b8335613a3f816139f5565b925060208401356001600160401b03811115613a59575f5ffd5b613a6586828701613a0c565b92505060408401356001600160401b03811115613a80575f5ffd5b613a8c86828701613a0c565b9150509250925092565b5f5f83601f840112613aa6575f5ffd5b5081356001600160401b03811115613abc575f5ffd5b6020830191508360208260051b8501011115613ad6575f5ffd5b9250929050565b5f5f60208385031215613aee575f5ffd5b82356001600160401b03811115613b03575f5ffd5b613b0f85828601613a96565b90969095509350505050565b5f5f5f5f5f5f5f5f60a0898b031215613b32575f5ffd5b8835613b3d816139f5565b975060208901356001600160401b03811115613b57575f5ffd5b613b638b828c01613a0c565b97505060408901356001600160401b03811115613b7e575f5ffd5b613b8a8b828c01613a96565b90975095505060608901356001600160401b03811115613ba8575f5ffd5b613bb48b828c01613a96565b90955093505060808901356001600160401b03811115613bd2575f5ffd5b613bde8b828c01613a96565b999c989b5096995094979396929594505050565b5f60208284031215613c02575f5ffd5b8135612345816139f5565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6123456020830184613c0d565b5f5f83601f840112613c5d575f5ffd5b5081356001600160401b03811115613c73575f5ffd5b602083019150836020828501011115613ad6575f5ffd5b5f5f60208385031215613c9b575f5ffd5b82356001600160401b03811115613cb0575f5ffd5b613b0f85828601613c4d565b634e487b7160e01b5f52602160045260245ffd5b60038110613cec57634e487b7160e01b5f52602160045260245ffd5b9052565b602081016110d18284613cd0565b5f60208284031215613d0e575f5ffd5b5035919050565b5f6080820190506001600160401b0383511682526001600160401b0360208401511660208301526001600160401b0360408401511660408301526060830151613d616060840182613cd0565b5092915050565b8015158114613a09575f5ffd5b5f60208284031215613d85575f5ffd5b813561234581613d68565b5f5f5f5f5f60608688031215613da4575f5ffd5b85356001600160401b03811115613db9575f5ffd5b613dc588828901613c4d565b90965094505060208601356001600160401b03811115613de3575f5ffd5b613def88828901613c4d565b96999598509660400135949350505050565b6001600160a01b0381168114613a09575f5ffd5b8035613e2081613e01565b919050565b5f5f60408385031215613e36575f5ffd5b8235613e4181613e01565b946020939093013593505050565b5f60208284031215613e5f575f5ffd5b813561234581613e01565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715613ea657613ea6613e6a565b604052919050565b5f6001600160401b03821115613ec657613ec6613e6a565b5060051b60200190565b5f82601f830112613edf575f5ffd5b8135613ef2613eed82613eae565b613e7e565b8082825260208201915060208360051b860101925085831115613f13575f5ffd5b602085015b83811015613f30578035835260209283019201613f18565b5095945050505050565b5f5f5f60608486031215613f4c575f5ffd5b83356001600160401b03811115613f61575f5ffd5b8401601f81018613613f71575f5ffd5b8035613f7f613eed82613eae565b8082825260208201915060208360051b850101925088831115613fa0575f5ffd5b6020840193505b82841015613fcb578335613fba81613e01565b825260209384019390910190613fa7565b955050505060208401356001600160401b03811115613fe8575f5ffd5b613ff486828701613ed0565b92505061400360408501613e15565b90509250925092565b5f5f5f6040848603121561401e575f5ffd5b83356001600160401b03811115614033575f5ffd5b61403f86828701613a0c565b93505060208401356001600160401b0381111561405a575f5ffd5b61406686828701613a96565b9497909650939450505050565b5f60208284031215614083575f5ffd5b815161234581613d68565b5f5f8335601e198436030181126140a3575f5ffd5b8301803591506001600160401b038211156140bc575f5ffd5b6020019150600581901b3603821315613ad6575f5ffd5b5f5f8335601e198436030181126140e8575f5ffd5b8301803591506001600160401b03821115614101575f5ffd5b602001915036819003821315613ad6575f5ffd5b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176110d1576110d1614115565b818103818111156110d1576110d1614115565b634e487b7160e01b5f52603260045260245ffd5b5f8235603e1983360301811261417b575f5ffd5b9190910192915050565b8284823760c09190911b6001600160c01b0319169101908152600801919050565b5f81518060208401855e5f93019283525090919050565b5f61234582846141a6565b5f602082840312156141d8575f5ffd5b813564ffffffffff81168114612345575f5ffd5b808201808211156110d1576110d1614115565b838582375f8482015f8152838582375f93019283525090949350505050565b5f6020828403121561422e575f5ffd5b5051919050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b608081525f61427060808301888a614235565b82810360208401526142828188613c0d565b90508281036040840152614297818688614235565b915050826060830152979650505050505050565b634e487b7160e01b5f52601260045260245ffd5b5f826142cd576142cd6142ab565b500490565b6001600160401b0382811682821603908111156110d1576110d1614115565b5f8235605e1983360301811261417b575f5ffd5b5f62ffffff82168061431957614319614115565b5f190192915050565b6001600160401b0381811683821601908111156110d1576110d1614115565b600781810b9083900b01677fffffffffffffff8113677fffffffffffffff19821217156110d1576110d1614115565b5f60208284031215614380575f5ffd5b8151612345816139f5565b80516020808301519190811015613a1c575f1960209190910360031b1b16919050565b5f6143b982856141a6565b6001600160801b03199390931683525050601001919050565b5f600182016143e3576143e3614115565b5060010190565b6001600160f81b03199390931683526001600160a81b031991909116600183015260601b6bffffffffffffffffffffffff1916600c82015260200190565b600782810b9082900b03677fffffffffffffff198112677fffffffffffffff821317156110d1576110d1614115565b5f8161446557614465614115565b505f190190565b5f8160070b677fffffffffffffff19810361448957614489614115565b5f0392915050565b8082025f8212600160ff1b841416156144ac576144ac614115565b81810583148215176110d1576110d1614115565b5f64ffffffffff8316806144d6576144d66142ab565b8064ffffffffff84160491505092915050565b5f826144f7576144f76142ab565b500690565b5f64ffffffffff831680614512576145126142ab565b8064ffffffffff84160691505092915050565b64ffffffffff8181168382160290811690818114613d6157613d6161411556fea2646970667358221220df25bf74091fccc75b585648f8457afd9f5b9a6239c2833d5cd58126b8bc989d64736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000005312e362e31000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _ethPOS (address): 0x00000000219ab540356cBB839Cbe05303d7705Fa
Arg [1] : _eigenPodManager (address): 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338
Arg [2] : _version (string): 1.6.1
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000219ab540356cbb839cbe05303d7705fa
Arg [1] : 00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [4] : 312e362e31000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.