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
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
DelegationManager
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun 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/access/OwnableUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/security/ReentrancyGuardUpgradeable.sol";
import "../mixins/SignatureUtilsMixin.sol";
import "../mixins/PermissionControllerMixin.sol";
import "../permissions/Pausable.sol";
import "../libraries/SlashingLib.sol";
import "../libraries/Snapshots.sol";
import "./DelegationManagerStorage.sol";
/**
* @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)
*/
contract DelegationManager is
Initializable,
OwnableUpgradeable,
Pausable,
DelegationManagerStorage,
ReentrancyGuardUpgradeable,
PermissionControllerMixin,
SignatureUtilsMixin
{
using SlashingLib for *;
using Snapshots for Snapshots.DefaultZeroHistory;
using EnumerableSet for EnumerableSet.Bytes32Set;
// @notice Simple permission for functions that are only callable by the StrategyManager contract OR by the EigenPodManagerContract
modifier onlyStrategyManagerOrEigenPodManager() {
require(
(msg.sender == address(strategyManager) || msg.sender == address(eigenPodManager)),
OnlyStrategyManagerOrEigenPodManager()
);
_;
}
modifier onlyEigenPodManager() {
require(msg.sender == address(eigenPodManager), OnlyEigenPodManager());
_;
}
modifier onlyAllocationManager() {
require(msg.sender == address(allocationManager), OnlyAllocationManager());
_;
}
/**
*
* INITIALIZING FUNCTIONS
*
*/
/**
* @dev Initializes the immutable addresses of the strategy manager, eigenpod manager, and allocation manager.
*/
constructor(
IStrategyManager _strategyManager,
IEigenPodManager _eigenPodManager,
IAllocationManager _allocationManager,
IPauserRegistry _pauserRegistry,
IPermissionController _permissionController,
uint32 _MIN_WITHDRAWAL_DELAY,
string memory _version
)
DelegationManagerStorage(_strategyManager, _eigenPodManager, _allocationManager, _MIN_WITHDRAWAL_DELAY)
Pausable(_pauserRegistry)
PermissionControllerMixin(_permissionController)
SignatureUtilsMixin(_version)
{
_disableInitializers();
}
function initialize(address initialOwner, uint256 initialPausedStatus) external initializer {
_setPausedStatus(initialPausedStatus);
_transferOwnership(initialOwner);
}
/**
*
* EXTERNAL FUNCTIONS
*
*/
/// @inheritdoc IDelegationManager
function registerAsOperator(
address initDelegationApprover,
uint32 allocationDelay,
string calldata metadataURI
) external nonReentrant {
require(!isDelegated(msg.sender), ActivelyDelegated());
allocationManager.setAllocationDelay(msg.sender, allocationDelay);
_setDelegationApprover(msg.sender, initDelegationApprover);
// delegate from the operator to themselves
_delegate(msg.sender, msg.sender);
emit OperatorRegistered(msg.sender, initDelegationApprover);
emit OperatorMetadataURIUpdated(msg.sender, metadataURI);
}
/// @inheritdoc IDelegationManager
function modifyOperatorDetails(
address operator,
address newDelegationApprover
) external checkCanCall(operator) nonReentrant {
require(isOperator(operator), OperatorNotRegistered());
_setDelegationApprover(operator, newDelegationApprover);
}
/// @inheritdoc IDelegationManager
function updateOperatorMetadataURI(address operator, string calldata metadataURI) external checkCanCall(operator) {
require(isOperator(operator), OperatorNotRegistered());
emit OperatorMetadataURIUpdated(operator, metadataURI);
}
/// @inheritdoc IDelegationManager
function delegateTo(
address operator,
SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) public nonReentrant {
require(!isDelegated(msg.sender), ActivelyDelegated());
require(isOperator(operator), OperatorNotRegistered());
// If the operator has a `delegationApprover`, check the provided signature
_checkApproverSignature({
staker: msg.sender,
operator: operator,
signature: approverSignatureAndExpiry,
salt: approverSalt
});
// Delegate msg.sender to the operator
_delegate(msg.sender, operator);
}
/// @inheritdoc IDelegationManager
function undelegate(
address staker
) public nonReentrant returns (bytes32[] memory withdrawalRoots) {
// Check that the `staker` can undelegate
require(isDelegated(staker), NotActivelyDelegated());
require(!isOperator(staker), OperatorsCannotUndelegate());
// If the action is not being initiated by the staker, validate that it is initiated
// by the operator or their delegationApprover.
if (msg.sender != staker) {
address operator = delegatedTo[staker];
require(_checkCanCall(operator) || msg.sender == delegationApprover(operator), CallerCannotUndelegate());
emit StakerForceUndelegated(staker, operator);
}
return _undelegate(staker);
}
/// @inheritdoc IDelegationManager
function redelegate(
address newOperator,
SignatureWithExpiry memory newOperatorApproverSig,
bytes32 approverSalt
) external returns (bytes32[] memory withdrawalRoots) {
withdrawalRoots = undelegate(msg.sender);
// delegateTo uses msg.sender as staker
delegateTo(newOperator, newOperatorApproverSig, approverSalt);
}
/// @inheritdoc IDelegationManager
function queueWithdrawals(
QueuedWithdrawalParams[] calldata params
) external onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) nonReentrant returns (bytes32[] memory) {
bytes32[] memory withdrawalRoots = new bytes32[](params.length);
address operator = delegatedTo[msg.sender];
for (uint256 i = 0; i < params.length; i++) {
require(params[i].strategies.length == params[i].depositShares.length, InputArrayLengthMismatch());
uint256[] memory slashingFactors = _getSlashingFactors(msg.sender, operator, params[i].strategies);
// Remove shares from staker's strategies and place strategies/shares in queue.
// If the staker is delegated to an operator, the operator's delegated shares are also reduced
// NOTE: This will fail if the staker doesn't have the shares implied by the input parameters.
// The view function getWithdrawableShares() can be used to check what shares are available for withdrawal.
withdrawalRoots[i] = _removeSharesAndQueueWithdrawal({
staker: msg.sender,
operator: operator,
strategies: params[i].strategies,
depositSharesToWithdraw: params[i].depositShares,
slashingFactors: slashingFactors
});
}
return withdrawalRoots;
}
/// @inheritdoc IDelegationManager
function completeQueuedWithdrawal(
Withdrawal calldata withdrawal,
IERC20[] calldata tokens,
bool receiveAsTokens
) external onlyWhenNotPaused(PAUSED_EXIT_WITHDRAWAL_QUEUE) nonReentrant {
_completeQueuedWithdrawal(withdrawal, tokens, receiveAsTokens);
}
/// @inheritdoc IDelegationManager
function completeQueuedWithdrawals(
Withdrawal[] calldata withdrawals,
IERC20[][] calldata tokens,
bool[] calldata receiveAsTokens
) external onlyWhenNotPaused(PAUSED_EXIT_WITHDRAWAL_QUEUE) nonReentrant {
uint256 n = withdrawals.length;
for (uint256 i; i < n; ++i) {
_completeQueuedWithdrawal(withdrawals[i], tokens[i], receiveAsTokens[i]);
}
}
/// @inheritdoc IDelegationManager
function increaseDelegatedShares(
address staker,
IStrategy strategy,
uint256 prevDepositShares,
uint256 addedShares
) external onlyStrategyManagerOrEigenPodManager nonReentrant {
/// Note: Unlike `decreaseDelegatedShares`, we don't return early if the staker has no operator.
/// This is because `_increaseDelegation` updates the staker's deposit scaling factor, which we
/// need to do even if not delegated.
address operator = delegatedTo[staker];
uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, strategy);
uint256 slashingFactor = _getSlashingFactor(staker, strategy, maxMagnitude);
// Increase the staker's deposit scaling factor and delegate shares to the operator
_increaseDelegation({
operator: operator,
staker: staker,
strategy: strategy,
prevDepositShares: prevDepositShares,
addedShares: addedShares,
slashingFactor: slashingFactor
});
}
/// @inheritdoc IDelegationManager
function decreaseDelegatedShares(
address staker,
uint256 curDepositShares,
uint64 beaconChainSlashingFactorDecrease
) external onlyEigenPodManager nonReentrant {
if (!isDelegated(staker)) {
return;
}
address operator = delegatedTo[staker];
// Calculate the shares to remove from the operator by calculating difference in shares
// from the newly updated beaconChainSlashingFactor
uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, beaconChainETHStrategy);
DepositScalingFactor memory dsf = _depositScalingFactor[staker][beaconChainETHStrategy];
uint256 sharesToRemove = dsf.calcWithdrawable({
depositShares: curDepositShares,
slashingFactor: maxMagnitude.mulWad(beaconChainSlashingFactorDecrease)
});
// Decrease the operator's shares
_decreaseDelegation({
operator: operator,
staker: staker,
strategy: beaconChainETHStrategy,
sharesToDecrease: sharesToRemove
});
}
/// @inheritdoc IDelegationManager
function slashOperatorShares(
address operator,
IStrategy strategy,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) external onlyAllocationManager nonReentrant {
/// forgefmt: disable-next-item
uint256 operatorSharesSlashed = SlashingLib.calcSlashedAmount({
operatorShares: operatorShares[operator][strategy],
prevMaxMagnitude: prevMaxMagnitude,
newMaxMagnitude: newMaxMagnitude
});
uint256 scaledSharesSlashedFromQueue = _getSlashableSharesInQueue({
operator: operator,
strategy: strategy,
prevMaxMagnitude: prevMaxMagnitude,
newMaxMagnitude: newMaxMagnitude
});
// Calculate the total deposit shares to burn - slashed operator shares plus still-slashable
// shares sitting in the withdrawal queue.
uint256 totalDepositSharesToBurn = operatorSharesSlashed + scaledSharesSlashedFromQueue;
// Remove shares from operator
_decreaseDelegation({
operator: operator,
staker: address(0), // we treat this as a decrease for the 0-staker (only used for events)
strategy: strategy,
sharesToDecrease: operatorSharesSlashed
});
// Emit event for operator shares being slashed
emit OperatorSharesSlashed(operator, strategy, totalDepositSharesToBurn);
IShareManager shareManager = _getShareManager(strategy);
// NOTE: for beaconChainETHStrategy, increased burnable shares currently have no mechanism for burning
shareManager.increaseBurnableShares(strategy, totalDepositSharesToBurn);
}
/**
*
* INTERNAL FUNCTIONS
*
*/
/**
* @notice Sets operator parameters in the `_operatorDetails` mapping.
* @param operator The account registered as an operator updating their operatorDetails
* @param newDelegationApprover The new parameters for the operator
*/
function _setDelegationApprover(address operator, address newDelegationApprover) internal {
_operatorDetails[operator].delegationApprover = newDelegationApprover;
emit DelegationApproverUpdated(operator, newDelegationApprover);
}
/**
* @notice Delegates *from* a `staker` *to* an `operator`.
* @param staker The address to delegate *from* -- this address is delegating control of its own assets.
* @param operator The address to delegate *to* -- this address is being given power to place the `staker`'s assets at risk on services
* @dev Assumes the following is checked before calling this function:
* 1) the `staker` is not already delegated to an operator
* 2) the `operator` has indeed registered as an operator in EigenLayer
* 3) if applicable, the `operator's` `delegationApprover` signed off on delegation
* Ensures that:
* 1) new delegations are not paused (PAUSED_NEW_DELEGATION)
*/
function _delegate(address staker, address operator) internal onlyWhenNotPaused(PAUSED_NEW_DELEGATION) {
// When a staker is not delegated to an operator, their deposit shares are equal to their
// withdrawable shares -- except for the beaconChainETH strategy, which is handled below
(IStrategy[] memory strategies, uint256[] memory withdrawableShares) = getDepositedShares(staker);
// Retrieve the amount of slashing experienced by the operator in each strategy so far.
// When delegating, we "forgive" the staker for this slashing by adjusting their
// deposit scaling factor.
uint256[] memory operatorSlashingFactors = _getSlashingFactors(address(0), operator, strategies);
// Delegate to the operator
delegatedTo[staker] = operator;
emit StakerDelegated(staker, operator);
for (uint256 i = 0; i < strategies.length; ++i) {
// Special case for beacon chain slashing - ensure the staker's beacon chain slashing is
// reflected in the number of shares they delegate.
if (strategies[i] == beaconChainETHStrategy) {
uint64 stakerBeaconChainSlashing = eigenPodManager.beaconChainSlashingFactor(staker);
DepositScalingFactor memory dsf = _depositScalingFactor[staker][strategies[i]];
withdrawableShares[i] = dsf.calcWithdrawable(withdrawableShares[i], stakerBeaconChainSlashing);
}
// forgefmt: disable-next-item
_increaseDelegation({
operator: operator,
staker: staker,
strategy: strategies[i],
prevDepositShares: uint256(0),
addedShares: withdrawableShares[i],
slashingFactor: operatorSlashingFactors[i]
});
}
}
/**
* @dev Undelegates `staker` from their operator, queueing a withdrawal for all
* their deposited shares in the process.
* @dev Assumes the following is checked before calling this function:
* 1) the `staker` is currently delegated to an operator
* 2) the `staker` is not an operator themselves
* Ensures that:
* 1) the withdrawal queue is not paused (PAUSED_ENTER_WITHDRAWAL_QUEUE)
*/
function _undelegate(
address staker
) internal onlyWhenNotPaused(PAUSED_ENTER_WITHDRAWAL_QUEUE) returns (bytes32[] memory withdrawalRoots) {
// Undelegate the staker
address operator = delegatedTo[staker];
delegatedTo[staker] = address(0);
emit StakerUndelegated(staker, operator);
// Get all of the staker's deposited strategies/shares. These will be removed from the operator
// and queued for withdrawal.
(IStrategy[] memory strategies, uint256[] memory depositedShares) = getDepositedShares(staker);
if (strategies.length == 0) {
return withdrawalRoots;
}
// For the operator and each of the staker's strategies, get the slashing factors to apply
// when queueing for withdrawal
withdrawalRoots = new bytes32[](strategies.length);
uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies);
// Queue a withdrawal for each strategy independently. This is done for UX reasons.
for (uint256 i = 0; i < strategies.length; i++) {
IStrategy[] memory singleStrategy = new IStrategy[](1);
uint256[] memory singleDepositShares = new uint256[](1);
uint256[] memory singleSlashingFactor = new uint256[](1);
singleStrategy[0] = strategies[i];
singleDepositShares[0] = depositedShares[i];
singleSlashingFactor[0] = slashingFactors[i];
// Remove shares from staker's strategies and place strategies/shares in queue.
// The operator's delegated shares are also reduced.
withdrawalRoots[i] = _removeSharesAndQueueWithdrawal({
staker: staker,
operator: operator,
strategies: singleStrategy,
depositSharesToWithdraw: singleDepositShares,
slashingFactors: singleSlashingFactor
});
}
return withdrawalRoots;
}
/**
* @notice Removes `sharesToWithdraw` in `strategies` from `staker` who is currently delegated to `operator` and queues a withdrawal to the `withdrawer`.
* @param staker The staker queuing a withdrawal
* @param operator The operator the staker is delegated to
* @param strategies The strategies to queue a withdrawal for
* @param depositSharesToWithdraw The amount of deposit shares the staker wishes to withdraw, must be less than staker's depositShares in storage
* @param slashingFactors The corresponding slashing factor for the staker/operator for each strategy
*
* @dev The amount withdrawable by the staker may not actually be the same as the depositShares that are in storage in the StrategyManager/EigenPodManager.
* This is a result of any slashing that has occurred during the time the staker has been delegated to an operator. So the proportional amount that is withdrawn
* out of the amount withdrawable for the staker has to also be decremented from the staker's deposit shares.
* So the amount of depositShares withdrawn out has to be proportionally scaled down depending on the slashing that has occurred.
* Ex. Suppose as a staker, I have 100 depositShares for a strategy thats sitting in the StrategyManager in the `stakerDepositShares` mapping but I actually have been slashed 50%
* and my real withdrawable amount is 50 shares.
* Now when I go to withdraw 40 depositShares, I'm proportionally withdrawing 40% of my withdrawable shares. We calculate below the actual shares withdrawn via the `toShares()` function to
* get 20 shares to queue withdraw. The end state is that I have 60 depositShares and 30 withdrawable shares now, this still accurately reflects a 50% slashing that has occurred on my existing stake.
* @dev depositSharesToWithdraw are converted to sharesToWithdraw using the `toShares` library function. sharesToWithdraw are then divided by the current maxMagnitude of the operator (at queue time)
* and this value is stored in the Withdrawal struct as `scaledShares.
* Upon completion the `scaledShares` are then multiplied by the maxMagnitude of the operator at completion time. This is how we factor in any slashing events
* that occurred during the withdrawal delay period. Shares in a withdrawal are no longer slashable once the withdrawal is completable.
* @dev If the `operator` is indeed an operator, then the operator's delegated shares in the `strategies` are also decreased appropriately.
*/
function _removeSharesAndQueueWithdrawal(
address staker,
address operator,
IStrategy[] memory strategies,
uint256[] memory depositSharesToWithdraw,
uint256[] memory slashingFactors
) internal returns (bytes32) {
require(staker != address(0), InputAddressZero());
require(strategies.length != 0, InputArrayLengthZero());
uint256[] memory scaledShares = new uint256[](strategies.length);
uint256[] memory withdrawableShares = new uint256[](strategies.length);
// Remove shares from staker and operator
// Each of these operations fail if we attempt to remove more shares than exist
for (uint256 i = 0; i < strategies.length; ++i) {
IShareManager shareManager = _getShareManager(strategies[i]);
DepositScalingFactor storage dsf = _depositScalingFactor[staker][strategies[i]];
// Calculate how many shares can be withdrawn after factoring in slashing
withdrawableShares[i] = dsf.calcWithdrawable(depositSharesToWithdraw[i], slashingFactors[i]);
// Scale shares for queue withdrawal
scaledShares[i] = dsf.scaleForQueueWithdrawal(depositSharesToWithdraw[i]);
// Remove delegated shares from the operator
if (operator != address(0)) {
// Staker was delegated and remains slashable during the withdrawal delay period
// Cumulative withdrawn scaled shares are updated for the strategy, this is for accounting
// purposes for burning shares if slashed
_addQueuedSlashableShares(operator, strategies[i], scaledShares[i]);
// forgefmt: disable-next-item
_decreaseDelegation({
operator: operator,
staker: staker,
strategy: strategies[i],
sharesToDecrease: withdrawableShares[i]
});
}
// Remove deposit shares from EigenPodManager/StrategyManager
uint256 sharesAfter = shareManager.removeDepositShares(staker, strategies[i], depositSharesToWithdraw[i]);
if (sharesAfter == 0) {
dsf.reset();
emit DepositScalingFactorUpdated(staker, strategies[i], dsf.scalingFactor());
}
}
// Create queue entry and increment withdrawal nonce
uint256 nonce = cumulativeWithdrawalsQueued[staker];
cumulativeWithdrawalsQueued[staker]++;
Withdrawal memory withdrawal = Withdrawal({
staker: staker,
delegatedTo: operator,
withdrawer: staker,
nonce: nonce,
startBlock: uint32(block.number),
strategies: strategies,
scaledShares: scaledShares
});
bytes32 withdrawalRoot = calculateWithdrawalRoot(withdrawal);
pendingWithdrawals[withdrawalRoot] = true;
_queuedWithdrawals[withdrawalRoot] = withdrawal;
_stakerQueuedWithdrawalRoots[staker].add(withdrawalRoot);
emit SlashingWithdrawalQueued(withdrawalRoot, withdrawal, withdrawableShares);
return withdrawalRoot;
}
/**
* @dev This function completes a queued withdrawal for a staker.
* This will apply any slashing that has occurred since the the withdrawal was queued by multiplying the withdrawal's
* scaledShares by the operator's maxMagnitude for each strategy. This ensures that any slashing that has occurred
* during the period the withdrawal was queued until its slashableUntil block is applied to the withdrawal amount.
* If receiveAsTokens is true, then these shares will be withdrawn as tokens.
* If receiveAsTokens is false, then they will be redeposited according to the current operator the staker is delegated to,
* and added back to the operator's delegatedShares.
*/
function _completeQueuedWithdrawal(
Withdrawal memory withdrawal,
IERC20[] calldata tokens,
bool receiveAsTokens
) internal {
require(tokens.length == withdrawal.strategies.length, InputArrayLengthMismatch());
require(msg.sender == withdrawal.withdrawer, WithdrawerNotCaller());
bytes32 withdrawalRoot = calculateWithdrawalRoot(withdrawal);
require(pendingWithdrawals[withdrawalRoot], WithdrawalNotQueued());
uint256[] memory prevSlashingFactors;
{
// slashableUntil is block inclusive so we need to check if the current block is strictly greater than the slashableUntil block
// meaning the withdrawal can be completed.
uint32 slashableUntil = withdrawal.startBlock + MIN_WITHDRAWAL_DELAY_BLOCKS;
require(uint32(block.number) > slashableUntil, WithdrawalDelayNotElapsed());
// Given the max magnitudes of the operator the staker was originally delegated to, calculate
// the slashing factors for each of the withdrawal's strategies.
prevSlashingFactors = _getSlashingFactorsAtBlock({
staker: withdrawal.staker,
operator: withdrawal.delegatedTo,
strategies: withdrawal.strategies,
blockNumber: slashableUntil
});
}
// Remove the withdrawal from the queue. Note that for legacy withdrawals, the removals
// from `_stakerQueuedWithdrawalRoots` and `queuedWithdrawals` will no-op.
_stakerQueuedWithdrawalRoots[withdrawal.staker].remove(withdrawalRoot);
delete _queuedWithdrawals[withdrawalRoot];
delete pendingWithdrawals[withdrawalRoot];
emit SlashingWithdrawalCompleted(withdrawalRoot);
// Given the max magnitudes of the operator the staker is now delegated to, calculate the current
// slashing factors to apply to each withdrawal if it is received as shares.
address newOperator = delegatedTo[withdrawal.staker];
uint256[] memory newSlashingFactors = _getSlashingFactors(withdrawal.staker, newOperator, withdrawal.strategies);
for (uint256 i = 0; i < withdrawal.strategies.length; i++) {
IShareManager shareManager = _getShareManager(withdrawal.strategies[i]);
// Calculate how much slashing to apply, as well as shares to withdraw
uint256 sharesToWithdraw = SlashingLib.scaleForCompleteWithdrawal({
scaledShares: withdrawal.scaledShares[i],
slashingFactor: prevSlashingFactors[i]
});
//Do nothing if 0 shares to withdraw
if (sharesToWithdraw == 0) {
continue;
}
if (receiveAsTokens) {
// Withdraws `shares` in `strategy` to `withdrawer`. If the shares are virtual beaconChainETH shares,
// then a call is ultimately forwarded to the `staker`s EigenPod; otherwise a call is ultimately forwarded
// to the `strategy` with info on the `token`.
shareManager.withdrawSharesAsTokens({
staker: withdrawal.staker,
strategy: withdrawal.strategies[i],
token: tokens[i],
shares: sharesToWithdraw
});
} else {
// Award shares back in StrategyManager/EigenPodManager.
(uint256 prevDepositShares, uint256 addedShares) = shareManager.addShares({
staker: withdrawal.staker,
strategy: withdrawal.strategies[i],
shares: sharesToWithdraw
});
// Update the staker's deposit scaling factor and delegate shares to their operator
_increaseDelegation({
operator: newOperator,
staker: withdrawal.staker,
strategy: withdrawal.strategies[i],
prevDepositShares: prevDepositShares,
addedShares: addedShares,
slashingFactor: newSlashingFactors[i]
});
}
}
}
/**
* @notice Increases `operator`s depositedShares in `strategy` based on staker's addedDepositShares
* and updates the staker's depositScalingFactor for the strategy.
* @param operator The operator to increase the delegated delegatedShares for
* @param staker The staker to increase the depositScalingFactor for
* @param strategy The strategy to increase the delegated delegatedShares and the depositScalingFactor for
* @param prevDepositShares The number of delegated deposit shares the staker had in the strategy prior to the increase
* @param addedShares The shares added to the staker in the StrategyManager/EigenPodManager
* @param slashingFactor The current slashing factor for the staker/operator/strategy
*/
function _increaseDelegation(
address operator,
address staker,
IStrategy strategy,
uint256 prevDepositShares,
uint256 addedShares,
uint256 slashingFactor
) internal {
// Ensure that the operator has not been fully slashed for a strategy
// and that the staker has not been fully slashed if it is the beaconChainStrategy
// This is to prevent a divWad by 0 when updating the depositScalingFactor
require(slashingFactor != 0, FullySlashed());
// If `addedShares` is 0, do nothing
if (addedShares == 0) {
return;
}
// Update the staker's depositScalingFactor. This only results in an update
// if the slashing factor has changed for this strategy.
DepositScalingFactor storage dsf = _depositScalingFactor[staker][strategy];
dsf.update(prevDepositShares, addedShares, slashingFactor);
emit DepositScalingFactorUpdated(staker, strategy, dsf.scalingFactor());
// If the staker is delegated to an operator, update the operator's shares
if (isDelegated(staker)) {
operatorShares[operator][strategy] += addedShares;
emit OperatorSharesIncreased(operator, staker, strategy, addedShares);
}
}
/**
* @notice Decreases `operator`s shares in `strategy` based on staker's removed shares
* @param operator The operator to decrease the delegated delegated shares for
* @param staker The staker to decrease the delegated delegated shares for
* @param strategy The strategy to decrease the delegated delegated shares for
* @param sharesToDecrease The shares to remove from the operator's delegated shares
*/
function _decreaseDelegation(
address operator,
address staker,
IStrategy strategy,
uint256 sharesToDecrease
) internal {
// Decrement operator shares
operatorShares[operator][strategy] -= sharesToDecrease;
emit OperatorSharesDecreased(operator, staker, strategy, sharesToDecrease);
}
/// @dev If `operator` has configured a `delegationApprover`, check that `signature` and `salt`
/// are a valid approval for `staker` delegating to `operator`.
function _checkApproverSignature(
address staker,
address operator,
SignatureWithExpiry memory signature,
bytes32 salt
) internal {
address approver = _operatorDetails[operator].delegationApprover;
if (approver == address(0)) {
return;
}
// Check that the salt hasn't been used previously, then mark the salt as spent
require(!delegationApproverSaltIsSpent[approver][salt], SaltSpent());
delegationApproverSaltIsSpent[approver][salt] = true;
// Validate the signature
_checkIsValidSignatureNow({
signer: approver,
signableDigest: calculateDelegationApprovalDigestHash(staker, operator, approver, salt, signature.expiry),
signature: signature.signature,
expiry: signature.expiry
});
}
/// @dev Calculate the amount of slashing to apply to the staker's shares.
/// @dev Be mindful of rounding in `mulWad()`, it's possible for the slashing factor to round down to 0
/// even when both operatorMaxMagnitude and beaconChainSlashingFactor are non-zero. This is only possible
/// in an edge case where the operator has a very low maxMagnitude.
function _getSlashingFactor(
address staker,
IStrategy strategy,
uint64 operatorMaxMagnitude
) internal view returns (uint256) {
if (strategy == beaconChainETHStrategy) {
uint64 beaconChainSlashingFactor = eigenPodManager.beaconChainSlashingFactor(staker);
return operatorMaxMagnitude.mulWad(beaconChainSlashingFactor);
}
return operatorMaxMagnitude;
}
/// @dev Calculate the amount of slashing to apply to the staker's shares across multiple strategies
function _getSlashingFactors(
address staker,
address operator,
IStrategy[] memory strategies
) internal view returns (uint256[] memory) {
uint256[] memory slashingFactors = new uint256[](strategies.length);
uint64[] memory maxMagnitudes = allocationManager.getMaxMagnitudes(operator, strategies);
for (uint256 i = 0; i < strategies.length; i++) {
slashingFactors[i] = _getSlashingFactor(staker, strategies[i], maxMagnitudes[i]);
}
return slashingFactors;
}
/// @dev Calculate the amount of slashing to apply to the staker's shares across multiple strategies
/// Note: specifically checks the operator's magnitude at a prior block, used for completing withdrawals
function _getSlashingFactorsAtBlock(
address staker,
address operator,
IStrategy[] memory strategies,
uint32 blockNumber
) internal view returns (uint256[] memory) {
uint256[] memory slashingFactors = new uint256[](strategies.length);
uint64[] memory maxMagnitudes = allocationManager.getMaxMagnitudesAtBlock({
operator: operator,
strategies: strategies,
blockNumber: blockNumber
});
for (uint256 i = 0; i < strategies.length; i++) {
slashingFactors[i] = _getSlashingFactor(staker, strategies[i], maxMagnitudes[i]);
}
return slashingFactors;
}
/**
* @dev Calculate amount of slashable shares that would be slashed from the queued withdrawals from an operator for a strategy
* given the previous maxMagnitude and the new maxMagnitude.
* Note: To get the total amount of slashable shares in the queue withdrawable, set newMaxMagnitude to 0 and prevMaxMagnitude
* is the current maxMagnitude of the operator.
*/
function _getSlashableSharesInQueue(
address operator,
IStrategy strategy,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) internal view returns (uint256) {
// We want ALL shares added to the withdrawal queue in the window [block.number - MIN_WITHDRAWAL_DELAY_BLOCKS, block.number]
//
// To get this, we take the current shares in the withdrawal queue and subtract the number of shares
// that were in the queue before MIN_WITHDRAWAL_DELAY_BLOCKS.
uint256 curQueuedScaledShares = _cumulativeScaledSharesHistory[operator][strategy].latest();
uint256 prevQueuedScaledShares = _cumulativeScaledSharesHistory[operator][strategy].upperLookup({
key: uint32(block.number) - MIN_WITHDRAWAL_DELAY_BLOCKS - 1
});
// The difference between these values is the number of scaled shares that entered the withdrawal queue
// less than or equal to MIN_WITHDRAWAL_DELAY_BLOCKS ago. These shares are still slashable.
uint256 scaledSharesAdded = curQueuedScaledShares - prevQueuedScaledShares;
return SlashingLib.scaleForBurning({
scaledShares: scaledSharesAdded,
prevMaxMagnitude: prevMaxMagnitude,
newMaxMagnitude: newMaxMagnitude
});
}
/// @dev Add to the cumulative withdrawn scaled shares from an operator for a given strategy
function _addQueuedSlashableShares(address operator, IStrategy strategy, uint256 scaledShares) internal {
uint256 currCumulativeScaledShares = _cumulativeScaledSharesHistory[operator][strategy].latest();
_cumulativeScaledSharesHistory[operator][strategy].push({
key: uint32(block.number),
value: currCumulativeScaledShares + scaledShares
});
}
/// @dev Get the shares from a queued withdrawal.
function _getSharesByWithdrawalRoot(
bytes32 withdrawalRoot
) internal view returns (Withdrawal memory withdrawal, uint256[] memory shares) {
withdrawal = _queuedWithdrawals[withdrawalRoot];
shares = new uint256[](withdrawal.strategies.length);
uint32 slashableUntil = withdrawal.startBlock + MIN_WITHDRAWAL_DELAY_BLOCKS;
// If the slashableUntil block is in the past, read the slashing factors at that block.
// Otherwise, read the current slashing factors. Note that if the slashableUntil block is the current block
// or in the future, then the slashing factors are still subject to change before the withdrawal is completable,
// which may result in fewer shares being withdrawn.
uint256[] memory slashingFactors = slashableUntil < uint32(block.number)
? _getSlashingFactorsAtBlock({
staker: withdrawal.staker,
operator: withdrawal.delegatedTo,
strategies: withdrawal.strategies,
blockNumber: slashableUntil
})
: _getSlashingFactors({
staker: withdrawal.staker,
operator: withdrawal.delegatedTo,
strategies: withdrawal.strategies
});
for (uint256 j; j < withdrawal.strategies.length; ++j) {
shares[j] = SlashingLib.scaleForCompleteWithdrawal({
scaledShares: withdrawal.scaledShares[j],
slashingFactor: slashingFactors[j]
});
}
}
/// @dev Depending on the strategy used, determine which ShareManager contract to make external calls to
function _getShareManager(
IStrategy strategy
) internal view returns (IShareManager) {
return strategy == beaconChainETHStrategy
? IShareManager(address(eigenPodManager))
: IShareManager(address(strategyManager));
}
/**
*
* VIEW FUNCTIONS
*
*/
/// @inheritdoc IDelegationManager
function isDelegated(
address staker
) public view returns (bool) {
return (delegatedTo[staker] != address(0));
}
/// @inheritdoc IDelegationManager
function isOperator(
address operator
) public view returns (bool) {
return operator != address(0) && delegatedTo[operator] == operator;
}
/// @inheritdoc IDelegationManager
function delegationApprover(
address operator
) public view returns (address) {
return _operatorDetails[operator].delegationApprover;
}
/// @inheritdoc IDelegationManager
function depositScalingFactor(address staker, IStrategy strategy) external view returns (uint256) {
return _depositScalingFactor[staker][strategy].scalingFactor();
}
/// @inheritdoc IDelegationManager
function getOperatorShares(
address operator,
IStrategy[] memory strategies
) public view returns (uint256[] memory) {
uint256[] memory shares = new uint256[](strategies.length);
for (uint256 i = 0; i < strategies.length; ++i) {
shares[i] = operatorShares[operator][strategies[i]];
}
return shares;
}
/// @inheritdoc IDelegationManager
function getOperatorsShares(
address[] memory operators,
IStrategy[] memory strategies
) public view returns (uint256[][] memory) {
uint256[][] memory shares = new uint256[][](operators.length);
for (uint256 i = 0; i < operators.length; ++i) {
shares[i] = getOperatorShares(operators[i], strategies);
}
return shares;
}
/// @inheritdoc IDelegationManager
function getSlashableSharesInQueue(address operator, IStrategy strategy) public view returns (uint256) {
uint64 maxMagnitude = allocationManager.getMaxMagnitude(operator, strategy);
// Return amount of slashable scaled shares remaining
return _getSlashableSharesInQueue({
operator: operator,
strategy: strategy,
prevMaxMagnitude: maxMagnitude,
newMaxMagnitude: 0
});
}
/// @inheritdoc IDelegationManager
function getWithdrawableShares(
address staker,
IStrategy[] memory strategies
) public view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares) {
withdrawableShares = new uint256[](strategies.length);
depositShares = new uint256[](strategies.length);
// Get the slashing factors for the staker/operator/strategies
address operator = delegatedTo[staker];
uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies);
for (uint256 i = 0; i < strategies.length; ++i) {
IShareManager shareManager = _getShareManager(strategies[i]);
depositShares[i] = shareManager.stakerDepositShares(staker, strategies[i]);
// Calculate the withdrawable shares based on the slashing factor
DepositScalingFactor memory dsf = _depositScalingFactor[staker][strategies[i]];
withdrawableShares[i] = dsf.calcWithdrawable(depositShares[i], slashingFactors[i]);
}
return (withdrawableShares, depositShares);
}
/// @inheritdoc IDelegationManager
function getDepositedShares(
address staker
) public view returns (IStrategy[] memory, uint256[] memory) {
// Get a list of the staker's deposited strategies/shares in the strategy manager
(IStrategy[] memory tokenStrategies, uint256[] memory tokenDeposits) = strategyManager.getDeposits(staker);
// If the staker has no beacon chain ETH shares, return any shares from the strategy manager
uint256 podOwnerShares = eigenPodManager.stakerDepositShares(staker, beaconChainETHStrategy);
if (podOwnerShares == 0) {
return (tokenStrategies, tokenDeposits);
}
// Allocate extra space for beaconChainETHStrategy and shares
IStrategy[] memory strategies = new IStrategy[](tokenStrategies.length + 1);
uint256[] memory shares = new uint256[](tokenStrategies.length + 1);
strategies[tokenStrategies.length] = beaconChainETHStrategy;
shares[tokenStrategies.length] = podOwnerShares;
// Copy any strategy manager shares to complete array
for (uint256 i = 0; i < tokenStrategies.length; i++) {
strategies[i] = tokenStrategies[i];
shares[i] = tokenDeposits[i];
}
return (strategies, shares);
}
/// @inheritdoc IDelegationManager
function queuedWithdrawals(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal) {
return _queuedWithdrawals[withdrawalRoot];
}
/// @inheritdoc IDelegationManager
function getQueuedWithdrawal(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal, uint256[] memory shares) {
(withdrawal, shares) = _getSharesByWithdrawalRoot(withdrawalRoot);
}
/// @inheritdoc IDelegationManager
function getQueuedWithdrawals(
address staker
) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares) {
bytes32[] memory withdrawalRoots = getQueuedWithdrawalRoots(staker);
uint256 totalQueued = withdrawalRoots.length;
withdrawals = new Withdrawal[](totalQueued);
shares = new uint256[][](totalQueued);
for (uint256 i; i < totalQueued; ++i) {
(withdrawals[i], shares[i]) = _getSharesByWithdrawalRoot(withdrawalRoots[i]);
}
}
/// @inheritdoc IDelegationManager
function getQueuedWithdrawalRoots(
address staker
) public view returns (bytes32[] memory) {
return _stakerQueuedWithdrawalRoots[staker].values();
}
/// @inheritdoc IDelegationManager
function convertToDepositShares(
address staker,
IStrategy[] memory strategies,
uint256[] memory withdrawableShares
) external view returns (uint256[] memory) {
// Get the slashing factors for the staker/operator/strategies
address operator = delegatedTo[staker];
uint256[] memory slashingFactors = _getSlashingFactors(staker, operator, strategies);
// Calculate the deposit shares based on the slashing factor
uint256[] memory depositShares = new uint256[](strategies.length);
for (uint256 i = 0; i < strategies.length; ++i) {
DepositScalingFactor memory dsf = _depositScalingFactor[staker][strategies[i]];
depositShares[i] = dsf.calcDepositShares(withdrawableShares[i], slashingFactors[i]);
}
return depositShares;
}
/// @inheritdoc IDelegationManager
function calculateWithdrawalRoot(
Withdrawal memory withdrawal
) public pure returns (bytes32) {
return keccak256(abi.encode(withdrawal));
}
/// @inheritdoc IDelegationManager
function minWithdrawalDelayBlocks() external view returns (uint32) {
return MIN_WITHDRAWAL_DELAY_BLOCKS;
}
/// @inheritdoc IDelegationManager
function calculateDelegationApprovalDigestHash(
address staker,
address operator,
address approver,
bytes32 approverSalt,
uint256 expiry
) public view returns (bytes32) {
/// forgefmt: disable-next-item
return _calculateSignableDigest(
keccak256(
abi.encode(
DELEGATION_APPROVAL_TYPEHASH,
approver,
staker,
operator,
approverSalt,
expiry
)
)
);
}
}// 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) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// 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: BUSL-1.1
pragma solidity ^0.8.0;
import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol";
import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol";
import "../interfaces/ISignatureUtilsMixin.sol";
import "./SemVerMixin.sol";
/// @dev The EIP-712 domain type hash used for computing the domain separator
/// See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator
bytes32 constant EIP712_DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/// @title SignatureUtilsMixin
/// @notice A mixin contract that provides utilities for validating signatures according to EIP-712 and EIP-1271 standards.
/// @dev The domain name is hardcoded to "EigenLayer". This contract implements signature validation functionality that can be
/// inherited by other contracts. The domain separator uses the major version (e.g., "v1") to maintain EIP-712
/// signature compatibility across minor and patch version updates.
abstract contract SignatureUtilsMixin is ISignatureUtilsMixin, SemVerMixin {
using SignatureCheckerUpgradeable for address;
/// @notice Initializes the contract with a semantic version string.
/// @param _version The SemVer-formatted version string (e.g., "v1.1.1") to use for this contract's domain separator.
/// @dev Version should follow SemVer 2.0.0 format with 'v' prefix: vMAJOR.MINOR.PATCH.
/// Only the major version component is used in the domain separator to maintain signature compatibility
/// across minor and patch version updates.
constructor(
string memory _version
) SemVerMixin(_version) {}
/// EXTERNAL FUNCTIONS ///
/// @inheritdoc ISignatureUtilsMixin
function domainSeparator() public view virtual returns (bytes32) {
// forgefmt: disable-next-item
return
keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(bytes("EigenLayer")),
keccak256(bytes(_majorVersion())),
block.chainid,
address(this)
)
);
}
/// INTERNAL HELPERS ///
/// @notice Creates a digest that can be signed using EIP-712.
/// @dev Prepends the EIP-712 prefix ("\x19\x01") and domain separator to the input hash.
/// This follows the EIP-712 specification for creating structured data hashes.
/// See https://eips.ethereum.org/EIPS/eip-712#specification.
/// @param hash The hash of the typed data to be signed.
/// @return The complete digest that should be signed according to EIP-712.
function _calculateSignableDigest(
bytes32 hash
) internal view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator(), hash));
}
/// @notice Validates a signature against a signer and digest, with an expiry timestamp.
/// @dev Reverts if the signature is invalid or expired. Uses EIP-1271 for smart contract signers.
/// For EOA signers, validates ECDSA signatures directly.
/// For contract signers, calls isValidSignature according to EIP-1271.
/// See https://eips.ethereum.org/EIPS/eip-1271#specification.
/// @param signer The address that should have signed the digest.
/// @param signableDigest The digest that was signed, created via _calculateSignableDigest.
/// @param signature The signature bytes to validate.
/// @param expiry The timestamp after which the signature is no longer valid.
function _checkIsValidSignatureNow(
address signer,
bytes32 signableDigest,
bytes memory signature,
uint256 expiry
) internal view {
// First, check if the signature has expired by comparing the expiry timestamp
// against the current block timestamp.
require(expiry >= block.timestamp, SignatureExpired());
// Next, verify that the signature is valid for the given signer and digest.
// For EOA signers, this performs standard ECDSA signature verification.
// For contract signers, this calls the EIP-1271 isValidSignature method.
require(signer.isValidSignatureNow(signableDigest, signature), InvalidSignature());
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "../interfaces/IPermissionController.sol";
abstract contract PermissionControllerMixin {
/// @dev Thrown when the caller is not allowed to call a function on behalf of an account.
error InvalidPermissions();
/// @notice Pointer to the permission controller contract.
IPermissionController public immutable permissionController;
constructor(
IPermissionController _permissionController
) {
permissionController = _permissionController;
}
/// @notice Checks if the caller (msg.sender) can call on behalf of an account.
modifier checkCanCall(
address account
) {
require(_checkCanCall(account), InvalidPermissions());
_;
}
/**
* @notice Checks if the caller is allowed to call a function on behalf of an account.
* @param account the account to check
* @dev `msg.sender` is the caller to check that can call the function on behalf of `account`.
* @dev Returns a bool, instead of reverting
*/
function _checkCanCall(
address account
) internal returns (bool) {
return permissionController.canCall(account, msg.sender, address(this), msg.sig);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "../interfaces/IPausable.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
*/
abstract contract Pausable is IPausable {
/// Constants
uint256 internal constant _UNPAUSE_ALL = 0;
uint256 internal constant _PAUSE_ALL = type(uint256).max;
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
IPauserRegistry public immutable pauserRegistry;
/// Storage
/// @dev Do not remove, deprecated storage.
IPauserRegistry private __deprecated_pauserRegistry;
/// @dev Returns a bitmap representing the paused status of the contract.
uint256 private _paused;
/// Modifiers
/// @dev Thrown if the caller is not a valid pauser according to the pauser registry.
modifier onlyPauser() {
require(pauserRegistry.isPauser(msg.sender), OnlyPauser());
_;
}
/// @dev Thrown if the caller is not a valid unpauser according to the pauser registry.
modifier onlyUnpauser() {
require(msg.sender == pauserRegistry.unpauser(), OnlyUnpauser());
_;
}
/// @dev Thrown if the contract is paused, i.e. if any of the bits in `_paused` is flipped to 1.
modifier whenNotPaused() {
require(_paused == 0, CurrentlyPaused());
_;
}
/// @dev Thrown if the `indexed`th bit of `_paused` is 1, i.e. if the `index`th pause switch is flipped.
modifier onlyWhenNotPaused(
uint8 index
) {
require(!paused(index), CurrentlyPaused());
_;
}
/// Construction
constructor(
IPauserRegistry _pauserRegistry
) {
require(address(_pauserRegistry) != address(0), InputAddressZero());
pauserRegistry = _pauserRegistry;
}
/// @inheritdoc IPausable
function pause(
uint256 newPausedStatus
) external onlyPauser {
uint256 currentPausedStatus = _paused;
// verify that the `newPausedStatus` does not *unflip* any bits (i.e. doesn't unpause anything, all 1 bits remain)
require((currentPausedStatus & newPausedStatus) == currentPausedStatus, InvalidNewPausedStatus());
_setPausedStatus(newPausedStatus);
}
/// @inheritdoc IPausable
function pauseAll() external onlyPauser {
_setPausedStatus(_PAUSE_ALL);
}
/// @inheritdoc IPausable
function unpause(
uint256 newPausedStatus
) external onlyUnpauser {
uint256 currentPausedStatus = _paused;
// verify that the `newPausedStatus` does not *flip* any bits (i.e. doesn't pause anything, all 0 bits remain)
require(((~currentPausedStatus) & (~newPausedStatus)) == (~currentPausedStatus), InvalidNewPausedStatus());
_paused = newPausedStatus;
emit Unpaused(msg.sender, newPausedStatus);
}
/// @inheritdoc IPausable
function paused() public view virtual returns (uint256) {
return _paused;
}
/// @inheritdoc IPausable
function paused(
uint8 index
) public view virtual returns (bool) {
uint256 mask = 1 << index;
return ((_paused & mask) == mask);
}
/// @dev Internal helper for setting the paused status, and emitting the corresponding event.
function _setPausedStatus(
uint256 pausedStatus
) internal {
_paused = pausedStatus;
emit Paused(msg.sender, pausedStatus);
}
/**
* @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[48] private __gap;
}// 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;
// 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;
}
/// @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: MIT
pragma solidity ^0.8.0;
import "@openzeppelin-upgrades/contracts/utils/math/MathUpgradeable.sol";
import "./SlashingLib.sol";
/**
* @title Library for handling snapshots as part of allocating and slashing.
* @notice This library is using OpenZeppelin's CheckpointsUpgradeable library (v4.9.0)
* and removes structs and functions that are unessential.
* Interfaces and structs are renamed for clarity and usage.
* Some additional functions have also been added for convenience.
* @dev This library defines the `DefaultWadHistory` and `DefaultZeroHistory` struct, for snapshotting values as they change at different points in
* time, and later looking up past values by block number. See {Votes} as an example.
*
* To create a history of snapshots define a variable type `Snapshots.DefaultWadHistory` or `Snapshots.DefaultZeroHistory` in your contract,
* and store a new snapshot for the current transaction block using the {push} function. If there is no history yet, the value is either WAD or 0,
* depending on the type of History struct used. This is implemented because for the AllocationManager we want the
* the default value to be WAD(1e18) but when used in the DelegationManager we want the default value to be 0.
*
* _Available since v4.5._
*/
library Snapshots {
struct DefaultWadHistory {
Snapshot[] _snapshots;
}
struct DefaultZeroHistory {
Snapshot[] _snapshots;
}
struct Snapshot {
uint32 _key;
uint224 _value;
}
error InvalidSnapshotOrdering();
/**
* @dev Pushes a (`key`, `value`) pair into a DefaultWadHistory so that it is stored as the snapshot.
*/
function push(DefaultWadHistory storage self, uint32 key, uint64 value) internal {
_insert(self._snapshots, key, value);
}
/**
* @dev Pushes a (`key`, `value`) pair into a DefaultZeroHistory so that it is stored as the snapshot.
* `value` is cast to uint224. Responsibility for the safety of this operation falls outside of this library.
*/
function push(DefaultZeroHistory storage self, uint32 key, uint256 value) internal {
_insert(self._snapshots, key, uint224(value));
}
/**
* @dev Return default value of WAD if there are no snapshots for DefaultWadHistory.
* This is used for looking up maxMagnitudes in the AllocationManager.
*/
function upperLookup(DefaultWadHistory storage self, uint32 key) internal view returns (uint64) {
return uint64(_upperLookup(self._snapshots, key, WAD));
}
/**
* @dev Return default value of 0 if there are no snapshots for DefaultZeroHistory.
* This is used for looking up cumulative scaled shares in the DelegationManager.
*/
function upperLookup(DefaultZeroHistory storage self, uint32 key) internal view returns (uint256) {
return _upperLookup(self._snapshots, key, 0);
}
/**
* @dev Returns the value in the most recent snapshot, or WAD if there are no snapshots.
*/
function latest(
DefaultWadHistory storage self
) internal view returns (uint64) {
return uint64(_latest(self._snapshots, WAD));
}
/**
* @dev Returns the value in the most recent snapshot, or 0 if there are no snapshots.
*/
function latest(
DefaultZeroHistory storage self
) internal view returns (uint256) {
return uint256(_latest(self._snapshots, 0));
}
/**
* @dev Returns the number of snapshots.
*/
function length(
DefaultWadHistory storage self
) internal view returns (uint256) {
return self._snapshots.length;
}
/**
* @dev Returns the number of snapshots.
*/
function length(
DefaultZeroHistory storage self
) internal view returns (uint256) {
return self._snapshots.length;
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of snapshots, either by inserting a new snapshot,
* or by updating the last one.
*/
function _insert(Snapshot[] storage self, uint32 key, uint224 value) private {
uint256 pos = self.length;
if (pos > 0) {
// Validate that inserted keys are always >= the previous key
Snapshot memory last = _unsafeAccess(self, pos - 1);
require(last._key <= key, InvalidSnapshotOrdering());
// Update existing snapshot if `key` matches
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
return;
}
}
// `key` was not in the list; push as a new entry
self.push(Snapshot({_key: key, _value: value}));
}
/**
* @dev Returns the value in the last (most recent) snapshot with key lower or equal than the search key, or `defaultValue` if there is none.
*/
function _upperLookup(
Snapshot[] storage snapshots,
uint32 key,
uint224 defaultValue
) private view returns (uint224) {
uint256 len = snapshots.length;
uint256 pos = _upperBinaryLookup(snapshots, key, 0, len);
return pos == 0 ? defaultValue : _unsafeAccess(snapshots, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent snapshot, or `defaultValue` if there are no snapshots.
*/
function _latest(Snapshot[] storage snapshots, uint224 defaultValue) private view returns (uint224) {
uint256 pos = snapshots.length;
return pos == 0 ? defaultValue : _unsafeAccess(snapshots, pos - 1)._value;
}
/**
* @dev Return the index of the last (most recent) snapshot with key lower or equal than the search key, or `high` if there is none.
* `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Snapshot[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = MathUpgradeable.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(Snapshot[] storage self, uint256 pos) private pure returns (Snapshot storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../libraries/SlashingLib.sol";
import "../interfaces/IDelegationManager.sol";
import "../interfaces/IEigenPodManager.sol";
import "../interfaces/IAllocationManager.sol";
import {Snapshots} from "../libraries/Snapshots.sol";
/**
* @title Storage variables for the `DelegationManager` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This storage contract is separate from the logic to simplify the upgrade process.
*/
abstract contract DelegationManagerStorage is IDelegationManager {
using Snapshots for Snapshots.DefaultZeroHistory;
// Constants
/// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract
bytes32 public constant DELEGATION_APPROVAL_TYPEHASH = keccak256(
"DelegationApproval(address delegationApprover,address staker,address operator,bytes32 salt,uint256 expiry)"
);
/// @dev Index for flag that pauses new delegations when set
uint8 internal constant PAUSED_NEW_DELEGATION = 0;
/// @dev Index for flag that pauses queuing new withdrawals when set.
uint8 internal constant PAUSED_ENTER_WITHDRAWAL_QUEUE = 1;
/// @dev Index for flag that pauses completing existing withdrawals when set.
uint8 internal constant PAUSED_EXIT_WITHDRAWAL_QUEUE = 2;
/// @notice Canonical, virtual beacon chain ETH strategy
IStrategy public constant beaconChainETHStrategy = IStrategy(0xbeaC0eeEeeeeEEeEeEEEEeeEEeEeeeEeeEEBEaC0);
// Immutables
/// @notice The StrategyManager contract for EigenLayer
IStrategyManager public immutable strategyManager;
/// @notice The EigenPodManager contract for EigenLayer
IEigenPodManager public immutable eigenPodManager;
/// @notice The AllocationManager contract for EigenLayer
IAllocationManager public immutable allocationManager;
/// @notice Minimum withdrawal delay in blocks until a queued withdrawal can be completed.
uint32 internal immutable MIN_WITHDRAWAL_DELAY_BLOCKS;
// Mutatables
/// @dev Do not remove, deprecated storage.
bytes32 internal __deprecated_DOMAIN_SEPARATOR;
/**
* @notice Tracks the current balance of shares an `operator` is delegated according to each `strategy`.
* Updated by both the `StrategyManager` and `EigenPodManager` when a staker's delegatable balance changes,
* and by the `AllocationManager` when the `operator` is slashed.
*
* @dev The following invariant should hold for each `strategy`:
*
* operatorShares[operator] = sum(withdrawable shares of all stakers delegated to operator)
*/
mapping(address operator => mapping(IStrategy strategy => uint256 shares)) public operatorShares;
/// @notice Returns the operator details for a given `operator`.
/// Note: two of the `OperatorDetails` fields are deprecated. The only relevant field
/// is `OperatorDetails.delegationApprover`.
mapping(address operator => OperatorDetails) internal _operatorDetails;
/// @notice Returns the `operator` a `staker` is delegated to, or address(0) if not delegated.
/// Note: operators are delegated to themselves
mapping(address staker => address operator) public delegatedTo;
/// @notice Do not remove, deprecated storage.
mapping(address staker => uint256 nonce) private __deprecated_stakerNonce;
/// @notice Returns whether `delegationApprover` has already used the given `salt`.
mapping(address delegationApprover => mapping(bytes32 salt => bool spent)) public delegationApproverSaltIsSpent;
/// @dev Do not remove, deprecated storage.
uint256 private __deprecated_minWithdrawalDelayBlocks;
/// @dev Returns whether a withdrawal is pending for a given `withdrawalRoot`.
/// @dev This variable will be deprecated in the future, values should only be read or deleted.
mapping(bytes32 withdrawalRoot => bool pending) public pendingWithdrawals;
/// @notice Returns the total number of withdrawals that have been queued for a given `staker`.
/// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes.
mapping(address staker => uint256 totalQueued) public cumulativeWithdrawalsQueued;
/// @dev Do not remove, deprecated storage.
/// See conversation here: https://github.com/Layr-Labs/eigenlayer-contracts/pull/365/files#r1417525270
address private __deprecated_stakeRegistry;
/// @dev Do not remove, deprecated storage.
mapping(IStrategy strategy => uint256 delayBlocks) private __deprecated_strategyWithdrawalDelayBlocks;
/// @notice Returns the scaling factor applied to a `staker` for a given `strategy`
mapping(address staker => mapping(IStrategy strategy => DepositScalingFactor)) internal _depositScalingFactor;
/// @notice Returns a list of queued withdrawals for a given `staker`.
/// @dev Entries are removed when the withdrawal is completed.
/// @dev This variable only reflects withdrawals that were made after the slashing release.
mapping(address staker => EnumerableSet.Bytes32Set withdrawalRoots) internal _stakerQueuedWithdrawalRoots;
/// @notice Returns the details of a queued withdrawal given by `withdrawalRoot`.
/// @dev This variable only reflects withdrawals that were made after the slashing release.
mapping(bytes32 withdrawalRoot => Withdrawal withdrawal) internal _queuedWithdrawals;
/// @notice Contains history of the total cumulative staker withdrawals for an operator and a given strategy.
/// Used to calculate burned StrategyManager shares when an operator is slashed.
/// @dev Stores scaledShares instead of total withdrawn shares to track current slashable shares, dependent on the maxMagnitude
mapping(address operator => mapping(IStrategy strategy => Snapshots.DefaultZeroHistory)) internal
_cumulativeScaledSharesHistory;
// Construction
constructor(
IStrategyManager _strategyManager,
IEigenPodManager _eigenPodManager,
IAllocationManager _allocationManager,
uint32 _MIN_WITHDRAWAL_DELAY_BLOCKS
) {
strategyManager = _strategyManager;
eigenPodManager = _eigenPodManager;
allocationManager = _allocationManager;
MIN_WITHDRAWAL_DELAY_BLOCKS = _MIN_WITHDRAWAL_DELAY_BLOCKS;
}
/**
* @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 v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// 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 (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSAUpgradeable.sol";
import "../../interfaces/IERC1271Upgradeable.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureCheckerUpgradeable {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSAUpgradeable.RecoverError error) = ECDSAUpgradeable.tryRecover(hash, signature);
return
(error == ECDSAUpgradeable.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271Upgradeable.isValidSignature.selector, hash, signature)
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271Upgradeable.isValidSignature.selector));
}
}// 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: 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/). Prefixed with 'v' (e.g., "v1.2.3").
ShortString internal immutable _VERSION;
/// @notice Initializes the contract with a semantic version string.
/// @param _version The SemVer-formatted version string (e.g., "v1.2.3")
/// @dev Version should follow SemVer 2.0.0 format with 'v' prefix: vMAJOR.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., "v1" for version "v1.2.3")
/// @return The major version string (e.g., "v1" for version "v1.2.3")
function _majorVersion() internal view returns (string memory) {
bytes memory v = bytes(_VERSION.toString());
return string(bytes.concat(v[0], v[1]));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "./ISemVerMixin.sol";
interface IPermissionControllerErrors {
/// @notice Thrown when a non-admin caller attempts to perform an admin-only action.
error NotAdmin();
/// @notice Thrown when attempting to remove an admin that does not exist.
error AdminNotSet();
/// @notice Thrown when attempting to set an appointee for a function that already has one.
error AppointeeAlreadySet();
/// @notice Thrown when attempting to interact with a non-existent appointee.
error AppointeeNotSet();
/// @notice Thrown when attempting to remove the last remaining admin.
error CannotHaveZeroAdmins();
/// @notice Thrown when attempting to set an admin that is already registered.
error AdminAlreadySet();
/// @notice Thrown when attempting to interact with an admin that is not in pending status.
error AdminNotPending();
/// @notice Thrown when attempting to add an admin that is already pending.
error AdminAlreadyPending();
}
interface IPermissionControllerEvents {
/// @notice Emitted when an appointee is set for an account to handle specific function calls.
event AppointeeSet(address indexed account, address indexed appointee, address target, bytes4 selector);
/// @notice Emitted when an appointee's permission to handle function calls for an account is revoked.
event AppointeeRemoved(address indexed account, address indexed appointee, address target, bytes4 selector);
/// @notice Emitted when an address is set as a pending admin for an account, requiring acceptance.
event PendingAdminAdded(address indexed account, address admin);
/// @notice Emitted when a pending admin status is removed for an account before acceptance.
event PendingAdminRemoved(address indexed account, address admin);
/// @notice Emitted when an address accepts and becomes an active admin for an account.
event AdminSet(address indexed account, address admin);
/// @notice Emitted when an admin's permissions are removed from an account.
event AdminRemoved(address indexed account, address admin);
}
interface IPermissionController is IPermissionControllerErrors, IPermissionControllerEvents, ISemVerMixin {
/**
* @notice Sets a pending admin for an account.
* @param account The account to set the pending admin for.
* @param admin The address to set as pending admin.
* @dev The pending admin must accept the role before becoming an active admin.
* @dev Multiple admins can be set for a single account.
*/
function addPendingAdmin(address account, address admin) external;
/**
* @notice Removes a pending admin from an account before they have accepted the role.
* @param account The account to remove the pending admin from.
* @param admin The pending admin address to remove.
* @dev Only an existing admin of the account can remove a pending admin.
*/
function removePendingAdmin(address account, address admin) external;
/**
* @notice Allows a pending admin to accept their admin role for an account.
* @param account The account to accept the admin role for.
* @dev Only addresses that were previously set as pending admins can accept the role.
*/
function acceptAdmin(
address account
) external;
/**
* @notice Removes an active admin from an account.
* @param account The account to remove the admin from.
* @param admin The admin address to remove.
* @dev Only an existing admin of the account can remove another admin.
* @dev Will revert if removing this admin would leave the account with zero admins.
*/
function removeAdmin(address account, address admin) external;
/**
* @notice Sets an appointee who can call specific functions on behalf of an account.
* @param account The account to set the appointee for.
* @param appointee The address to be given permission.
* @param target The contract address the appointee can interact with.
* @param selector The function selector the appointee can call.
* @dev Only an admin of the account can set appointees.
*/
function setAppointee(address account, address appointee, address target, bytes4 selector) external;
/**
* @notice Removes an appointee's permission to call a specific function.
* @param account The account to remove the appointee from.
* @param appointee The appointee address to remove.
* @param target The contract address to remove permissions for.
* @param selector The function selector to remove permissions for.
* @dev Only an admin of the account can remove appointees.
*/
function removeAppointee(address account, address appointee, address target, bytes4 selector) external;
/**
* @notice Checks if a given address is an admin of an account.
* @param account The account to check admin status for.
* @param caller The address to check.
* @dev If the account has no admins, returns true only if the caller is the account itself.
* @return Returns true if the caller is an admin, false otherwise.
*/
function isAdmin(address account, address caller) external view returns (bool);
/**
* @notice Checks if an address is currently a pending admin for an account.
* @param account The account to check pending admin status for.
* @param pendingAdmin The address to check.
* @return Returns true if the address is a pending admin, false otherwise.
*/
function isPendingAdmin(address account, address pendingAdmin) external view returns (bool);
/**
* @notice Retrieves all active admins for an account.
* @param account The account to get the admins for.
* @dev If the account has no admins, returns an array containing only the account address.
* @return An array of admin addresses.
*/
function getAdmins(
address account
) external view returns (address[] memory);
/**
* @notice Retrieves all pending admins for an account.
* @param account The account to get the pending admins for.
* @return An array of pending admin addresses.
*/
function getPendingAdmins(
address account
) external view returns (address[] memory);
/**
* @notice Checks if a caller has permission to call a specific function.
* @param account The account to check permissions for.
* @param caller The address attempting to make the call.
* @param target The contract address being called.
* @param selector The function selector being called.
* @dev Returns true if the caller is either an admin or an appointed caller.
* @dev Be mindful that upgrades to the contract may invalidate the appointee's permissions.
* This is only possible if a function's selector changes (e.g. if a function's parameters are modified).
* @return Returns true if the caller has permission, false otherwise.
*/
function canCall(address account, address caller, address target, bytes4 selector) external returns (bool);
/**
* @notice Retrieves all permissions granted to an appointee for a given account.
* @param account The account to check appointee permissions for.
* @param appointee The appointee address to check.
* @return Two arrays: target contract addresses and their corresponding function selectors.
*/
function getAppointeePermissions(
address account,
address appointee
) external returns (address[] memory, bytes4[] memory);
/**
* @notice Retrieves all appointees that can call a specific function for an account.
* @param account The account to get appointees for.
* @param target The contract address to check.
* @param selector The function selector to check.
* @dev Does not include admins in the returned list, even though they have calling permission.
* @return An array of appointee addresses.
*/
function getAppointees(address account, address target, bytes4 selector) external returns (address[] memory);
}// 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: 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);
}
}// 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 MathUpgradeable {
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.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will 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. Developers 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 set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will 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. Developers 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 set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will 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. Developers 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 set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will 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. Developers 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 set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./IStrategy.sol";
import "./IPauserRegistry.sol";
import "./ISignatureUtilsMixin.sol";
import "../libraries/SlashingLib.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(address initialOwner, 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 operators 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 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.
*/
function slashOperatorShares(
address operator,
IStrategy strategy,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) external;
/**
*
* 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.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();
}
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);
}
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 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);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import {OperatorSet} from "../libraries/OperatorSetLib.sol";
import "./IPauserRegistry.sol";
import "./IStrategy.sol";
import "./IAVSRegistrar.sol";
import "./ISemVerMixin.sol";
interface IAllocationManagerErrors {
/// Input Validation
/// @dev Thrown when `wadToSlash` is zero or greater than 1e18
error InvalidWadToSlash();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when the AVSRegistrar is not correctly configured to prevent an AVSRegistrar contract
/// from being used with the wrong AVS
error InvalidAVSRegistrar();
/// Caller
/// @dev Thrown when caller is not authorized to call a function.
error InvalidCaller();
/// Operator Status
/// @dev Thrown when an invalid operator is provided.
error InvalidOperator();
/// @dev Thrown when an invalid avs whose metadata is not registered is provided.
error NonexistentAVSMetadata();
/// @dev Thrown when an operator's allocation delay has yet to be set.
error UninitializedAllocationDelay();
/// @dev Thrown when attempting to slash an operator when they are not slashable.
error OperatorNotSlashable();
/// @dev Thrown when trying to add an operator to a set they are already a member of
error AlreadyMemberOfSet();
/// @dev Thrown when trying to slash/remove an operator from a set they are not a member of
error NotMemberOfSet();
/// Operator Set Status
/// @dev Thrown when an invalid operator set is provided.
error InvalidOperatorSet();
/// @dev Thrown when provided `strategies` are not in ascending order.
error StrategiesMustBeInAscendingOrder();
/// @dev Thrown when trying to add a strategy to an operator set that already contains it.
error StrategyAlreadyInOperatorSet();
/// @dev Thrown when a strategy is referenced that does not belong to an operator set.
error StrategyNotInOperatorSet();
/// Modifying Allocations
/// @dev Thrown when an operator attempts to set their allocation for an operatorSet to the same value
error SameMagnitude();
/// @dev Thrown when an allocation is attempted for a given operator when they have pending allocations or deallocations.
error ModificationAlreadyPending();
/// @dev Thrown when an allocation is attempted that exceeds a given operators total allocatable magnitude.
error InsufficientMagnitude();
}
interface IAllocationManagerTypes {
/**
* @notice Defines allocation information from a strategy to an operator set, for an operator
* @param currentMagnitude the current magnitude allocated from the strategy to the operator set
* @param pendingDiff a pending change in magnitude, if it exists (0 otherwise)
* @param effectBlock the block at which the pending magnitude diff will take effect
*/
struct Allocation {
uint64 currentMagnitude;
int128 pendingDiff;
uint32 effectBlock;
}
/**
* @notice Struct containing allocation delay metadata for a given operator.
* @param delay Current allocation delay
* @param isSet Whether the operator has initially set an allocation delay. Note that this could be false but the
* block.number >= effectBlock in which we consider their delay to be configured and active.
* @param pendingDelay The delay that will take effect after `effectBlock`
* @param effectBlock The block number after which a pending delay will take effect
*/
struct AllocationDelayInfo {
uint32 delay;
bool isSet;
uint32 pendingDelay;
uint32 effectBlock;
}
/**
* @notice Contains registration details for an operator pertaining to an operator set
* @param registered Whether the operator is currently registered for the operator set
* @param slashableUntil If the operator is not registered, they are still slashable until
* this block is reached.
*/
struct RegistrationStatus {
bool registered;
uint32 slashableUntil;
}
/**
* @notice Contains allocation info for a specific strategy
* @param maxMagnitude the maximum magnitude that can be allocated between all operator sets
* @param encumberedMagnitude the currently-allocated magnitude for the strategy
*/
struct StrategyInfo {
uint64 maxMagnitude;
uint64 encumberedMagnitude;
}
/**
* @notice Struct containing parameters to slashing
* @param operator the address to slash
* @param operatorSetId the ID of the operatorSet the operator is being slashed on behalf of
* @param strategies the set of strategies to slash
* @param wadsToSlash the parts in 1e18 to slash, this will be proportional to the operator's
* slashable stake allocation for the operatorSet
* @param description the description of the slashing provided by the AVS for legibility
*/
struct SlashingParams {
address operator;
uint32 operatorSetId;
IStrategy[] strategies;
uint256[] wadsToSlash;
string description;
}
/**
* @notice struct used to modify the allocation of slashable magnitude to an operator set
* @param operatorSet the operator set to modify the allocation for
* @param strategies the strategies to modify allocations for
* @param newMagnitudes the new magnitude to allocate for each strategy to this operator set
*/
struct AllocateParams {
OperatorSet operatorSet;
IStrategy[] strategies;
uint64[] newMagnitudes;
}
/**
* @notice Parameters used to register for an AVS's operator sets
* @param avs the AVS being registered for
* @param operatorSetIds the operator sets within the AVS to register for
* @param data extra data to be passed to the AVS to complete registration
*/
struct RegisterParams {
address avs;
uint32[] operatorSetIds;
bytes data;
}
/**
* @notice Parameters used to deregister from an AVS's operator sets
* @param operator the operator being deregistered
* @param avs the avs being deregistered from
* @param operatorSetIds the operator sets within the AVS being deregistered from
*/
struct DeregisterParams {
address operator;
address avs;
uint32[] operatorSetIds;
}
/**
* @notice Parameters used by an AVS to create new operator sets
* @param operatorSetId the id of the operator set to create
* @param strategies the strategies to add as slashable to the operator set
*/
struct CreateSetParams {
uint32 operatorSetId;
IStrategy[] strategies;
}
}
interface IAllocationManagerEvents is IAllocationManagerTypes {
/// @notice Emitted when operator updates their allocation delay.
event AllocationDelaySet(address operator, uint32 delay, uint32 effectBlock);
/// @notice Emitted when an operator's magnitude is updated for a given operatorSet and strategy
event AllocationUpdated(
address operator, OperatorSet operatorSet, IStrategy strategy, uint64 magnitude, uint32 effectBlock
);
/// @notice Emitted when operator's encumbered magnitude is updated for a given strategy
event EncumberedMagnitudeUpdated(address operator, IStrategy strategy, uint64 encumberedMagnitude);
/// @notice Emitted when an operator's max magnitude is updated for a given strategy
event MaxMagnitudeUpdated(address operator, IStrategy strategy, uint64 maxMagnitude);
/// @notice Emitted when an operator is slashed by an operator set for a strategy
/// `wadSlashed` is the proportion of the operator's total delegated stake that was slashed
event OperatorSlashed(
address operator, OperatorSet operatorSet, IStrategy[] strategies, uint256[] wadSlashed, string description
);
/// @notice Emitted when an AVS configures the address that will handle registration/deregistration
event AVSRegistrarSet(address avs, IAVSRegistrar registrar);
/// @notice Emitted when an AVS updates their metadata URI (Uniform Resource Identifier).
/// @dev The URI is never stored; it is simply emitted through an event for off-chain indexing.
event AVSMetadataURIUpdated(address indexed avs, string metadataURI);
/// @notice Emitted when an operator set is created by an AVS.
event OperatorSetCreated(OperatorSet operatorSet);
/// @notice Emitted when an operator is added to an operator set.
event OperatorAddedToOperatorSet(address indexed operator, OperatorSet operatorSet);
/// @notice Emitted when an operator is removed from an operator set.
event OperatorRemovedFromOperatorSet(address indexed operator, OperatorSet operatorSet);
/// @notice Emitted when a strategy is added to an operator set.
event StrategyAddedToOperatorSet(OperatorSet operatorSet, IStrategy strategy);
/// @notice Emitted when a strategy is removed from an operator set.
event StrategyRemovedFromOperatorSet(OperatorSet operatorSet, IStrategy strategy);
}
interface IAllocationManager is IAllocationManagerErrors, IAllocationManagerEvents, ISemVerMixin {
/**
* @dev Initializes the initial owner and paused status.
*/
function initialize(address initialOwner, uint256 initialPausedStatus) external;
/**
* @notice Called by an AVS to slash an operator in a given operator set. The operator must be registered
* and have slashable stake allocated to the operator set.
*
* @param avs The AVS address initiating the slash.
* @param params The slashing parameters, containing:
* - operator: The operator to slash.
* - operatorSetId: The ID of the operator set the operator is being slashed from.
* - strategies: Array of strategies to slash allocations from (must be in ascending order).
* - wadsToSlash: Array of proportions to slash from each strategy (must be between 0 and 1e18).
* - description: Description of why the operator was slashed.
*
* @dev For each strategy:
* 1. Reduces the operator's current allocation magnitude by wadToSlash proportion.
* 2. Reduces the strategy's max and encumbered magnitudes proportionally.
* 3. If there is a pending deallocation, reduces it proportionally.
* 4. Updates the operator's shares in the DelegationManager.
*
* @dev Small slashing amounts may not result in actual token burns due to
* rounding, which will result in small amounts of tokens locked in the contract
* rather than fully burning through the burn mechanism.
*/
function slashOperator(address avs, SlashingParams calldata params) external;
/**
* @notice Modifies the proportions of slashable stake allocated to an operator set from a list of strategies
* Note that deallocations remain slashable for DEALLOCATION_DELAY blocks therefore when they are cleared they may
* free up less allocatable magnitude than initially deallocated.
* @param operator the operator to modify allocations for
* @param params array of magnitude adjustments for one or more operator sets
* @dev Updates encumberedMagnitude for the updated strategies
*/
function modifyAllocations(address operator, AllocateParams[] calldata params) external;
/**
* @notice This function takes a list of strategies and for each strategy, removes from the deallocationQueue
* all clearable deallocations up to max `numToClear` number of deallocations, updating the encumberedMagnitude
* of the operator as needed.
*
* @param operator address to clear deallocations for
* @param strategies a list of strategies to clear deallocations for
* @param numToClear a list of number of pending deallocations to clear for each strategy
*
* @dev can be called permissionlessly by anyone
*/
function clearDeallocationQueue(
address operator,
IStrategy[] calldata strategies,
uint16[] calldata numToClear
) external;
/**
* @notice Allows an operator to register for one or more operator sets for an AVS. If the operator
* has any stake allocated to these operator sets, it immediately becomes slashable.
* @dev After registering within the ALM, this method calls the AVS Registrar's `IAVSRegistrar.
* registerOperator` method to complete registration. This call MUST succeed in order for
* registration to be successful.
*/
function registerForOperatorSets(address operator, RegisterParams calldata params) external;
/**
* @notice Allows an operator or AVS to deregister the operator from one or more of the AVS's operator sets.
* If the operator has any slashable stake allocated to the AVS, it remains slashable until the
* DEALLOCATION_DELAY has passed.
* @dev After deregistering within the ALM, this method calls the AVS Registrar's `IAVSRegistrar.
* deregisterOperator` method to complete deregistration. This call MUST succeed in order for
* deregistration to be successful.
*/
function deregisterFromOperatorSets(
DeregisterParams calldata params
) external;
/**
* @notice Called by the delegation manager OR an operator to set an operator's allocation delay.
* This is set when the operator first registers, and is the number of blocks between an operator
* allocating magnitude to an operator set, and the magnitude becoming slashable.
* @param operator The operator to set the delay on behalf of.
* @param delay the allocation delay in blocks
*/
function setAllocationDelay(address operator, uint32 delay) external;
/**
* @notice Called by an AVS to configure the address that is called when an operator registers
* or is deregistered from the AVS's operator sets. If not set (or set to 0), defaults
* to the AVS's address.
* @param registrar the new registrar address
*/
function setAVSRegistrar(address avs, IAVSRegistrar registrar) external;
/**
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
*
* @param metadataURI The URI for metadata associated with an AVS.
*
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
*/
function updateAVSMetadataURI(address avs, string calldata metadataURI) external;
/**
* @notice Allows an AVS to create new operator sets, defining strategies that the operator set uses
*/
function createOperatorSets(address avs, CreateSetParams[] calldata params) external;
/**
* @notice Allows an AVS to add strategies to an operator set
* @dev Strategies MUST NOT already exist in the operator set
* @param avs the avs to set strategies for
* @param operatorSetId the operator set to add strategies to
* @param strategies the strategies to add
*/
function addStrategiesToOperatorSet(address avs, uint32 operatorSetId, IStrategy[] calldata strategies) external;
/**
* @notice Allows an AVS to remove strategies from an operator set
* @dev Strategies MUST already exist in the operator set
* @param avs the avs to remove strategies for
* @param operatorSetId the operator set to remove strategies from
* @param strategies the strategies to remove
*/
function removeStrategiesFromOperatorSet(
address avs,
uint32 operatorSetId,
IStrategy[] calldata strategies
) external;
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice Returns the number of operator sets for the AVS
* @param avs the AVS to query
*/
function getOperatorSetCount(
address avs
) external view returns (uint256);
/**
* @notice Returns the list of operator sets the operator has current or pending allocations/deallocations in
* @param operator the operator to query
* @return the list of operator sets the operator has current or pending allocations/deallocations in
*/
function getAllocatedSets(
address operator
) external view returns (OperatorSet[] memory);
/**
* @notice Returns the list of strategies an operator has current or pending allocations/deallocations from
* given a specific operator set.
* @param operator the operator to query
* @param operatorSet the operator set to query
* @return the list of strategies
*/
function getAllocatedStrategies(
address operator,
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory);
/**
* @notice Returns the current/pending stake allocation an operator has from a strategy to an operator set
* @param operator the operator to query
* @param operatorSet the operator set to query
* @param strategy the strategy to query
* @return the current/pending stake allocation
*/
function getAllocation(
address operator,
OperatorSet memory operatorSet,
IStrategy strategy
) external view returns (Allocation memory);
/**
* @notice Returns the current/pending stake allocations for multiple operators from a strategy to an operator set
* @param operators the operators to query
* @param operatorSet the operator set to query
* @param strategy the strategy to query
* @return each operator's allocation
*/
function getAllocations(
address[] memory operators,
OperatorSet memory operatorSet,
IStrategy strategy
) external view returns (Allocation[] memory);
/**
* @notice Given a strategy, returns a list of operator sets and corresponding stake allocations.
* @dev Note that this returns a list of ALL operator sets the operator has allocations in. This means
* some of the returned allocations may be zero.
* @param operator the operator to query
* @param strategy the strategy to query
* @return the list of all operator sets the operator has allocations for
* @return the corresponding list of allocations from the specific `strategy`
*/
function getStrategyAllocations(
address operator,
IStrategy strategy
) external view returns (OperatorSet[] memory, Allocation[] memory);
/**
* @notice For a strategy, get the amount of magnitude that is allocated across one or more operator sets
* @param operator the operator to query
* @param strategy the strategy to get allocatable magnitude for
* @return currently allocated magnitude
*/
function getEncumberedMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice For a strategy, get the amount of magnitude not currently allocated to any operator set
* @param operator the operator to query
* @param strategy the strategy to get allocatable magnitude for
* @return magnitude available to be allocated to an operator set
*/
function getAllocatableMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategy
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategy the strategy to get the max magnitude for
* @return the max magnitude for the strategy
*/
function getMaxMagnitude(address operator, IStrategy strategy) external view returns (uint64);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategies
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategies the strategies to get the max magnitudes for
* @return the max magnitudes for each strategy
*/
function getMaxMagnitudes(
address operator,
IStrategy[] calldata strategies
) external view returns (uint64[] memory);
/**
* @notice Returns the maximum magnitudes each operator can allocate for the given strategy
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operators the operators to query
* @param strategy the strategy to get the max magnitudes for
* @return the max magnitudes for each operator
*/
function getMaxMagnitudes(
address[] calldata operators,
IStrategy strategy
) external view returns (uint64[] memory);
/**
* @notice Returns the maximum magnitude an operator can allocate for the given strategies
* at a given block number
* @dev The max magnitude of an operator starts at WAD (1e18), and is decreased anytime
* the operator is slashed. This value acts as a cap on the max magnitude of the operator.
* @param operator the operator to query
* @param strategies the strategies to get the max magnitudes for
* @param blockNumber the blockNumber at which to check the max magnitudes
* @return the max magnitudes for each strategy
*/
function getMaxMagnitudesAtBlock(
address operator,
IStrategy[] calldata strategies,
uint32 blockNumber
) external view returns (uint64[] memory);
/**
* @notice Returns the time in blocks between an operator allocating slashable magnitude
* and the magnitude becoming slashable. If the delay has not been set, `isSet` will be false.
* @dev The operator must have a configured delay before allocating magnitude
* @param operator The operator to query
* @return isSet Whether the operator has configured a delay
* @return delay The time in blocks between allocating magnitude and magnitude becoming slashable
*/
function getAllocationDelay(
address operator
) external view returns (bool isSet, uint32 delay);
/**
* @notice Returns a list of all operator sets the operator is registered for
* @param operator The operator address to query.
*/
function getRegisteredSets(
address operator
) external view returns (OperatorSet[] memory operatorSets);
/**
* @notice Returns whether the operator is registered for the operator set
* @param operator The operator to query
* @param operatorSet The operator set to query
*/
function isMemberOfOperatorSet(address operator, OperatorSet memory operatorSet) external view returns (bool);
/**
* @notice Returns whether the operator set exists
*/
function isOperatorSet(
OperatorSet memory operatorSet
) external view returns (bool);
/**
* @notice Returns all the operators registered to an operator set
* @param operatorSet The operatorSet to query.
*/
function getMembers(
OperatorSet memory operatorSet
) external view returns (address[] memory operators);
/**
* @notice Returns the number of operators registered to an operatorSet.
* @param operatorSet The operatorSet to get the member count for
*/
function getMemberCount(
OperatorSet memory operatorSet
) external view returns (uint256);
/**
* @notice Returns the address that handles registration/deregistration for the AVS
* If not set, defaults to the input address (`avs`)
*/
function getAVSRegistrar(
address avs
) external view returns (IAVSRegistrar);
/**
* @notice Returns an array of strategies in the operatorSet.
* @param operatorSet The operatorSet to query.
*/
function getStrategiesInOperatorSet(
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory strategies);
/**
* @notice Returns the minimum amount of stake that will be slashable as of some future block,
* according to each operator's allocation from each strategy to the operator set. Note that this function
* will return 0 for the slashable stake if the operator is not slashable at the time of the call.
* @dev This method queries actual delegated stakes in the DelegationManager and applies
* each operator's allocation to the stake to produce the slashable stake each allocation
* represents. This method does not consider slashable stake in the withdrawal queue even though there could be
* slashable stake in the queue.
* @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude
* diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true
* minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number
* @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future,
* or the values returned from this method may not be accurate due to deallocations.
* @param operatorSet the operator set to query
* @param operators the list of operators whose slashable stakes will be returned
* @param strategies the strategies that each slashable stake corresponds to
* @param futureBlock the block at which to get allocation information. Should be a future block.
*/
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns the current allocated stake, irrespective of the operator's slashable status for the operatorSet.
* @param operatorSet the operator set to query
* @param operators the operators to query
* @param strategies the strategies to query
*/
function getAllocatedStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns whether an operator is slashable by an operator set.
* This returns true if the operator is registered or their slashableUntil block has not passed.
* This is because even when operators are deregistered, they still remain slashable for a period of time.
* @param operator the operator to check slashability for
* @param operatorSet the operator set to check slashability for
*/
function isOperatorSlashable(address operator, OperatorSet memory operatorSet) external view returns (bool);
}// 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: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../StringsUpgradeable.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSAUpgradeable {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", StringsUpgradeable.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271Upgradeable {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// 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., "v1.1.1")
function version() 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: 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.
*/
function withdraw(address recipient, IERC20 token, uint256 amountShares) external;
/**
* @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: 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: 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 "./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();
}
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 are increased
event BurnableSharesIncreased(IStrategy strategy, uint256 shares);
/// @notice Emitted when shares are burned
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 Burns 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.
*/
function burnShares(
IStrategy strategy
) external;
/**
* @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
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
*
* 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);
}// 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();
/// 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();
}
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
}
struct ValidatorInfo {
// index of the validator in the beacon chain
uint64 validatorIndex;
// amount of beacon chain ETH restaked on EigenLayer in gwei
uint64 restakedBalanceGwei;
//timestamp of the validator's most recent balance update
uint64 lastCheckpointedAt;
// status of the validator
VALIDATOR_STATUS status;
}
struct Checkpoint {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int64 balanceDeltasGwei;
uint64 prevBeaconBalanceGwei;
}
}
interface IEigenPodEvents is IEigenPodTypes {
/// @notice Emitted when an ETH validator stakes via this eigenPod
event EigenPodStaked(bytes pubkey);
/// @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(uint40 validatorIndex);
/// @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(uint40 validatorIndex, 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, uint40 indexed validatorIndex);
/// @notice Emitted when a validaor is proven to have 0 balance at a given checkpoint
event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, uint40 indexed validatorIndex);
}
/**
* @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.
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;
/**
* @notice Transfers `amountWei` in ether from this contract to the specified `recipient` address
* @notice Called by EigenPodManager to withdrawBeaconChainETH that has been added to the EigenPod's balance due to a withdrawal from the beacon chain.
* @dev The podOwner must have already proved sufficient withdrawals, so that this pod's `restakedExecutionLayerGwei` exceeds the
* `amountWei` input (when converted to GWEI).
* @dev Reverts if `amountWei` is not a whole Gwei amount
*/
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 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 `startCheckpoint` and `verifyWithdrawalCredentials`.
/// @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 `startCheckpoint` and `verifyWithdrawalCredentials`
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 the amount of execution layer ETH in this contract that is staked in EigenLayer (i.e. withdrawn from beaconchain but not EigenLayer),
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 This returns the status of a given validator
function validatorStatus(
bytes32 pubkeyHash
) external view returns (VALIDATOR_STATUS);
/// @notice This returns the status of 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
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);
}// 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";
/**
* @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 shares for a given Strategy. This is called by the DelegationManager
* when an operator is slashed in EigenLayer.
* @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 increaseBurnableShares(IStrategy strategy, uint256 addedSharesToBurn) external;
}// 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;
interface IAVSRegistrar {
/**
* @notice Called by the AllocationManager when an operator wants to register
* for one or more operator sets. This method should revert if registration
* is unsuccessful.
* @param operator the registering operator
* @param avs the AVS the operator is registering for. This should be the same as IAVSRegistrar.avs()
* @param operatorSetIds the list of operator set ids being registered for
* @param data arbitrary data the operator can provide as part of registration
*/
function registerOperator(
address operator,
address avs,
uint32[] calldata operatorSetIds,
bytes calldata data
) external;
/**
* @notice Called by the AllocationManager when an operator is deregistered from
* one or more operator sets. If this method reverts, it is ignored.
* @param operator the deregistering operator
* @param avs the AVS the operator is deregistering from. This should be the same as IAVSRegistrar.avs()
* @param operatorSetIds the list of operator set ids being deregistered from
*/
function deregisterOperator(address operator, address avs, uint32[] calldata operatorSetIds) external;
/**
* @notice Returns true if the AVS is supported by the registrar
* @param avs the AVS to check
* @return true if the AVS is supported, false otherwise
*/
function supportsAVS(
address avs
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// 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: 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 BEACON_STATE_TREE_HEIGHT = 5;
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 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(
bytes32 beaconStateRoot,
bytes32[] calldata validatorFields,
bytes calldata validatorFieldsProof,
uint40 validatorIndex
) internal view {
require(validatorFields.length == VALIDATOR_FIELDS_LENGTH, InvalidValidatorFieldsLength());
/// 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) + BEACON_STATE_TREE_HEIGHT),
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(bytes32 beaconBlockRoot, BalanceContainerProof calldata proof) internal view {
require(
proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + BEACON_STATE_TREE_HEIGHT),
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 << (BEACON_STATE_TREE_HEIGHT)) | 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]);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// 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);
}
}{
"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": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract IEigenPodManager","name":"_eigenPodManager","type":"address"},{"internalType":"contract IAllocationManager","name":"_allocationManager","type":"address"},{"internalType":"contract IPauserRegistry","name":"_pauserRegistry","type":"address"},{"internalType":"contract IPermissionController","name":"_permissionController","type":"address"},{"internalType":"uint32","name":"_MIN_WITHDRAWAL_DELAY","type":"uint32"},{"internalType":"string","name":"_version","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ActivelyDelegated","type":"error"},{"inputs":[],"name":"CallerCannotUndelegate","type":"error"},{"inputs":[],"name":"CurrentlyPaused","type":"error"},{"inputs":[],"name":"FullySlashed","type":"error"},{"inputs":[],"name":"InputAddressZero","type":"error"},{"inputs":[],"name":"InputArrayLengthMismatch","type":"error"},{"inputs":[],"name":"InputArrayLengthZero","type":"error"},{"inputs":[],"name":"InvalidNewPausedStatus","type":"error"},{"inputs":[],"name":"InvalidPermissions","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSnapshotOrdering","type":"error"},{"inputs":[],"name":"NotActivelyDelegated","type":"error"},{"inputs":[],"name":"OnlyAllocationManager","type":"error"},{"inputs":[],"name":"OnlyEigenPodManager","type":"error"},{"inputs":[],"name":"OnlyPauser","type":"error"},{"inputs":[],"name":"OnlyStrategyManagerOrEigenPodManager","type":"error"},{"inputs":[],"name":"OnlyUnpauser","type":"error"},{"inputs":[],"name":"OperatorNotRegistered","type":"error"},{"inputs":[],"name":"OperatorsCannotUndelegate","type":"error"},{"inputs":[],"name":"SaltSpent","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"WithdrawalDelayNotElapsed","type":"error"},{"inputs":[],"name":"WithdrawalNotQueued","type":"error"},{"inputs":[],"name":"WithdrawerNotCaller","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"newDelegationApprover","type":"address"}],"name":"DelegationApproverUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"newDepositScalingFactor","type":"uint256"}],"name":"DepositScalingFactorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"OperatorMetadataURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"delegationApprover","type":"address"}],"name":"OperatorRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"OperatorSharesDecreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"OperatorSharesIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"contract IStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalSlashedShares","type":"uint256"}],"name":"OperatorSharesSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"SlashingWithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"indexed":false,"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"},{"indexed":false,"internalType":"uint256[]","name":"sharesToWithdraw","type":"uint256[]"}],"name":"SlashingWithdrawalQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerDelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerForceUndelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"StakerUndelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DELEGATION_APPROVAL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allocationManager","outputs":[{"internalType":"contract IAllocationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beaconChainETHStrategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"approver","type":"address"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"name":"calculateDelegationApprovalDigestHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"calculateWithdrawalRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"bool","name":"receiveAsTokens","type":"bool"}],"name":"completeQueuedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"internalType":"contract IERC20[][]","name":"tokens","type":"address[][]"},{"internalType":"bool[]","name":"receiveAsTokens","type":"bool[]"}],"name":"completeQueuedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"withdrawableShares","type":"uint256[]"}],"name":"convertToDepositShares","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"cumulativeWithdrawalsQueued","outputs":[{"internalType":"uint256","name":"totalQueued","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"uint256","name":"curDepositShares","type":"uint256"},{"internalType":"uint64","name":"beaconChainSlashingFactorDecrease","type":"uint64"}],"name":"decreaseDelegatedShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtilsMixinTypes.SignatureWithExpiry","name":"approverSignatureAndExpiry","type":"tuple"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"}],"name":"delegateTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"delegatedTo","outputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"delegationApprover","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegationApprover","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"delegationApproverSaltIsSpent","outputs":[{"internalType":"bool","name":"spent","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"}],"name":"depositScalingFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eigenPodManager","outputs":[{"internalType":"contract IEigenPodManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getDepositedShares","outputs":[{"internalType":"contract IStrategy[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"}],"name":"getOperatorShares","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"operators","type":"address[]"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"}],"name":"getOperatorsShares","outputs":[{"internalType":"uint256[][]","name":"","type":"uint256[][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"getQueuedWithdrawal","outputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"},{"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getQueuedWithdrawalRoots","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getQueuedWithdrawals","outputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal[]","name":"withdrawals","type":"tuple[]"},{"internalType":"uint256[][]","name":"shares","type":"uint256[][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"}],"name":"getSlashableSharesInQueue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"}],"name":"getWithdrawableShares","outputs":[{"internalType":"uint256[]","name":"withdrawableShares","type":"uint256[]"},{"internalType":"uint256[]","name":"depositShares","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"prevDepositShares","type":"uint256"},{"internalType":"uint256","name":"addedShares","type":"uint256"}],"name":"increaseDelegatedShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"uint256","name":"initialPausedStatus","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"isDelegated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minWithdrawalDelayBlocks","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"newDelegationApprover","type":"address"}],"name":"modifyOperatorDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"}],"name":"operatorShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauseAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"pendingWithdrawals","outputs":[{"internalType":"bool","name":"pending","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"permissionController","outputs":[{"internalType":"contract IPermissionController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"depositShares","type":"uint256[]"},{"internalType":"address","name":"__deprecated_withdrawer","type":"address"}],"internalType":"struct IDelegationManagerTypes.QueuedWithdrawalParams[]","name":"params","type":"tuple[]"}],"name":"queueWithdrawals","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"}],"name":"queuedWithdrawals","outputs":[{"components":[{"internalType":"address","name":"staker","type":"address"},{"internalType":"address","name":"delegatedTo","type":"address"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"internalType":"uint256[]","name":"scaledShares","type":"uint256[]"}],"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct ISignatureUtilsMixinTypes.SignatureWithExpiry","name":"newOperatorApproverSig","type":"tuple"},{"internalType":"bytes32","name":"approverSalt","type":"bytes32"}],"name":"redelegate","outputs":[{"internalType":"bytes32[]","name":"withdrawalRoots","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initDelegationApprover","type":"address"},{"internalType":"uint32","name":"allocationDelay","type":"uint32"},{"internalType":"string","name":"metadataURI","type":"string"}],"name":"registerAsOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint64","name":"prevMaxMagnitude","type":"uint64"},{"internalType":"uint64","name":"newMaxMagnitude","type":"uint64"}],"name":"slashOperatorShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"undelegate","outputs":[{"internalType":"bytes32[]","name":"withdrawalRoots","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPausedStatus","type":"uint256"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"string","name":"metadataURI","type":"string"}],"name":"updateOperatorMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610160604052348015610010575f5ffd5b506040516162ad3803806162ad83398101604081905261002f916101d9565b808084898989878a6001600160a01b03811661005e576040516339b190bb60e11b815260040160405180910390fd5b6001600160a01b0390811660805293841660a05291831660c052821660e05263ffffffff16610100521661012052610095816100b0565b61014052506100a490506100f6565b50505050505050610364565b5f5f829050601f815111156100e3578260405163305a27a960e01b81526004016100da9190610309565b60405180910390fd5b80516100ee8261033e565b179392505050565b5f54610100900460ff161561015d5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b60648201526084016100da565b5f5460ff908116146101ac575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146101c2575f5ffd5b50565b634e487b7160e01b5f52604160045260245ffd5b5f5f5f5f5f5f5f60e0888a0312156101ef575f5ffd5b87516101fa816101ae565b602089015190975061020b816101ae565b604089015190965061021c816101ae565b606089015190955061022d816101ae565b608089015190945061023e816101ae565b60a089015190935063ffffffff81168114610257575f5ffd5b60c08901519092506001600160401b03811115610272575f5ffd5b88015f601f82018b13610283575f5ffd5b81516001600160401b0381111561029c5761029c6101c5565b604051601f8201601f19908116603f011681016001600160401b03811182821017156102ca576102ca6101c5565b6040528181528382016020018d10156102e1575f5ffd5b8160208501602083015e5f602083830101528092508094505050505092959891949750929550565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b8051602080830151919081101561035e575f198160200360031b1b821691505b50919050565b60805160a05160c05160e051610100516101205161014051615e5061045d5f395f8181611112015261412c01525f8181610460015261340b01525f818161076a0152818161361b0152818161375d0152613a4001525f81816107ba01528181610e2701528181610fea0152818161136b01528181611584015281816119e6015281816127a0015261435601525f818161048701528181610f68015281816114e3015281816117570152818161300c015281816131ed01526138a301525f81816103bd01528181610f36015281816116ab015261387d01525f818161063801528181610bb70152818161115001526125960152615e505ff3fe608060405234801561000f575f5ffd5b50600436106102ff575f3560e01c8063715018a611610195578063bfae3fd2116100e4578063e4cc3f901161009e578063f2fde38b11610079578063f2fde38b14610848578063f698da251461085b578063fabc1cbc14610863578063fd8aa88d14610876575f5ffd5b8063e4cc3f9014610802578063eea9064b14610815578063f0e0e67614610828575f5ffd5b8063bfae3fd21461074d578063c448feb814610760578063c978f7ac14610794578063ca8aa7c7146107b5578063cd6dc687146107dc578063da8be864146107ef575f5ffd5b80639104c3191161014f578063a17884841161012a578063a1788484146106cc578063a33a3433146106eb578063b7f06ebe146106fe578063bb45fef214610720575f5ffd5b80639104c3191461067e5780639435bb431461069957806399f5371b146106ac575f5ffd5b8063715018a6146105ee578063778e55f3146105f657806378296ec514610620578063886f1195146106335780638da5cb5b1461065a578063900413471461066b575f5ffd5b806354fd4d50116102515780635dd685791161020b57806365da1264116101e657806365da12641461057f57806366d5ba93146105a75780636d70f7ae146105c85780636e174448146105db575f5ffd5b80635dd6857914610538578063601bb36f1461055957806360a0d1ce1461056c575f5ffd5b806354fd4d50146104bc578063595c6a67146104d1578063597b36da146104d95780635ac86ab7146104ec5780635c975abb1461050f5780635d975e8814610517575f5ffd5b806339b70e38116102bc5780633e28391d116102975780633e28391d146104385780634657e26a1461045b5780634665bcda1461048257806354b7c96c146104a9575f5ffd5b806339b70e38146103b85780633c651cf2146103f75780633cdeb5e01461040a575f5ffd5b806304a4f979146103035780630b9f487a1461033d5780630dd8dd0214610350578063136439dd1461037057806325df922e146103855780632aa6d888146103a5575b5f5ffd5b61032a7f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad81565b6040519081526020015b60405180910390f35b61032a61034b366004614d3f565b610889565b61036361035e366004614dd6565b610911565b6040516103349190614e14565b61038361037e366004614e4b565b610ba2565b005b610398610393366004614fe0565b610c77565b604051610334919061508e565b6103836103b33660046150f0565b610dd7565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610334565b61038361040536600461514e565b610f2b565b6103df610418366004615191565b6001600160a01b039081165f908152609960205260409020600101541690565b61044b610446366004615191565b61107e565b6040519015158152602001610334565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6103836104b73660046151ac565b61109d565b6104c461110b565b6040516103349190615211565b61038361113b565b61032a6104e73660046152df565b6111ea565b61044b6104fa366004615310565b606654600160ff9092169190911b9081161490565b60665461032a565b61052a610525366004614e4b565b611219565b6040516103349291906153e7565b61054b610546366004615191565b611236565b604051610334929190615459565b6103836105673660046154da565b611360565b61038361057a366004615533565b6114d8565b6103df61058d366004615191565b609a6020525f90815260409020546001600160a01b031681565b6105ba6105b5366004615191565b611683565b604051610334929190615572565b61044b6105d6366004615191565b611983565b61032a6105e93660046151ac565b6119bb565b610383611a65565b61032a6106043660046151ac565b609860209081525f928352604080842090915290825290205481565b61038361062e366004615584565b611a76565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6033546001600160a01b03166103df565b6103986106793660046155d4565b611b0c565b6103df73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b6103836106a7366004615620565b611be2565b6106bf6106ba366004614e4b565b611cbb565b60405161033491906156bc565b61032a6106da366004615191565b609f6020525f908152604090205481565b6103636106f93660046156ce565b611dd7565b61044b61070c366004614e4b565b609e6020525f908152604090205460ff1681565b61044b61072e3660046157b5565b609c60209081525f928352604080842090915290825290205460ff1681565b61032a61075b3660046151ac565b611def565b60405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610334565b6107a76107a23660046155d4565b611e2b565b6040516103349291906157df565b6103df7f000000000000000000000000000000000000000000000000000000000000000081565b6103836107ea3660046157b5565b6120b8565b6103636107fd366004615191565b6121d3565b6103836108103660046157fe565b6122fc565b6103836108233660046156ce565b612352565b61083b610836366004615871565b6123bd565b604051610334919061591e565b610383610856366004615191565b612462565b61032a6124db565b610383610871366004614e4b565b612594565b610363610884366004615191565b6126ab565b604080517f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad60208201526001600160a01b03808616928201929092528187166060820152908516608082015260a0810183905260c081018290525f906109079060e001604051602081830303815290604052805190602001206126ce565b9695505050505050565b60665460609060019060029081160361093d5760405163840a48d560e01b815260040160405180910390fd5b6109456126fc565b5f836001600160401b0381111561095e5761095e614e62565b604051908082528060200260200182016040528015610987578160200160208202803683370190505b50335f908152609a60205260408120549192506001600160a01b03909116905b85811015610b93578686828181106109c1576109c1615930565b90506020028101906109d39190615944565b6109e1906020810190615962565b90508787838181106109f5576109f5615930565b9050602002810190610a079190615944565b610a119080615962565b905014610a31576040516343714afd60e01b815260040160405180910390fd5b5f610a9b33848a8a86818110610a4957610a49615930565b9050602002810190610a5b9190615944565b610a659080615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061275592505050565b9050610b6d33848a8a86818110610ab457610ab4615930565b9050602002810190610ac69190615944565b610ad09080615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508e92508d9150889050818110610b1557610b15615930565b9050602002810190610b279190615944565b610b35906020810190615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508892506128a7915050565b848381518110610b7f57610b7f615930565b6020908102919091010152506001016109a7565b5050600160c955949350505050565b60405163237dfb4760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610c04573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2891906159a7565b610c4557604051631d77d47760e21b815260040160405180910390fd5b6066548181168114610c6a5760405163c61dca5d60e01b815260040160405180910390fd5b610c7382612e42565b5050565b6001600160a01b038084165f908152609a60205260408120546060921690610ca0868387612755565b90505f85516001600160401b03811115610cbc57610cbc614e62565b604051908082528060200260200182016040528015610ce5578160200160208202803683370190505b5090505f5b8651811015610dca576001600160a01b0388165f90815260a260205260408120885182908a9085908110610d2057610d20615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f820154815250509050610da4878381518110610d7257610d72615930565b6020026020010151858481518110610d8c57610d8c615930565b602002602001015183612e7f9092919063ffffffff16565b838381518110610db657610db6615930565b602090810291909101015250600101610cea565b50925050505b9392505050565b610ddf6126fc565b610de83361107e565b15610e0657604051633bf2b50360e11b815260040160405180910390fd5b604051632b6241f360e11b815233600482015263ffffffff841660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906356c483e6906044015f604051808303815f87803b158015610e70575f5ffd5b505af1158015610e82573d5f5f3e3d5ffd5b50505050610e903385612e9d565b610e9a3333612eff565b6040516001600160a01b038516815233907fa453db612af59e5521d6ab9284dc3e2d06af286eb1b1b7b771fce4716c19f2c19060200160405180910390a2336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908383604051610f139291906159c2565b60405180910390a2610f25600160c955565b50505050565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f8a5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b610fa75760405163045206a560e21b815260040160405180910390fd5b610faf6126fc565b6001600160a01b038481165f908152609a602052604080822054905163152667d960e31b8152908316600482018190528684166024830152927f0000000000000000000000000000000000000000000000000000000000000000169063a9333ec890604401602060405180830381865afa15801561102f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061105391906159f0565b90505f6110618787846131a6565b9050611071838888888886613288565b505050610f25600160c955565b6001600160a01b039081165f908152609a602052604090205416151590565b816110a7816133cd565b6110c45760405163932d94f760e01b815260040160405180910390fd5b6110cc6126fc565b6110d583611983565b6110f2576040516325ec6c1f60e01b815260040160405180910390fd5b6110fc8383612e9d565b611106600160c955565b505050565b60606111367f0000000000000000000000000000000000000000000000000000000000000000613477565b905090565b60405163237dfb4760e11b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906346fbf68e90602401602060405180830381865afa15801561119d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c191906159a7565b6111de57604051631d77d47760e21b815260040160405180910390fd5b6111e85f19612e42565b565b5f816040516020016111fc91906156bc565b604051602081830303815290604052805190602001209050919050565b611221614c00565b606061122c836134b4565b9094909350915050565b6060805f611243846126ab565b8051909150806001600160401b0381111561126057611260614e62565b60405190808252806020026020018201604052801561129957816020015b611286614c00565b81526020019060019003908161127e5790505b509350806001600160401b038111156112b4576112b4614e62565b6040519080825280602002602001820160405280156112e757816020015b60608152602001906001900390816112d25790505b5092505f5b818110156113585761131683828151811061130957611309615930565b60200260200101516134b4565b86838151811061132857611328615930565b6020026020010186848151811061134157611341615930565b6020908102919091010191909152526001016112ec565b505050915091565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146113a9576040516323d871a560e01b815260040160405180910390fd5b6113b16126fc565b6001600160a01b038085165f9081526098602090815260408083209387168352929052908120546113ef906001600160401b03808616908516613707565b90505f6113fe8686868661371f565b90505f61140b8284615a1f565b9050611419875f88866137dc565b604080516001600160a01b038881168252602082018490528916917fdd611f4ef63f4385f1756c86ce1f1f389a9013ba6fa07daba8528291bc2d3c30910160405180910390a25f61146987613856565b60405163debe1eab60e01b81526001600160a01b038981166004830152602482018590529192509082169063debe1eab906044015f604051808303815f87803b1580156114b4575f5ffd5b505af11580156114c6573d5f5f3e3d5ffd5b5050505050505050610f25600160c955565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461152157604051633213a66160e21b815260040160405180910390fd5b6115296126fc565b6115328361107e565b156110fc576001600160a01b038381165f908152609a602052604080822054905163152667d960e31b81529083166004820181905273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06024830152927f0000000000000000000000000000000000000000000000000000000000000000169063a9333ec890604401602060405180830381865afa1580156115c9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ed91906159f0565b6001600160a01b0386165f90815260a26020908152604080832073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac08452825280832081519283019091525481529192506116538661164b6001600160401b038087169089166138c8565b8491906138dc565b9050611675848873beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0846137dc565b50505050611106600160c955565b6040516394f649dd60e01b81526001600160a01b03828116600483015260609182915f9182917f000000000000000000000000000000000000000000000000000000000000000016906394f649dd906024015f60405180830381865afa1580156116ef573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117169190810190615a8d565b60405163fe243a1760e01b81526001600160a01b03888116600483015273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac060248301529294509092505f917f0000000000000000000000000000000000000000000000000000000000000000169063fe243a1790604401602060405180830381865afa15801561179c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c09190615b48565b9050805f036117d457509094909350915050565b5f835160016117e39190615a1f565b6001600160401b038111156117fa576117fa614e62565b604051908082528060200260200182016040528015611823578160200160208202803683370190505b5090505f845160016118359190615a1f565b6001600160401b0381111561184c5761184c614e62565b604051908082528060200260200182016040528015611875578160200160208202803683370190505b50905073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0828651815181106118a0576118a0615930565b60200260200101906001600160a01b031690816001600160a01b03168152505082818651815181106118d4576118d4615930565b60209081029190910101525f5b8551811015611975578581815181106118fc576118fc615930565b602002602001015183828151811061191657611916615930565b60200260200101906001600160a01b031690816001600160a01b03168152505084818151811061194857611948615930565b602002602001015182828151811061196257611962615930565b60209081029190910101526001016118e1565b509097909650945050505050565b5f6001600160a01b038216158015906119b557506001600160a01b038083165f818152609a6020526040902054909116145b92915050565b60405163152667d960e31b81526001600160a01b03838116600483015282811660248301525f9182917f0000000000000000000000000000000000000000000000000000000000000000169063a9333ec890604401602060405180830381865afa158015611a2b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a4f91906159f0565b9050611a5d8484835f61371f565b949350505050565b611a6d6138fa565b6111e85f613954565b82611a80816133cd565b611a9d5760405163932d94f760e01b815260040160405180910390fd5b611aa684611983565b611ac3576040516325ec6c1f60e01b815260040160405180910390fd5b836001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908484604051611afe9291906159c2565b60405180910390a250505050565b60605f82516001600160401b03811115611b2857611b28614e62565b604051908082528060200260200182016040528015611b51578160200160208202803683370190505b5090505f5b8351811015611bda576001600160a01b0385165f9081526098602052604081208551909190869084908110611b8d57611b8d615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054828281518110611bc757611bc7615930565b6020908102919091010152600101611b56565b509392505050565b606654600290600490811603611c0b5760405163840a48d560e01b815260040160405180910390fd5b611c136126fc565b855f5b81811015611ca657611c9e898983818110611c3357611c33615930565b9050602002810190611c459190615b5f565b611c4e90615b73565b888884818110611c6057611c60615930565b9050602002810190611c729190615962565b888886818110611c8457611c84615930565b9050602002016020810190611c999190615b7e565b6139a5565b600101611c16565b5050611cb2600160c955565b50505050505050565b611cc3614c00565b5f82815260a46020908152604091829020825160e08101845281546001600160a01b03908116825260018301548116828501526002830154168185015260038201546060820152600482015463ffffffff1660808201526005820180548551818602810186019096528086529194929360a08601939290830182828015611d7157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611d53575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020018280548015611dc757602002820191905f5260205f20905b815481526020019060010190808311611db3575b5050505050815250509050919050565b6060611de2336121d3565b9050610dd0848484612352565b6001600160a01b038083165f90815260a260209081526040808320938516835292815282822083519182019093529154825290610dd090613de7565b60608082516001600160401b03811115611e4757611e47614e62565b604051908082528060200260200182016040528015611e70578160200160208202803683370190505b50915082516001600160401b03811115611e8c57611e8c614e62565b604051908082528060200260200182016040528015611eb5578160200160208202803683370190505b506001600160a01b038086165f908152609a6020526040812054929350911690611ee0868387612755565b90505f5b85518110156120ad575f611f10878381518110611f0357611f03615930565b6020026020010151613856565b9050806001600160a01b031663fe243a1789898581518110611f3457611f34615930565b60200260200101516040518363ffffffff1660e01b8152600401611f6e9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611f89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fad9190615b48565b858381518110611fbf57611fbf615930565b6020026020010181815250505f60a25f8a6001600160a01b03166001600160a01b031681526020019081526020015f205f89858151811061200257612002615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f82015481525050905061208686848151811061205457612054615930565b602002602001015185858151811061206e5761206e615930565b6020026020010151836138dc9092919063ffffffff16565b87848151811061209857612098615930565b60209081029190910101525050600101611ee4565b5050505b9250929050565b5f54610100900460ff16158080156120d657505f54600160ff909116105b806120ef5750303b1580156120ef57505f5460ff166001145b6121575760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015612178575f805461ff0019166101001790555b61218182612e42565b61218a83613954565b8015611106575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b60606121dd6126fc565b6121e68261107e565b6122035760405163a5c7c44560e01b815260040160405180910390fd5b61220c82611983565b1561222a576040516311ca333560e31b815260040160405180910390fd5b336001600160a01b038316146122e2576001600160a01b038083165f908152609a60205260409020541661225d816133cd565b8061228357506001600160a01b038181165f908152609960205260409020600101541633145b6122a057604051631e499a2360e11b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03167ff0eddf07e6ea14f388b47e1e94a0f464ecbd9eed4171130e0fc0e99fb4030a8a60405160405180910390a3505b6122eb82613e06565b90506122f7600160c955565b919050565b6066546002906004908116036123255760405163840a48d560e01b815260040160405180910390fd5b61232d6126fc565b61234161233986615b73565b8585856139a5565b61234b600160c955565b5050505050565b61235a6126fc565b6123633361107e565b1561238157604051633bf2b50360e11b815260040160405180910390fd5b61238a83611983565b6123a7576040516325ec6c1f60e01b815260040160405180910390fd5b6123b333848484614065565b6110fc3384612eff565b60605f83516001600160401b038111156123d9576123d9614e62565b60405190808252806020026020018201604052801561240c57816020015b60608152602001906001900390816123f75790505b5090505f5b8451811015611bda5761243d85828151811061242f5761242f615930565b602002602001015185611b0c565b82828151811061244f5761244f615930565b6020908102919091010152600101612411565b61246a6138fa565b6001600160a01b0381166124cf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161214e565b6124d881613954565b50565b60408051808201909152600a81526922b4b3b2b72630bcb2b960b11b6020909101525f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea612548614124565b805160209182012060408051928301949094529281019190915260608101919091524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126149190615b99565b6001600160a01b0316336001600160a01b0316146126455760405163794821ff60e01b815260040160405180910390fd5b6066548019821981161461266c5760405163c61dca5d60e01b815260040160405180910390fd5b606682905560405182815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020015b60405180910390a25050565b6001600160a01b0381165f90815260a3602052604090206060906119b5906141c0565b5f6126d76124db565b60405161190160f01b60208201526022810191909152604281018390526062016111fc565b600260c9540361274e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161214e565b600260c955565b60605f82516001600160401b0381111561277157612771614e62565b60405190808252806020026020018201604052801561279a578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663547afb8786866040518363ffffffff1660e01b81526004016127ec929190615bb4565b5f60405180830381865afa158015612806573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261282d9190810190615bd7565b90505f5b845181101561289c576128778786838151811061285057612850615930565b602002602001015184848151811061286a5761286a615930565b60200260200101516131a6565b83828151811061288957612889615930565b6020908102919091010152600101612831565b509095945050505050565b5f6001600160a01b0386166128cf576040516339b190bb60e11b815260040160405180910390fd5b83515f036128f05760405163796cc52560e01b815260040160405180910390fd5b5f84516001600160401b0381111561290a5761290a614e62565b604051908082528060200260200182016040528015612933578160200160208202803683370190505b5090505f85516001600160401b0381111561295057612950614e62565b604051908082528060200260200182016040528015612979578160200160208202803683370190505b5090505f5b8651811015612c75575f61299d888381518110611f0357611f03615930565b90505f60a25f8c6001600160a01b03166001600160a01b031681526020019081526020015f205f8a85815181106129d6576129d6615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f209050612a4f888481518110612a1457612a14615930565b6020026020010151888581518110612a2e57612a2e615930565b602090810291909101810151604080519283019052845482529091906138dc565b848481518110612a6157612a61615930565b602002602001018181525050612aa0888481518110612a8257612a82615930565b602090810291909101810151604080519283019052835482526141cc565b858481518110612ab257612ab2615930565b60209081029190910101526001600160a01b038a1615612b4757612b098a8a8581518110612ae257612ae2615930565b6020026020010151878681518110612afc57612afc615930565b60200260200101516141e0565b612b478a8c8b8681518110612b2057612b20615930565b6020026020010151878781518110612b3a57612b3a615930565b60200260200101516137dc565b5f826001600160a01b031663724af4238d8c8781518110612b6a57612b6a615930565b60200260200101518c8881518110612b8457612b84615930565b60200260200101516040518463ffffffff1660e01b8152600401612baa93929190615c66565b6020604051808303815f875af1158015612bc6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bea9190615b48565b9050805f03612c67575f82557f8be932bac54561f27260f95463d9b8ab37e06b2842e5ee2404157cc13df6eb8f8c8b8681518110612c2a57612c2a615930565b6020026020010151612c4f856040518060200160405290815f82015481525050613de7565b604051612c5e93929190615c66565b60405180910390a15b50505080600101905061297e565b506001600160a01b0388165f908152609f60205260408120805491829190612c9c83615c8a565b91905055505f6040518060e001604052808b6001600160a01b031681526020018a6001600160a01b031681526020018b6001600160a01b031681526020018381526020014363ffffffff1681526020018981526020018581525090505f612d02826111ea565b5f818152609e602090815260408083208054600160ff19909116811790915560a4835292819020865181546001600160a01b03199081166001600160a01b039283161783558885015195830180548216968316969096179095559187015160028201805490951692169190911790925560608501516003830155608085015160048301805463ffffffff191663ffffffff90921691909117905560a085015180519394508593612db89260058501920190614c59565b5060c08201518051612dd4916006840191602090910190614cbc565b5050506001600160a01b038b165f90815260a360205260409020612df8908261424a565b507f26b2aae26516e8719ef50ea2f6831a2efbd4e37dccdf0f6936b27bc08e793e30818386604051612e2c93929190615ca2565b60405180910390a19a9950505050505050505050565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a250565b5f611a5d82612e97612e9087613de7565b8690614255565b90614255565b6001600160a01b038281165f8181526099602090815260409182902060010180546001600160a01b0319169486169485179055905192835290917f773b54c04d756fcc5e678111f7d730de3be98192000799eee3d63716055a87c6910161269f565b6066545f90600190811603612f275760405163840a48d560e01b815260040160405180910390fd5b5f5f612f3285611683565b915091505f612f425f8685612755565b6001600160a01b038781165f818152609a602052604080822080546001600160a01b031916948b16948517905551939450919290917fc3ee9f2e5fda98e8066a1f745b2df9285f416fe98cf2559cd21484b3d874330491a35f5b8351811015611cb25773beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06001600160a01b0316848281518110612fd557612fd5615930565b60200260200101516001600160a01b0316036131455760405163a3d75e0960e01b81526001600160a01b0388811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063a3d75e0990602401602060405180830381865afa158015613053573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061307791906159f0565b90505f60a25f8a6001600160a01b03166001600160a01b031681526020019081526020015f205f8785815181106130b0576130b0615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f82015481525050905061312485848151811061310257613102615930565b6020026020010151836001600160401b0316836138dc9092919063ffffffff16565b85848151811061313657613136615930565b60200260200101818152505050505b61319e868886848151811061315c5761315c615930565b60200260200101515f87868151811061317757613177615930565b602002602001015187878151811061319157613191615930565b6020026020010151613288565b600101612f9c565b5f73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeabf196001600160a01b038416016132785760405163a3d75e0960e01b81526001600160a01b0385811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063a3d75e0990602401602060405180830381865afa158015613234573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061325891906159f0565b90506132706001600160401b038481169083166138c8565b915050610dd0565b506001600160401b031692915050565b805f036132a857604051630a33bc6960e21b815260040160405180910390fd5b81156133c5576001600160a01b038086165f90815260a2602090815260408083209388168352929052206132de81858585614269565b6040805160208101909152815481527f8be932bac54561f27260f95463d9b8ab37e06b2842e5ee2404157cc13df6eb8f908790879061331c90613de7565b60405161332b93929190615c66565b60405180910390a161333c8661107e565b15611cb2576001600160a01b038088165f90815260986020908152604080832093891683529290529081208054859290613377908490615a1f565b92505081905550866001600160a01b03167f1ec042c965e2edd7107b51188ee0f383e22e76179041ab3a9d18ff151405166c8787866040516133bb93929190615c66565b60405180910390a2505b505050505050565b604051631beb2b9760e31b81526001600160a01b0382811660048301523360248301523060448301525f80356001600160e01b0319166064840152917f00000000000000000000000000000000000000000000000000000000000000009091169063df595cb8906084016020604051808303815f875af1158015613453573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119b591906159a7565b60605f613483836142e4565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b6134bc614c00565b5f82815260a46020908152604091829020825160e08101845281546001600160a01b0390811682526001830154811682850152600283015416818501526003820154606082810191909152600483015463ffffffff1660808301526005830180548651818702810187019097528087529195929460a0860193929083018282801561356e57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613550575b50505050508152602001600682018054806020026020016040519081016040528092919081815260200182805480156135c457602002820191905f5260205f20905b8154815260200190600101908083116135b0575b50505050508152505091508160a00151516001600160401b038111156135ec576135ec614e62565b604051908082528060200260200182016040528015613615578160200160208202803683370190505b5090505f7f000000000000000000000000000000000000000000000000000000000000000083608001516136499190615ccc565b90505f4363ffffffff168263ffffffff161061367a57613675845f015185602001518660a00151612755565b613691565b613691845f015185602001518660a001518561430b565b90505f5b8460a0015151811015611358576136e28560c0015182815181106136bb576136bb615930565b60200260200101518383815181106136d5576136d5615930565b6020026020010151614439565b8482815181106136f4576136f4615930565b6020908102919091010152600101613695565b5f6137158483856001614444565b611a5d9085615ce8565b6001600160a01b038085165f90815260a560209081526040808320938716835292905290812081906137509061449f565b90505f6137b660016137827f000000000000000000000000000000000000000000000000000000000000000043615cfb565b61378c9190615cfb565b6001600160a01b03808a165f90815260a560209081526040808320938c16835292905220906144b9565b90505f6137c38284615ce8565b90506137d08187876144d5565b98975050505050505050565b6001600160a01b038085165f90815260986020908152604080832093861683529290529081208054839290613812908490615ce8565b92505081905550836001600160a01b03167f6909600037b75d7b4733aedd815442b5ec018a827751c832aaff64eba5d6d2dd848484604051611afe93929190615c66565b5f6001600160a01b03821673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0146138a1577f00000000000000000000000000000000000000000000000000000000000000006119b5565b7f000000000000000000000000000000000000000000000000000000000000000092915050565b5f610dd08383670de0b6b3a76400006144f3565b5f611a5d826138f46138ed87613de7565b86906138c8565b906138c8565b6033546001600160a01b031633146111e85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161214e565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60a08401515182146139ca576040516343714afd60e01b815260040160405180910390fd5b83604001516001600160a01b0316336001600160a01b031614613a00576040516316110d3560e21b815260040160405180910390fd5b5f613a0a856111ea565b5f818152609e602052604090205490915060ff16613a3b576040516387c9d21960e01b815260040160405180910390fd5b60605f7f00000000000000000000000000000000000000000000000000000000000000008760800151613a6e9190615ccc565b90508063ffffffff164363ffffffff1611613a9c576040516378f67ae160e11b815260040160405180910390fd5b613ab3875f015188602001518960a001518461430b565b87516001600160a01b03165f90815260a360205260409020909250613ad99150836145d8565b505f82815260a46020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101805463ffffffff1916905590613b306005830182614cf5565b613b3d600683015f614cf5565b50505f828152609e602052604090819020805460ff19169055517f1f40400889274ed07b24845e5054a87a0cab969eb1277aafe61ae352e7c32a0090613b869084815260200190565b60405180910390a185516001600160a01b039081165f908152609a6020526040812054885160a08a01519190931692613bc0918490612755565b90505f5b8860a0015151811015613ddc575f613beb8a60a001518381518110611f0357611f03615930565b90505f613c218b60c001518481518110613c0757613c07615930565b60200260200101518785815181106136d5576136d5615930565b9050805f03613c31575050613dd4565b8715613cff57816001600160a01b0316632eae418c8c5f01518d60a001518681518110613c6057613c60615930565b60200260200101518d8d88818110613c7a57613c7a615930565b9050602002016020810190613c8f9190615191565b60405160e085901b6001600160e01b03191681526001600160a01b03938416600482015291831660248301529091166044820152606481018490526084015f604051808303815f87803b158015613ce4575f5ffd5b505af1158015613cf6573d5f5f3e3d5ffd5b50505050613dd1565b5f5f836001600160a01b03166350ff72258e5f01518f60a001518881518110613d2a57613d2a615930565b6020026020010151866040518463ffffffff1660e01b8152600401613d5193929190615c66565b60408051808303815f875af1158015613d6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d909190615d17565b91509150613dce878e5f01518f60a001518881518110613db257613db2615930565b602002602001015185858b8b8151811061319157613191615930565b50505b50505b600101613bc4565b505050505050505050565b80515f9015613df75781516119b5565b670de0b6b3a764000092915050565b606654606090600190600290811603613e325760405163840a48d560e01b815260040160405180910390fd5b6001600160a01b038084165f818152609a602052604080822080546001600160a01b0319811690915590519316928392917ffee30966a256b71e14bc0ebfc94315e28ef4a97a7131a9e2b7a310a73af4467691a35f5f613e9186611683565b9150915081515f03613ea55750505061405f565b81516001600160401b03811115613ebe57613ebe614e62565b604051908082528060200260200182016040528015613ee7578160200160208202803683370190505b5094505f613ef6878585612755565b90505f5b8351811015614059576040805160018082528183019092525f916020808301908036833750506040805160018082528183019092529293505f9291506020808301908036833750506040805160018082528183019092529293505f92915060208083019080368337019050509050868481518110613f7a57613f7a615930565b6020026020010151835f81518110613f9457613f94615930565b60200260200101906001600160a01b031690816001600160a01b031681525050858481518110613fc657613fc6615930565b6020026020010151825f81518110613fe057613fe0615930565b602002602001018181525050848481518110613ffe57613ffe615930565b6020026020010151815f8151811061401857614018615930565b6020026020010181815250506140318b898585856128a7565b8a858151811061404357614043615930565b6020908102919091010152505050600101613efa565b50505050505b50919050565b6001600160a01b038084165f90815260996020526040902060010154168061408d5750610f25565b6001600160a01b0381165f908152609c6020908152604080832085845290915290205460ff16156140d157604051630d4c4c9160e21b815260040160405180910390fd5b6001600160a01b0381165f908152609c602090815260408083208584528252909120805460ff1916600117905583015161234b908290614118908890889084908890610889565b855160208701516145e3565b60605f6141507f0000000000000000000000000000000000000000000000000000000000000000613477565b9050805f8151811061416457614164615930565b602001015160f81c60f81b8160018151811061418257614182615930565b016020908101516040516001600160f81b03199384169281019290925291909116602182015260220160405160208183030381529060405291505090565b60605f610dd083614635565b5f610dd06141d984613de7565b83906138c8565b6001600160a01b038084165f90815260a560209081526040808320938616835292905290812061420f9061449f565b9050610f254361421f8484615a1f565b6001600160a01b038088165f90815260a560209081526040808320938a16835292905220919061468e565b5f610dd08383614699565b5f610dd083670de0b6b3a7640000846144f3565b825f036142955760408051602081019091528454815261428e908290612e9790613de7565b8455610f25565b6040805160208101909152845481525f906142b19085846138dc565b90505f6142be8483615a1f565b90505f6142d984612e976142d2888a615a1f565b8590614255565b875550505050505050565b5f60ff8216601f8111156119b557604051632cd44ac360e21b815260040160405180910390fd5b60605f83516001600160401b0381111561432757614327614e62565b604051908082528060200260200182016040528015614350578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166394d7d00c8787876040518463ffffffff1660e01b81526004016143a493929190615d39565b5f60405180830381865afa1580156143be573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526143e59190810190615bd7565b90505f5b855181101561442d576144088887838151811061285057612850615930565b83828151811061441a5761441a615930565b60209081029190910101526001016143e9565b50909695505050505050565b5f610dd083836138c8565b5f5f6144518686866144f3565b9050600183600281111561446757614467615d72565b14801561448357505f848061447e5761447e615d86565b868809115b1561449657614493600182615a1f565b90505b95945050505050565b5f6144aa82826146e5565b6001600160e01b031692915050565b5f6144c583838361472a565b6001600160e01b03169392505050565b5f611a5d6144e38385615d9a565b85906001600160401b03166138c8565b5f80805f19858709858702925082811083820303915050805f0361452a5783828161452057614520615d86565b0492505050610dd0565b8084116145715760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161214e565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f610dd08383614773565b4281101561460457604051630819bdcd60e01b815260040160405180910390fd5b6146186001600160a01b0385168484614856565b610f2557604051638baa579f60e01b815260040160405180910390fd5b6060815f0180548060200260200160405190810160405280929190818152602001828054801561468257602002820191905f5260205f20905b81548152602001906001019080831161466e575b50505050509050919050565b6111068383836148aa565b5f8181526001830160205260408120546146de57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556119b5565b505f6119b5565b81545f9080156147225761470b846146fe600184615ce8565b5f91825260209091200190565b5464010000000090046001600160e01b0316611a5d565b509092915050565b82545f908161473b868683856149b0565b9050801561476957614752866146fe600184615ce8565b5464010000000090046001600160e01b0316610907565b5091949350505050565b5f818152600183016020526040812054801561484d575f614795600183615ce8565b85549091505f906147a890600190615ce8565b9050818114614807575f865f0182815481106147c6576147c6615930565b905f5260205f200154905080875f0184815481106147e6576147e6615930565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061481857614818615db9565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506119b5565b5f9150506119b5565b5f5f5f6148638585614a03565b90925090505f81600481111561487b5761487b615d72565b1480156148995750856001600160a01b0316826001600160a01b0316145b806109075750610907868686614a42565b82548015614962575f6148c2856146fe600185615ce8565b60408051808201909152905463ffffffff8082168084526401000000009092046001600160e01b0316602084015291925090851610156149155760405163151b8e3f60e11b815260040160405180910390fd5b805163ffffffff8086169116036149605782614936866146fe600186615ce8565b80546001600160e01b03929092166401000000000263ffffffff9092169190911790555050505050565b505b506040805180820190915263ffffffff92831681526001600160e01b03918216602080830191825285546001810187555f968752952091519051909216640100000000029190921617910155565b5f5b81831015611bda575f6149c58484614b29565b5f8781526020902090915063ffffffff86169082015463ffffffff1611156149ef578092506149fd565b6149fa816001615a1f565b93505b506149b2565b5f5f8251604103614a37576020830151604084015160608501515f1a614a2b87828585614b43565b945094505050506120b1565b505f905060026120b1565b5f5f5f856001600160a01b0316631626ba7e60e01b8686604051602401614a6a929190615dcd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614aa89190615de5565b5f60405180830381855afa9150503d805f8114614ae0576040519150601f19603f3d011682016040523d82523d5f602084013e614ae5565b606091505b5091509150818015614af957506020815110155b801561090757508051630b135d3f60e11b90614b1e9083016020908101908401615b48565b149695505050505050565b5f614b376002848418615dfb565b610dd090848416615a1f565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b7857505f90506003614bf7565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614bc9573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116614bf1575f60019250925050614bf7565b91505f90505b94509492505050565b6040518060e001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f63ffffffff16815260200160608152602001606081525090565b828054828255905f5260205f20908101928215614cac579160200282015b82811115614cac57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614c77565b50614cb8929150614d0c565b5090565b828054828255905f5260205f20908101928215614cac579160200282015b82811115614cac578251825591602001919060010190614cda565b5080545f8255905f5260205f20908101906124d891905b5b80821115614cb8575f8155600101614d0d565b6001600160a01b03811681146124d8575f5ffd5b80356122f781614d20565b5f5f5f5f5f60a08688031215614d53575f5ffd5b8535614d5e81614d20565b94506020860135614d6e81614d20565b93506040860135614d7e81614d20565b94979396509394606081013594506080013592915050565b5f5f83601f840112614da6575f5ffd5b5081356001600160401b03811115614dbc575f5ffd5b6020830191508360208260051b85010111156120b1575f5ffd5b5f5f60208385031215614de7575f5ffd5b82356001600160401b03811115614dfc575f5ffd5b614e0885828601614d96565b90969095509350505050565b602080825282518282018190525f918401906040840190835b8181101561289c578351835260209384019390920191600101614e2d565b5f60208284031215614e5b575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b0381118282101715614e9857614e98614e62565b60405290565b604080519081016001600160401b0381118282101715614e9857614e98614e62565b604051601f8201601f191681016001600160401b0381118282101715614ee857614ee8614e62565b604052919050565b5f6001600160401b03821115614f0857614f08614e62565b5060051b60200190565b5f82601f830112614f21575f5ffd5b8135614f34614f2f82614ef0565b614ec0565b8082825260208201915060208360051b860101925085831115614f55575f5ffd5b602085015b83811015614f7b578035614f6d81614d20565b835260209283019201614f5a565b5095945050505050565b5f82601f830112614f94575f5ffd5b8135614fa2614f2f82614ef0565b8082825260208201915060208360051b860101925085831115614fc3575f5ffd5b602085015b83811015614f7b578035835260209283019201614fc8565b5f5f5f60608486031215614ff2575f5ffd5b8335614ffd81614d20565b925060208401356001600160401b03811115615017575f5ffd5b61502386828701614f12565b92505060408401356001600160401b0381111561503e575f5ffd5b61504a86828701614f85565b9150509250925092565b5f8151808452602084019350602083015f5b82811015615084578151865260209586019590910190600101615066565b5093949350505050565b602081525f610dd06020830184615054565b803563ffffffff811681146122f7575f5ffd5b5f5f83601f8401126150c3575f5ffd5b5081356001600160401b038111156150d9575f5ffd5b6020830191508360208285010111156120b1575f5ffd5b5f5f5f5f60608587031215615103575f5ffd5b843561510e81614d20565b935061511c602086016150a0565b925060408501356001600160401b03811115615136575f5ffd5b615142878288016150b3565b95989497509550505050565b5f5f5f5f60808587031215615161575f5ffd5b843561516c81614d20565b9350602085013561517c81614d20565b93969395505050506040820135916060013590565b5f602082840312156151a1575f5ffd5b8135610dd081614d20565b5f5f604083850312156151bd575f5ffd5b82356151c881614d20565b915060208301356151d881614d20565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610dd060208301846151e3565b5f60e08284031215615233575f5ffd5b61523b614e76565b905061524682614d34565b815261525460208301614d34565b602082015261526560408301614d34565b604082015260608281013590820152615280608083016150a0565b608082015260a08201356001600160401b0381111561529d575f5ffd5b6152a984828501614f12565b60a08301525060c08201356001600160401b038111156152c7575f5ffd5b6152d384828501614f85565b60c08301525092915050565b5f602082840312156152ef575f5ffd5b81356001600160401b03811115615304575f5ffd5b611a5d84828501615223565b5f60208284031215615320575f5ffd5b813560ff81168114610dd0575f5ffd5b5f8151808452602084019350602083015f5b828110156150845781516001600160a01b0316865260209586019590910190600101615342565b80516001600160a01b03908116835260208083015182169084015260408083015190911690830152606080820151908301526080808201515f916153b49085018263ffffffff169052565b5060a082015160e060a08501526153ce60e0850182615330565b905060c083015184820360c08601526144968282615054565b604081525f6153f96040830185615369565b82810360208401526144968185615054565b5f82825180855260208501945060208160051b830101602085015f5b8381101561442d57601f19858403018852615443838351615054565b6020988901989093509190910190600101615427565b5f604082016040835280855180835260608501915060608160051b8601019250602087015f5b828110156154b057605f1987860301845261549b858351615369565b9450602093840193919091019060010161547f565b505050508281036020840152614496818561540b565b6001600160401b03811681146124d8575f5ffd5b5f5f5f5f608085870312156154ed575f5ffd5b84356154f881614d20565b9350602085013561550881614d20565b92506040850135615518816154c6565b91506060850135615528816154c6565b939692955090935050565b5f5f5f60608486031215615545575f5ffd5b833561555081614d20565b9250602084013591506040840135615567816154c6565b809150509250925092565b604081525f6153f96040830185615330565b5f5f5f60408486031215615596575f5ffd5b83356155a181614d20565b925060208401356001600160401b038111156155bb575f5ffd5b6155c7868287016150b3565b9497909650939450505050565b5f5f604083850312156155e5575f5ffd5b82356155f081614d20565b915060208301356001600160401b0381111561560a575f5ffd5b61561685828601614f12565b9150509250929050565b5f5f5f5f5f5f60608789031215615635575f5ffd5b86356001600160401b0381111561564a575f5ffd5b61565689828a01614d96565b90975095505060208701356001600160401b03811115615674575f5ffd5b61568089828a01614d96565b90955093505060408701356001600160401b0381111561569e575f5ffd5b6156aa89828a01614d96565b979a9699509497509295939492505050565b602081525f610dd06020830184615369565b5f5f5f606084860312156156e0575f5ffd5b83356156eb81614d20565b925060208401356001600160401b03811115615705575f5ffd5b840160408187031215615716575f5ffd5b61571e614e9e565b81356001600160401b03811115615733575f5ffd5b8201601f81018813615743575f5ffd5b80356001600160401b0381111561575c5761575c614e62565b61576f601f8201601f1916602001614ec0565b818152896020838501011115615783575f5ffd5b816020840160208301375f60209282018301528352928301359282019290925293969395505050506040919091013590565b5f5f604083850312156157c6575f5ffd5b82356157d181614d20565b946020939093013593505050565b604081525f6153f96040830185615054565b80151581146124d8575f5ffd5b5f5f5f5f60608587031215615811575f5ffd5b84356001600160401b03811115615826575f5ffd5b850160e08188031215615837575f5ffd5b935060208501356001600160401b03811115615851575f5ffd5b61585d87828801614d96565b9094509250506040850135615528816157f1565b5f5f60408385031215615882575f5ffd5b82356001600160401b03811115615897575f5ffd5b8301601f810185136158a7575f5ffd5b80356158b5614f2f82614ef0565b8082825260208201915060208360051b8501019250878311156158d6575f5ffd5b6020840193505b828410156159015783356158f081614d20565b8252602093840193909101906158dd565b945050505060208301356001600160401b0381111561560a575f5ffd5b602081525f610dd0602083018461540b565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112615958575f5ffd5b9190910192915050565b5f5f8335601e19843603018112615977575f5ffd5b8301803591506001600160401b03821115615990575f5ffd5b6020019150600581901b36038213156120b1575f5ffd5b5f602082840312156159b7575f5ffd5b8151610dd0816157f1565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f60208284031215615a00575f5ffd5b8151610dd0816154c6565b634e487b7160e01b5f52601160045260245ffd5b808201808211156119b5576119b5615a0b565b5f82601f830112615a41575f5ffd5b8151615a4f614f2f82614ef0565b8082825260208201915060208360051b860101925085831115615a70575f5ffd5b602085015b83811015614f7b578051835260209283019201615a75565b5f5f60408385031215615a9e575f5ffd5b82516001600160401b03811115615ab3575f5ffd5b8301601f81018513615ac3575f5ffd5b8051615ad1614f2f82614ef0565b8082825260208201915060208360051b850101925087831115615af2575f5ffd5b6020840193505b82841015615b1d578351615b0c81614d20565b825260209384019390910190615af9565b8095505050505060208301516001600160401b03811115615b3c575f5ffd5b61561685828601615a32565b5f60208284031215615b58575f5ffd5b5051919050565b5f823560de19833603018112615958575f5ffd5b5f6119b53683615223565b5f60208284031215615b8e575f5ffd5b8135610dd0816157f1565b5f60208284031215615ba9575f5ffd5b8151610dd081614d20565b6001600160a01b03831681526040602082018190525f90611a5d90830184615330565b5f60208284031215615be7575f5ffd5b81516001600160401b03811115615bfc575f5ffd5b8201601f81018413615c0c575f5ffd5b8051615c1a614f2f82614ef0565b8082825260208201915060208360051b850101925086831115615c3b575f5ffd5b6020840193505b82841015610907578351615c55816154c6565b825260209384019390910190615c42565b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f60018201615c9b57615c9b615a0b565b5060010190565b838152606060208201525f615cba6060830185615369565b82810360408401526109078185615054565b63ffffffff81811683821601908111156119b5576119b5615a0b565b818103818111156119b5576119b5615a0b565b63ffffffff82811682821603908111156119b5576119b5615a0b565b5f5f60408385031215615d28575f5ffd5b505080516020909101519092909150565b6001600160a01b03841681526060602082018190525f90615d5c90830185615330565b905063ffffffff83166040830152949350505050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b6001600160401b0382811682821603908111156119b5576119b5615a0b565b634e487b7160e01b5f52603160045260245ffd5b828152604060208201525f611a5d60408301846151e3565b5f82518060208501845e5f920191825250919050565b5f82615e1557634e487b7160e01b5f52601260045260245ffd5b50049056fea264697066735822122028823ec872a9df95048c08df1bd11d6833b239643a395c032aeedc56c3554f0e64736f6c634300081b0033000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef1280600000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e500000000000000000000000000000000000000000000000000000000000189c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005312e332e30000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106102ff575f3560e01c8063715018a611610195578063bfae3fd2116100e4578063e4cc3f901161009e578063f2fde38b11610079578063f2fde38b14610848578063f698da251461085b578063fabc1cbc14610863578063fd8aa88d14610876575f5ffd5b8063e4cc3f9014610802578063eea9064b14610815578063f0e0e67614610828575f5ffd5b8063bfae3fd21461074d578063c448feb814610760578063c978f7ac14610794578063ca8aa7c7146107b5578063cd6dc687146107dc578063da8be864146107ef575f5ffd5b80639104c3191161014f578063a17884841161012a578063a1788484146106cc578063a33a3433146106eb578063b7f06ebe146106fe578063bb45fef214610720575f5ffd5b80639104c3191461067e5780639435bb431461069957806399f5371b146106ac575f5ffd5b8063715018a6146105ee578063778e55f3146105f657806378296ec514610620578063886f1195146106335780638da5cb5b1461065a578063900413471461066b575f5ffd5b806354fd4d50116102515780635dd685791161020b57806365da1264116101e657806365da12641461057f57806366d5ba93146105a75780636d70f7ae146105c85780636e174448146105db575f5ffd5b80635dd6857914610538578063601bb36f1461055957806360a0d1ce1461056c575f5ffd5b806354fd4d50146104bc578063595c6a67146104d1578063597b36da146104d95780635ac86ab7146104ec5780635c975abb1461050f5780635d975e8814610517575f5ffd5b806339b70e38116102bc5780633e28391d116102975780633e28391d146104385780634657e26a1461045b5780634665bcda1461048257806354b7c96c146104a9575f5ffd5b806339b70e38146103b85780633c651cf2146103f75780633cdeb5e01461040a575f5ffd5b806304a4f979146103035780630b9f487a1461033d5780630dd8dd0214610350578063136439dd1461037057806325df922e146103855780632aa6d888146103a5575b5f5ffd5b61032a7f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad81565b6040519081526020015b60405180910390f35b61032a61034b366004614d3f565b610889565b61036361035e366004614dd6565b610911565b6040516103349190614e14565b61038361037e366004614e4b565b610ba2565b005b610398610393366004614fe0565b610c77565b604051610334919061508e565b6103836103b33660046150f0565b610dd7565b6103df7f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a81565b6040516001600160a01b039091168152602001610334565b61038361040536600461514e565b610f2b565b6103df610418366004615191565b6001600160a01b039081165f908152609960205260409020600101541690565b61044b610446366004615191565b61107e565b6040519015158152602001610334565b6103df7f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e581565b6103df7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33881565b6103836104b73660046151ac565b61109d565b6104c461110b565b6040516103349190615211565b61038361113b565b61032a6104e73660046152df565b6111ea565b61044b6104fa366004615310565b606654600160ff9092169190911b9081161490565b60665461032a565b61052a610525366004614e4b565b611219565b6040516103349291906153e7565b61054b610546366004615191565b611236565b604051610334929190615459565b6103836105673660046154da565b611360565b61038361057a366004615533565b6114d8565b6103df61058d366004615191565b609a6020525f90815260409020546001600160a01b031681565b6105ba6105b5366004615191565b611683565b604051610334929190615572565b61044b6105d6366004615191565b611983565b61032a6105e93660046151ac565b6119bb565b610383611a65565b61032a6106043660046151ac565b609860209081525f928352604080842090915290825290205481565b61038361062e366004615584565b611a76565b6103df7f000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef1280681565b6033546001600160a01b03166103df565b6103986106793660046155d4565b611b0c565b6103df73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac081565b6103836106a7366004615620565b611be2565b6106bf6106ba366004614e4b565b611cbb565b60405161033491906156bc565b61032a6106da366004615191565b609f6020525f908152604090205481565b6103636106f93660046156ce565b611dd7565b61044b61070c366004614e4b565b609e6020525f908152604090205460ff1681565b61044b61072e3660046157b5565b609c60209081525f928352604080842090915290825290205460ff1681565b61032a61075b3660046151ac565b611def565b60405163ffffffff7f00000000000000000000000000000000000000000000000000000000000189c0168152602001610334565b6107a76107a23660046155d4565b611e2b565b6040516103349291906157df565b6103df7f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc3981565b6103836107ea3660046157b5565b6120b8565b6103636107fd366004615191565b6121d3565b6103836108103660046157fe565b6122fc565b6103836108233660046156ce565b612352565b61083b610836366004615871565b6123bd565b604051610334919061591e565b610383610856366004615191565b612462565b61032a6124db565b610383610871366004614e4b565b612594565b610363610884366004615191565b6126ab565b604080517f14bde674c9f64b2ad00eaaee4a8bed1fabef35c7507e3c5b9cfc9436909a2dad60208201526001600160a01b03808616928201929092528187166060820152908516608082015260a0810183905260c081018290525f906109079060e001604051602081830303815290604052805190602001206126ce565b9695505050505050565b60665460609060019060029081160361093d5760405163840a48d560e01b815260040160405180910390fd5b6109456126fc565b5f836001600160401b0381111561095e5761095e614e62565b604051908082528060200260200182016040528015610987578160200160208202803683370190505b50335f908152609a60205260408120549192506001600160a01b03909116905b85811015610b93578686828181106109c1576109c1615930565b90506020028101906109d39190615944565b6109e1906020810190615962565b90508787838181106109f5576109f5615930565b9050602002810190610a079190615944565b610a119080615962565b905014610a31576040516343714afd60e01b815260040160405180910390fd5b5f610a9b33848a8a86818110610a4957610a49615930565b9050602002810190610a5b9190615944565b610a659080615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061275592505050565b9050610b6d33848a8a86818110610ab457610ab4615930565b9050602002810190610ac69190615944565b610ad09080615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508e92508d9150889050818110610b1557610b15615930565b9050602002810190610b279190615944565b610b35906020810190615962565b808060200260200160405190810160405280939291908181526020018383602002808284375f920191909152508892506128a7915050565b848381518110610b7f57610b7f615930565b6020908102919091010152506001016109a7565b5050600160c955949350505050565b60405163237dfb4760e11b81523360048201527f000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef128066001600160a01b0316906346fbf68e90602401602060405180830381865afa158015610c04573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c2891906159a7565b610c4557604051631d77d47760e21b815260040160405180910390fd5b6066548181168114610c6a5760405163c61dca5d60e01b815260040160405180910390fd5b610c7382612e42565b5050565b6001600160a01b038084165f908152609a60205260408120546060921690610ca0868387612755565b90505f85516001600160401b03811115610cbc57610cbc614e62565b604051908082528060200260200182016040528015610ce5578160200160208202803683370190505b5090505f5b8651811015610dca576001600160a01b0388165f90815260a260205260408120885182908a9085908110610d2057610d20615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f820154815250509050610da4878381518110610d7257610d72615930565b6020026020010151858481518110610d8c57610d8c615930565b602002602001015183612e7f9092919063ffffffff16565b838381518110610db657610db6615930565b602090810291909101015250600101610cea565b50925050505b9392505050565b610ddf6126fc565b610de83361107e565b15610e0657604051633bf2b50360e11b815260040160405180910390fd5b604051632b6241f360e11b815233600482015263ffffffff841660248201527f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b0316906356c483e6906044015f604051808303815f87803b158015610e70575f5ffd5b505af1158015610e82573d5f5f3e3d5ffd5b50505050610e903385612e9d565b610e9a3333612eff565b6040516001600160a01b038516815233907fa453db612af59e5521d6ab9284dc3e2d06af286eb1b1b7b771fce4716c19f2c19060200160405180910390a2336001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908383604051610f139291906159c2565b60405180910390a2610f25600160c955565b50505050565b336001600160a01b037f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a161480610f8a5750336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33816145b610fa75760405163045206a560e21b815260040160405180910390fd5b610faf6126fc565b6001600160a01b038481165f908152609a602052604080822054905163152667d960e31b8152908316600482018190528684166024830152927f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39169063a9333ec890604401602060405180830381865afa15801561102f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061105391906159f0565b90505f6110618787846131a6565b9050611071838888888886613288565b505050610f25600160c955565b6001600160a01b039081165f908152609a602052604090205416151590565b816110a7816133cd565b6110c45760405163932d94f760e01b815260040160405180910390fd5b6110cc6126fc565b6110d583611983565b6110f2576040516325ec6c1f60e01b815260040160405180910390fd5b6110fc8383612e9d565b611106600160c955565b505050565b60606111367f312e332e30000000000000000000000000000000000000000000000000000005613477565b905090565b60405163237dfb4760e11b81523360048201527f000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef128066001600160a01b0316906346fbf68e90602401602060405180830381865afa15801561119d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111c191906159a7565b6111de57604051631d77d47760e21b815260040160405180910390fd5b6111e85f19612e42565b565b5f816040516020016111fc91906156bc565b604051602081830303815290604052805190602001209050919050565b611221614c00565b606061122c836134b4565b9094909350915050565b6060805f611243846126ab565b8051909150806001600160401b0381111561126057611260614e62565b60405190808252806020026020018201604052801561129957816020015b611286614c00565b81526020019060019003908161127e5790505b509350806001600160401b038111156112b4576112b4614e62565b6040519080825280602002602001820160405280156112e757816020015b60608152602001906001900390816112d25790505b5092505f5b818110156113585761131683828151811061130957611309615930565b60200260200101516134b4565b86838151811061132857611328615930565b6020026020010186848151811061134157611341615930565b6020908102919091010191909152526001016112ec565b505050915091565b336001600160a01b037f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc3916146113a9576040516323d871a560e01b815260040160405180910390fd5b6113b16126fc565b6001600160a01b038085165f9081526098602090815260408083209387168352929052908120546113ef906001600160401b03808616908516613707565b90505f6113fe8686868661371f565b90505f61140b8284615a1f565b9050611419875f88866137dc565b604080516001600160a01b038881168252602082018490528916917fdd611f4ef63f4385f1756c86ce1f1f389a9013ba6fa07daba8528291bc2d3c30910160405180910390a25f61146987613856565b60405163debe1eab60e01b81526001600160a01b038981166004830152602482018590529192509082169063debe1eab906044015f604051808303815f87803b1580156114b4575f5ffd5b505af11580156114c6573d5f5f3e3d5ffd5b5050505050505050610f25600160c955565b336001600160a01b037f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338161461152157604051633213a66160e21b815260040160405180910390fd5b6115296126fc565b6115328361107e565b156110fc576001600160a01b038381165f908152609a602052604080822054905163152667d960e31b81529083166004820181905273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06024830152927f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39169063a9333ec890604401602060405180830381865afa1580156115c9573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ed91906159f0565b6001600160a01b0386165f90815260a26020908152604080832073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac08452825280832081519283019091525481529192506116538661164b6001600160401b038087169089166138c8565b8491906138dc565b9050611675848873beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0846137dc565b50505050611106600160c955565b6040516394f649dd60e01b81526001600160a01b03828116600483015260609182915f9182917f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a16906394f649dd906024015f60405180830381865afa1580156116ef573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117169190810190615a8d565b60405163fe243a1760e01b81526001600160a01b03888116600483015273beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac060248301529294509092505f917f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338169063fe243a1790604401602060405180830381865afa15801561179c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117c09190615b48565b9050805f036117d457509094909350915050565b5f835160016117e39190615a1f565b6001600160401b038111156117fa576117fa614e62565b604051908082528060200260200182016040528015611823578160200160208202803683370190505b5090505f845160016118359190615a1f565b6001600160401b0381111561184c5761184c614e62565b604051908082528060200260200182016040528015611875578160200160208202803683370190505b50905073beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0828651815181106118a0576118a0615930565b60200260200101906001600160a01b031690816001600160a01b03168152505082818651815181106118d4576118d4615930565b60209081029190910101525f5b8551811015611975578581815181106118fc576118fc615930565b602002602001015183828151811061191657611916615930565b60200260200101906001600160a01b031690816001600160a01b03168152505084818151811061194857611948615930565b602002602001015182828151811061196257611962615930565b60209081029190910101526001016118e1565b509097909650945050505050565b5f6001600160a01b038216158015906119b557506001600160a01b038083165f818152609a6020526040902054909116145b92915050565b60405163152667d960e31b81526001600160a01b03838116600483015282811660248301525f9182917f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39169063a9333ec890604401602060405180830381865afa158015611a2b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a4f91906159f0565b9050611a5d8484835f61371f565b949350505050565b611a6d6138fa565b6111e85f613954565b82611a80816133cd565b611a9d5760405163932d94f760e01b815260040160405180910390fd5b611aa684611983565b611ac3576040516325ec6c1f60e01b815260040160405180910390fd5b836001600160a01b03167f02a919ed0e2acad1dd90f17ef2fa4ae5462ee1339170034a8531cca4b67080908484604051611afe9291906159c2565b60405180910390a250505050565b60605f82516001600160401b03811115611b2857611b28614e62565b604051908082528060200260200182016040528015611b51578160200160208202803683370190505b5090505f5b8351811015611bda576001600160a01b0385165f9081526098602052604081208551909190869084908110611b8d57611b8d615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f2054828281518110611bc757611bc7615930565b6020908102919091010152600101611b56565b509392505050565b606654600290600490811603611c0b5760405163840a48d560e01b815260040160405180910390fd5b611c136126fc565b855f5b81811015611ca657611c9e898983818110611c3357611c33615930565b9050602002810190611c459190615b5f565b611c4e90615b73565b888884818110611c6057611c60615930565b9050602002810190611c729190615962565b888886818110611c8457611c84615930565b9050602002016020810190611c999190615b7e565b6139a5565b600101611c16565b5050611cb2600160c955565b50505050505050565b611cc3614c00565b5f82815260a46020908152604091829020825160e08101845281546001600160a01b03908116825260018301548116828501526002830154168185015260038201546060820152600482015463ffffffff1660808201526005820180548551818602810186019096528086529194929360a08601939290830182828015611d7157602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311611d53575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020018280548015611dc757602002820191905f5260205f20905b815481526020019060010190808311611db3575b5050505050815250509050919050565b6060611de2336121d3565b9050610dd0848484612352565b6001600160a01b038083165f90815260a260209081526040808320938516835292815282822083519182019093529154825290610dd090613de7565b60608082516001600160401b03811115611e4757611e47614e62565b604051908082528060200260200182016040528015611e70578160200160208202803683370190505b50915082516001600160401b03811115611e8c57611e8c614e62565b604051908082528060200260200182016040528015611eb5578160200160208202803683370190505b506001600160a01b038086165f908152609a6020526040812054929350911690611ee0868387612755565b90505f5b85518110156120ad575f611f10878381518110611f0357611f03615930565b6020026020010151613856565b9050806001600160a01b031663fe243a1789898581518110611f3457611f34615930565b60200260200101516040518363ffffffff1660e01b8152600401611f6e9291906001600160a01b0392831681529116602082015260400190565b602060405180830381865afa158015611f89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fad9190615b48565b858381518110611fbf57611fbf615930565b6020026020010181815250505f60a25f8a6001600160a01b03166001600160a01b031681526020019081526020015f205f89858151811061200257612002615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f82015481525050905061208686848151811061205457612054615930565b602002602001015185858151811061206e5761206e615930565b6020026020010151836138dc9092919063ffffffff16565b87848151811061209857612098615930565b60209081029190910101525050600101611ee4565b5050505b9250929050565b5f54610100900460ff16158080156120d657505f54600160ff909116105b806120ef5750303b1580156120ef57505f5460ff166001145b6121575760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b5f805460ff191660011790558015612178575f805461ff0019166101001790555b61218182612e42565b61218a83613954565b8015611106575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b60606121dd6126fc565b6121e68261107e565b6122035760405163a5c7c44560e01b815260040160405180910390fd5b61220c82611983565b1561222a576040516311ca333560e31b815260040160405180910390fd5b336001600160a01b038316146122e2576001600160a01b038083165f908152609a60205260409020541661225d816133cd565b8061228357506001600160a01b038181165f908152609960205260409020600101541633145b6122a057604051631e499a2360e11b815260040160405180910390fd5b806001600160a01b0316836001600160a01b03167ff0eddf07e6ea14f388b47e1e94a0f464ecbd9eed4171130e0fc0e99fb4030a8a60405160405180910390a3505b6122eb82613e06565b90506122f7600160c955565b919050565b6066546002906004908116036123255760405163840a48d560e01b815260040160405180910390fd5b61232d6126fc565b61234161233986615b73565b8585856139a5565b61234b600160c955565b5050505050565b61235a6126fc565b6123633361107e565b1561238157604051633bf2b50360e11b815260040160405180910390fd5b61238a83611983565b6123a7576040516325ec6c1f60e01b815260040160405180910390fd5b6123b333848484614065565b6110fc3384612eff565b60605f83516001600160401b038111156123d9576123d9614e62565b60405190808252806020026020018201604052801561240c57816020015b60608152602001906001900390816123f75790505b5090505f5b8451811015611bda5761243d85828151811061242f5761242f615930565b602002602001015185611b0c565b82828151811061244f5761244f615930565b6020908102919091010152600101612411565b61246a6138fa565b6001600160a01b0381166124cf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161214e565b6124d881613954565b50565b60408051808201909152600a81526922b4b3b2b72630bcb2b960b11b6020909101525f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f71b625cfad44bac63b13dba07f2e1d6084ee04b6f8752101ece6126d584ee6ea612548614124565b805160209182012060408051928301949094529281019190915260608101919091524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b7f000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef128066001600160a01b031663eab66d7a6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125f0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126149190615b99565b6001600160a01b0316336001600160a01b0316146126455760405163794821ff60e01b815260040160405180910390fd5b6066548019821981161461266c5760405163c61dca5d60e01b815260040160405180910390fd5b606682905560405182815233907f3582d1828e26bf56bd801502bc021ac0bc8afb57c826e4986b45593c8fad389c906020015b60405180910390a25050565b6001600160a01b0381165f90815260a3602052604090206060906119b5906141c0565b5f6126d76124db565b60405161190160f01b60208201526022810191909152604281018390526062016111fc565b600260c9540361274e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161214e565b600260c955565b60605f82516001600160401b0381111561277157612771614e62565b60405190808252806020026020018201604052801561279a578160200160208202803683370190505b5090505f7f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b031663547afb8786866040518363ffffffff1660e01b81526004016127ec929190615bb4565b5f60405180830381865afa158015612806573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261282d9190810190615bd7565b90505f5b845181101561289c576128778786838151811061285057612850615930565b602002602001015184848151811061286a5761286a615930565b60200260200101516131a6565b83828151811061288957612889615930565b6020908102919091010152600101612831565b509095945050505050565b5f6001600160a01b0386166128cf576040516339b190bb60e11b815260040160405180910390fd5b83515f036128f05760405163796cc52560e01b815260040160405180910390fd5b5f84516001600160401b0381111561290a5761290a614e62565b604051908082528060200260200182016040528015612933578160200160208202803683370190505b5090505f85516001600160401b0381111561295057612950614e62565b604051908082528060200260200182016040528015612979578160200160208202803683370190505b5090505f5b8651811015612c75575f61299d888381518110611f0357611f03615930565b90505f60a25f8c6001600160a01b03166001600160a01b031681526020019081526020015f205f8a85815181106129d6576129d6615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f209050612a4f888481518110612a1457612a14615930565b6020026020010151888581518110612a2e57612a2e615930565b602090810291909101810151604080519283019052845482529091906138dc565b848481518110612a6157612a61615930565b602002602001018181525050612aa0888481518110612a8257612a82615930565b602090810291909101810151604080519283019052835482526141cc565b858481518110612ab257612ab2615930565b60209081029190910101526001600160a01b038a1615612b4757612b098a8a8581518110612ae257612ae2615930565b6020026020010151878681518110612afc57612afc615930565b60200260200101516141e0565b612b478a8c8b8681518110612b2057612b20615930565b6020026020010151878781518110612b3a57612b3a615930565b60200260200101516137dc565b5f826001600160a01b031663724af4238d8c8781518110612b6a57612b6a615930565b60200260200101518c8881518110612b8457612b84615930565b60200260200101516040518463ffffffff1660e01b8152600401612baa93929190615c66565b6020604051808303815f875af1158015612bc6573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bea9190615b48565b9050805f03612c67575f82557f8be932bac54561f27260f95463d9b8ab37e06b2842e5ee2404157cc13df6eb8f8c8b8681518110612c2a57612c2a615930565b6020026020010151612c4f856040518060200160405290815f82015481525050613de7565b604051612c5e93929190615c66565b60405180910390a15b50505080600101905061297e565b506001600160a01b0388165f908152609f60205260408120805491829190612c9c83615c8a565b91905055505f6040518060e001604052808b6001600160a01b031681526020018a6001600160a01b031681526020018b6001600160a01b031681526020018381526020014363ffffffff1681526020018981526020018581525090505f612d02826111ea565b5f818152609e602090815260408083208054600160ff19909116811790915560a4835292819020865181546001600160a01b03199081166001600160a01b039283161783558885015195830180548216968316969096179095559187015160028201805490951692169190911790925560608501516003830155608085015160048301805463ffffffff191663ffffffff90921691909117905560a085015180519394508593612db89260058501920190614c59565b5060c08201518051612dd4916006840191602090910190614cbc565b5050506001600160a01b038b165f90815260a360205260409020612df8908261424a565b507f26b2aae26516e8719ef50ea2f6831a2efbd4e37dccdf0f6936b27bc08e793e30818386604051612e2c93929190615ca2565b60405180910390a19a9950505050505050505050565b606681905560405181815233907fab40a374bc51de372200a8bc981af8c9ecdc08dfdaef0bb6e09f88f3c616ef3d9060200160405180910390a250565b5f611a5d82612e97612e9087613de7565b8690614255565b90614255565b6001600160a01b038281165f8181526099602090815260409182902060010180546001600160a01b0319169486169485179055905192835290917f773b54c04d756fcc5e678111f7d730de3be98192000799eee3d63716055a87c6910161269f565b6066545f90600190811603612f275760405163840a48d560e01b815260040160405180910390fd5b5f5f612f3285611683565b915091505f612f425f8685612755565b6001600160a01b038781165f818152609a602052604080822080546001600160a01b031916948b16948517905551939450919290917fc3ee9f2e5fda98e8066a1f745b2df9285f416fe98cf2559cd21484b3d874330491a35f5b8351811015611cb25773beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac06001600160a01b0316848281518110612fd557612fd5615930565b60200260200101516001600160a01b0316036131455760405163a3d75e0960e01b81526001600160a01b0388811660048301525f917f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3389091169063a3d75e0990602401602060405180830381865afa158015613053573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061307791906159f0565b90505f60a25f8a6001600160a01b03166001600160a01b031681526020019081526020015f205f8785815181106130b0576130b0615930565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020015f206040518060200160405290815f82015481525050905061312485848151811061310257613102615930565b6020026020010151836001600160401b0316836138dc9092919063ffffffff16565b85848151811061313657613136615930565b60200260200101818152505050505b61319e868886848151811061315c5761315c615930565b60200260200101515f87868151811061317757613177615930565b602002602001015187878151811061319157613191615930565b6020026020010151613288565b600101612f9c565b5f73beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeabf196001600160a01b038416016132785760405163a3d75e0960e01b81526001600160a01b0385811660048301525f917f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a3389091169063a3d75e0990602401602060405180830381865afa158015613234573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061325891906159f0565b90506132706001600160401b038481169083166138c8565b915050610dd0565b506001600160401b031692915050565b805f036132a857604051630a33bc6960e21b815260040160405180910390fd5b81156133c5576001600160a01b038086165f90815260a2602090815260408083209388168352929052206132de81858585614269565b6040805160208101909152815481527f8be932bac54561f27260f95463d9b8ab37e06b2842e5ee2404157cc13df6eb8f908790879061331c90613de7565b60405161332b93929190615c66565b60405180910390a161333c8661107e565b15611cb2576001600160a01b038088165f90815260986020908152604080832093891683529290529081208054859290613377908490615a1f565b92505081905550866001600160a01b03167f1ec042c965e2edd7107b51188ee0f383e22e76179041ab3a9d18ff151405166c8787866040516133bb93929190615c66565b60405180910390a2505b505050505050565b604051631beb2b9760e31b81526001600160a01b0382811660048301523360248301523060448301525f80356001600160e01b0319166064840152917f00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e59091169063df595cb8906084016020604051808303815f875af1158015613453573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119b591906159a7565b60605f613483836142e4565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b6134bc614c00565b5f82815260a46020908152604091829020825160e08101845281546001600160a01b0390811682526001830154811682850152600283015416818501526003820154606082810191909152600483015463ffffffff1660808301526005830180548651818702810187019097528087529195929460a0860193929083018282801561356e57602002820191905f5260205f20905b81546001600160a01b03168152600190910190602001808311613550575b50505050508152602001600682018054806020026020016040519081016040528092919081815260200182805480156135c457602002820191905f5260205f20905b8154815260200190600101908083116135b0575b50505050508152505091508160a00151516001600160401b038111156135ec576135ec614e62565b604051908082528060200260200182016040528015613615578160200160208202803683370190505b5090505f7f00000000000000000000000000000000000000000000000000000000000189c083608001516136499190615ccc565b90505f4363ffffffff168263ffffffff161061367a57613675845f015185602001518660a00151612755565b613691565b613691845f015185602001518660a001518561430b565b90505f5b8460a0015151811015611358576136e28560c0015182815181106136bb576136bb615930565b60200260200101518383815181106136d5576136d5615930565b6020026020010151614439565b8482815181106136f4576136f4615930565b6020908102919091010152600101613695565b5f6137158483856001614444565b611a5d9085615ce8565b6001600160a01b038085165f90815260a560209081526040808320938716835292905290812081906137509061449f565b90505f6137b660016137827f00000000000000000000000000000000000000000000000000000000000189c043615cfb565b61378c9190615cfb565b6001600160a01b03808a165f90815260a560209081526040808320938c16835292905220906144b9565b90505f6137c38284615ce8565b90506137d08187876144d5565b98975050505050505050565b6001600160a01b038085165f90815260986020908152604080832093861683529290529081208054839290613812908490615ce8565b92505081905550836001600160a01b03167f6909600037b75d7b4733aedd815442b5ec018a827751c832aaff64eba5d6d2dd848484604051611afe93929190615c66565b5f6001600160a01b03821673beac0eeeeeeeeeeeeeeeeeeeeeeeeeeeeeebeac0146138a1577f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a6119b5565b7f00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a33892915050565b5f610dd08383670de0b6b3a76400006144f3565b5f611a5d826138f46138ed87613de7565b86906138c8565b906138c8565b6033546001600160a01b031633146111e85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161214e565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60a08401515182146139ca576040516343714afd60e01b815260040160405180910390fd5b83604001516001600160a01b0316336001600160a01b031614613a00576040516316110d3560e21b815260040160405180910390fd5b5f613a0a856111ea565b5f818152609e602052604090205490915060ff16613a3b576040516387c9d21960e01b815260040160405180910390fd5b60605f7f00000000000000000000000000000000000000000000000000000000000189c08760800151613a6e9190615ccc565b90508063ffffffff164363ffffffff1611613a9c576040516378f67ae160e11b815260040160405180910390fd5b613ab3875f015188602001518960a001518461430b565b87516001600160a01b03165f90815260a360205260409020909250613ad99150836145d8565b505f82815260a46020526040812080546001600160a01b031990811682556001820180548216905560028201805490911690556003810182905560048101805463ffffffff1916905590613b306005830182614cf5565b613b3d600683015f614cf5565b50505f828152609e602052604090819020805460ff19169055517f1f40400889274ed07b24845e5054a87a0cab969eb1277aafe61ae352e7c32a0090613b869084815260200190565b60405180910390a185516001600160a01b039081165f908152609a6020526040812054885160a08a01519190931692613bc0918490612755565b90505f5b8860a0015151811015613ddc575f613beb8a60a001518381518110611f0357611f03615930565b90505f613c218b60c001518481518110613c0757613c07615930565b60200260200101518785815181106136d5576136d5615930565b9050805f03613c31575050613dd4565b8715613cff57816001600160a01b0316632eae418c8c5f01518d60a001518681518110613c6057613c60615930565b60200260200101518d8d88818110613c7a57613c7a615930565b9050602002016020810190613c8f9190615191565b60405160e085901b6001600160e01b03191681526001600160a01b03938416600482015291831660248301529091166044820152606481018490526084015f604051808303815f87803b158015613ce4575f5ffd5b505af1158015613cf6573d5f5f3e3d5ffd5b50505050613dd1565b5f5f836001600160a01b03166350ff72258e5f01518f60a001518881518110613d2a57613d2a615930565b6020026020010151866040518463ffffffff1660e01b8152600401613d5193929190615c66565b60408051808303815f875af1158015613d6c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d909190615d17565b91509150613dce878e5f01518f60a001518881518110613db257613db2615930565b602002602001015185858b8b8151811061319157613191615930565b50505b50505b600101613bc4565b505050505050505050565b80515f9015613df75781516119b5565b670de0b6b3a764000092915050565b606654606090600190600290811603613e325760405163840a48d560e01b815260040160405180910390fd5b6001600160a01b038084165f818152609a602052604080822080546001600160a01b0319811690915590519316928392917ffee30966a256b71e14bc0ebfc94315e28ef4a97a7131a9e2b7a310a73af4467691a35f5f613e9186611683565b9150915081515f03613ea55750505061405f565b81516001600160401b03811115613ebe57613ebe614e62565b604051908082528060200260200182016040528015613ee7578160200160208202803683370190505b5094505f613ef6878585612755565b90505f5b8351811015614059576040805160018082528183019092525f916020808301908036833750506040805160018082528183019092529293505f9291506020808301908036833750506040805160018082528183019092529293505f92915060208083019080368337019050509050868481518110613f7a57613f7a615930565b6020026020010151835f81518110613f9457613f94615930565b60200260200101906001600160a01b031690816001600160a01b031681525050858481518110613fc657613fc6615930565b6020026020010151825f81518110613fe057613fe0615930565b602002602001018181525050848481518110613ffe57613ffe615930565b6020026020010151815f8151811061401857614018615930565b6020026020010181815250506140318b898585856128a7565b8a858151811061404357614043615930565b6020908102919091010152505050600101613efa565b50505050505b50919050565b6001600160a01b038084165f90815260996020526040902060010154168061408d5750610f25565b6001600160a01b0381165f908152609c6020908152604080832085845290915290205460ff16156140d157604051630d4c4c9160e21b815260040160405180910390fd5b6001600160a01b0381165f908152609c602090815260408083208584528252909120805460ff1916600117905583015161234b908290614118908890889084908890610889565b855160208701516145e3565b60605f6141507f312e332e30000000000000000000000000000000000000000000000000000005613477565b9050805f8151811061416457614164615930565b602001015160f81c60f81b8160018151811061418257614182615930565b016020908101516040516001600160f81b03199384169281019290925291909116602182015260220160405160208183030381529060405291505090565b60605f610dd083614635565b5f610dd06141d984613de7565b83906138c8565b6001600160a01b038084165f90815260a560209081526040808320938616835292905290812061420f9061449f565b9050610f254361421f8484615a1f565b6001600160a01b038088165f90815260a560209081526040808320938a16835292905220919061468e565b5f610dd08383614699565b5f610dd083670de0b6b3a7640000846144f3565b825f036142955760408051602081019091528454815261428e908290612e9790613de7565b8455610f25565b6040805160208101909152845481525f906142b19085846138dc565b90505f6142be8483615a1f565b90505f6142d984612e976142d2888a615a1f565b8590614255565b875550505050505050565b5f60ff8216601f8111156119b557604051632cd44ac360e21b815260040160405180910390fd5b60605f83516001600160401b0381111561432757614327614e62565b604051908082528060200260200182016040528015614350578160200160208202803683370190505b5090505f7f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b03166394d7d00c8787876040518463ffffffff1660e01b81526004016143a493929190615d39565b5f60405180830381865afa1580156143be573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526143e59190810190615bd7565b90505f5b855181101561442d576144088887838151811061285057612850615930565b83828151811061441a5761441a615930565b60209081029190910101526001016143e9565b50909695505050505050565b5f610dd083836138c8565b5f5f6144518686866144f3565b9050600183600281111561446757614467615d72565b14801561448357505f848061447e5761447e615d86565b868809115b1561449657614493600182615a1f565b90505b95945050505050565b5f6144aa82826146e5565b6001600160e01b031692915050565b5f6144c583838361472a565b6001600160e01b03169392505050565b5f611a5d6144e38385615d9a565b85906001600160401b03166138c8565b5f80805f19858709858702925082811083820303915050805f0361452a5783828161452057614520615d86565b0492505050610dd0565b8084116145715760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161214e565b5f8486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091025f889003889004909101858311909403939093029303949094049190911702949350505050565b5f610dd08383614773565b4281101561460457604051630819bdcd60e01b815260040160405180910390fd5b6146186001600160a01b0385168484614856565b610f2557604051638baa579f60e01b815260040160405180910390fd5b6060815f0180548060200260200160405190810160405280929190818152602001828054801561468257602002820191905f5260205f20905b81548152602001906001019080831161466e575b50505050509050919050565b6111068383836148aa565b5f8181526001830160205260408120546146de57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556119b5565b505f6119b5565b81545f9080156147225761470b846146fe600184615ce8565b5f91825260209091200190565b5464010000000090046001600160e01b0316611a5d565b509092915050565b82545f908161473b868683856149b0565b9050801561476957614752866146fe600184615ce8565b5464010000000090046001600160e01b0316610907565b5091949350505050565b5f818152600183016020526040812054801561484d575f614795600183615ce8565b85549091505f906147a890600190615ce8565b9050818114614807575f865f0182815481106147c6576147c6615930565b905f5260205f200154905080875f0184815481106147e6576147e6615930565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061481857614818615db9565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506119b5565b5f9150506119b5565b5f5f5f6148638585614a03565b90925090505f81600481111561487b5761487b615d72565b1480156148995750856001600160a01b0316826001600160a01b0316145b806109075750610907868686614a42565b82548015614962575f6148c2856146fe600185615ce8565b60408051808201909152905463ffffffff8082168084526401000000009092046001600160e01b0316602084015291925090851610156149155760405163151b8e3f60e11b815260040160405180910390fd5b805163ffffffff8086169116036149605782614936866146fe600186615ce8565b80546001600160e01b03929092166401000000000263ffffffff9092169190911790555050505050565b505b506040805180820190915263ffffffff92831681526001600160e01b03918216602080830191825285546001810187555f968752952091519051909216640100000000029190921617910155565b5f5b81831015611bda575f6149c58484614b29565b5f8781526020902090915063ffffffff86169082015463ffffffff1611156149ef578092506149fd565b6149fa816001615a1f565b93505b506149b2565b5f5f8251604103614a37576020830151604084015160608501515f1a614a2b87828585614b43565b945094505050506120b1565b505f905060026120b1565b5f5f5f856001600160a01b0316631626ba7e60e01b8686604051602401614a6a929190615dcd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051614aa89190615de5565b5f60405180830381855afa9150503d805f8114614ae0576040519150601f19603f3d011682016040523d82523d5f602084013e614ae5565b606091505b5091509150818015614af957506020815110155b801561090757508051630b135d3f60e11b90614b1e9083016020908101908401615b48565b149695505050505050565b5f614b376002848418615dfb565b610dd090848416615a1f565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614b7857505f90506003614bf7565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015614bc9573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b038116614bf1575f60019250925050614bf7565b91505f90505b94509492505050565b6040518060e001604052805f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81526020015f63ffffffff16815260200160608152602001606081525090565b828054828255905f5260205f20908101928215614cac579160200282015b82811115614cac57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614c77565b50614cb8929150614d0c565b5090565b828054828255905f5260205f20908101928215614cac579160200282015b82811115614cac578251825591602001919060010190614cda565b5080545f8255905f5260205f20908101906124d891905b5b80821115614cb8575f8155600101614d0d565b6001600160a01b03811681146124d8575f5ffd5b80356122f781614d20565b5f5f5f5f5f60a08688031215614d53575f5ffd5b8535614d5e81614d20565b94506020860135614d6e81614d20565b93506040860135614d7e81614d20565b94979396509394606081013594506080013592915050565b5f5f83601f840112614da6575f5ffd5b5081356001600160401b03811115614dbc575f5ffd5b6020830191508360208260051b85010111156120b1575f5ffd5b5f5f60208385031215614de7575f5ffd5b82356001600160401b03811115614dfc575f5ffd5b614e0885828601614d96565b90969095509350505050565b602080825282518282018190525f918401906040840190835b8181101561289c578351835260209384019390920191600101614e2d565b5f60208284031215614e5b575f5ffd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b60405160e081016001600160401b0381118282101715614e9857614e98614e62565b60405290565b604080519081016001600160401b0381118282101715614e9857614e98614e62565b604051601f8201601f191681016001600160401b0381118282101715614ee857614ee8614e62565b604052919050565b5f6001600160401b03821115614f0857614f08614e62565b5060051b60200190565b5f82601f830112614f21575f5ffd5b8135614f34614f2f82614ef0565b614ec0565b8082825260208201915060208360051b860101925085831115614f55575f5ffd5b602085015b83811015614f7b578035614f6d81614d20565b835260209283019201614f5a565b5095945050505050565b5f82601f830112614f94575f5ffd5b8135614fa2614f2f82614ef0565b8082825260208201915060208360051b860101925085831115614fc3575f5ffd5b602085015b83811015614f7b578035835260209283019201614fc8565b5f5f5f60608486031215614ff2575f5ffd5b8335614ffd81614d20565b925060208401356001600160401b03811115615017575f5ffd5b61502386828701614f12565b92505060408401356001600160401b0381111561503e575f5ffd5b61504a86828701614f85565b9150509250925092565b5f8151808452602084019350602083015f5b82811015615084578151865260209586019590910190600101615066565b5093949350505050565b602081525f610dd06020830184615054565b803563ffffffff811681146122f7575f5ffd5b5f5f83601f8401126150c3575f5ffd5b5081356001600160401b038111156150d9575f5ffd5b6020830191508360208285010111156120b1575f5ffd5b5f5f5f5f60608587031215615103575f5ffd5b843561510e81614d20565b935061511c602086016150a0565b925060408501356001600160401b03811115615136575f5ffd5b615142878288016150b3565b95989497509550505050565b5f5f5f5f60808587031215615161575f5ffd5b843561516c81614d20565b9350602085013561517c81614d20565b93969395505050506040820135916060013590565b5f602082840312156151a1575f5ffd5b8135610dd081614d20565b5f5f604083850312156151bd575f5ffd5b82356151c881614d20565b915060208301356151d881614d20565b809150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f610dd060208301846151e3565b5f60e08284031215615233575f5ffd5b61523b614e76565b905061524682614d34565b815261525460208301614d34565b602082015261526560408301614d34565b604082015260608281013590820152615280608083016150a0565b608082015260a08201356001600160401b0381111561529d575f5ffd5b6152a984828501614f12565b60a08301525060c08201356001600160401b038111156152c7575f5ffd5b6152d384828501614f85565b60c08301525092915050565b5f602082840312156152ef575f5ffd5b81356001600160401b03811115615304575f5ffd5b611a5d84828501615223565b5f60208284031215615320575f5ffd5b813560ff81168114610dd0575f5ffd5b5f8151808452602084019350602083015f5b828110156150845781516001600160a01b0316865260209586019590910190600101615342565b80516001600160a01b03908116835260208083015182169084015260408083015190911690830152606080820151908301526080808201515f916153b49085018263ffffffff169052565b5060a082015160e060a08501526153ce60e0850182615330565b905060c083015184820360c08601526144968282615054565b604081525f6153f96040830185615369565b82810360208401526144968185615054565b5f82825180855260208501945060208160051b830101602085015f5b8381101561442d57601f19858403018852615443838351615054565b6020988901989093509190910190600101615427565b5f604082016040835280855180835260608501915060608160051b8601019250602087015f5b828110156154b057605f1987860301845261549b858351615369565b9450602093840193919091019060010161547f565b505050508281036020840152614496818561540b565b6001600160401b03811681146124d8575f5ffd5b5f5f5f5f608085870312156154ed575f5ffd5b84356154f881614d20565b9350602085013561550881614d20565b92506040850135615518816154c6565b91506060850135615528816154c6565b939692955090935050565b5f5f5f60608486031215615545575f5ffd5b833561555081614d20565b9250602084013591506040840135615567816154c6565b809150509250925092565b604081525f6153f96040830185615330565b5f5f5f60408486031215615596575f5ffd5b83356155a181614d20565b925060208401356001600160401b038111156155bb575f5ffd5b6155c7868287016150b3565b9497909650939450505050565b5f5f604083850312156155e5575f5ffd5b82356155f081614d20565b915060208301356001600160401b0381111561560a575f5ffd5b61561685828601614f12565b9150509250929050565b5f5f5f5f5f5f60608789031215615635575f5ffd5b86356001600160401b0381111561564a575f5ffd5b61565689828a01614d96565b90975095505060208701356001600160401b03811115615674575f5ffd5b61568089828a01614d96565b90955093505060408701356001600160401b0381111561569e575f5ffd5b6156aa89828a01614d96565b979a9699509497509295939492505050565b602081525f610dd06020830184615369565b5f5f5f606084860312156156e0575f5ffd5b83356156eb81614d20565b925060208401356001600160401b03811115615705575f5ffd5b840160408187031215615716575f5ffd5b61571e614e9e565b81356001600160401b03811115615733575f5ffd5b8201601f81018813615743575f5ffd5b80356001600160401b0381111561575c5761575c614e62565b61576f601f8201601f1916602001614ec0565b818152896020838501011115615783575f5ffd5b816020840160208301375f60209282018301528352928301359282019290925293969395505050506040919091013590565b5f5f604083850312156157c6575f5ffd5b82356157d181614d20565b946020939093013593505050565b604081525f6153f96040830185615054565b80151581146124d8575f5ffd5b5f5f5f5f60608587031215615811575f5ffd5b84356001600160401b03811115615826575f5ffd5b850160e08188031215615837575f5ffd5b935060208501356001600160401b03811115615851575f5ffd5b61585d87828801614d96565b9094509250506040850135615528816157f1565b5f5f60408385031215615882575f5ffd5b82356001600160401b03811115615897575f5ffd5b8301601f810185136158a7575f5ffd5b80356158b5614f2f82614ef0565b8082825260208201915060208360051b8501019250878311156158d6575f5ffd5b6020840193505b828410156159015783356158f081614d20565b8252602093840193909101906158dd565b945050505060208301356001600160401b0381111561560a575f5ffd5b602081525f610dd0602083018461540b565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112615958575f5ffd5b9190910192915050565b5f5f8335601e19843603018112615977575f5ffd5b8301803591506001600160401b03821115615990575f5ffd5b6020019150600581901b36038213156120b1575f5ffd5b5f602082840312156159b7575f5ffd5b8151610dd0816157f1565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b5f60208284031215615a00575f5ffd5b8151610dd0816154c6565b634e487b7160e01b5f52601160045260245ffd5b808201808211156119b5576119b5615a0b565b5f82601f830112615a41575f5ffd5b8151615a4f614f2f82614ef0565b8082825260208201915060208360051b860101925085831115615a70575f5ffd5b602085015b83811015614f7b578051835260209283019201615a75565b5f5f60408385031215615a9e575f5ffd5b82516001600160401b03811115615ab3575f5ffd5b8301601f81018513615ac3575f5ffd5b8051615ad1614f2f82614ef0565b8082825260208201915060208360051b850101925087831115615af2575f5ffd5b6020840193505b82841015615b1d578351615b0c81614d20565b825260209384019390910190615af9565b8095505050505060208301516001600160401b03811115615b3c575f5ffd5b61561685828601615a32565b5f60208284031215615b58575f5ffd5b5051919050565b5f823560de19833603018112615958575f5ffd5b5f6119b53683615223565b5f60208284031215615b8e575f5ffd5b8135610dd0816157f1565b5f60208284031215615ba9575f5ffd5b8151610dd081614d20565b6001600160a01b03831681526040602082018190525f90611a5d90830184615330565b5f60208284031215615be7575f5ffd5b81516001600160401b03811115615bfc575f5ffd5b8201601f81018413615c0c575f5ffd5b8051615c1a614f2f82614ef0565b8082825260208201915060208360051b850101925086831115615c3b575f5ffd5b6020840193505b82841015610907578351615c55816154c6565b825260209384019390910190615c42565b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f60018201615c9b57615c9b615a0b565b5060010190565b838152606060208201525f615cba6060830185615369565b82810360408401526109078185615054565b63ffffffff81811683821601908111156119b5576119b5615a0b565b818103818111156119b5576119b5615a0b565b63ffffffff82811682821603908111156119b5576119b5615a0b565b5f5f60408385031215615d28575f5ffd5b505080516020909101519092909150565b6001600160a01b03841681526060602082018190525f90615d5c90830185615330565b905063ffffffff83166040830152949350505050565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601260045260245ffd5b6001600160401b0382811682821603908111156119b5576119b5615a0b565b634e487b7160e01b5f52603160045260245ffd5b828152604060208201525f611a5d60408301846151e3565b5f82518060208501845e5f920191825250919050565b5f82615e1557634e487b7160e01b5f52601260045260245ffd5b50049056fea264697066735822122028823ec872a9df95048c08df1bd11d6833b239643a395c032aeedc56c3554f0e64736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef1280600000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e500000000000000000000000000000000000000000000000000000000000189c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000005312e332e30000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _strategyManager (address): 0x858646372CC42E1A627fcE94aa7A7033e7CF075A
Arg [1] : _eigenPodManager (address): 0x91E677b07F7AF907ec9a428aafA9fc14a0d3A338
Arg [2] : _allocationManager (address): 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39
Arg [3] : _pauserRegistry (address): 0xB8765ed72235d279c3Fb53936E4606db0Ef12806
Arg [4] : _permissionController (address): 0x25E5F8B1E7aDf44518d35D5B2271f114e081f0E5
Arg [5] : _MIN_WITHDRAWAL_DELAY (uint32): 100800
Arg [6] : _version (string): 1.3.0
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
Arg [1] : 00000000000000000000000091e677b07f7af907ec9a428aafa9fc14a0d3a338
Arg [2] : 000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39
Arg [3] : 000000000000000000000000b8765ed72235d279c3fb53936e4606db0ef12806
Arg [4] : 00000000000000000000000025e5f8b1e7adf44518d35d5b2271f114e081f0e5
Arg [5] : 00000000000000000000000000000000000000000000000000000000000189c0
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [8] : 312e332e30000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
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.