Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
EzRVault
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "./EzRvaultStorage.sol";
import "../Errors/Errors.sol";
import "../EigenLayer/interfaces/IStrategyManager.sol";
import "../EigenLayer/interfaces/IDelegationManager.sol";
import "../EigenLayer/interfaces/IRewardsCoordinator.sol";
import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IBeacon } from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import "./libraries/EzRVaultLib.sol";
contract EzRVault is
ERC20Upgradeable,
OwnableUpgradeable,
ReentrancyGuardUpgradeable,
EzRVaultStorageV5
{
using SafeERC20 for IERC20;
uint256 public constant BASIS_POINTS = 10000; // BASIS_POINTS used for percentage (10000 basis points equal 100%)
uint256 public constant SHARE_OFFSET = 1e3;
uint256 public constant BALANCE_OFFSET = 1e3;
// Withdraw buffer Beacon
IBeacon public immutable withdrawBufferBeacon;
// EigenLayer configs
IStrategyManager public immutable strategyManager;
IDelegationManager public immutable delegationManager;
IRewardsCoordinator public immutable rewardsCoordinator;
IERC20 public immutable EIGEN;
IERC20 public immutable B_EIGEN;
// Protocol fee on rewards
uint256 public immutable protocolFee;
address public immutable protocolTreasury;
// 7 days in blocks number (60*60*24*7 / 12)
uint256 public constant SEVEN_DAYS_BLOCKS = 50_400;
// Max cooldown blocks basis points
uint256 public immutable maxCooldownBlocksBasisPoints;
event DelegationAddressUpdated(address delegateAddress);
event VaultCooldownUpdated(uint256 oldVaultCooldown, uint256 newVaultCooldown);
event Deposit(address user, uint256 underlyingAmount, uint256 lpMinted);
event WithdrawStarted(
bytes32 withdrawRoot,
address user,
address staker,
address delegatedTo,
address withdrawer,
uint nonce,
uint startBlock,
IStrategy[] strategies,
uint256[] shares
);
event WithdrawRequestClaimed(
bytes32 withdrawalRoot,
address user,
uint256 underlyingClaimAmount,
IDelegationManager.Withdrawal withdrawal
);
event AdminWithdrawalStarted(
bytes32 withdrawRoot,
address admin,
address staker,
address delegatedTo,
address withdrawer,
uint nonce,
uint startBlock,
IStrategy[] strategies,
uint256[] shares
);
event AdminWithdrawalCompleted(
bytes32 withdrawalRoot,
address admin,
uint256 underlyingClaimAmount,
IDelegationManager.Withdrawal withdrawal
);
event EmergencyWithdrawalTracked(IDelegationManager.Withdrawal withdrawal);
event EmergencyWithdrawalCompleted(IDelegationManager.Withdrawal withdrawal);
event IncentiveDeposited(uint256 amount);
event Paused(bool paused);
event PauserUpdated(address oldPauser, address newPauser);
event VaultRewardsDestinationUpdated(
address oldRewardsDestination,
address newRewardsDestination
);
event RewardsProofSubmitterUpdated(
address oldRewardsProofSubmitter,
address newRewardsProofSubmitter
);
event TvlLimitUpdated(uint256 newTvlLimit);
event WithdrawUnlockTimestampUpdated(uint256 newWithdrawUnlockTimestamp);
event WithdrawalBufferFilled(uint256 _amount);
event InstantWithdrawEnabled(IWithdrawalBuffer _withdrawalBuffer);
event WithdrawalBufferAdminUpdated(address oldAdmin, address newAdmin);
/// @dev Only allows deposit when Delegated
modifier onlyWhenDelegated() {
_checkIfDelegated();
_;
}
/// @dev Only allows deposit and withdraw when not paused
modifier whenNotPaused() {
_checkIfPaused();
_;
}
/// @dev Only allowed pauser and owner to change pause state
modifier onlyOwnerOrPauser() {
if (msg.sender != owner() && msg.sender != pauser) revert NotPauser();
_;
}
/// @dev only allowed rewardsProodSubmitter(If set) and owner can submit proofs to claim rewards.
modifier onlyRewardsProofSubmitter() {
if (msg.sender != owner() && msg.sender != rewardsProofSubmitter)
revert NotRewardsProofSubmitter();
_;
}
/// @dev only allowed withdrawalBuffer(If set) can burn LP tokens through instant withdrawal
modifier onlyWithdrawalBuffer() {
if (msg.sender != address(withdrawalBuffer) || address(withdrawalBuffer) == address(0))
revert NotWithdrawalBuffer();
_;
}
/// @dev only allows owner or withdrawalBufferAdmin to call the function
modifier onlyOwnerOrWithdrawalBufferAdmin() {
_checkIfOwnerOrWithdrawalBufferAdmin();
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
IStrategyManager _strategyManager,
IDelegationManager _delegationManager,
IRewardsCoordinator _rewardsCoordinator,
IERC20 _eigen,
IERC20 _bEigen,
uint256 _protocolFee,
address _protocolTreasury,
uint256 _maxCooldownBlocksBasisPoints,
IBeacon _withdrawBufferBeacon
) {
if (
address(_strategyManager) == address(0) ||
address(_delegationManager) == address(0) ||
address(_rewardsCoordinator) == address(0) ||
address(_eigen) == address(0) ||
address(_bEigen) == address(0) ||
_protocolFee == 0 ||
_protocolTreasury == address(0) ||
_maxCooldownBlocksBasisPoints == 0 ||
address(_withdrawBufferBeacon) == address(0)
) revert InvalidZeroInput();
// verify protocol fee
if (_protocolFee > BASIS_POINTS) revert InvalidFee();
if (_maxCooldownBlocksBasisPoints > BASIS_POINTS)
revert InvalidMaxCooldownBlocksBasisPoints();
strategyManager = _strategyManager;
delegationManager = _delegationManager;
rewardsCoordinator = _rewardsCoordinator;
protocolFee = _protocolFee;
protocolTreasury = _protocolTreasury;
maxCooldownBlocksBasisPoints = _maxCooldownBlocksBasisPoints;
EIGEN = _eigen;
B_EIGEN = _bEigen;
withdrawBufferBeacon = _withdrawBufferBeacon;
_disableInitializers();
}
function initialize(
string memory _name,
string memory _symbol,
IERC20 _underlying,
IStrategy _strategy,
address vaultOwner,
uint256 _cooldownBlocks,
uint256 _vaultFee,
address _vaultFeeDestination,
address _rewardsDestination
) public initializer {
// check for zero values
if (
address(_underlying) == address(0) ||
address(_strategy) == address(0) ||
vaultOwner == address(0) ||
_vaultFeeDestination == address(0) ||
_rewardsDestination == address(0) ||
bytes(_name).length == 0 ||
bytes(_symbol).length == 0
) revert InvalidZeroInput();
// verify vault fee
if (_vaultFee + protocolFee > BASIS_POINTS) revert InvalidFee();
// check strategy whitelisted,
// Note: beaconStrategy will fail as it is not whitelisted under strategyManager
if (!strategyManager.strategyIsWhitelistedForDeposit(_strategy)) revert InvalidStrategy();
// check if underlying token is EIGEN
if (_underlying == EIGEN || _underlying == B_EIGEN) {
// revert if strategy underlying is not bEIGEN
if (IStrategy(_strategy).underlyingToken() != B_EIGEN) revert InvalidUnderlyingToken();
} else {
// check underlying token
if (IStrategy(_strategy).underlyingToken() != _underlying)
revert InvalidUnderlyingToken();
}
// check for cooldown blocks
if (_cooldownBlocks < delegationManager.minWithdrawalDelayBlocks())
revert InvalidWithdrawalCooldown();
__ERC20_init(_name, _symbol);
// ReentrancyGuard init
__ReentrancyGuard_init();
// transfer ownership to vaultOwner
_transferOwnership(vaultOwner);
// set underlying asset and strategy
underlying = _underlying;
underlyingStrategy = _strategy;
underlyingDecimals = ERC20(address(_underlying)).decimals();
vaultCooldownBlocks = _cooldownBlocks;
cooldownBlocksUpdatedAt = block.number;
vaultFee = _vaultFee;
vaultFeeDestination = _vaultFeeDestination;
vaultRewardsDestination = _rewardsDestination;
}
// /**
// * @notice reinitializing the EzRVaults to track pre Slashing Upgrade queued shares,
// * @notice reinitialize with version 2
// * @dev permissioned call (onlyOwner)
// * @param withdrawRoots list of pending withdrawal roots
// * @param initialWithdrawableShares list of initial withdrawable shares for each withdrawal root
// */
// function reinitialize(
// bytes32[] calldata withdrawRoots,
// uint256[] calldata initialWithdrawableShares
// ) external onlyOwner reinitializer(2) {
// // check for zero values
// if (withdrawRoots.length != initialWithdrawableShares.length) revert InvalidZeroInput();
// // set the initial withdrawable shares for each withdrawal root
// for (uint256 i = 0; i < withdrawRoots.length; ) {
// queuedWithdrawalInfo[withdrawRoots[i]]
// .initialWithdrawableShares = initialWithdrawableShares[i];
// unchecked {
// ++i;
// }
// }
// }
function decimals() public view override returns (uint8) {
return underlyingDecimals;
}
/// @dev Sets the address to delegate tokens to in EigenLayer - Can only delegate to Single Operator
function setDelegateAddress(
address _delegateAddress,
ISignatureUtilsMixinTypes.SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) external nonReentrant onlyOwner {
_checkZeroValue(address(_delegateAddress));
// check the delegation status on EigenLayer
// Note: In case of force undelegation by delegatedOperator delegatedTo will be updated to address(0)
if (delegationManager.delegatedTo(address(this)) != address(0)) revert AlreadyDelegated();
delegationManager.delegateTo(_delegateAddress, approverSignatureAndExpiry, approverSalt);
emit DelegationAddressUpdated(_delegateAddress);
}
function setCooldownBlocks(uint256 _cooldownBlocks) external nonReentrant onlyOwner {
uint256 minCooldownBlocks = delegationManager.minWithdrawalDelayBlocks();
// check for cooldown blocks
if (_cooldownBlocks < minCooldownBlocks || _cooldownBlocks == 0)
revert InvalidWithdrawalCooldown();
// check for valid cooldownBlocks config
if (_cooldownBlocks > minCooldownBlocks) {
uint256 maxCooldownBlocksAllowed = minCooldownBlocks +
(minCooldownBlocks * maxCooldownBlocksBasisPoints) /
BASIS_POINTS;
// check for max cooldownblocks allowed
if (_cooldownBlocks > maxCooldownBlocksAllowed) revert ExceedMaxCooldownBlocks();
// check for cooldown config last updated
_checkCooldownBlocksUpdateDelay();
}
emit VaultCooldownUpdated(vaultCooldownBlocks, _cooldownBlocks);
vaultCooldownBlocks = _cooldownBlocks;
cooldownBlocksUpdatedAt = block.number;
}
function setRewardsDestination(address _rewardsDestination) external nonReentrant onlyOwner {
_checkZeroValue(_rewardsDestination);
emit VaultRewardsDestinationUpdated(vaultRewardsDestination, _rewardsDestination);
vaultRewardsDestination = _rewardsDestination;
}
/**
* @notice Sets the TVL limit for the vault
* @dev permissioned call (onlyOwner), 0 means no limit
* @param _tvlLimit new TVL limit for the vault
*/
function setTvlLimit(uint256 _tvlLimit) external onlyOwner {
// Set the value
tvlLimit = _tvlLimit;
// Emit event for tvl limit update
emit TvlLimitUpdated(_tvlLimit);
}
/**
* @notice Sets the withdraw unlock timestamp for the vault
* @dev permissioned call (onlyOwner), this is the timestamp after which users can withdraw their funds, 0 means no unlock timestamp (users can withdraw immediately)
* @param _withdrawUnlockTimestamp new withdraw unlock timestamp for the vault
*/
function setWithdrawUnlockTimestamp(uint256 _withdrawUnlockTimestamp) external onlyOwner {
// Ensure the new timestamp is not in the past
if (_withdrawUnlockTimestamp > 0 && _withdrawUnlockTimestamp <= block.timestamp) {
revert InvalidWithdrawUnlockTimestamp();
}
// set the withdraw unlock timestamp
withdrawUnlockTimestamp = _withdrawUnlockTimestamp;
// Emit event for withdraw unlock timestamp update
emit WithdrawUnlockTimestampUpdated(_withdrawUnlockTimestamp);
}
/**
* @notice Pause the vault
* @dev permissioned call (onlyPuaser)
*/
function pause() external onlyOwnerOrPauser {
paused = true;
emit Paused(true);
}
/**
* @notice UnPause the vault
* @dev permissioned call (onlyOwner)
*/
function unpause() external onlyOwner {
paused = false;
emit Paused(false);
}
/**
* @notice Sets a proof submitter address which can call processRewards
* @dev permissioned call (onlyOwner), cannot be set to address(0)
* @param _rewardsProofSubmitter new proof submitter address
*/
function setRewardsProofSubmitter(address _rewardsProofSubmitter) external onlyOwner {
_checkZeroValue(_rewardsProofSubmitter);
emit RewardsProofSubmitterUpdated(rewardsProofSubmitter, _rewardsProofSubmitter);
rewardsProofSubmitter = _rewardsProofSubmitter;
}
/**
* @notice Update pauser address
* @dev permissioned call (onlyOwner)
* @param _pauser new pauser address
*/
function setPauser(address _pauser) external onlyOwner {
_checkZeroValue(_pauser);
emit PauserUpdated(pauser, _pauser);
pauser = _pauser;
}
function setWithdrawalBufferAdmin(address _withdrawalBufferAdmin) external onlyOwner {
_checkZeroValue(_withdrawalBufferAdmin);
emit WithdrawalBufferAdminUpdated(withdrawalBufferAdmin, _withdrawalBufferAdmin);
withdrawalBufferAdmin = _withdrawalBufferAdmin;
}
/**
* @notice Enable InstantWithdrawal by deploying a withdrawal buffer beacon proxy
* @dev permissioned call (onlyOwner), can be called only once
* @param _instantWithdrawalFeeBps Fee BPS for instant withdrawal
* @param _withdrawalBufferTarget Max Buffer capacity for Instant Withdrawals
* @param _feeDestination destination address for instant withdrawal fee
*/
function enableInstantWithdrawals(
uint256 _instantWithdrawalFeeBps,
uint256 _withdrawalBufferTarget,
address _feeDestination,
address _withdrawalBufferAdmin
) external onlyOwner {
// Check for zero values
_checkZeroValue(_withdrawalBufferAdmin);
// Check if withdrawalBuffer is already enabled
if (address(withdrawalBuffer) != address(0)) revert InstantWithdrawAlreadyEnabled();
withdrawalBuffer = IWithdrawalBuffer(
EzRVaultLib.createWithdrawBuffer(
address(withdrawBufferBeacon),
_instantWithdrawalFeeBps,
_withdrawalBufferTarget,
_feeDestination,
owner()
)
);
// update withdrawal buffer admin
emit WithdrawalBufferAdminUpdated(withdrawalBufferAdmin, _withdrawalBufferAdmin);
withdrawalBufferAdmin = _withdrawalBufferAdmin;
emit InstantWithdrawEnabled(withdrawalBuffer);
}
/// @dev Deposit tokens into the EigenLayer. This call assumes any balance of tokens in this contract will be delegated
/// so do not directly send tokens here or they will be delegated and attributed to the next caller.
/// @return shares The amount of new shares in the `strategy` created as part of the action.
function deposit(
uint256 tokenAmount
) external nonReentrant onlyWhenDelegated whenNotPaused returns (uint256 shares) {
_checkZeroValue(tokenAmount);
// Verify it is not over the TVL limit
if (tvlLimit > 0) {
uint256 currentTvl = getUnderlyingBalanceFromStrategy();
if (currentTvl + tokenAmount > tvlLimit) revert TvlLimitExceeded();
}
// Move the tokens into vault
underlying.safeTransferFrom(msg.sender, address(this), tokenAmount);
// calculate mint amount
// if totalSupply of LP token is 0 mint the initial amount at 1:1
uint256 mintAmount = (tokenAmount * scaleFactor()) / getRate();
// sanity check
if (mintAmount == 0) revert InvalidTokenAmount();
_mint(msg.sender, mintAmount);
// check and fill the withdraw buffer if it is set
uint256 remainingAmount = _checkAndFillWithdrawBuffer(tokenAmount);
// deposit the remaining amount into EigenLayer
if (remainingAmount > 0) {
_deposit(remainingAmount);
}
emit Deposit(msg.sender, tokenAmount, mintAmount);
}
/**
* @notice Perform necessary checks on input data and deposits into EigenLayer
* @param _tokenAmount amount of given token to deposit
* @return shares shares for deposited amount
*/
function _deposit(uint256 _tokenAmount) internal returns (uint256 shares) {
// Approve the strategy manager to spend the tokens
underlying.safeIncreaseAllowance(address(strategyManager), _tokenAmount);
// Deposit the tokens via the strategy manager
return strategyManager.depositIntoStrategy(underlyingStrategy, underlying, _tokenAmount);
}
/**
* @notice Tracks the pending queued withdrawal shares cause by Operator force undelegating the Vault
* @dev permissioned call (onlyOwner of Vault),
* EigenLayer link - https://github.com/Layr-Labs/eigenlayer-contracts/blob/dev/src/contracts/core/DelegationManager.sol#L242
* @param withdrawal Withdrawal struct needs to be tracked
*/
function emergencyTrackQueuedWithdrawal(
IDelegationManager.Withdrawal memory withdrawal
) external onlyOwner {
if (withdrawal.strategies[0] != underlyingStrategy) revert InvalidStrategy();
bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal);
// verify withdrawal is not user initiated or admin initiated
if (
withdrawRequest[withdrawalRoot].withdrawer != address(0) ||
adminWithdrawalRequest[withdrawalRoot].shares != 0
) revert WithdrawalAlreadyTracked();
// verify emergency withdrawal is not tracked
if (emergencyWithdrawal[withdrawalRoot]) revert WithdrawalAlreadyTracked();
// verify withdrawal is pending and vault not double counting
if (!delegationManager.pendingWithdrawals(withdrawalRoot))
revert WithdrawalAlreadyCompleted();
uint256 withdrawableShares;
// get current shares of queuedWithdrawal from EigenLayer DelegationManager
(, uint256[] memory currentShares) = delegationManager.getQueuedWithdrawal(withdrawalRoot);
// track queued shares for the underlying in withdrawable shares
queuedShares += currentShares[0];
withdrawableShares = currentShares[0];
// track initial withdrawable shares of the underlying in queuedWithdrawal
queuedWithdrawalInfo[withdrawalRoot].initialWithdrawableShares = withdrawableShares;
// track in emergencyWithdrawal
emergencyWithdrawal[withdrawalRoot] = true;
emit EmergencyWithdrawalTracked(withdrawal);
}
/**
* @notice Complete Emergency queued withdrwal initiated by force undelegation by Operator
* @dev permissioned call by OnlyOwner of vault
* @param withdrawal Withdrawal struct for EigenLayer
*/
function completeEmergencyTrackedWithdrawal(
IDelegationManager.Withdrawal memory withdrawal
) external onlyOwner {
bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal);
if (!emergencyWithdrawal[withdrawalRoot]) revert InvalidWithdrawal();
IERC20[] memory tokens = new IERC20[](1);
tokens[0] = underlying;
// reduce queuedShares to avoid double counting
queuedShares -= queuedWithdrawalInfo[withdrawalRoot].initialWithdrawableShares;
// reset slashing delta to avoid double counting
_resetSlashingDelta(withdrawalRoot);
// complete the queued withdrawal from EigenLayer with receiveAsToken set to true
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true);
// reset emergencyQueuedWithdrawal
delete emergencyWithdrawal[withdrawalRoot];
// redeposit funds to strategy
_deposit(underlying.balanceOf(address(this)));
emit EmergencyWithdrawalCompleted(withdrawal);
}
// TODO: emergency track slashed queued withdrawal
/**
* @notice Tracks Slashing delta of queuedWithdrawal
* @param withdrawalRoots EigenLayer withdrawal roots to track slashing delta for
*/
function emergencyTrackSlashedQueuedWithdrawalDelta(
bytes32[] calldata withdrawalRoots
) external {
for (uint256 i = 0; i < withdrawalRoots.length; ) {
// revert if withdrawalRoot not in withdrawRequest, not in adminWithdrawalRequest and not emergencyWithdrawal
if (
withdrawRequest[withdrawalRoots[i]].withdrawer == address(0) &&
adminWithdrawalRequest[withdrawalRoots[i]].shares == 0 &&
!emergencyWithdrawal[withdrawalRoots[i]]
) revert WithdrawalNotQueued();
// get withdrawal and current shares of queuedWithdrawal from EigenLayer DelegationManager
(, uint256[] memory currentShares) = delegationManager.getQueuedWithdrawal(
withdrawalRoots[i]
);
// Only underlying token will be present in queuedWithdrawal. Therefore currentShares length will be 1
// calculate new slashing delta for each token
uint256 slashingDelta = (queuedWithdrawalInfo[withdrawalRoots[i]]
.initialWithdrawableShares > currentShares[0])
? queuedWithdrawalInfo[withdrawalRoots[i]].initialWithdrawableShares -
currentShares[0]
: 0;
// reduce totalQueuedSharesSlashedDelta with old slashing delta for queuedWithdrawal
totalQueuedSharesSlashedDelta -= queuedWithdrawalInfo[withdrawalRoots[i]]
.sharesSlashedDelta;
// track new slashed delta for each token
totalQueuedSharesSlashedDelta += slashingDelta;
// track new slashed delta for queuedWithdrawal
queuedWithdrawalInfo[withdrawalRoots[i]].sharesSlashedDelta = slashingDelta;
unchecked {
++i;
}
}
}
/**
* @notice Creates a withdraw request for user and queueWithdrawal on EigenLayer
* @param tokenAmount amount of LP token to withdraw
*/
function withdraw(
uint256 tokenAmount
) external nonReentrant onlyWhenDelegated whenNotPaused returns (bytes32) {
_checkZeroValue(tokenAmount);
// check if withdraw unlock timestamp is set and not reached
if (withdrawUnlockTimestamp > 0 && block.timestamp < withdrawUnlockTimestamp)
revert WithdrawUnlockNotReached();
// Move LP tokens to vault
_transfer(msg.sender, address(this), tokenAmount);
// get rate of LP tokens -> underlying tokens
uint256 underlyingAmount = (tokenAmount * getRate()) / scaleFactor();
// start withdrawal from EigenLayer
(
IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams,
bytes32 withdrawalRoot,
uint256 withdrawableShares,
uint96 nonce
) = _startWithdrawFromEigen(underlyingAmount);
// track user withdraw request
withdrawRequest[withdrawalRoot] = UserWithdrawRequest(
msg.sender,
tokenAmount,
block.number
);
// Emit the withdrawal started event
emit WithdrawStarted(
withdrawalRoot,
msg.sender,
address(this),
delegationManager.delegatedTo(address(this)),
address(this),
nonce,
block.number,
queuedWithdrawalParams[0].strategies,
queuedWithdrawalParams[0].depositShares
);
return withdrawalRoot;
}
/**
* @notice Claim the requested withdraw
* @dev only the withdrawer can claim the request after vault cooldownBlocks
* @param withdrawal Withdrawal struct for EigenLayer completeQueuedWithdrawal
*/
function claim(
IDelegationManager.Withdrawal calldata withdrawal
) external nonReentrant onlyWhenDelegated whenNotPaused {
bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal);
if (msg.sender != withdrawRequest[withdrawalRoot].withdrawer || msg.sender == address(0))
revert UnAuthorizedClaimer();
_checkEarlyClaim(withdrawRequest[withdrawalRoot].createdAt);
// burn LP token
_burn(address(this), withdrawRequest[withdrawalRoot].lpTokenAmountLocked);
uint256 underlyingClaimAmount = _trackSharesAndCompleteWithdrawal(
withdrawalRoot,
withdrawal
);
// transfer received amount of underlying to msg.sender
underlying.safeTransfer(msg.sender, underlyingClaimAmount);
emit WithdrawRequestClaimed(withdrawalRoot, msg.sender, underlyingClaimAmount, withdrawal);
// delete recorded withdrawRequest
delete withdrawRequest[withdrawalRoot];
}
/**
* @notice Claim ERC20 rewards from EigenLayer
* @dev permissioned call (onlyOwner)
* @param _claim RewardsMerkleClaim object to process claim
*/
function processRewards(
IRewardsCoordinator.RewardsMerkleClaim calldata _claim
) external onlyRewardsProofSubmitter {
// check rewards Destination is configured
if (vaultRewardsDestination == address(0)) revert RewardsDestinationNotConfigured();
rewardsCoordinator.processClaim(_claim, address(this));
for (uint256 i = 0; i < _claim.tokenLeaves.length; ) {
// deduct fee for each rewards token
uint256 remainingRewards = _processRewardsFee(_claim.tokenLeaves[i].token);
// process the rewards
_processRewards(_claim.tokenLeaves[i].token, remainingRewards);
unchecked {
++i;
}
}
}
/**
* @notice Allows admin to start a withdrawal from EigenLayer to Fill the withdrawal buffer
* @dev permissioned call (onlyOwner or withdrawalBufferAdmin),
* @param underlyingAmount amount of underlying tokens to withdraw from EigenLayer
*/
function adminStartWithdrawal(
uint256 underlyingAmount
)
external
nonReentrant
onlyOwnerOrWithdrawalBufferAdmin
whenNotPaused
onlyWhenDelegated
returns (bytes32)
{
_checkZeroValue(underlyingAmount);
// check if withdrawalBuffer is enabled
_checkIfWithdrawalBufferEnabled();
// start withdrawal from EigenLayer
(
IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams,
bytes32 withdrawalRoot,
uint256 withdrawableShares,
uint96 nonce
) = _startWithdrawFromEigen(underlyingAmount);
// track admin withdrawal request
adminWithdrawalRequest[withdrawalRoot] = AdminWithdrawRequest(
withdrawableShares,
block.number
);
// Emit the withdrawal started event
emit AdminWithdrawalStarted(
withdrawalRoot,
msg.sender,
address(this),
delegationManager.delegatedTo(address(this)),
address(this),
nonce,
block.number,
queuedWithdrawalParams[0].strategies,
queuedWithdrawalParams[0].depositShares
);
return withdrawalRoot;
}
/**
* @notice Allows admin to complete a withdrawal request from EigenLayer and fill the withdraw buffer or redeposit
* @dev permissioned call (onlyOwner or withdrawalBufferAdmin),
* @param withdrawal Withdrawal struct for EigenLayer completeQueuedWithdrawal
*/
function adminCompleteWithdrawal(
IDelegationManager.Withdrawal calldata withdrawal
) external nonReentrant onlyOwnerOrWithdrawalBufferAdmin whenNotPaused onlyWhenDelegated {
bytes32 withdrawalRoot = delegationManager.calculateWithdrawalRoot(withdrawal);
_checkIfWithdrawalBufferEnabled();
_checkEarlyClaim(adminWithdrawalRequest[withdrawalRoot].createdAt);
uint256 underlyingClaimAmount = _trackSharesAndCompleteWithdrawal(
withdrawalRoot,
withdrawal
);
// check and fill the withdraw buffer if it is set
uint256 remainingAmount = _checkAndFillWithdrawBuffer(underlyingClaimAmount);
// redeposit the remaining amount into EigenLayer
if (remainingAmount > 0) {
_deposit(remainingAmount);
}
emit AdminWithdrawalCompleted(
withdrawalRoot,
msg.sender,
underlyingClaimAmount,
withdrawal
);
// delete recorded admin withdraw request
delete adminWithdrawalRequest[withdrawalRoot];
}
/**
* @notice Burn LP tokens from user account through instant withdrawal
* @dev permissioned call (onlyWithdrawalBuffer),
* @param _user address of user to burn LP tokens from
* @param _amount amount of LP tokens to burn
*/
function burnByInstantWithdrawal(address _user, uint256 _amount) external onlyWithdrawalBuffer {
// burn the LP tokens from user
_burn(_user, _amount);
}
/**
* @notice Allows anyone to incentivize the vault by donating underlying
* @dev does not mint LP token for the incentive deposited
* @param amount amount of underlying tokens
*/
function depositIncentive(uint256 amount) external nonReentrant {
_checkZeroValue(amount);
// transfer underlying from caller to vault
underlying.safeTransferFrom(msg.sender, address(this), amount);
// deposit the underlying in underlyingStrategy
_deposit(amount);
emit IncentiveDeposited(amount);
}
/**
* @notice sweep any ERC20 token from vault contract
* @dev considers any token balance in vault as rewards, permissioned call (onlyOwner)
* @param token token contract to perform sweep
*/
function sweepERC20(IERC20 token) external nonReentrant onlyOwner {
// revert if owner tries to sweep lp tokens
if (address(token) == address(this)) revert InvalidTokenSweep();
uint256 tokenBalance = token.balanceOf(address(this));
if (tokenBalance == 0) revert InvalidZeroBalance();
uint256 remainingBalance = _processRewardsFee(token);
_processRewards(token, remainingBalance);
}
/// @dev getter for vault cooldown blocks. returns max cooldown blocks for strategy
function cooldownBlocks() public view returns (uint256) {
return
(delegationManager.minWithdrawalDelayBlocks() > vaultCooldownBlocks)
? delegationManager.minWithdrawalDelayBlocks()
: vaultCooldownBlocks;
}
/// @dev Gets the underlying token amount from the amount of shares + queued withdrawal shares
function getUnderlyingBalanceFromStrategy() public view returns (uint256) {
// calculate the underlying balance from the strategy through lib
return
EzRVaultLib.getUnderlyingBalance(
underlyingStrategy,
delegationManager,
_getQueuedSharesWithSlashing(),
underlying.balanceOf(address(withdrawalBuffer))
);
}
function _getQueuedSharesWithSlashing() internal view returns (uint256) {
return queuedShares - totalQueuedSharesSlashedDelta;
}
/// @dev returns the scale factor according to underlying decimals
function scaleFactor() public view returns (uint256) {
return (10 ** underlyingDecimals);
}
/// @dev Gets the current rate of LP token
function getRate() public view returns (uint256) {
return
((getUnderlyingBalanceFromStrategy() + BALANCE_OFFSET) * scaleFactor()) /
(totalSupply() + SHARE_OFFSET);
}
/**
* @notice View function for getting a user's underlying token balance
* @dev For the user specified, get the amount of tokens they can claim
* @param userAddress user address to query
* @return uint256 Amount of underlying tokens they have a claim on
*/
function userUnderlying(address userAddress) public view returns (uint256) {
return (balanceOf(userAddress) * getRate()) / scaleFactor();
}
/// @dev process the rewards received for specified token
function _processRewards(IERC20 token, uint256 rewardsAmount) internal {
// if reward token is underlying then redeposit
if (token == underlying) {
// redeposit into strategy
_deposit(rewardsAmount);
} else {
// if reward token is not underlying then forward to RewardsDestination
token.safeTransfer(vaultRewardsDestination, rewardsAmount);
}
}
/// @dev process fee for the rewards received
function _processRewardsFee(IERC20 token) internal returns (uint256) {
uint256 totalRewards = token.balanceOf(address(this));
// transfer protocol fee to protocol treasury
uint256 protocolFeeShare = (totalRewards * protocolFee) / BASIS_POINTS;
token.safeTransfer(protocolTreasury, protocolFeeShare);
// transfer vault fee to configured vault fee destination
uint256 vaultFeeShare = (totalRewards * vaultFee) / BASIS_POINTS;
token.safeTransfer(vaultFeeDestination, vaultFeeShare);
return totalRewards - (protocolFeeShare + vaultFeeShare);
}
/// @dev ensures users have 7 days window to withdraw funds before owner can update the vaulCooldownBlocks
function _checkCooldownBlocksUpdateDelay() internal view {
if (block.number - cooldownBlocksUpdatedAt < vaultCooldownBlocks + SEVEN_DAYS_BLOCKS)
revert EarlyCooldownBlocksUpdate();
}
function _resetSlashingDelta(bytes32 withdrawalRoot) internal {
if (queuedWithdrawalInfo[withdrawalRoot].sharesSlashedDelta > 0) {
// reduce total slashed delta with queuedWithdrawalInfo
totalQueuedSharesSlashedDelta -= queuedWithdrawalInfo[withdrawalRoot]
.sharesSlashedDelta;
// delete queuedWithdrawalInfo for the withdrawal root
delete queuedWithdrawalInfo[withdrawalRoot].sharesSlashedDelta;
}
}
function _checkAndFillWithdrawBuffer(
uint256 _amount
) internal returns (uint256 remainingAmount) {
remainingAmount = _amount;
// Check if withdrawal Buffer is enabled
if (address(withdrawalBuffer) != address(0)) {
// check if withdraw buffer is set and fill it with underlying balance
uint256 deficit = withdrawalBuffer.getBufferDeficit();
if (deficit > 0) {
uint256 bufferToFill = deficit > _amount ? _amount : deficit;
// Transfer the deficit amount to withdrawal buffer
underlying.safeTransfer(address(withdrawalBuffer), bufferToFill);
// update the remaining amount
remainingAmount -= bufferToFill;
emit WithdrawalBufferFilled(bufferToFill);
}
}
}
function _startWithdrawFromEigen(
uint256 underlyingAmount
)
internal
returns (
IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams,
bytes32 withdrawalRoot,
uint256 withdrawableShares,
uint96 nonce
)
{
// create queuedWithdrawalParams struct for withdrawRequest
(queuedWithdrawalParams, withdrawableShares, nonce) = EzRVaultLib.getQueuedWithdrawalParam(
underlyingAmount,
delegationManager,
underlyingStrategy
);
// queue withdrawal in EigenLayer
withdrawalRoot = _trackSharesAndQueueWithdrawal(withdrawableShares, queuedWithdrawalParams);
}
function _checkZeroValue(uint256 value) internal pure {
if (value == 0) revert InvalidZeroInput();
}
function _checkZeroValue(address value) internal pure {
if (value == address(0)) revert InvalidZeroInput();
}
function _checkIfDelegated() internal view {
if (delegationManager.delegatedTo(address(this)) == address(0)) revert VaultNotDelegated();
}
function _checkIfPaused() internal view {
if (paused) revert VaultPaused();
}
function _checkEarlyClaim(uint256 createdAt) internal view {
// check if cooldownBlocks is set and not reached
if (block.number - createdAt < cooldownBlocks()) revert EarlyClaim();
}
function _checkIfOwnerOrWithdrawalBufferAdmin() internal view {
if (msg.sender != owner() && msg.sender != withdrawalBufferAdmin)
revert NotWithdrawalBufferAdmin();
}
function _checkIfWithdrawalBufferEnabled() internal view {
// check if withdrawalBuffer is enabled
if (address(withdrawalBuffer) == address(0)) revert InstantWithdrawNotEnabled();
// check if withdrawalBuffer is paused
if (withdrawalBuffer.paused()) revert InstantWithdrawPaused();
}
function _trackSharesAndQueueWithdrawal(
uint256 withdrawableShares,
IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams
) internal returns (bytes32 withdrawalRoot) {
// track queued shares by withdrawable shares
queuedShares += withdrawableShares;
// queue withdrawal in EigenLayer
withdrawalRoot = delegationManager.queueWithdrawals(queuedWithdrawalParams)[0];
// track initial withdrawable shares of the token in queuedWithdrawal
queuedWithdrawalInfo[withdrawalRoot].initialWithdrawableShares = withdrawableShares;
}
function _trackSharesAndCompleteWithdrawal(
bytes32 withdrawalRoot,
IDelegationManager.Withdrawal memory withdrawal
) internal returns (uint256 underlyingClaimAmount) {
IERC20[] memory tokens = new IERC20[](1);
tokens[0] = underlying;
// reduce initial withdrawable queued Shares for this request
queuedShares -= queuedWithdrawalInfo[withdrawalRoot].initialWithdrawableShares;
// reset slashing delta to avoid double counting
_resetSlashingDelta(withdrawalRoot);
// check balance before completing queuedWithdrawal
uint256 balanceBefore = underlying.balanceOf(address(this));
// complete the queued withdrawal from EigenLayer with receiveAsToken set to true
delegationManager.completeQueuedWithdrawal(withdrawal, tokens, true);
// Calculate the amount of underlying tokens claimed
underlyingClaimAmount = underlying.balanceOf(address(this)) - balanceBefore;
}
}// 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) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* 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) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @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[45] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// 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 IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @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.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol)
pragma solidity ^0.8.0;
import "./IBeacon.sol";
import "../Proxy.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}.
*
* The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
* conflict with the storage layout of the implementation behind the proxy.
*
* _Available since v3.4._
*/
contract BeaconProxy is Proxy, ERC1967Upgrade {
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
*/
constructor(address beacon, bytes memory data) payable {
_upgradeBeaconToAndCall(beacon, data, false);
}
/**
* @dev Returns the current beacon address.
*/
function _beacon() internal view virtual returns (address) {
return _getBeacon();
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_getBeacon()).implementation();
}
/**
* @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
*
* Requirements:
*
* - `beacon` must be a contract.
* - The implementation returned by `beacon` must be a contract.
*/
function _setBeacon(address beacon, bytes memory data) internal virtual {
_upgradeBeaconToAndCall(beacon, data, false);
}
}// 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: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/IERC1967.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967Upgrade is IERC1967 {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
pragma solidity ^0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive() external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overridden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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 Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// 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.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 StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import { 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.
* @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: 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: 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
{
// Access to public vars - hack locally
function pendingWithdrawals(bytes32 withdrawalRoot) external view returns (bool);
/**
* @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 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/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.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: 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 "../interfaces/IPauserRegistry.sol";
/**
* @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
* These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
* @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
* Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
* For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
* you can only flip (any number of) switches to off/0 (aka "paused").
* If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
* 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
* 2) update the paused state to this new value
* @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
* indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
*/
interface IPausable {
/// @dev Thrown when caller is not pauser.
error OnlyPauser();
/// @dev Thrown when caller is not unpauser.
error OnlyUnpauser();
/// @dev Thrown when currently paused.
error CurrentlyPaused();
/// @dev Thrown when invalid `newPausedStatus` is provided.
error InvalidNewPausedStatus();
/// @dev Thrown when a null address input is provided.
error InputAddressZero();
/// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`.
event Paused(address indexed account, uint256 newPausedStatus);
/// @notice Emitted when the pause is lifted by `account`, and changed to `newPausedStatus`.
event Unpaused(address indexed account, uint256 newPausedStatus);
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
function pauserRegistry() external view returns (IPauserRegistry);
/**
* @notice This function is used to pause an EigenLayer contract's functionality.
* It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
*/
function pause(uint256 newPausedStatus) external;
/**
* @notice Alias for `pause(type(uint256).max)`.
*/
function pauseAll() external;
/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(uint256 newPausedStatus) external;
/// @notice Returns the current paused status as a uint256.
function paused() external view returns (uint256);
/// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
function paused(uint8 index) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.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.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.8.27;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/OperatorSetLib.sol";
import "./IAllocationManager.sol";
import "./IDelegationManager.sol";
import "./IStrategyManager.sol";
import "./IPauserRegistry.sol";
import "./IPermissionController.sol";
import "./IStrategy.sol";
import "./ISemVerMixin.sol";
interface IRewardsCoordinatorErrors {
/// @dev Thrown when msg.sender is not allowed to call a function
error UnauthorizedCaller();
/// @dev Thrown when a earner not an AVS or Operator
error InvalidEarner();
/// Invalid Inputs
/// @dev Thrown when an input address is zero
error InvalidAddressZero();
/// @dev Thrown when an invalid root is provided.
error InvalidRoot();
/// @dev Thrown when an invalid root index is provided.
error InvalidRootIndex();
/// @dev Thrown when input arrays length is zero.
error InputArrayLengthZero();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when provided root is not for new calculated period.
error NewRootMustBeForNewCalculatedPeriod();
/// @dev Thrown when rewards end timestamp has not elapsed.
error RewardsEndTimestampNotElapsed();
/// @dev Thrown when an invalid operator set is provided.
error InvalidOperatorSet();
/// Rewards Submissions
/// @dev Thrown when input `amount` is zero.
error AmountIsZero();
/// @dev Thrown when input `amount` exceeds maximum.
error AmountExceedsMax();
/// @dev Thrown when input `split` exceeds `ONE_HUNDRED_IN_BIPS`
error SplitExceedsMax();
/// @dev Thrown when an operator attempts to set a split before the previous one becomes active
error PreviousSplitPending();
/// @dev Thrown when input `duration` exceeds maximum.
error DurationExceedsMax();
/// @dev Thrown when input `duration` is not evenly divisble by CALCULATION_INTERVAL_SECONDS.
error InvalidDurationRemainder();
/// @dev Thrown when GENESIS_REWARDS_TIMESTAMP is not evenly divisble by CALCULATION_INTERVAL_SECONDS.
error InvalidGenesisRewardsTimestampRemainder();
/// @dev Thrown when CALCULATION_INTERVAL_SECONDS is not evenly divisble by SNAPSHOT_CADENCE.
error InvalidCalculationIntervalSecondsRemainder();
/// @dev Thrown when `startTimestamp` is not evenly divisble by CALCULATION_INTERVAL_SECONDS.
error InvalidStartTimestampRemainder();
/// @dev Thrown when `startTimestamp` is too far in the future.
error StartTimestampTooFarInFuture();
/// @dev Thrown when `startTimestamp` is too far in the past.
error StartTimestampTooFarInPast();
/// @dev Thrown when an attempt to use a non-whitelisted strategy is made.
error StrategyNotWhitelisted();
/// @dev Thrown when `strategies` is not sorted in ascending order.
error StrategiesNotInAscendingOrder();
/// @dev Thrown when `operators` are not sorted in ascending order
error OperatorsNotInAscendingOrder();
/// @dev Thrown when an operator-directed rewards submission is not retroactive
error SubmissionNotRetroactive();
/// Claims
/// @dev Thrown when an invalid earner claim proof is provided.
error InvalidClaimProof();
/// @dev Thrown when an invalid token leaf index is provided.
error InvalidTokenLeafIndex();
/// @dev Thrown when an invalid earner leaf index is provided.
error InvalidEarnerLeafIndex();
/// @dev Thrown when cumulative earnings are not greater than cumulative claimed.
error EarningsNotGreaterThanClaimed();
/// Reward Root Checks
/// @dev Thrown if a root has already been disabled.
error RootDisabled();
/// @dev Thrown if a root has not been activated yet.
error RootNotActivated();
/// @dev Thrown if a root has already been activated.
error RootAlreadyActivated();
}
interface IRewardsCoordinatorTypes {
/**
* @notice A linear combination of strategies and multipliers for AVSs to weigh
* EigenLayer strategies.
* @param strategy The EigenLayer strategy to be used for the rewards submission
* @param multiplier The weight of the strategy in the rewards submission
*/
struct StrategyAndMultiplier {
IStrategy strategy;
uint96 multiplier;
}
/**
* @notice A reward struct for an operator
* @param operator The operator to be rewarded
* @param amount The reward amount for the operator
*/
struct OperatorReward {
address operator;
uint256 amount;
}
/**
* @notice A split struct for an Operator
* @param oldSplitBips The old split in basis points. This is the split that is active if `block.timestamp < activatedAt`
* @param newSplitBips The new split in basis points. This is the split that is active if `block.timestamp >= activatedAt`
* @param activatedAt The timestamp at which the split will be activated
*/
struct OperatorSplit {
uint16 oldSplitBips;
uint16 newSplitBips;
uint32 activatedAt;
}
/**
* Sliding Window for valid RewardsSubmission startTimestamp
*
* Scenario A: GENESIS_REWARDS_TIMESTAMP IS WITHIN RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <--------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
*
*
* Scenario B: GENESIS_REWARDS_TIMESTAMP IS OUT OF RANGE
* <-----MAX_RETROACTIVE_LENGTH-----> t (block.timestamp) <---MAX_FUTURE_LENGTH--->
* <------------------------valid range for startTimestamp------------------------>
* ^
* GENESIS_REWARDS_TIMESTAMP
* @notice RewardsSubmission struct submitted by AVSs when making rewards for their operators and stakers
* RewardsSubmission can be for a time range within the valid window for startTimestamp and must be within max duration.
* See `createAVSRewardsSubmission()` for more details.
* @param strategiesAndMultipliers The strategies and their relative weights
* cannot have duplicate strategies and need to be sorted in ascending address order
* @param token The rewards token to be distributed
* @param amount The total amount of tokens to be distributed
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution
* could start in the past or in the future but within a valid range. See the diagram above.
* @param duration The duration of the submission range in seconds. Must be <= MAX_REWARDS_DURATION
*/
struct RewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
IERC20 token;
uint256 amount;
uint32 startTimestamp;
uint32 duration;
}
/**
* @notice OperatorDirectedRewardsSubmission struct submitted by AVSs when making operator-directed rewards for their operators and stakers.
* @param strategiesAndMultipliers The strategies and their relative weights.
* @param token The rewards token to be distributed.
* @param operatorRewards The rewards for the operators.
* @param startTimestamp The timestamp (seconds) at which the submission range is considered for distribution.
* @param duration The duration of the submission range in seconds.
* @param description Describes what the rewards submission is for.
*/
struct OperatorDirectedRewardsSubmission {
StrategyAndMultiplier[] strategiesAndMultipliers;
IERC20 token;
OperatorReward[] operatorRewards;
uint32 startTimestamp;
uint32 duration;
string description;
}
/**
* @notice A distribution root is a merkle root of the distribution of earnings for a given period.
* The RewardsCoordinator stores all historical distribution roots so that earners can claim their earnings against older roots
* if they wish but the merkle tree contains the cumulative earnings of all earners and tokens for a given period so earners (or their claimers if set)
* only need to claim against the latest root to claim all available earnings.
* @param root The merkle root of the distribution
* @param rewardsCalculationEndTimestamp The timestamp (seconds) until which rewards have been calculated
* @param activatedAt The timestamp (seconds) at which the root can be claimed against
*/
struct DistributionRoot {
bytes32 root;
uint32 rewardsCalculationEndTimestamp;
uint32 activatedAt;
bool disabled;
}
/**
* @notice Internal leaf in the merkle tree for the earner's account leaf
* @param earner The address of the earner
* @param earnerTokenRoot The merkle root of the earner's token subtree
* Each leaf in the earner's token subtree is a TokenTreeMerkleLeaf
*/
struct EarnerTreeMerkleLeaf {
address earner;
bytes32 earnerTokenRoot;
}
/**
* @notice The actual leaves in the distribution merkle tree specifying the token earnings
* for the respective earner's subtree. Each leaf is a claimable amount of a token for an earner.
* @param token The token for which the earnings are being claimed
* @param cumulativeEarnings The cumulative earnings of the earner for the token
*/
struct TokenTreeMerkleLeaf {
IERC20 token;
uint256 cumulativeEarnings;
}
/**
* @notice A claim against a distribution root called by an
* earners claimer (could be the earner themselves). Each token claim will claim the difference
* between the cumulativeEarnings of the earner and the cumulativeClaimed of the claimer.
* Each claim can specify which of the earner's earned tokens they want to claim.
* See `processClaim()` for more details.
* @param rootIndex The index of the root in the list of DistributionRoots
* @param earnerIndex The index of the earner's account root in the merkle tree
* @param earnerTreeProof The proof of the earner's EarnerTreeMerkleLeaf against the merkle root
* @param earnerLeaf The earner's EarnerTreeMerkleLeaf struct, providing the earner address and earnerTokenRoot
* @param tokenIndices The indices of the token leaves in the earner's subtree
* @param tokenTreeProofs The proofs of the token leaves against the earner's earnerTokenRoot
* @param tokenLeaves The token leaves to be claimed
* @dev The merkle tree is structured with the merkle root at the top and EarnerTreeMerkleLeaf as internal leaves
* in the tree. Each earner leaf has its own subtree with TokenTreeMerkleLeaf as leaves in the subtree.
* To prove a claim against a specified rootIndex(which specifies the distributionRoot being used),
* the claim will first verify inclusion of the earner leaf in the tree against _distributionRoots[rootIndex].root.
* Then for each token, it will verify inclusion of the token leaf in the earner's subtree against the earner's earnerTokenRoot.
*/
struct RewardsMerkleClaim {
uint32 rootIndex;
uint32 earnerIndex;
bytes earnerTreeProof;
EarnerTreeMerkleLeaf earnerLeaf;
uint32[] tokenIndices;
bytes[] tokenTreeProofs;
TokenTreeMerkleLeaf[] tokenLeaves;
}
/**
* @notice Parameters for the RewardsCoordinator constructor
* @param delegationManager The address of the DelegationManager contract
* @param strategyManager The address of the StrategyManager contract
* @param allocationManager The address of the AllocationManager contract
* @param pauserRegistry The address of the PauserRegistry contract
* @param permissionController The address of the PermissionController contract
* @param CALCULATION_INTERVAL_SECONDS The interval at which rewards are calculated
* @param MAX_REWARDS_DURATION The maximum duration of a rewards submission
* @param MAX_RETROACTIVE_LENGTH The maximum retroactive length of a rewards submission
* @param MAX_FUTURE_LENGTH The maximum future length of a rewards submission
* @param GENESIS_REWARDS_TIMESTAMP The timestamp at which rewards are first calculated
* @param version The semantic version of the contract (e.g. "v1.2.3")
* @dev Needed to avoid stack-too-deep errors
*/
struct RewardsCoordinatorConstructorParams {
IDelegationManager delegationManager;
IStrategyManager strategyManager;
IAllocationManager allocationManager;
IPauserRegistry pauserRegistry;
IPermissionController permissionController;
uint32 CALCULATION_INTERVAL_SECONDS;
uint32 MAX_REWARDS_DURATION;
uint32 MAX_RETROACTIVE_LENGTH;
uint32 MAX_FUTURE_LENGTH;
uint32 GENESIS_REWARDS_TIMESTAMP;
string version;
}
}
interface IRewardsCoordinatorEvents is IRewardsCoordinatorTypes {
/// @notice emitted when an AVS creates a valid RewardsSubmission
event AVSRewardsSubmissionCreated(
address indexed avs,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/// @notice emitted when a valid RewardsSubmission is created for all stakers by a valid submitter
event RewardsSubmissionForAllCreated(
address indexed submitter,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/// @notice emitted when a valid RewardsSubmission is created when rewardAllStakersAndOperators is called
event RewardsSubmissionForAllEarnersCreated(
address indexed tokenHopper,
uint256 indexed submissionNonce,
bytes32 indexed rewardsSubmissionHash,
RewardsSubmission rewardsSubmission
);
/**
* @notice Emitted when an AVS creates a valid `OperatorDirectedRewardsSubmission`
* @param caller The address calling `createOperatorDirectedAVSRewardsSubmission`.
* @param avs The avs on behalf of which the operator-directed rewards are being submitted.
* @param operatorDirectedRewardsSubmissionHash Keccak256 hash of (`avs`, `submissionNonce` and `operatorDirectedRewardsSubmission`).
* @param submissionNonce Current nonce of the avs. Used to generate a unique submission hash.
* @param operatorDirectedRewardsSubmission The Operator-Directed Rewards Submission. Contains the token, start timestamp, duration, operator rewards, description and, strategy and multipliers.
*/
event OperatorDirectedAVSRewardsSubmissionCreated(
address indexed caller,
address indexed avs,
bytes32 indexed operatorDirectedRewardsSubmissionHash,
uint256 submissionNonce,
OperatorDirectedRewardsSubmission operatorDirectedRewardsSubmission
);
/**
* @notice Emitted when an AVS creates a valid `OperatorDirectedRewardsSubmission` for an operator set.
* @param caller The address calling `createOperatorDirectedOperatorSetRewardsSubmission`.
* @param operatorDirectedRewardsSubmissionHash Keccak256 hash of (`avs`, `submissionNonce` and `operatorDirectedRewardsSubmission`).
* @param operatorSet The operatorSet on behalf of which the operator-directed rewards are being submitted.
* @param submissionNonce Current nonce of the avs. Used to generate a unique submission hash.
* @param operatorDirectedRewardsSubmission The Operator-Directed Rewards Submission. Contains the token, start timestamp, duration, operator rewards, description and, strategy and multipliers.
*/
event OperatorDirectedOperatorSetRewardsSubmissionCreated(
address indexed caller,
bytes32 indexed operatorDirectedRewardsSubmissionHash,
OperatorSet operatorSet,
uint256 submissionNonce,
OperatorDirectedRewardsSubmission operatorDirectedRewardsSubmission
);
/// @notice rewardsUpdater is responsible for submitting DistributionRoots, only owner can set rewardsUpdater
event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater);
event RewardsForAllSubmitterSet(
address indexed rewardsForAllSubmitter,
bool indexed oldValue,
bool indexed newValue
);
event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay);
event DefaultOperatorSplitBipsSet(
uint16 oldDefaultOperatorSplitBips,
uint16 newDefaultOperatorSplitBips
);
/**
* @notice Emitted when the operator split for an AVS is set.
* @param caller The address calling `setOperatorAVSSplit`.
* @param operator The operator on behalf of which the split is being set.
* @param avs The avs for which the split is being set by the operator.
* @param activatedAt The timestamp at which the split will be activated.
* @param oldOperatorAVSSplitBips The old split for the operator for the AVS.
* @param newOperatorAVSSplitBips The new split for the operator for the AVS.
*/
event OperatorAVSSplitBipsSet(
address indexed caller,
address indexed operator,
address indexed avs,
uint32 activatedAt,
uint16 oldOperatorAVSSplitBips,
uint16 newOperatorAVSSplitBips
);
/**
* @notice Emitted when the operator split for Programmatic Incentives is set.
* @param caller The address calling `setOperatorPISplit`.
* @param operator The operator on behalf of which the split is being set.
* @param activatedAt The timestamp at which the split will be activated.
* @param oldOperatorPISplitBips The old split for the operator for Programmatic Incentives.
* @param newOperatorPISplitBips The new split for the operator for Programmatic Incentives.
*/
event OperatorPISplitBipsSet(
address indexed caller,
address indexed operator,
uint32 activatedAt,
uint16 oldOperatorPISplitBips,
uint16 newOperatorPISplitBips
);
/**
* @notice Emitted when the operator split for a given operatorSet is set.
* @param caller The address calling `setOperatorSetSplit`.
* @param operator The operator on behalf of which the split is being set.
* @param operatorSet The operatorSet for which the split is being set.
* @param activatedAt The timestamp at which the split will be activated.
* @param oldOperatorSetSplitBips The old split for the operator for the operatorSet.
* @param newOperatorSetSplitBips The new split for the operator for the operatorSet.
*/
event OperatorSetSplitBipsSet(
address indexed caller,
address indexed operator,
OperatorSet operatorSet,
uint32 activatedAt,
uint16 oldOperatorSetSplitBips,
uint16 newOperatorSetSplitBips
);
event ClaimerForSet(
address indexed earner,
address indexed oldClaimer,
address indexed claimer
);
/// @notice rootIndex is the specific array index of the newly created root in the storage array
event DistributionRootSubmitted(
uint32 indexed rootIndex,
bytes32 indexed root,
uint32 indexed rewardsCalculationEndTimestamp,
uint32 activatedAt
);
event DistributionRootDisabled(uint32 indexed rootIndex);
/// @notice root is one of the submitted distribution roots that was claimed against
event RewardsClaimed(
bytes32 root,
address indexed earner,
address indexed claimer,
address indexed recipient,
IERC20 token,
uint256 claimedAmount
);
}
/**
* @title Interface for the `IRewardsCoordinator` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Allows AVSs to make "Rewards Submissions", which get distributed amongst the AVSs' confirmed
* Operators and the Stakers delegated to those Operators.
* Calculations are performed based on the completed RewardsSubmission, with the results posted in
* a Merkle root against which Stakers & Operators can make claims.
*/
interface IRewardsCoordinator is
IRewardsCoordinatorErrors,
IRewardsCoordinatorEvents,
ISemVerMixin
{
/**
* @dev Initializes the addresses of the initial owner, pauser registry, rewardsUpdater and
* configures the initial paused status, activationDelay, and defaultOperatorSplitBips.
*/
function initialize(
address initialOwner,
uint256 initialPausedStatus,
address _rewardsUpdater,
uint32 _activationDelay,
uint16 _defaultSplitBips
) external;
/**
* @notice Creates a new rewards submission on behalf of an AVS, to be split amongst the
* set of stakers delegated to operators who are registered to the `avs`
* @param rewardsSubmissions The rewards submissions being created
* @dev Expected to be called by the ServiceManager of the AVS on behalf of which the submission is being made
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
* @dev The tokens are sent to the `RewardsCoordinator` contract
* @dev Strategies must be in ascending order of addresses to check for duplicates
* @dev This function will revert if the `rewardsSubmission` is malformed,
* e.g. if the `strategies` and `weights` arrays are of non-equal lengths
*/
function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external;
/**
* @notice similar to `createAVSRewardsSubmission` except the rewards are split amongst *all* stakers
* rather than just those delegated to operators who are registered to a single avs and is
* a permissioned call based on isRewardsForAllSubmitter mapping.
* @param rewardsSubmissions The rewards submissions being created
*/
function createRewardsForAllSubmission(
RewardsSubmission[] calldata rewardsSubmissions
) external;
/**
* @notice Creates a new rewards submission for all earners across all AVSs.
* Earners in this case indicating all operators and their delegated stakers. Undelegated stake
* is not rewarded from this RewardsSubmission. This interface is only callable
* by the token hopper contract from the Eigen Foundation
* @param rewardsSubmissions The rewards submissions being created
*/
function createRewardsForAllEarners(RewardsSubmission[] calldata rewardsSubmissions) external;
/**
* @notice Creates a new operator-directed rewards submission on behalf of an AVS, to be split amongst the operators and
* set of stakers delegated to operators who are registered to the `avs`.
* @param avs The AVS on behalf of which the reward is being submitted
* @param operatorDirectedRewardsSubmissions The operator-directed rewards submissions being created
* @dev Expected to be called by the ServiceManager of the AVS on behalf of which the submission is being made
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
* @dev The tokens are sent to the `RewardsCoordinator` contract
* @dev The `RewardsCoordinator` contract needs a token approval of sum of all `operatorRewards` in the `operatorDirectedRewardsSubmissions`, before calling this function.
* @dev Strategies must be in ascending order of addresses to check for duplicates
* @dev Operators must be in ascending order of addresses to check for duplicates.
* @dev This function will revert if the `operatorDirectedRewardsSubmissions` is malformed.
*/
function createOperatorDirectedAVSRewardsSubmission(
address avs,
OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions
) external;
/**
* @notice Creates a new operator-directed rewards submission for an operator set, to be split amongst the operators and
* set of stakers delegated to operators who are part of the operator set.
* @param operatorSet The operator set for which the rewards are being submitted
* @param operatorDirectedRewardsSubmissions The operator-directed rewards submissions being created
* @dev Expected to be called by the AVS that created the operator set
* @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`
* @dev The tokens are sent to the `RewardsCoordinator` contract
* @dev The `RewardsCoordinator` contract needs a token approval of sum of all `operatorRewards` in the `operatorDirectedRewardsSubmissions`, before calling this function
* @dev Strategies must be in ascending order of addresses to check for duplicates
* @dev Operators must be in ascending order of addresses to check for duplicates
* @dev This function will revert if the `operatorDirectedRewardsSubmissions` is malformed
*/
function createOperatorDirectedOperatorSetRewardsSubmission(
OperatorSet calldata operatorSet,
OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions
) external;
/**
* @notice Claim rewards against a given root (read from _distributionRoots[claim.rootIndex]).
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for,
* they can simply claim against the latest root and the contract will calculate the difference between
* their cumulativeEarnings and cumulativeClaimed. This difference is then transferred to recipient address.
* @param claim The RewardsMerkleClaim to be processed.
* Contains the root index, earner, token leaves, and required proofs
* @param recipient The address recipient that receives the ERC20 rewards
* @dev only callable by the valid claimer, that is
* if claimerFor[claim.earner] is address(0) then only the earner can claim, otherwise only
* claimerFor[claim.earner] can claim the rewards.
*/
function processClaim(RewardsMerkleClaim calldata claim, address recipient) external;
/**
* @notice Batch claim rewards against a given root (read from _distributionRoots[claim.rootIndex]).
* Earnings are cumulative so earners don't have to claim against all distribution roots they have earnings for,
* they can simply claim against the latest root and the contract will calculate the difference between
* their cumulativeEarnings and cumulativeClaimed. This difference is then transferred to recipient address.
* @param claims The RewardsMerkleClaims to be processed.
* Contains the root index, earner, token leaves, and required proofs
* @param recipient The address recipient that receives the ERC20 rewards
* @dev only callable by the valid claimer, that is
* if claimerFor[claim.earner] is address(0) then only the earner can claim, otherwise only
* claimerFor[claim.earner] can claim the rewards.
* @dev This function may fail to execute with a large number of claims due to gas limits. Use a smaller array of claims if necessary.
*/
function processClaims(RewardsMerkleClaim[] calldata claims, address recipient) external;
/**
* @notice Creates a new distribution root. activatedAt is set to block.timestamp + activationDelay
* @param root The merkle root of the distribution
* @param rewardsCalculationEndTimestamp The timestamp until which rewards have been calculated
* @dev Only callable by the rewardsUpdater
*/
function submitRoot(bytes32 root, uint32 rewardsCalculationEndTimestamp) external;
/**
* @notice allow the rewardsUpdater to disable/cancel a pending root submission in case of an error
* @param rootIndex The index of the root to be disabled
*/
function disableRoot(uint32 rootIndex) external;
/**
* @notice Sets the address of the entity that can call `processClaim` on ehalf of an earner
* @param claimer The address of the entity that can call `processClaim` on behalf of the earner
* @dev Assumes msg.sender is the earner
*/
function setClaimerFor(address claimer) external;
/**
* @notice Sets the address of the entity that can call `processClaim` on behalf of an earner
* @param earner The address to set the claimer for
* @param claimer The address of the entity that can call `processClaim` on behalf of the earner
* @dev Only callable by operators or AVSs. We define an AVS that has created at least one
* operatorSet in the `AllocationManager`
*/
function setClaimerFor(address earner, address claimer) external;
/**
* @notice Sets the delay in timestamp before a posted root can be claimed against
* @dev Only callable by the contract owner
* @param _activationDelay The new value for activationDelay
*/
function setActivationDelay(uint32 _activationDelay) external;
/**
* @notice Sets the default split for all operators across all avss.
* @param split The default split for all operators across all avss in bips.
* @dev Only callable by the contract owner.
*/
function setDefaultOperatorSplit(uint16 split) external;
/**
* @notice Sets the split for a specific operator for a specific avs
* @param operator The operator who is setting the split
* @param avs The avs for which the split is being set by the operator
* @param split The split for the operator for the specific avs in bips.
* @dev Only callable by the operator
* @dev Split has to be between 0 and 10000 bips (inclusive)
* @dev The split will be activated after the activation delay
*/
function setOperatorAVSSplit(address operator, address avs, uint16 split) external;
/**
* @notice Sets the split for a specific operator for Programmatic Incentives.
* @param operator The operator on behalf of which the split is being set.
* @param split The split for the operator for Programmatic Incentives in bips.
* @dev Only callable by the operator
* @dev Split has to be between 0 and 10000 bips (inclusive)
* @dev The split will be activated after the activation delay
*/
function setOperatorPISplit(address operator, uint16 split) external;
/**
* @notice Sets the split for a specific operator for a specific operatorSet.
* @param operator The operator who is setting the split.
* @param operatorSet The operatorSet for which the split is being set by the operator.
* @param split The split for the operator for the specific operatorSet in bips.
* @dev Only callable by the operator
* @dev Split has to be between 0 and 10000 bips (inclusive)
* @dev The split will be activated after the activation delay
*/
function setOperatorSetSplit(
address operator,
OperatorSet calldata operatorSet,
uint16 split
) external;
/**
* @notice Sets the permissioned `rewardsUpdater` address which can post new roots
* @dev Only callable by the contract owner
* @param _rewardsUpdater The address of the new rewardsUpdater
*/
function setRewardsUpdater(address _rewardsUpdater) external;
/**
* @notice Sets the permissioned `rewardsForAllSubmitter` address which can submit createRewardsForAllSubmission
* @dev Only callable by the contract owner
* @param _submitter The address of the rewardsForAllSubmitter
* @param _newValue The new value for isRewardsForAllSubmitter
*/
function setRewardsForAllSubmitter(address _submitter, bool _newValue) external;
/**
*
* VIEW FUNCTIONS
*
*/
/// @notice Delay in timestamp (seconds) before a posted root can be claimed against
function activationDelay() external view returns (uint32);
/// @notice The timestamp until which RewardsSubmissions have been calculated
function currRewardsCalculationEndTimestamp() external view returns (uint32);
/// @notice Mapping: earner => the address of the entity who can call `processClaim` on behalf of the earner
function claimerFor(address earner) external view returns (address);
/// @notice Mapping: claimer => token => total amount claimed
function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256);
/// @notice the default split for all operators across all avss
function defaultOperatorSplitBips() external view returns (uint16);
/// @notice the split for a specific `operator` for a specific `avs`
function getOperatorAVSSplit(address operator, address avs) external view returns (uint16);
/// @notice the split for a specific `operator` for Programmatic Incentives
function getOperatorPISplit(address operator) external view returns (uint16);
/// @notice Returns the split for a specific `operator` for a given `operatorSet`
function getOperatorSetSplit(
address operator,
OperatorSet calldata operatorSet
) external view returns (uint16);
/// @notice return the hash of the earner's leaf
function calculateEarnerLeafHash(
EarnerTreeMerkleLeaf calldata leaf
) external pure returns (bytes32);
/// @notice returns the hash of the earner's token leaf
function calculateTokenLeafHash(
TokenTreeMerkleLeaf calldata leaf
) external pure returns (bytes32);
/// @notice returns 'true' if the claim would currently pass the check in `processClaims`
/// but will revert if not valid
function checkClaim(RewardsMerkleClaim calldata claim) external view returns (bool);
/// @notice returns the number of distribution roots posted
function getDistributionRootsLength() external view returns (uint256);
/// @notice returns the distributionRoot at the specified index
function getDistributionRootAtIndex(
uint256 index
) external view returns (DistributionRoot memory);
/// @notice returns the current distributionRoot
function getCurrentDistributionRoot() external view returns (DistributionRoot memory);
/// @notice loop through the distribution roots from reverse and get latest root that is not disabled and activated
/// i.e. a root that can be claimed against
function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory);
/// @notice loop through distribution roots from reverse and return index from hash
function getRootIndexFromHash(bytes32 rootHash) external view returns (uint32);
/// @notice The address of the entity that can update the contract with new merkle roots
function rewardsUpdater() external view returns (address);
/**
* @notice The interval in seconds at which the calculation for a RewardsSubmission distribution is done.
* @dev Rewards Submission durations must be multiples of this interval.
*/
function CALCULATION_INTERVAL_SECONDS() external view returns (uint32);
/// @notice The maximum amount of time (seconds) that a RewardsSubmission can span over
function MAX_REWARDS_DURATION() external view returns (uint32);
/// @notice max amount of time (seconds) that a submission can start in the past
function MAX_RETROACTIVE_LENGTH() external view returns (uint32);
/// @notice max amount of time (seconds) that a submission can start in the future
function MAX_FUTURE_LENGTH() external view returns (uint32);
/// @notice absolute min timestamp (seconds) that a submission can start at
function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32);
}// 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.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.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.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.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(uint256 amountShares) external returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(uint256 amountUnderlying) external returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(address user) external returns (uint256);
/**
* @notice 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.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(address user) external view returns (uint256);
/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);
/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);
/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}// 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
{
// Access to public vars - hack locally
function stakerStrategyList(address staker, uint256 index) external view returns (IStrategy);
/**
* @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.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: BUSL-1.1
pragma solidity ^0.8.0;
library Endian {
/**
* @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64
* @param lenum little endian-formatted uint64 input, provided as 'bytes32' type
* @return n The big endian-formatted uint64
* @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits)
* through a right-shift/shr operation.
*/
function fromLittleEndianUint64(bytes32 lenum) internal pure returns (uint64 n) {
// the number needs to be stored in little-endian encoding (ie in bytes 0-8)
n = uint64(uint256(lenum >> 192));
// forgefmt: disable-next-item
return
(n >> 56) |
((0x00FF000000000000 & n) >> 40) |
((0x0000FF0000000000 & n) >> 24) |
((0x000000FF00000000 & n) >> 8) |
((0x00000000FF000000 & n) << 8) |
((0x0000000000FF0000 & n) << 24) |
((0x000000000000FF00 & n) << 40) |
((0x00000000000000FF & n) << 56);
}
}// SPDX-License-Identifier: 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.27;
/**
* @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.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);
}
/**
* @notice Used as part of calculating wadSlashed in the EPM to ensure that we don't overslash
*/
function divWadRoundUp(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(WAD, y, 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 this is the staker's first deposit, set the scaling factor to
// the inverse of slashingFactor
if (prevDepositShares == 0) {
dsf._scalingFactor = uint256(WAD).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;
}
// CONVERSION
function calcWithdrawable(
DepositScalingFactor memory dsf,
uint256 depositShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return depositShares.mulWad(dsf.scalingFactor()).mulWad(slashingFactor);
}
function calcDepositShares(
DepositScalingFactor memory dsf,
uint256 withdrawableShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return withdrawableShares.divWad(dsf.scalingFactor()).divWad(slashingFactor);
}
function calcSlashedAmount(
uint256 operatorShares,
uint256 prevMaxMagnitude,
uint256 newMaxMagnitude
) internal pure returns (uint256) {
// round up mulDiv so we don't overslash
return
operatorShares -
operatorShares.mulDiv(newMaxMagnitude, prevMaxMagnitude, Math.Rounding.Up);
}
}// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.27; /// @dev Error for 0x0 address inputs error InvalidZeroInput(); /// @dev Error when owner tries to sweep 0 balance token error InvalidZeroBalance(); /// @dev Error when strategy does not have specified underlying error InvalidStrategy(); /// @dev Error when vault with same salt already created error VaultAlreadyCreated(); /// @dev Error when vault is already delegated error AlreadyDelegated(); /// @dev Error when strategy underlying token does not match vault underlying token error InvalidUnderlyingToken(); /// @dev Error when invalid token amount is deposited error InvalidTokenAmount(); /// @dev Error when withdrawer is not the claimer error UnAuthorizedClaimer(); /// @dev Error when vault is not delegated to any Operator error VaultNotDelegated(); /// @dev error when try to configure maxCooldownBlocksBasisPoints > 100% error InvalidMaxCooldownBlocksBasisPoints(); /// @dev Error when vault owner tries to configure cooldown less than EigenLayer cooldown error InvalidWithdrawalCooldown(); /// @dev Error when admin tried to update cooldown more than 50% of minCooldownBlocks error ExceedMaxCooldownBlocks(); /// @dev Error when admin tries to update cooldown blocks before cooldownBlocksUpdateDelay error EarlyCooldownBlocksUpdate(); /// @dev Error when user tries to claim withdrawRequest before cooldownBlocks error EarlyClaim(); /// @dev Error when vault owner tries to track user initiated/admin initiated withdrawal through emergency tracking error WithdrawalAlreadyTracked(); /// @dev Error when emergency tracking already completed withdrawal error WithdrawalAlreadyCompleted(); /// @dev Error when vault owner tries to complete invalid Withdrawal error InvalidWithdrawal(); /// @dev Error when vault owner tries to configure more than 100% as fee error InvalidFee(); /// @dev Error when vault owner tried to claim rewards without specifying rewards destination error RewardsDestinationNotConfigured(); /// @dev Error when vault is paused error VaultPaused(); /// @dev Error when non pauser tries to change pause state error NotPauser(); /// @dev Error when vaultOwner tries to sweep LP token error InvalidTokenSweep(); /// @dev Error when someone tries to buy auction when not started error AuctionNotStarted(); /// @dev Error when Initial price is lower than min error InitPriceBelowMin(); /// @dev Error when Initial price greater than max error InitPriceExceedsMax(); /// @dev Error when Epoch Period is lower than min error EpochPeriodBelowMin(); /// @dev Error when Epoch Period is greater than max error EpochPeriodExceedsMax(); /// @dev Error when Price Multiplier is lower than min error PriceMultiplierBelowMin(); /// @dev Error when Price Multiplier is greater than max error PriceMultiplierExceedsMax(); /// @dev Error when minimum Initial Price lower than Min error MinInitPriceBelowMin(); /// @dev Error when user tries to buy auction while Deadline is passed error DeadlinePassed(); /// @dev Error when user tries to buy auction with empty asset list error EmptyAssets(); /// @dev Error when user tries to buy auction with incorrect Epoch Id error EpochIdMismatch(); /// @dev Error when auction price is greater than max amount provided by user error MaxPaymentTokenAmountExceeded(); /// @dev Error when owner tries to update already started auction error AuctionAlreadyStarted(); /// @dev Error when auctionId already present in EzAuctionFactory error AuctionAlreadyCreated(); /// @dev Error when owner tries to start auction with a lower initial price error InvalidInitPrice(); /// @dev Error when user tries to buy auction when paused error AuctionPaused(); /// @dev Error when called is not allowed to call processRewards error NotRewardsProofSubmitter(); /// @dev Error when unexpected token received error InvalidToken(); /// @dev Error when function called by account that is not owner or auctionStarter error NotOwnerOrAuctionStarter(); /// @dev Error when low level call fails error CallFailed(); /// @dev Error when Withdrawal is not queued error WithdrawalNotQueued(); /// @dev Error when TVL limit is exceeded error TvlLimitExceeded(); /// @dev Error when withdraw timestamp is not reached error WithdrawUnlockNotReached(); /// @dev Error when withdraw timestamp is in the past error InvalidWithdrawUnlockTimestamp(); /// @dev Error when not enough liquidity in the withdrawal buffer error NotEnoughLiquidity(); /// @dev Error when withdrawal buffer is not the caller or not set error NotWithdrawalBuffer(); /// @dev Error when Instant Withdraw Already Enabled error InstantWithdrawAlreadyEnabled(); /// @dev Error when array lengths do not match error MismatchedArrayLengths(); /// @dev Error when caller is not the WithdrawalBufferAdmin error NotWithdrawalBufferAdmin(); /// @dev Error when instant withdrawal is not enabled error InstantWithdrawNotEnabled(); /// @dev Error when instant withdrawal is paused error InstantWithdrawPaused();
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../EigenLayer/interfaces/IStrategy.sol";
import "./InstantWithdrawal/IWithdrawalBuffer.sol";
import "./IEzRVault.sol";
abstract contract EzRVaultStorageV1 {
struct UserWithdrawRequest {
address withdrawer;
uint256 lpTokenAmountLocked;
uint256 createdAt;
}
/// @dev scale factor for underlying token as decimals
uint8 public underlyingDecimals;
/// @dev Underlying token for vault
IERC20 public underlying;
/// @dev EigenLayer Strategy for underlying token
IStrategy public underlyingStrategy;
/// @dev min vault cooldown blocks for user withdrawals
uint256 public vaultCooldownBlocks;
/// @dev tracks the block number at which cooldownBlocks got updated
uint256 public cooldownBlocksUpdatedAt;
/// @dev Track of token shares in withdraw queue of EigenLayer
uint256 public queuedShares;
/// @dev mapping to track withdraw request owner with withdrawalRoot key
mapping(bytes32 => UserWithdrawRequest) public withdrawRequest;
/// @dev mapping to track emergencyQueued withdrawals
mapping(bytes32 => bool) public emergencyWithdrawal;
/// @dev rewards fee on vault
uint256 public vaultFee;
/// @dev rewards fee destination specified by vaultOwner
address public vaultFeeDestination;
/// @dev destination for non underlying reward tokens
address public vaultRewardsDestination;
/// @dev track the pause status of vault
bool public paused;
/// @dev track the pauser account address
address public pauser;
}
abstract contract EzRVaultStorageV2 is EzRVaultStorageV1 {
/// @dev Track the rewards Claimer account which can submit proofs and call processRewards
address public rewardsProofSubmitter;
}
abstract contract EzRVaultStorageV3 is EzRVaultStorageV2 {
struct QueuedWithdrawalInfo {
uint256 sharesSlashedDelta;
uint256 initialWithdrawableShares;
}
mapping(bytes32 => QueuedWithdrawalInfo) public queuedWithdrawalInfo;
uint256 public totalQueuedSharesSlashedDelta;
}
abstract contract EzRVaultStorageV4 is EzRVaultStorageV3 {
/// @dev TVL Limit fo the vault - users will not be able to deposit if TVL exceeds this limit - 0 means no limit
uint256 public tvlLimit;
/// @dev Timestamp preventing withdrawals until the period ends - note that this only eforces starting a withdrawal
/// and does not prevent the claiming an existing withdrawal (in case a rolling bond is used that creates new lock periods)
uint256 public withdrawUnlockTimestamp;
}
abstract contract EzRVaultStorageV5 is EzRVaultStorageV4 {
struct AdminWithdrawRequest {
uint256 shares;
uint256 createdAt;
}
/// @dev The maximum cooldown blocks that can be configured by vault owner
IWithdrawalBuffer public withdrawalBuffer;
/// @dev Tracks the address for admin responsible for managing the withdrawal buffer
address public withdrawalBufferAdmin;
/// @dev Tracks the withdrawal started by admin
mapping(bytes32 => AdminWithdrawRequest) public adminWithdrawalRequest;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IEzRVault {
function underlying() external view returns (IERC20);
function scaleFactor() external view returns (uint256);
function getRate() external view returns (uint256);
function burnByInstantWithdrawal(address _user, uint256 _amount) external;
}pragma solidity 0.8.27;
interface IWithdrawalBuffer {
function getBufferDeficit() external view returns (uint256);
function paused() external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {
ReentrancyGuardUpgradeable
} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./WithdrawalBufferStorage.sol";
import "../../Errors/Errors.sol";
contract WithdrawalBuffer is
OwnableUpgradeable,
ReentrancyGuardUpgradeable,
WithdrawalBufferStorageV1
{
using SafeERC20 for IERC20;
uint256 public constant BASIS_POINTS = 10000; // BASIS_POINTS used for percentage (10000 basis points equal 100%)
event InstantWithdrawalCompleted(
address user,
uint256 vaultTokenAmount,
uint256 underlyingAmount,
uint256 feeAmount
);
event Paused(bool paused);
event PauserUpdated(address oldPauser, address newPauser);
/// @dev Only allows deposit and withdraw when not paused
modifier whenNotPaused() {
_checkIfPaused();
_;
}
/// @dev Only allowed pauser and owner to change pause state
modifier onlyOwnerOrPauser() {
if (msg.sender != owner() && msg.sender != pauser) revert NotPauser();
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(
uint256 _instantWithdrawalFeeBps,
uint256 _withdrawBufferTarget,
address _feeDestination,
address _owner,
IEzRVault _ezRVault
) external initializer {
__ReentrancyGuard_init();
// Check for zero values
if (
_instantWithdrawalFeeBps == 0 ||
_feeDestination == address(0) ||
_withdrawBufferTarget == 0 ||
_owner == address(0) ||
address(_ezRVault) == address(0)
) revert InvalidZeroInput();
// Verify instant withdrawal fee is within valid range
if (_instantWithdrawalFeeBps > BASIS_POINTS) revert InvalidFee();
instantWithdrawalFeeBps = _instantWithdrawalFeeBps;
feeDestination = _feeDestination;
withdrawBufferTarget = _withdrawBufferTarget;
ezRVault = _ezRVault;
_transferOwnership(_owner);
}
/**
* @notice Function to set the whitelisted users for instant withdrawals.
* @dev Permissioned call (onlyOwner)
* @param _users list of user addresses to be whitelisted or removed from whitelist
* @param _isWhitelisted list of boolean values indicating whether the user should be whitelisted or not
*/
function setWhitelisted(
address[] calldata _users,
bool[] calldata _isWhitelisted
) external onlyOwner {
if (_users.length == 0) revert InvalidZeroInput();
if (_users.length != _isWhitelisted.length) revert MismatchedArrayLengths();
for (uint256 i = 0; i < _users.length; ) {
if (_users[i] == address(0)) revert InvalidZeroInput();
isWhitelisted[_users[i]] = _isWhitelisted[i];
unchecked {
++i;
}
}
}
/**
* @notice Pause the withdrawal buffer
* @dev permissioned call (onlyPuaser)
*/
function pause() external onlyOwnerOrPauser {
paused = true;
emit Paused(true);
}
/**
* @notice UnPause the withdrawal buffer
* @dev permissioned call (onlyOwner)
*/
function unpause() external onlyOwner {
paused = false;
emit Paused(false);
}
/**
* @notice Update pauser address
* @dev permissioned call (onlyOwner)
* @param _pauser new pauser address
*/
function setPauser(address _pauser) external onlyOwner {
if (_pauser == address(0)) revert InvalidZeroInput();
emit PauserUpdated(pauser, _pauser);
pauser = _pauser;
}
/**
* @notice Updates the withdrawal buffer target amount
* @dev permissioned call (onlyOwner)
* @param _withdrawBufferTarget new target amount for the withdrawal buffer
*/
function updateWithdrawBufferConfig(
uint256 _withdrawBufferTarget,
uint256 _instantWithdrawalFeeBps,
address _feeDestination
) external onlyOwner {
if (
_withdrawBufferTarget == 0 ||
_instantWithdrawalFeeBps == 0 ||
_feeDestination == address(0)
) revert InvalidZeroInput();
// Verify instant withdrawal fee is within valid range
if (_instantWithdrawalFeeBps > BASIS_POINTS) revert InvalidFee();
// Update the withdrawal buffer target amount
withdrawBufferTarget = _withdrawBufferTarget;
// Update the instant withdrawal fee basis points
instantWithdrawalFeeBps = _instantWithdrawalFeeBps;
// Update the fee destination address
feeDestination = _feeDestination;
}
/**
* @notice Instantly withdraws a specified amount of LP tokens from the EzRVault
* @dev This function allows users to withdraw their LP tokens instantly with a fee and burns their LP tokens instantly
* @dev Whitelisted users do not incur any fees.
* @param _amount amount of LP tokens to withdraw
*/
function withdraw(uint256 _amount) external nonReentrant whenNotPaused {
if (_amount == 0) revert InvalidZeroInput();
IERC20 underlyingToken = ezRVault.underlying();
// Calculate the amountToRedeem
uint256 underlyingAmount = (_amount * ezRVault.getRate()) / ezRVault.scaleFactor();
// Check if the withdrawal buffer has enough balance
if (underlyingToken.balanceOf(address(this)) < underlyingAmount)
revert NotEnoughLiquidity();
// Calculate the fee amount
// If user is whitelisted, no fee is charged
uint256 feeAmount = isWhitelisted[msg.sender]
? 0
: (underlyingAmount * instantWithdrawalFeeBps) / BASIS_POINTS;
// Transfer the fee to the fee destination
if (feeAmount > 0) {
underlyingToken.safeTransfer(feeDestination, feeAmount);
}
// Calculate the amount to withdraw after deducting the fee
uint256 amountToWithdraw = underlyingAmount - feeAmount;
// Transfer the remaining amount to the user
underlyingToken.safeTransfer(msg.sender, amountToWithdraw);
// Burn the LP tokens
ezRVault.burnByInstantWithdrawal(msg.sender, _amount);
// Emit the event for successful withdrawal
emit InstantWithdrawalCompleted(msg.sender, _amount, amountToWithdraw, feeAmount);
}
/**
* @notice Get the current underlying deficit in the withdrawal buffer.
* @return uint256 amount of underlying tokens needed to reach the target withdrawal buffer.
*/
function getBufferDeficit() external view returns (uint256) {
// Calculate the deficit in the withdrawal buffer
uint256 currentBalance = ezRVault.underlying().balanceOf(address(this));
// Return 0 if the current balance is greater than or equal to the target
if (currentBalance >= withdrawBufferTarget) return 0;
// return the difference between the target and current balance
return withdrawBufferTarget - currentBalance;
}
function _checkIfPaused() internal view {
if (paused) revert InstantWithdrawPaused();
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import { IEzRVault } from "../../EzRVault/IEzRVault.sol";
abstract contract WithdrawalBufferStorageV1 {
/// @dev Tracks the Fee BPS for instant withdrawals.
uint256 public instantWithdrawalFeeBps;
/// @dev Tracks the fee destination address for instant withdrawals.
address public feeDestination;
/// @dev Tracks the target amount of the withdrawal buffer.
uint256 public withdrawBufferTarget;
/// @dev Tracks the EzRVault contract instance.
IEzRVault public ezRVault;
/// @dev Tracks the whitelisted users for instant withdrawals.
mapping(address => bool) public isWhitelisted;
/// @dev track the pause status of withdrawal buffer
bool public paused;
/// @dev track the pauser account address
address public pauser;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import { WithdrawalBuffer } from "../InstantWithdrawal/WithdrawalBuffer.sol";
import { IEzRVault } from "../IEzRVault.sol";
import { IDelegationManager } from "../../EigenLayer/interfaces/IDelegationManager.sol";
import { IStrategy } from "../../EigenLayer/interfaces/IStrategy.sol";
library EzRVaultLib {
function createWithdrawBuffer(
address _withdrawBufferBeacon,
uint256 _instantWithdrawalFeeBps,
uint256 _withdrawBufferTarget,
address _feeDestination,
address _owner
) external returns (address _withdrawBuffer) {
_withdrawBuffer = address(
new BeaconProxy(
address(_withdrawBufferBeacon),
abi.encodeWithSelector(
WithdrawalBuffer.initialize.selector,
_instantWithdrawalFeeBps,
_withdrawBufferTarget,
_feeDestination,
_owner,
IEzRVault(address(this))
)
)
);
}
/// @dev build the QueuedWithdrawalParam struct for EigenLayer withdrawals
function getQueuedWithdrawalParam(
uint256 underlyingAmount,
IDelegationManager delegationManager,
IStrategy underlyingStrategy
)
external
returns (
IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams,
uint256,
uint96
)
{
// create queuedWithdrawalParams struct for withdrawRequest
queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1);
queuedWithdrawalParams[0].strategies = new IStrategy[](1);
queuedWithdrawalParams[0].depositShares = new uint256[](1);
// length 1 array for withdrawableShares
uint256[] memory withdrawableShares = new uint256[](1);
// set vault strategy for 0th index only
queuedWithdrawalParams[0].strategies[0] = underlyingStrategy;
// set the withdrawable shares of the underlying
withdrawableShares[0] = underlyingStrategy.underlyingToSharesView(underlyingAmount);
// set deposit shares for the token
// After upgrade
uint256[] memory depositShares = delegationManager.convertToDepositShares(
address(this),
queuedWithdrawalParams[0].strategies,
withdrawableShares
);
queuedWithdrawalParams[0].depositShares[0] = depositShares[0];
// set withdrawer as this contract address
queuedWithdrawalParams[0].__deprecated_withdrawer = address(this);
// Save the nonce before starting the withdrawal
uint96 nonce = uint96(delegationManager.cumulativeWithdrawalsQueued(address(this)));
return (queuedWithdrawalParams, withdrawableShares[0], nonce);
}
function getUnderlyingBalance(
IStrategy underlyingStrategy,
IDelegationManager delegationManager,
uint256 queuedSharesWithSlashing,
uint256 withdrawBufferUnderlyingBalance
) external view returns (uint256) {
IStrategy[] memory strategies = new IStrategy[](1);
strategies[0] = underlyingStrategy;
(uint256[] memory withdrawableShares, ) = delegationManager.getWithdrawableShares(
address(this),
strategies
);
// get withdrawable shares from EigenLayer
uint256 collateralBalance = withdrawableShares[0];
// add queued shares for the token with slashing
collateralBalance += queuedSharesWithSlashing;
// convert shares to underlying
return
underlyingStrategy.sharesToUnderlyingView(collateralBalance) +
withdrawBufferUnderlyingBalance;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"contracts/EzRVault/libraries/EzRVaultLib.sol": {
"EzRVaultLib": "0x47fbab3dbaebfcf6173b9637bb020c0ca05158e2"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract IDelegationManager","name":"_delegationManager","type":"address"},{"internalType":"contract IRewardsCoordinator","name":"_rewardsCoordinator","type":"address"},{"internalType":"contract IERC20","name":"_eigen","type":"address"},{"internalType":"contract IERC20","name":"_bEigen","type":"address"},{"internalType":"uint256","name":"_protocolFee","type":"uint256"},{"internalType":"address","name":"_protocolTreasury","type":"address"},{"internalType":"uint256","name":"_maxCooldownBlocksBasisPoints","type":"uint256"},{"internalType":"contract IBeacon","name":"_withdrawBufferBeacon","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyDelegated","type":"error"},{"inputs":[],"name":"EarlyClaim","type":"error"},{"inputs":[],"name":"EarlyCooldownBlocksUpdate","type":"error"},{"inputs":[],"name":"ExceedMaxCooldownBlocks","type":"error"},{"inputs":[],"name":"InstantWithdrawAlreadyEnabled","type":"error"},{"inputs":[],"name":"InstantWithdrawNotEnabled","type":"error"},{"inputs":[],"name":"InstantWithdrawPaused","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidMaxCooldownBlocksBasisPoints","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidTokenAmount","type":"error"},{"inputs":[],"name":"InvalidTokenSweep","type":"error"},{"inputs":[],"name":"InvalidUnderlyingToken","type":"error"},{"inputs":[],"name":"InvalidWithdrawUnlockTimestamp","type":"error"},{"inputs":[],"name":"InvalidWithdrawal","type":"error"},{"inputs":[],"name":"InvalidWithdrawalCooldown","type":"error"},{"inputs":[],"name":"InvalidZeroBalance","type":"error"},{"inputs":[],"name":"InvalidZeroInput","type":"error"},{"inputs":[],"name":"NotPauser","type":"error"},{"inputs":[],"name":"NotRewardsProofSubmitter","type":"error"},{"inputs":[],"name":"NotWithdrawalBuffer","type":"error"},{"inputs":[],"name":"NotWithdrawalBufferAdmin","type":"error"},{"inputs":[],"name":"RewardsDestinationNotConfigured","type":"error"},{"inputs":[],"name":"TvlLimitExceeded","type":"error"},{"inputs":[],"name":"UnAuthorizedClaimer","type":"error"},{"inputs":[],"name":"VaultNotDelegated","type":"error"},{"inputs":[],"name":"VaultPaused","type":"error"},{"inputs":[],"name":"WithdrawUnlockNotReached","type":"error"},{"inputs":[],"name":"WithdrawalAlreadyCompleted","type":"error"},{"inputs":[],"name":"WithdrawalAlreadyTracked","type":"error"},{"inputs":[],"name":"WithdrawalNotQueued","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingClaimAmount","type":"uint256"},{"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"}],"name":"AdminWithdrawalCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"delegatedTo","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":false,"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"name":"AdminWithdrawalStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegateAddress","type":"address"}],"name":"DelegationAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpMinted","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"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[]"}],"indexed":false,"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"EmergencyWithdrawalCompleted","type":"event"},{"anonymous":false,"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[]"}],"indexed":false,"internalType":"struct IDelegationManagerTypes.Withdrawal","name":"withdrawal","type":"tuple"}],"name":"EmergencyWithdrawalTracked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"IncentiveDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IWithdrawalBuffer","name":"_withdrawalBuffer","type":"address"}],"name":"InstantWithdrawEnabled","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":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauser","type":"address"},{"indexed":false,"internalType":"address","name":"newPauser","type":"address"}],"name":"PauserUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRewardsProofSubmitter","type":"address"},{"indexed":false,"internalType":"address","name":"newRewardsProofSubmitter","type":"address"}],"name":"RewardsProofSubmitterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newTvlLimit","type":"uint256"}],"name":"TvlLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldVaultCooldown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVaultCooldown","type":"uint256"}],"name":"VaultCooldownUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRewardsDestination","type":"address"},{"indexed":false,"internalType":"address","name":"newRewardsDestination","type":"address"}],"name":"VaultRewardsDestinationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawalRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"underlyingClaimAmount","type":"uint256"},{"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"}],"name":"WithdrawRequestClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"withdrawRoot","type":"bytes32"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"address","name":"delegatedTo","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":false,"internalType":"contract IStrategy[]","name":"strategies","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"}],"name":"WithdrawStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newWithdrawUnlockTimestamp","type":"uint256"}],"name":"WithdrawUnlockTimestampUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"WithdrawalBufferAdminUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"WithdrawalBufferFilled","type":"event"},{"inputs":[],"name":"BALANCE_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"B_EIGEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIGEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEVEN_DAYS_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"adminCompleteWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"underlyingAmount","type":"uint256"}],"name":"adminStartWithdrawal","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"adminWithdrawalRequest","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnByInstantWithdrawal","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":"withdrawal","type":"tuple"}],"name":"claim","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":"withdrawal","type":"tuple"}],"name":"completeEmergencyTrackedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldownBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cooldownBlocksUpdatedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegationManager","outputs":[{"internalType":"contract IDelegationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositIncentive","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":"withdrawal","type":"tuple"}],"name":"emergencyTrackQueuedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"withdrawalRoots","type":"bytes32[]"}],"name":"emergencyTrackSlashedQueuedWithdrawalDelta","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"emergencyWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_instantWithdrawalFeeBps","type":"uint256"},{"internalType":"uint256","name":"_withdrawalBufferTarget","type":"uint256"},{"internalType":"address","name":"_feeDestination","type":"address"},{"internalType":"address","name":"_withdrawalBufferAdmin","type":"address"}],"name":"enableInstantWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingBalanceFromStrategy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"contract IERC20","name":"_underlying","type":"address"},{"internalType":"contract IStrategy","name":"_strategy","type":"address"},{"internalType":"address","name":"vaultOwner","type":"address"},{"internalType":"uint256","name":"_cooldownBlocks","type":"uint256"},{"internalType":"uint256","name":"_vaultFee","type":"uint256"},{"internalType":"address","name":"_vaultFeeDestination","type":"address"},{"internalType":"address","name":"_rewardsDestination","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxCooldownBlocksBasisPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"rootIndex","type":"uint32"},{"internalType":"uint32","name":"earnerIndex","type":"uint32"},{"internalType":"bytes","name":"earnerTreeProof","type":"bytes"},{"components":[{"internalType":"address","name":"earner","type":"address"},{"internalType":"bytes32","name":"earnerTokenRoot","type":"bytes32"}],"internalType":"struct IRewardsCoordinatorTypes.EarnerTreeMerkleLeaf","name":"earnerLeaf","type":"tuple"},{"internalType":"uint32[]","name":"tokenIndices","type":"uint32[]"},{"internalType":"bytes[]","name":"tokenTreeProofs","type":"bytes[]"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"cumulativeEarnings","type":"uint256"}],"internalType":"struct IRewardsCoordinatorTypes.TokenTreeMerkleLeaf[]","name":"tokenLeaves","type":"tuple[]"}],"internalType":"struct IRewardsCoordinatorTypes.RewardsMerkleClaim","name":"_claim","type":"tuple"}],"name":"processRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolTreasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queuedShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"queuedWithdrawalInfo","outputs":[{"internalType":"uint256","name":"sharesSlashedDelta","type":"uint256"},{"internalType":"uint256","name":"initialWithdrawableShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsCoordinator","outputs":[{"internalType":"contract IRewardsCoordinator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsProofSubmitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scaleFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cooldownBlocks","type":"uint256"}],"name":"setCooldownBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegateAddress","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":"setDelegateAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pauser","type":"address"}],"name":"setPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsDestination","type":"address"}],"name":"setRewardsDestination","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsProofSubmitter","type":"address"}],"name":"setRewardsProofSubmitter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tvlLimit","type":"uint256"}],"name":"setTvlLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawUnlockTimestamp","type":"uint256"}],"name":"setWithdrawUnlockTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawalBufferAdmin","type":"address"}],"name":"setWithdrawalBufferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"sweepERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalQueuedSharesSlashedDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tvlLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlyingStrategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"}],"name":"userUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultCooldownBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultFeeDestination","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultRewardsDestination","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawBufferBeacon","outputs":[{"internalType":"contract IBeacon","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"withdrawRequest","outputs":[{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"lpTokenAmountLocked","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawUnlockTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalBuffer","outputs":[{"internalType":"contract IWithdrawalBuffer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalBufferAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101a060405234801561001157600080fd5b506040516162d53803806162d58339810160408190526100309161024a565b6001600160a01b038916158061004d57506001600160a01b038816155b8061005f57506001600160a01b038716155b8061007157506001600160a01b038616155b8061008357506001600160a01b038516155b8061008c575083155b8061009e57506001600160a01b038316155b806100a7575081155b806100b957506001600160a01b038116155b156100d75760405163862a606760e01b815260040160405180910390fd5b6127108411156100fa576040516358d620b360e01b815260040160405180910390fd5b61271082111561011d5760405163acd519f360e01b815260040160405180910390fd5b6001600160a01b03808a1660a05288811660c05287811660e0526101408590528381166101605261018083905286811661010052858116610120528116608052610165610173565b5050505050505050506102fa565b600054610100900460ff16156101df5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614610230576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b038116811461024757600080fd5b50565b60008060008060008060008060006101208a8c03121561026957600080fd5b895161027481610232565b60208b015190995061028581610232565b60408b015190985061029681610232565b60608b01519097506102a781610232565b60808b01519096506102b881610232565b60a08b015160c08c015191965094506102d081610232565b60e08b01516101008c015191945092506102e981610232565b809150509295985092959850929598565b60805160a05160c05160e0516101005161012051610140516101605161018051615e8461045160003960008181610a5e0152610e0f015260008181610744015261425c0152600081816108b5015281816121f7015261421c01526000818161088e0152818161231f015261235a015260008181610abf01526122e40152600081816107b60152612a01015260008181610a3701528181610c1701528181610cab01528181610d4b0152818161126c015281816114710152818161158b015281816116340152818161197201528181611c0801528181611e1d015281816124a50152818161281701528181612c7b01528181612dd001528181612f7f0152818161308e015281816131410152818161375e0152818161385d01528181613e4301526143890152600081816105bb0152818161225a01528181613a9a0152613af801526000818161078f0152610f1f0152615e846000f3fe608060405234801561001057600080fd5b506004361061045f5760003560e01c80638456cb591161024c578063ba285bd111610146578063e0540a9f116100c3578063efea6da711610087578063efea6da714610a59578063f2fde38b14610a80578063fc278fb714610a93578063fdc371ce14610aba578063ff02688614610ae157600080fd5b8063e0540a9f146109f0578063e1467e8514610a03578063e1f1c4a714610a16578063e58837df14610a1f578063ea4d3c9b14610a3257600080fd5b8063d6324e601161010a578063d6324e601461099b578063d83ad00c146109ae578063d9a90a8e146109b7578063dd62ed3e146109ca578063e00af4a7146109dd57600080fd5b8063ba285bd114610905578063c5f981ad1461090e578063c753965914610921578063c82b35ee1461097f578063d0b902461461099257600080fd5b80639fd0506d116101d4578063ad93b4b711610198578063ad93b4b7146104de578063b0e21e8a146108b0578063b6954532146108d7578063b6b55f25146108ea578063b8668738146108fd57600080fd5b80639fd0506d1461083d578063a194e8fe14610850578063a457c2d714610863578063a9059cbb14610876578063ab5a851b1461088957600080fd5b80638da5cb5b1161021b5780638da5cb5b146107eb5780638f6a6240146107fc57806390b187ba1461080f57806395d89b411461082257806396fd64421461082a57600080fd5b80638456cb5914610782578063865e02931461078a5780638a2fc4e3146107b15780638c01d542146107d857600080fd5b8063438cda2b1161035d5780636f307dc3116102e5578063772495c3116102a9578063772495c3146107195780637765a1021461072c578063803db96d1461073f5780638105165b14610766578063843eeecd1461076f57600080fd5b80636f307dc31461069a5780636fbec0cd146106b257806370a08231146106d5578063711f86d7146106fe578063715018a61461071157600080fd5b80635c975abb1161032c5780635c975abb146106315780635d1dd2391461064557806360cd4a6014610681578063679aefce1461068a578063683dd1911461069257600080fd5b8063438cda2b146105e55780634a27cc16146105f85780635361477b1461060b57806359f6adc71461061e57600080fd5b8063235a6e4c116103eb5780632e1a7d4d116103af5780632e1a7d4d14610585578063313ce5671461059857806339509351146105a357806339b70e38146105b65780633f4ba83a146105dd57600080fd5b8063235a6e4c1461050257806323b872dd1461051557806325a760c2146105285780632819c2d2146105475780632d88af4a1461057257600080fd5b80630baa9ed6116104325780630baa9ed6146104cd5780630bf35320146104d5578063101395fa146104de57806314626dc6146104e757806318160ddd146104fa57600080fd5b806301ac145b1461046457806306fdde0314610480578063095ea7b3146104955780630a785407146104b8575b600080fd5b61046d60d05481565b6040519081526020015b60405180910390f35b610488610aea565b604051610477919061480b565b6104a86104a336600461483e565b610b7c565b6040519015158152602001610477565b6104cb6104c636600461486a565b610b96565b005b61046d610c10565b61046d60d75481565b61046d6103e881565b6104cb6104f5366004614887565b610d37565b60355461046d565b6104cb6105103660046148a0565b610ec8565b6104a86105233660046148ea565b611093565b60c9546105359060ff1681565b60405160ff9091168152602001610477565b60d25461055a906001600160a01b031681565b6040516001600160a01b039091168152602001610477565b6104cb61058036600461486a565b6110b9565b61046d610593366004614887565b611133565b60c95460ff16610535565b6104a86105b136600461483e565b61134d565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b6104cb61136f565b61046d6105f3366004614887565b6113bb565b60d95461055a906001600160a01b031681565b6104cb610619366004614a38565b611552565b6104cb61062c366004614887565b6116eb565b60d2546104a890600160a01b900460ff1681565b61066c610653366004614887565b60d5602052600090815260409020805460019091015482565b60408051928352602083019190915201610477565b61046d60cb5481565b61046d611760565b61046d6117a9565b60c95461055a9061010090046001600160a01b031681565b6104a86106c0366004614887565b60cf6020526000908152604090205460ff1681565b61046d6106e336600461486a565b6001600160a01b031660009081526033602052604090205490565b6104cb61070c36600461486a565b6117bd565b6104cb611837565b6104cb61072736600461486a565b61184b565b6104cb61073a366004614887565b6118ce565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b61046d61c4e081565b6104cb61077d366004614ae4565b611940565b6104cb611b07565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b60d15461055a906001600160a01b031681565b6065546001600160a01b031661055a565b61046d61080a36600461486a565b611b8f565b6104cb61081d366004614ae4565b611bce565b610488611d30565b6104cb610838366004614b1e565b611d3f565b60d35461055a906001600160a01b031681565b60da5461055a906001600160a01b031681565b6104a861087136600461483e565b612011565b6104a861088436600461483e565b61209c565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b61046d7f000000000000000000000000000000000000000000000000000000000000000081565b6104cb6108e5366004614bb3565b6120aa565b61046d6108f8366004614887565b6126a9565b61046d6127ea565b61046d60cc5481565b60d45461055a906001600160a01b031681565b61095a61092f366004614887565b60ce602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b039094168452602084019290925290820152606001610477565b6104cb61098d36600461483e565b61292e565b61046d60d85481565b60ca5461055a906001600160a01b031681565b61046d60cd5481565b6104cb6109c5366004614c83565b61297d565b61046d6109d8366004614cbe565b612b07565b6104cb6109eb36600461486a565b612b32565b6104cb6109fe366004614887565b612c1c565b6104cb610a11366004614ecb565b612c59565b61046d61271081565b6104cb610a2d366004614ecb565b612f09565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b61046d7f000000000000000000000000000000000000000000000000000000000000000081565b6104cb610a8e36600461486a565b613262565b61066c610aa1366004614887565b60db602052600090815260409020805460019091015482565b61055a7f000000000000000000000000000000000000000000000000000000000000000081565b61046d60d65481565b606060368054610af990614eff565b80601f0160208091040260200160405190810160405280929190818152602001828054610b2590614eff565b8015610b725780601f10610b4757610100808354040283529160200191610b72565b820191906000526020600020905b815481529060010190602001808311610b5557829003601f168201915b5050505050905090565b600033610b8a8185856132d8565b60019150505b92915050565b610b9e6133fc565b610ba781613456565b60da54604080516001600160a01b03928316815291831660208301527fd591952303965b8a4599dc8f8a7b978ef62c3d6264dfe63102bc445af99e6dd7910160405180910390a160da80546001600160a01b0319166001600160a01b0392909216919091179055565b600060cb547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c979190614f3e565b63ffffffff1611610ca9575060cb5490565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2b9190614f3e565b63ffffffff165b905090565b610d3f61347d565b610d476133fc565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcb9190614f3e565b63ffffffff16905080821080610ddf575081155b15610dfd57604051630130feaf60e01b815260040160405180910390fd5b80821115610e75576000612710610e347f000000000000000000000000000000000000000000000000000000000000000084614f71565b610e3e9190614f88565b610e489083614faa565b905080831115610e6b57604051636108fcdb60e11b815260040160405180910390fd5b610e736134d6565b505b60cb5460408051918252602082018490527fea142c60fe44885a5d85aaac36e42beaab40f1e0c956960d5b9d3422b5d1c535910160405180910390a15060cb8190554360cc55610ec56001609755565b50565b610ed06133fc565b610ed981613456565b60d9546001600160a01b031615610f035760405163a9bdb05f60e01b815260040160405180910390fd5b7347fbab3dbaebfcf6173b9637bb020c0ca05158e263a88254597f0000000000000000000000000000000000000000000000000000000000000000868686610f536065546001600160a01b031690565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452604484019290925283166064830152909116608482015260a401602060405180830381865af4158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190614fc8565b60d980546001600160a01b0319166001600160a01b0392831617905560da5460408051918316825291831660208201527fd591952303965b8a4599dc8f8a7b978ef62c3d6264dfe63102bc445af99e6dd7910160405180910390a160da80546001600160a01b0319166001600160a01b038381169190911790915560d954604051911681527faea4902a18460819d7969a679a8553c2e99474de92f2d1442df092d139b165fa906020015b60405180910390a150505050565b6000336110a1858285613519565b6110ac858585613593565b60019150505b9392505050565b6110c16133fc565b6110ca81613456565b60d354604080516001600160a01b03928316815291831660208301527f1ff153f4b082245afbf3211a8d2d207da4c5df490e965f9a9ad141b0cd001dda910160405180910390a160d380546001600160a01b0319166001600160a01b0392909216919091179055565b600061113d61347d565b61114561373e565b61114d6137f0565b6111568261381b565b600060d854118015611169575060d85442105b1561118757604051635619a21360e11b815260040160405180910390fd5b611192333084613593565b600061119c6117a9565b6111a4611760565b6111ae9085614f71565b6111b89190614f88565b90506000806000806111c98561383c565b604080516060810182523380825260208083018f815243848601908152600089815260ce90935291859020935184546001600160a01b0319166001600160a01b039182161785559051600185015590516002909301929092559151631976849960e21b81523060048201819052969a509498509296509094507f0176007ec78c756143be1d2a6feec53fd9e31d37037259af455e8cfc1cb33811938793919290917f0000000000000000000000000000000000000000000000000000000000000000909116906365da126490602401602060405180830381865afa1580156112b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d99190614fc8565b3086438b6000815181106112ef576112ef614fe5565b6020026020010151600001518c60008151811061130e5761130e614fe5565b60200260200101516020015160405161132f99989796959493929190615072565b60405180910390a1509093505050506113486001609755565b919050565b600033610b8a8185856113608383612b07565b61136a9190614faa565b6132d8565b6113776133fc565b60d2805460ff60a01b19169055604051600081527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2906020015b60405180910390a1565b60006113c561347d565b6113cd613913565b6113d56137f0565b6113dd61373e565b6113e68261381b565b6113ee613957565b6000806000806113fd8661383c565b604080518082018252838152436020808301918252600087815260db909152839020915182555160019091015551631976849960e21b8152306004820181905294985092965090945092507f8172a150efcbbc7fbef8129ebf24a1e581d5769d11a8dec7dbba4b904b4e94f49185913391907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906365da126490602401602060405180830381865afa1580156114c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e49190614fc8565b3086438b6000815181106114fa576114fa614fe5565b6020026020010151600001518c60008151811061151957611519614fe5565b60200260200101516020015160405161153a99989796959493929190615072565b60405180910390a15090925050506113486001609755565b61155a61347d565b6115626133fc565b61156b83613456565b604051631976849960e21b81523060048201526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906365da126490602401602060405180830381865afa1580156115d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f69190614fc8565b6001600160a01b03161461161d57604051631a30c08d60e31b815260040160405180910390fd5b60405163eea9064b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063eea9064b9061166d908690869086906004016150f3565b600060405180830381600087803b15801561168757600080fd5b505af115801561169b573d6000803e3d6000fd5b50506040516001600160a01b03861681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a16116e66001609755565b505050565b6116f361347d565b6116fc8161381b565b60c9546117199061010090046001600160a01b0316333084613a15565b61172281613a80565b506040518181527fb02f19427b6324e7102facbe680a13b90e2424617afe32d862c9edf6dfaa83709060200160405180910390a1610ec56001609755565b60006103e861176e60355490565b6117789190614faa565b6117806117a9565b6103e861178b6127ea565b6117959190614faa565b61179f9190614f71565b610d329190614f88565b60c954600090610d329060ff16600a61521b565b6117c56133fc565b6117ce81613456565b60d454604080516001600160a01b03928316815291831660208301527fae8f8b46fdc10e05708993c545c5a2e35bf6b93c26ec5d017cde78090a41ea7a910160405180910390a160d480546001600160a01b0319166001600160a01b0392909216919091179055565b61183f6133fc565b6118496000613b67565b565b61185361347d565b61185b6133fc565b61186481613456565b60d254604080516001600160a01b03928316815291831660208301527fee962823afbca8ef78f872aa570b3bbbb7a9ac64c8bf15a0c6df38551bc5fe1a910160405180910390a160d280546001600160a01b0319166001600160a01b038316179055600160975550565b6118d66133fc565b6000811180156118e65750428111155b1561190457604051630c75503b60e31b815260040160405180910390fd5b60d88190556040518181527f9f4afb2b04a67e8eafc0e42d56f063553d977f47a054f39e4eea0cdb75a8547a906020015b60405180910390a150565b61194861347d565b61195061373e565b6119586137f0565b604051632cbd9b6d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063597b36da906119a79085906004016153a9565b602060405180830381865afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e891906153bc565b600081815260ce60205260409020549091506001600160a01b031633141580611a0f575033155b15611a2d57604051630bdbeed760e31b815260040160405180910390fd5b600081815260ce6020526040902060020154611a4890613bb9565b600081815260ce6020526040902060010154611a65903090613bea565b6000611a7982611a74856153d5565b613d1e565b60c954909150611a989061010090046001600160a01b03163383613f34565b7f8cc13279d432798ff883698cc787fdd496411d0d094093602f07fe03f087079082338386604051611acd94939291906153e1565b60405180910390a150600090815260ce6020526040812080546001600160a01b03191681556001810182905560020155610ec56001609755565b6065546001600160a01b03163314801590611b2d575060d3546001600160a01b03163314155b15611b4b5760405163492f678160e01b815260040160405180910390fd5b60d2805460ff60a01b1916600160a01b179055604051600181527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2906020016113b1565b6000611b996117a9565b611ba1611760565b6001600160a01b038416600090815260336020526040902054611bc49190614f71565b610b909190614f88565b611bd661347d565b611bde613913565b611be66137f0565b611bee61373e565b604051632cbd9b6d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063597b36da90611c3d9085906004016153a9565b602060405180830381865afa158015611c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7e91906153bc565b9050611c88613957565b600081815260db6020526040902060010154611ca390613bb9565b6000611cb282611a74856153d5565b90506000611cbf82613f64565b90508015611cd257611cd081613a80565b505b7ffc25fc5303a1c0280b151ff19469c472054bf8a05b56bffe7a82fcec9449b54c83338487604051611d0794939291906153e1565b60405180910390a15050600090815260db6020526040812081815560010155610ec56001609755565b606060378054610af990614eff565b60005b818110156116e657600060ce81858585818110611d6157611d61614fe5565b60209081029290920135835250810191909152604001600020546001600160a01b0316148015611dbf575060db6000848484818110611da257611da2614fe5565b905060200201358152602001908152602001600020600001546000145b8015611dfb575060cf6000848484818110611ddc57611ddc614fe5565b602090810292909201358352508101919091526040016000205460ff16155b15611e19576040516387c9d21960e01b815260040160405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635d975e88858585818110611e5c57611e5c614fe5565b905060200201356040518263ffffffff1660e01b8152600401611e8191815260200190565b600060405180830381865afa158015611e9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ec691908101906154d3565b915050600081600081518110611ede57611ede614fe5565b602002602001015160d56000878787818110611efc57611efc614fe5565b9050602002013581526020019081526020016000206001015411611f21576000611f75565b81600081518110611f3457611f34614fe5565b602002602001015160d56000878787818110611f5257611f52614fe5565b90506020020135815260200190815260200160002060010154611f7591906155e8565b905060d56000868686818110611f8d57611f8d614fe5565b9050602002013581526020019081526020016000206000015460d66000828254611fb791906155e8565b925050819055508060d66000828254611fd09190614faa565b9091555081905060d56000878787818110611fed57611fed614fe5565b60209081029290920135835250810191909152604001600020555050600101611d42565b6000338161201f8286612b07565b9050838110156120845760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b61209182868684036132d8565b506001949350505050565b600033610b8a818585613593565b600054610100900460ff16158080156120ca5750600054600160ff909116105b806120e45750303b1580156120e4575060005460ff166001145b6121475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161207b565b6000805460ff19166001179055801561216a576000805461ff0019166101001790555b6001600160a01b038816158061218757506001600160a01b038716155b8061219957506001600160a01b038616155b806121ab57506001600160a01b038316155b806121bd57506001600160a01b038216155b806121c757508951155b806121d157508851155b156121ef5760405163862a606760e01b815260040160405180910390fd5b61271061221c7f000000000000000000000000000000000000000000000000000000000000000086614faa565b111561223b576040516358d620b360e01b815260040160405180910390fd5b60405163198f077960e21b81526001600160a01b0388811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063663c1de490602401602060405180830381865afa1580156122a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c591906155fb565b6122e257604051632711b74d60e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316148061235357507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316145b15612410577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e49190614fc8565b6001600160a01b03161461240b576040516317dc37cb60e11b815260040160405180910390fd5b6124a3565b876001600160a01b0316876001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612458573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247c9190614fc8565b6001600160a01b0316146124a3576040516317dc37cb60e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125259190614f3e565b63ffffffff1685101561254b57604051630130feaf60e01b815260040160405180910390fd5b6125558a8a614070565b61255d6140a1565b61256686613b67565b60c98054610100600160a81b0319166101006001600160a01b038b81169182029290921790925560ca80546001600160a01b031916918a169190911790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156125df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612603919061561d565b60c9805460ff9290921660ff1990921691909117905560cb8590554360cc5560d084905560d180546001600160a01b038086166001600160a01b03199283161790925560d2805492851692909116919091179055801561269d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b60006126b361347d565b6126bb61373e565b6126c36137f0565b6126cc8261381b565b60d7541561270f5760006126de6127ea565b60d7549091506126ee8483614faa565b111561270d5760405163dc320e0f60e01b815260040160405180910390fd5b505b60c95461272c9061010090046001600160a01b0316333085613a15565b6000612736611760565b61273e6117a9565b6127489085614f71565b6127529190614f88565b90508060000361277557604051632160733960e01b815260040160405180910390fd5b61277f33826140d0565b600061278a84613f64565b9050801561279d5761279b81613a80565b505b60408051338152602081018690529081018390527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060600160405180910390a150506113486001609755565b60ca546000907347fbab3dbaebfcf6173b9637bb020c0ca05158e29063b4737f2f906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000061283e614191565b60c95460d9546040516370a0823160e01b81526001600160a01b03918216600482015261010090920416906370a0823190602401602060405180830381865afa15801561288f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b391906153bc565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015293909216602484015260448301526064820152608401602060405180830381865af415801561290a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3291906153bc565b60d9546001600160a01b031633141580612951575060d9546001600160a01b0316155b1561296f5760405163a2b4235760e01b815260040160405180910390fd5b6129798282613bea565b5050565b6065546001600160a01b031633148015906129a3575060d4546001600160a01b03163314155b156129c1576040516375c7a22760e01b815260040160405180910390fd5b60d2546001600160a01b03166129ea57604051630cd4f69d60e01b815260040160405180910390fd5b604051633ccc861d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633ccc861d90612a389084903090600401615800565b600060405180830381600087803b158015612a5257600080fd5b505af1158015612a66573d6000803e3d6000fd5b5050505060005b612a7a60e08301836158fa565b9050811015612979576000612ac0612a9560e08501856158fa565b84818110612aa557612aa5614fe5565b612abb926020604090920201908101915061486a565b6141a3565b9050612afe612ad260e08501856158fa565b84818110612ae257612ae2614fe5565b612af8926020604090920201908101915061486a565b826142cf565b50600101612a6d565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b612b3a61347d565b612b426133fc565b306001600160a01b03821603612b6b57604051631b533c7560e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd691906153bc565b905080600003612bf957604051630e3b112360e01b815260040160405180910390fd5b6000612c04836141a3565b9050612c1083826142cf565b5050610ec56001609755565b612c246133fc565b60d78190556040518181527fc3155206c3a231f7548908ce7c152e1fb064246a6eef8f45e686a51ce0b175fc90602001611935565b612c616133fc565b604051632cbd9b6d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063597b36da90612cb09085906004016159c2565b602060405180830381865afa158015612ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf191906153bc565b600081815260cf602052604090205490915060ff16612d235760405163c945242d60e01b815260040160405180910390fd5b6040805160018082528183019092526000916020808301908036833701905050905060c960019054906101000a90046001600160a01b031681600081518110612d6e57612d6e614fe5565b6001600160a01b03909216602092830291909101820152600083815260d5909152604081206001015460cd805491929091612daa9084906155e8565b90915550612db990508261430d565b604051630e4cc3f960e41b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e4cc3f9090612e0a90869085906001906004016159d5565b600060405180830381600087803b158015612e2457600080fd5b505af1158015612e38573d6000803e3d6000fd5b505050600083815260cf602052604090819020805460ff1916905560c95490516370a0823160e01b8152306004820152612ecc92506101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015612ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec791906153bc565b613a80565b507f9de94d299df82b41c8ef1c090ea1b6fc6bb0c7ac32732410eec0b58df27c57d783604051612efc91906159c2565b60405180910390a1505050565b612f116133fc565b60ca5460a082015180516001600160a01b0390921691600090612f3657612f36614fe5565b60200260200101516001600160a01b031614612f6557604051632711b74d60e11b815260040160405180910390fd5b604051632cbd9b6d60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063597b36da90612fb49085906004016159c2565b602060405180830381865afa158015612fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff591906153bc565b600081815260ce60205260409020549091506001600160a01b031615158061302a5750600081815260db602052604090205415155b156130485760405163eb3d1dcd60e01b815260040160405180910390fd5b600081815260cf602052604090205460ff16156130785760405163eb3d1dcd60e01b815260040160405180910390fd5b604051635bf8375f60e11b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b7f06ebe90602401602060405180830381865afa1580156130dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310191906155fb565b61311e576040516355780d0f60e11b815260040160405180910390fd5b604051630bb2ebd160e31b81526004810182905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635d975e8890602401600060405180830381865afa158015613188573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131b091908101906154d3565b915050806000815181106131c6576131c6614fe5565b602002602001015160cd60008282546131df9190614faa565b92505081905550806000815181106131f9576131f9614fe5565b602090810291909101810151600085815260d583526040808220600190810184905560cf90945290819020805460ff191690931790925590519092507f97c48b25f8fb5648d626126d6ba4b2d81315b243f41121822689297cdafff6a2906110859086906159c2565b61326a6133fc565b6001600160a01b0381166132cf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161207b565b610ec581613b67565b6001600160a01b03831661333a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161207b565b6001600160a01b03821661339b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161207b565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6065546001600160a01b031633146118495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161207b565b6001600160a01b038116610ec55760405163862a606760e01b815260040160405180910390fd5b6002609754036134cf5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161207b565b6002609755565b61c4e060cb546134e69190614faa565b60cc546134f390436155e8565b10156118495760405163df3e0d1960e01b815260040160405180910390fd5b6001609755565b60006135258484612b07565b9050600019811461358d57818110156135805760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161207b565b61358d84848484036132d8565b50505050565b6001600160a01b0383166135f75760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161207b565b6001600160a01b0382166136595760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161207b565b6001600160a01b038316600090815260336020526040902054818110156136d15760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161207b565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906137319086815260200190565b60405180910390a361358d565b604051631976849960e21b81523060048201526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906365da126490602401602060405180830381865afa1580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c99190614fc8565b6001600160a01b03160361184957604051635add22c560e01b815260040160405180910390fd5b60d254600160a01b900460ff1615611849576040516336a7e2cd60e21b815260040160405180910390fd5b80600003610ec55760405163862a606760e01b815260040160405180910390fd5b60ca5460405163c540d33160e01b8152600481018390526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301529091166044820152606090600090819081907347fbab3dbaebfcf6173b9637bb020c0ca05158e29063c540d33190606401600060405180830381865af41580156138d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f99190810190615a5f565b9195509250905061390a8285614359565b92509193509193565b6065546001600160a01b03163314801590613939575060da546001600160a01b03163314155b1561184957604051634e9e4da760e11b815260040160405180910390fd5b60d9546001600160a01b0316613980576040516371ffc72560e01b815260040160405180910390fd5b60d960009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f791906155fb565b15611849576040516319fab72b60e01b815260040160405180910390fd5b6040516001600160a01b038085166024830152831660448201526064810182905261358d9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614442565b60c954600090613abf9061010090046001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000084614517565b60ca5460c9546040516373d0285560e11b81526001600160a01b03928316600482015261010090910482166024820152604481018490527f00000000000000000000000000000000000000000000000000000000000000009091169063e7a050aa906064016020604051808303816000875af1158015613b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9091906153bc565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b613bc1610c10565b613bcb82436155e8565b1015610ec5576040516315844b9560e11b815260040160405180910390fd5b6001600160a01b038216613c4a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161207b565b6001600160a01b03821660009081526033602052604090205481811015613cbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161207b565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6040805160018082528183019092526000918291906020808301908036833701905050905060c960019054906101000a90046001600160a01b031681600081518110613d6c57613d6c614fe5565b6001600160a01b03909216602092830291909101820152600085815260d5909152604081206001015460cd805491929091613da89084906155e8565b90915550613db790508461430d565b60c9546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2991906153bc565b604051630e4cc3f960e41b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e4cc3f9090613e7d90879086906001906004016159d5565b600060405180830381600087803b158015613e9757600080fd5b505af1158015613eab573d6000803e3d6000fd5b505060c9546040516370a0823160e01b81523060048201528493506101009091046001600160a01b031691506370a0823190602401602060405180830381865afa158015613efd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f2191906153bc565b613f2b91906155e8565b95945050505050565b6040516001600160a01b0383166024820152604481018290526116e690849063a9059cbb60e01b90606401613a49565b60d95481906001600160a01b0316156113485760d954604080516374048c4760e01b815290516000926001600160a01b0316916374048c479160048083019260209291908290030181865afa158015613fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe591906153bc565b9050801561406a576000838211613ffc5781613ffe565b835b60d95460c9549192506140239161010090046001600160a01b03908116911683613f34565b61402d81846155e8565b92507fdbdcd7ad0943924f9daa43cdc362c9f00153489e7c5edb364597f7c4b45ce8538160405161406091815260200190565b60405180910390a1505b50919050565b600054610100900460ff166140975760405162461bcd60e51b815260040161207b90615bb0565b61297982826145c4565b600054610100900460ff166140c85760405162461bcd60e51b815260040161207b90615bb0565b611849614604565b6001600160a01b0382166141265760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161207b565b80603560008282546141389190614faa565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060d65460cd54610d3291906155e8565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa1580156141ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061421091906153bc565b905060006127106142417f000000000000000000000000000000000000000000000000000000000000000084614f71565b61424b9190614f88565b90506142816001600160a01b0385167f000000000000000000000000000000000000000000000000000000000000000083613f34565b600061271060d054846142949190614f71565b61429e9190614f88565b60d1549091506142bb906001600160a01b03878116911683613f34565b6142c58183614faa565b613f2b90846155e8565b60c9546001600160a01b036101009091048116908316036142f3576116e681613a80565b60d254612979906001600160a01b03848116911683613f34565b600081815260d5602052604090205415610ec557600081815260d5602052604081205460d68054919290916143439084906155e8565b9091555050600090815260d56020526040812055565b60008260cd600082825461436d9190614faa565b90915550506040516306ec6e8160e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630dd8dd02906143be908590600401615bfb565b6000604051808303816000875af11580156143dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526144059190810190615c9b565b60008151811061441757614417614fe5565b602002602001015190508260d560008381526020019081526020016000206001018190555092915050565b6000614497826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661462b9092919063ffffffff16565b90508051600014806144b85750808060200190518101906144b891906155fb565b6116e65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161207b565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015614567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061458b91906153bc565b905061358d8463095ea7b360e01b856145a48686614faa565b6040516001600160a01b0390921660248301526044820152606401613a49565b600054610100900460ff166145eb5760405162461bcd60e51b815260040161207b90615bb0565b60366145f78382615d74565b5060376116e68282615d74565b600054610100900460ff166135125760405162461bcd60e51b815260040161207b90615bb0565b606061463a8484600085614642565b949350505050565b6060824710156146a35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161207b565b600080866001600160a01b031685876040516146bf9190615e32565b60006040518083038185875af1925050503d80600081146146fc576040519150601f19603f3d011682016040523d82523d6000602084013e614701565b606091505b50915091506147128783838761471d565b979650505050505050565b6060831561478c578251600003614785576001600160a01b0385163b6147855760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161207b565b508161463a565b61463a83838151156147a15781518083602001fd5b8060405162461bcd60e51b815260040161207b919061480b565b60005b838110156147d65781810151838201526020016147be565b50506000910152565b600081518084526147f78160208601602086016147bb565b601f01601f19169290920160200192915050565b6020815260006110b260208301846147df565b6001600160a01b0381168114610ec557600080fd5b80356113488161481e565b6000806040838503121561485157600080fd5b823561485c8161481e565b946020939093013593505050565b60006020828403121561487c57600080fd5b81356110b28161481e565b60006020828403121561489957600080fd5b5035919050565b600080600080608085870312156148b657600080fd5b843593506020850135925060408501356148cf8161481e565b915060608501356148df8161481e565b939692955090935050565b6000806000606084860312156148ff57600080fd5b833561490a8161481e565b9250602084013561491a8161481e565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156149635761496361492b565b60405290565b60405160e081016001600160401b03811182821017156149635761496361492b565b604051606081016001600160401b03811182821017156149635761496361492b565b604051601f8201601f191681016001600160401b03811182821017156149d5576149d561492b565b604052919050565b6000806001600160401b038411156149f7576149f761492b565b50601f8301601f1916602001614a0c816149ad565b915050828152838383011115614a2157600080fd5b828260208301376000602084830101529392505050565b600080600060608486031215614a4d57600080fd5b8335614a588161481e565b925060208401356001600160401b03811115614a7357600080fd5b840160408187031215614a8557600080fd5b614a8d614941565b81356001600160401b03811115614aa357600080fd5b8201601f81018813614ab457600080fd5b614ac3888235602084016149dd565b82525060209182013591810191909152929592945050506040919091013590565b600060208284031215614af657600080fd5b81356001600160401b03811115614b0c57600080fd5b820160e081850312156110b257600080fd5b60008060208385031215614b3157600080fd5b82356001600160401b03811115614b4757600080fd5b8301601f81018513614b5857600080fd5b80356001600160401b03811115614b6e57600080fd5b8560208260051b8401011115614b8357600080fd5b6020919091019590945092505050565b600082601f830112614ba457600080fd5b6110b2838335602085016149dd565b60008060008060008060008060006101208a8c031215614bd257600080fd5b89356001600160401b03811115614be857600080fd5b614bf48c828d01614b93565b99505060208a01356001600160401b03811115614c1057600080fd5b614c1c8c828d01614b93565b98505060408a0135614c2d8161481e565b9650614c3b60608b01614833565b9550614c4960808b01614833565b945060a08a0135935060c08a01359250614c6560e08b01614833565b9150614c746101008b01614833565b90509295985092959850929598565b600060208284031215614c9557600080fd5b81356001600160401b03811115614cab57600080fd5b820161010081850312156110b257600080fd5b60008060408385031215614cd157600080fd5b8235614cdc8161481e565b91506020830135614cec8161481e565b809150509250929050565b63ffffffff81168114610ec557600080fd5b803561134881614cf7565b60006001600160401b03821115614d2d57614d2d61492b565b5060051b60200190565b600082601f830112614d4857600080fd5b8135614d5b614d5682614d14565b6149ad565b8082825260208201915060208360051b860101925085831115614d7d57600080fd5b602085015b83811015614da3578035614d958161481e565b835260209283019201614d82565b5095945050505050565b600082601f830112614dbe57600080fd5b8135614dcc614d5682614d14565b8082825260208201915060208360051b860101925085831115614dee57600080fd5b602085015b83811015614da3578035835260209283019201614df3565b600060e08284031215614e1d57600080fd5b614e25614969565b9050614e3082614833565b8152614e3e60208301614833565b6020820152614e4f60408301614833565b604082015260608281013590820152614e6a60808301614d09565b608082015260a08201356001600160401b03811115614e8857600080fd5b614e9484828501614d37565b60a08301525060c08201356001600160401b03811115614eb357600080fd5b614ebf84828501614dad565b60c08301525092915050565b600060208284031215614edd57600080fd5b81356001600160401b03811115614ef357600080fd5b61463a84828501614e0b565b600181811c90821680614f1357607f821691505b60208210810361406a57634e487b7160e01b600052602260045260246000fd5b805161134881614cf7565b600060208284031215614f5057600080fd5b81516110b281614cf7565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610b9057610b90614f5b565b600082614fa557634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610b9057610b90614f5b565b80516113488161481e565b600060208284031215614fda57600080fd5b81516110b28161481e565b634e487b7160e01b600052603260045260246000fd5b600081518084526020840193506020830160005b828110156150365781516001600160a01b031686526020958601959091019060010161500f565b5093949350505050565b600081518084526020840193506020830160005b82811015615036578151865260209586019590910190600101615054565b8981526001600160a01b03898116602083015288811660408301528781166060830152861660808201526bffffffffffffffffffffffff851660a082015260c0810184905261012060e082018190526000906150d090830185614ffb565b8281036101008401526150e38185615040565b9c9b505050505050505050505050565b60018060a01b038416815260606020820152600083516040606084015261511d60a08401826147df565b602095909501516080840152505060400152919050565b6001815b600184111561516f5780850481111561515357615153614f5b565b600184161561516157908102905b60019390931c928002615138565b935093915050565b60008261518657506001610b90565b8161519357506000610b90565b81600181146151a957600281146151b3576151cf565b6001915050610b90565b60ff8411156151c4576151c4614f5b565b50506001821b610b90565b5060208310610133831016604e8410600b84101617156151f2575081810a610b90565b6151ff6000198484615134565b806000190482111561521357615213614f5b565b029392505050565b60006110b260ff841683615177565b6000808335601e1984360301811261524157600080fd5b83016020810192503590506001600160401b0381111561526057600080fd5b8060051b360382131561527257600080fd5b9250929050565b81835260208301925060008160005b8481101561503657813561529b8161481e565b6001600160a01b031686526020958601959190910190600101615288565b81835260006001600160fb1b038311156152d257600080fd5b8260051b80836020870137939093016020019392505050565b600081356152f88161481e565b6001600160a01b0316835260208201356153118161481e565b6001600160a01b0316602084015261532b60408301614833565b6001600160a01b031660408401526060828101359084015261534f60808301614d09565b63ffffffff16608084015261536760a083018361522a565b60e060a086015261537c60e086018284615279565b91505061538c60c084018461522a565b85830360c087015261539f8382846152b9565b9695505050505050565b6020815260006110b260208301846152eb565b6000602082840312156153ce57600080fd5b5051919050565b6000610b903683614e0b565b84815260018060a01b038416602082015282604082015260806060820152600061539f60808301846152eb565b600082601f83011261541f57600080fd5b815161542d614d5682614d14565b8082825260208201915060208360051b86010192508583111561544f57600080fd5b602085015b83811015614da35780516154678161481e565b835260209283019201615454565b600082601f83011261548657600080fd5b8151615494614d5682614d14565b8082825260208201915060208360051b8601019250858311156154b657600080fd5b602085015b83811015614da35780518352602092830192016154bb565b600080604083850312156154e657600080fd5b82516001600160401b038111156154fc57600080fd5b830160e0818603121561550e57600080fd5b615516614969565b61551f82614fbd565b815261552d60208301614fbd565b602082015261553e60408301614fbd565b60408201526060828101519082015261555960808301614f33565b608082015260a08201516001600160401b0381111561557757600080fd5b6155838782850161540e565b60a08301525060c08201516001600160401b038111156155a257600080fd5b6155ae87828501615475565b60c083015250809350505060208301516001600160401b038111156155d257600080fd5b6155de85828601615475565b9150509250929050565b81810381811115610b9057610b90614f5b565b60006020828403121561560d57600080fd5b815180151581146110b257600080fd5b60006020828403121561562f57600080fd5b815160ff811681146110b257600080fd5b6000808335601e1984360301811261565757600080fd5b83016020810192503590506001600160401b0381111561567657600080fd5b80360382131561527257600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b80356156b98161481e565b6001600160a01b03168252602090810135910152565b81835260208301925060008160005b848110156150365781356156f181614cf7565b63ffffffff16865260209586019591909101906001016156de565b60008383855260208501945060208460051b8201018360005b8681101561576357838303601f190188526157408287615640565b61574b858284615685565b60209a8b019a90955093909301925050600101615725565b50909695505050505050565b6000808335601e1984360301811261578657600080fd5b83016020810192503590506001600160401b038111156157a557600080fd5b8060061b360382131561527257600080fd5b81835260208301925060008160005b848110156150365781356157d98161481e565b6001600160a01b0316865260208281013590870152604095860195909101906001016157c6565b604081526000833561581181614cf7565b63ffffffff16604083015261582860208501614d09565b63ffffffff1660608301526158406040850185615640565b610100608085015261585761014085018284615685565b91505061586a60a08401606087016156ae565b61587760a086018661522a565b848303603f190160e086015261588e8382846156cf565b9250505061589f60c086018661522a565b848303603f19016101008601526158b783828461570c565b925050506158c860e086018661576f565b848303603f19016101208601526158e08382846157b7565b93505050506110b260208301846001600160a01b03169052565b6000808335601e1984360301811261591157600080fd5b8301803591506001600160401b0382111561592b57600080fd5b6020019150600681901b360382131561527257600080fd5b80516001600160a01b039081168352602080830151821690840152604080830151909116908301526060808201519083015260808082015160009161598f9085018263ffffffff169052565b5060a082015160e060a08501526159a960e0850182614ffb565b905060c083015184820360c0860152613f2b8282615040565b6020815260006110b26020830184615943565b6060815260006159e86060830186615943565b828103602084015280855180835260208301915060208701925060005b81811015615a2c5783516001600160a01b0316835260209384019390920191600101615a05565b505080925050508215156040830152949350505050565b80516bffffffffffffffffffffffff8116811461134857600080fd5b600080600060608486031215615a7457600080fd5b83516001600160401b03811115615a8a57600080fd5b8401601f81018613615a9b57600080fd5b8051615aa9614d5682614d14565b8082825260208201915060208360051b850101925088831115615acb57600080fd5b602084015b83811015615b8b5780516001600160401b03811115615aee57600080fd5b85016060818c03601f19011215615b0457600080fd5b615b0c61498b565b60208201516001600160401b03811115615b2557600080fd5b615b348d60208386010161540e565b82525060408201516001600160401b03811115615b5057600080fd5b615b5f8d602083860101615475565b60208301525060608201519150615b758261481e565b6040810191909152835260209283019201615ad0565b5060208801519096509450615ba7925050604086019050615a43565b90509250925092565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015615c8f57603f198786030184528151805160608752615c496060880182614ffb565b905060208201518782036020890152615c628282615040565b6040938401516001600160a01b031698909301979097525094506020938401939190910190600101615c23565b50929695505050505050565b600060208284031215615cad57600080fd5b81516001600160401b03811115615cc357600080fd5b8201601f81018413615cd457600080fd5b8051615ce2614d5682614d14565b8082825260208201915060208360051b850101925086831115615d0457600080fd5b6020840193505b8284101561539f578351825260209384019390910190615d0b565b601f8211156116e657806000526020600020601f840160051c81016020851015615d4d5750805b601f840160051c820191505b81811015615d6d5760008155600101615d59565b5050505050565b81516001600160401b03811115615d8d57615d8d61492b565b615da181615d9b8454614eff565b84615d26565b6020601f821160018114615dd55760008315615dbd5750848201515b600019600385901b1c1916600184901b178455615d6d565b600084815260208120601f198516915b82811015615e055787850151825560209485019460019092019101615de5565b5084821015615e235786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60008251615e448184602087016147bb565b919091019291505056fea26469706673582212203373db8eb7aa6c4b5020b3a0deb19229b99b69a0bba50f76582bd1c19bc923d964736f6c634300081b0033000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda000000000000000000000000ec53bf9167f50cdeb3ae105f56099aaab9061f8300000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e750000000000000000000000000000000000000000000000000000000000000064000000000000000000000000d22fb2d2c09c108c44b622c37f6d2f4bc9f85668000000000000000000000000000000000000000000000000000000000000138800000000000000000000000018efef04f525a9bf0c6440b12ebb71bfa2ab5982
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061045f5760003560e01c80638456cb591161024c578063ba285bd111610146578063e0540a9f116100c3578063efea6da711610087578063efea6da714610a59578063f2fde38b14610a80578063fc278fb714610a93578063fdc371ce14610aba578063ff02688614610ae157600080fd5b8063e0540a9f146109f0578063e1467e8514610a03578063e1f1c4a714610a16578063e58837df14610a1f578063ea4d3c9b14610a3257600080fd5b8063d6324e601161010a578063d6324e601461099b578063d83ad00c146109ae578063d9a90a8e146109b7578063dd62ed3e146109ca578063e00af4a7146109dd57600080fd5b8063ba285bd114610905578063c5f981ad1461090e578063c753965914610921578063c82b35ee1461097f578063d0b902461461099257600080fd5b80639fd0506d116101d4578063ad93b4b711610198578063ad93b4b7146104de578063b0e21e8a146108b0578063b6954532146108d7578063b6b55f25146108ea578063b8668738146108fd57600080fd5b80639fd0506d1461083d578063a194e8fe14610850578063a457c2d714610863578063a9059cbb14610876578063ab5a851b1461088957600080fd5b80638da5cb5b1161021b5780638da5cb5b146107eb5780638f6a6240146107fc57806390b187ba1461080f57806395d89b411461082257806396fd64421461082a57600080fd5b80638456cb5914610782578063865e02931461078a5780638a2fc4e3146107b15780638c01d542146107d857600080fd5b8063438cda2b1161035d5780636f307dc3116102e5578063772495c3116102a9578063772495c3146107195780637765a1021461072c578063803db96d1461073f5780638105165b14610766578063843eeecd1461076f57600080fd5b80636f307dc31461069a5780636fbec0cd146106b257806370a08231146106d5578063711f86d7146106fe578063715018a61461071157600080fd5b80635c975abb1161032c5780635c975abb146106315780635d1dd2391461064557806360cd4a6014610681578063679aefce1461068a578063683dd1911461069257600080fd5b8063438cda2b146105e55780634a27cc16146105f85780635361477b1461060b57806359f6adc71461061e57600080fd5b8063235a6e4c116103eb5780632e1a7d4d116103af5780632e1a7d4d14610585578063313ce5671461059857806339509351146105a357806339b70e38146105b65780633f4ba83a146105dd57600080fd5b8063235a6e4c1461050257806323b872dd1461051557806325a760c2146105285780632819c2d2146105475780632d88af4a1461057257600080fd5b80630baa9ed6116104325780630baa9ed6146104cd5780630bf35320146104d5578063101395fa146104de57806314626dc6146104e757806318160ddd146104fa57600080fd5b806301ac145b1461046457806306fdde0314610480578063095ea7b3146104955780630a785407146104b8575b600080fd5b61046d60d05481565b6040519081526020015b60405180910390f35b610488610aea565b604051610477919061480b565b6104a86104a336600461483e565b610b7c565b6040519015158152602001610477565b6104cb6104c636600461486a565b610b96565b005b61046d610c10565b61046d60d75481565b61046d6103e881565b6104cb6104f5366004614887565b610d37565b60355461046d565b6104cb6105103660046148a0565b610ec8565b6104a86105233660046148ea565b611093565b60c9546105359060ff1681565b60405160ff9091168152602001610477565b60d25461055a906001600160a01b031681565b6040516001600160a01b039091168152602001610477565b6104cb61058036600461486a565b6110b9565b61046d610593366004614887565b611133565b60c95460ff16610535565b6104a86105b136600461483e565b61134d565b61055a7f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a81565b6104cb61136f565b61046d6105f3366004614887565b6113bb565b60d95461055a906001600160a01b031681565b6104cb610619366004614a38565b611552565b6104cb61062c366004614887565b6116eb565b60d2546104a890600160a01b900460ff1681565b61066c610653366004614887565b60d5602052600090815260409020805460019091015482565b60408051928352602083019190915201610477565b61046d60cb5481565b61046d611760565b61046d6117a9565b60c95461055a9061010090046001600160a01b031681565b6104a86106c0366004614887565b60cf6020526000908152604090205460ff1681565b61046d6106e336600461486a565b6001600160a01b031660009081526033602052604090205490565b6104cb61070c36600461486a565b6117bd565b6104cb611837565b6104cb61072736600461486a565b61184b565b6104cb61073a366004614887565b6118ce565b61055a7f000000000000000000000000d22fb2d2c09c108c44b622c37f6d2f4bc9f8566881565b61046d61c4e081565b6104cb61077d366004614ae4565b611940565b6104cb611b07565b61055a7f00000000000000000000000018efef04f525a9bf0c6440b12ebb71bfa2ab598281565b61055a7f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda81565b60d15461055a906001600160a01b031681565b6065546001600160a01b031661055a565b61046d61080a36600461486a565b611b8f565b6104cb61081d366004614ae4565b611bce565b610488611d30565b6104cb610838366004614b1e565b611d3f565b60d35461055a906001600160a01b031681565b60da5461055a906001600160a01b031681565b6104a861087136600461483e565b612011565b6104a861088436600461483e565b61209c565b61055a7f00000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e7581565b61046d7f000000000000000000000000000000000000000000000000000000000000006481565b6104cb6108e5366004614bb3565b6120aa565b61046d6108f8366004614887565b6126a9565b61046d6127ea565b61046d60cc5481565b60d45461055a906001600160a01b031681565b61095a61092f366004614887565b60ce602052600090815260409020805460018201546002909201546001600160a01b03909116919083565b604080516001600160a01b039094168452602084019290925290820152606001610477565b6104cb61098d36600461483e565b61292e565b61046d60d85481565b60ca5461055a906001600160a01b031681565b61046d60cd5481565b6104cb6109c5366004614c83565b61297d565b61046d6109d8366004614cbe565b612b07565b6104cb6109eb36600461486a565b612b32565b6104cb6109fe366004614887565b612c1c565b6104cb610a11366004614ecb565b612c59565b61046d61271081565b6104cb610a2d366004614ecb565b612f09565b61055a7f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a81565b61046d7f000000000000000000000000000000000000000000000000000000000000138881565b6104cb610a8e36600461486a565b613262565b61066c610aa1366004614887565b60db602052600090815260409020805460019091015482565b61055a7f000000000000000000000000ec53bf9167f50cdeb3ae105f56099aaab9061f8381565b61046d60d65481565b606060368054610af990614eff565b80601f0160208091040260200160405190810160405280929190818152602001828054610b2590614eff565b8015610b725780601f10610b4757610100808354040283529160200191610b72565b820191906000526020600020905b815481529060010190602001808311610b5557829003601f168201915b5050505050905090565b600033610b8a8185856132d8565b60019150505b92915050565b610b9e6133fc565b610ba781613456565b60da54604080516001600160a01b03928316815291831660208301527fd591952303965b8a4599dc8f8a7b978ef62c3d6264dfe63102bc445af99e6dd7910160405180910390a160da80546001600160a01b0319166001600160a01b0392909216919091179055565b600060cb547f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c979190614f3e565b63ffffffff1611610ca9575060cb5490565b7f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2b9190614f3e565b63ffffffff165b905090565b610d3f61347d565b610d476133fc565b60007f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcb9190614f3e565b63ffffffff16905080821080610ddf575081155b15610dfd57604051630130feaf60e01b815260040160405180910390fd5b80821115610e75576000612710610e347f000000000000000000000000000000000000000000000000000000000000138884614f71565b610e3e9190614f88565b610e489083614faa565b905080831115610e6b57604051636108fcdb60e11b815260040160405180910390fd5b610e736134d6565b505b60cb5460408051918252602082018490527fea142c60fe44885a5d85aaac36e42beaab40f1e0c956960d5b9d3422b5d1c535910160405180910390a15060cb8190554360cc55610ec56001609755565b50565b610ed06133fc565b610ed981613456565b60d9546001600160a01b031615610f035760405163a9bdb05f60e01b815260040160405180910390fd5b7347fbab3dbaebfcf6173b9637bb020c0ca05158e263a88254597f00000000000000000000000018efef04f525a9bf0c6440b12ebb71bfa2ab5982868686610f536065546001600160a01b031690565b60405160e087901b6001600160e01b03191681526001600160a01b0395861660048201526024810194909452604484019290925283166064830152909116608482015260a401602060405180830381865af4158015610fb6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fda9190614fc8565b60d980546001600160a01b0319166001600160a01b0392831617905560da5460408051918316825291831660208201527fd591952303965b8a4599dc8f8a7b978ef62c3d6264dfe63102bc445af99e6dd7910160405180910390a160da80546001600160a01b0319166001600160a01b038381169190911790915560d954604051911681527faea4902a18460819d7969a679a8553c2e99474de92f2d1442df092d139b165fa906020015b60405180910390a150505050565b6000336110a1858285613519565b6110ac858585613593565b60019150505b9392505050565b6110c16133fc565b6110ca81613456565b60d354604080516001600160a01b03928316815291831660208301527f1ff153f4b082245afbf3211a8d2d207da4c5df490e965f9a9ad141b0cd001dda910160405180910390a160d380546001600160a01b0319166001600160a01b0392909216919091179055565b600061113d61347d565b61114561373e565b61114d6137f0565b6111568261381b565b600060d854118015611169575060d85442105b1561118757604051635619a21360e11b815260040160405180910390fd5b611192333084613593565b600061119c6117a9565b6111a4611760565b6111ae9085614f71565b6111b89190614f88565b90506000806000806111c98561383c565b604080516060810182523380825260208083018f815243848601908152600089815260ce90935291859020935184546001600160a01b0319166001600160a01b039182161785559051600185015590516002909301929092559151631976849960e21b81523060048201819052969a509498509296509094507f0176007ec78c756143be1d2a6feec53fd9e31d37037259af455e8cfc1cb33811938793919290917f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a909116906365da126490602401602060405180830381865afa1580156112b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d99190614fc8565b3086438b6000815181106112ef576112ef614fe5565b6020026020010151600001518c60008151811061130e5761130e614fe5565b60200260200101516020015160405161132f99989796959493929190615072565b60405180910390a1509093505050506113486001609755565b919050565b600033610b8a8185856113608383612b07565b61136a9190614faa565b6132d8565b6113776133fc565b60d2805460ff60a01b19169055604051600081527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2906020015b60405180910390a1565b60006113c561347d565b6113cd613913565b6113d56137f0565b6113dd61373e565b6113e68261381b565b6113ee613957565b6000806000806113fd8661383c565b604080518082018252838152436020808301918252600087815260db909152839020915182555160019091015551631976849960e21b8152306004820181905294985092965090945092507f8172a150efcbbc7fbef8129ebf24a1e581d5769d11a8dec7dbba4b904b4e94f49185913391907f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b0316906365da126490602401602060405180830381865afa1580156114c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e49190614fc8565b3086438b6000815181106114fa576114fa614fe5565b6020026020010151600001518c60008151811061151957611519614fe5565b60200260200101516020015160405161153a99989796959493929190615072565b60405180910390a15090925050506113486001609755565b61155a61347d565b6115626133fc565b61156b83613456565b604051631976849960e21b81523060048201526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a16906365da126490602401602060405180830381865afa1580156115d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f69190614fc8565b6001600160a01b03161461161d57604051631a30c08d60e31b815260040160405180910390fd5b60405163eea9064b60e01b81526001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063eea9064b9061166d908690869086906004016150f3565b600060405180830381600087803b15801561168757600080fd5b505af115801561169b573d6000803e3d6000fd5b50506040516001600160a01b03861681527ffe608947467beb30a90e072fd2fc7d52baecf0935f542011fcd8fa6362a5d5b39250602001905060405180910390a16116e66001609755565b505050565b6116f361347d565b6116fc8161381b565b60c9546117199061010090046001600160a01b0316333084613a15565b61172281613a80565b506040518181527fb02f19427b6324e7102facbe680a13b90e2424617afe32d862c9edf6dfaa83709060200160405180910390a1610ec56001609755565b60006103e861176e60355490565b6117789190614faa565b6117806117a9565b6103e861178b6127ea565b6117959190614faa565b61179f9190614f71565b610d329190614f88565b60c954600090610d329060ff16600a61521b565b6117c56133fc565b6117ce81613456565b60d454604080516001600160a01b03928316815291831660208301527fae8f8b46fdc10e05708993c545c5a2e35bf6b93c26ec5d017cde78090a41ea7a910160405180910390a160d480546001600160a01b0319166001600160a01b0392909216919091179055565b61183f6133fc565b6118496000613b67565b565b61185361347d565b61185b6133fc565b61186481613456565b60d254604080516001600160a01b03928316815291831660208301527fee962823afbca8ef78f872aa570b3bbbb7a9ac64c8bf15a0c6df38551bc5fe1a910160405180910390a160d280546001600160a01b0319166001600160a01b038316179055600160975550565b6118d66133fc565b6000811180156118e65750428111155b1561190457604051630c75503b60e31b815260040160405180910390fd5b60d88190556040518181527f9f4afb2b04a67e8eafc0e42d56f063553d977f47a054f39e4eea0cdb75a8547a906020015b60405180910390a150565b61194861347d565b61195061373e565b6119586137f0565b604051632cbd9b6d60e11b81526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063597b36da906119a79085906004016153a9565b602060405180830381865afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e891906153bc565b600081815260ce60205260409020549091506001600160a01b031633141580611a0f575033155b15611a2d57604051630bdbeed760e31b815260040160405180910390fd5b600081815260ce6020526040902060020154611a4890613bb9565b600081815260ce6020526040902060010154611a65903090613bea565b6000611a7982611a74856153d5565b613d1e565b60c954909150611a989061010090046001600160a01b03163383613f34565b7f8cc13279d432798ff883698cc787fdd496411d0d094093602f07fe03f087079082338386604051611acd94939291906153e1565b60405180910390a150600090815260ce6020526040812080546001600160a01b03191681556001810182905560020155610ec56001609755565b6065546001600160a01b03163314801590611b2d575060d3546001600160a01b03163314155b15611b4b5760405163492f678160e01b815260040160405180910390fd5b60d2805460ff60a01b1916600160a01b179055604051600181527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2906020016113b1565b6000611b996117a9565b611ba1611760565b6001600160a01b038416600090815260336020526040902054611bc49190614f71565b610b909190614f88565b611bd661347d565b611bde613913565b611be66137f0565b611bee61373e565b604051632cbd9b6d60e11b81526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063597b36da90611c3d9085906004016153a9565b602060405180830381865afa158015611c5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7e91906153bc565b9050611c88613957565b600081815260db6020526040902060010154611ca390613bb9565b6000611cb282611a74856153d5565b90506000611cbf82613f64565b90508015611cd257611cd081613a80565b505b7ffc25fc5303a1c0280b151ff19469c472054bf8a05b56bffe7a82fcec9449b54c83338487604051611d0794939291906153e1565b60405180910390a15050600090815260db6020526040812081815560010155610ec56001609755565b606060378054610af990614eff565b60005b818110156116e657600060ce81858585818110611d6157611d61614fe5565b60209081029290920135835250810191909152604001600020546001600160a01b0316148015611dbf575060db6000848484818110611da257611da2614fe5565b905060200201358152602001908152602001600020600001546000145b8015611dfb575060cf6000848484818110611ddc57611ddc614fe5565b602090810292909201358352508101919091526040016000205460ff16155b15611e19576040516387c9d21960e01b815260040160405180910390fd5b60007f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b0316635d975e88858585818110611e5c57611e5c614fe5565b905060200201356040518263ffffffff1660e01b8152600401611e8191815260200190565b600060405180830381865afa158015611e9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ec691908101906154d3565b915050600081600081518110611ede57611ede614fe5565b602002602001015160d56000878787818110611efc57611efc614fe5565b9050602002013581526020019081526020016000206001015411611f21576000611f75565b81600081518110611f3457611f34614fe5565b602002602001015160d56000878787818110611f5257611f52614fe5565b90506020020135815260200190815260200160002060010154611f7591906155e8565b905060d56000868686818110611f8d57611f8d614fe5565b9050602002013581526020019081526020016000206000015460d66000828254611fb791906155e8565b925050819055508060d66000828254611fd09190614faa565b9091555081905060d56000878787818110611fed57611fed614fe5565b60209081029290920135835250810191909152604001600020555050600101611d42565b6000338161201f8286612b07565b9050838110156120845760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b61209182868684036132d8565b506001949350505050565b600033610b8a818585613593565b600054610100900460ff16158080156120ca5750600054600160ff909116105b806120e45750303b1580156120e4575060005460ff166001145b6121475760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161207b565b6000805460ff19166001179055801561216a576000805461ff0019166101001790555b6001600160a01b038816158061218757506001600160a01b038716155b8061219957506001600160a01b038616155b806121ab57506001600160a01b038316155b806121bd57506001600160a01b038216155b806121c757508951155b806121d157508851155b156121ef5760405163862a606760e01b815260040160405180910390fd5b61271061221c7f000000000000000000000000000000000000000000000000000000000000006486614faa565b111561223b576040516358d620b360e01b815260040160405180910390fd5b60405163198f077960e21b81526001600160a01b0388811660048301527f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a169063663c1de490602401602060405180830381865afa1580156122a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c591906155fb565b6122e257604051632711b74d60e11b815260040160405180910390fd5b7f000000000000000000000000ec53bf9167f50cdeb3ae105f56099aaab9061f836001600160a01b0316886001600160a01b0316148061235357507f00000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e756001600160a01b0316886001600160a01b0316145b15612410577f00000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e756001600160a01b0316876001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123e49190614fc8565b6001600160a01b03161461240b576040516317dc37cb60e11b815260040160405180910390fd5b6124a3565b876001600160a01b0316876001600160a01b0316632495a5996040518163ffffffff1660e01b8152600401602060405180830381865afa158015612458573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247c9190614fc8565b6001600160a01b0316146124a3576040516317dc37cb60e11b815260040160405180910390fd5b7f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b031663c448feb86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612501573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125259190614f3e565b63ffffffff1685101561254b57604051630130feaf60e01b815260040160405180910390fd5b6125558a8a614070565b61255d6140a1565b61256686613b67565b60c98054610100600160a81b0319166101006001600160a01b038b81169182029290921790925560ca80546001600160a01b031916918a169190911790556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156125df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612603919061561d565b60c9805460ff9290921660ff1990921691909117905560cb8590554360cc5560d084905560d180546001600160a01b038086166001600160a01b03199283161790925560d2805492851692909116919091179055801561269d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b60006126b361347d565b6126bb61373e565b6126c36137f0565b6126cc8261381b565b60d7541561270f5760006126de6127ea565b60d7549091506126ee8483614faa565b111561270d5760405163dc320e0f60e01b815260040160405180910390fd5b505b60c95461272c9061010090046001600160a01b0316333085613a15565b6000612736611760565b61273e6117a9565b6127489085614f71565b6127529190614f88565b90508060000361277557604051632160733960e01b815260040160405180910390fd5b61277f33826140d0565b600061278a84613f64565b9050801561279d5761279b81613a80565b505b60408051338152602081018690529081018390527f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060600160405180910390a150506113486001609755565b60ca546000907347fbab3dbaebfcf6173b9637bb020c0ca05158e29063b4737f2f906001600160a01b03167f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a61283e614191565b60c95460d9546040516370a0823160e01b81526001600160a01b03918216600482015261010090920416906370a0823190602401602060405180830381865afa15801561288f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b391906153bc565b6040516001600160e01b031960e087901b1681526001600160a01b03948516600482015293909216602484015260448301526064820152608401602060405180830381865af415801561290a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d3291906153bc565b60d9546001600160a01b031633141580612951575060d9546001600160a01b0316155b1561296f5760405163a2b4235760e01b815260040160405180910390fd5b6129798282613bea565b5050565b6065546001600160a01b031633148015906129a3575060d4546001600160a01b03163314155b156129c1576040516375c7a22760e01b815260040160405180910390fd5b60d2546001600160a01b03166129ea57604051630cd4f69d60e01b815260040160405180910390fd5b604051633ccc861d60e01b81526001600160a01b037f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda1690633ccc861d90612a389084903090600401615800565b600060405180830381600087803b158015612a5257600080fd5b505af1158015612a66573d6000803e3d6000fd5b5050505060005b612a7a60e08301836158fa565b9050811015612979576000612ac0612a9560e08501856158fa565b84818110612aa557612aa5614fe5565b612abb926020604090920201908101915061486a565b6141a3565b9050612afe612ad260e08501856158fa565b84818110612ae257612ae2614fe5565b612af8926020604090920201908101915061486a565b826142cf565b50600101612a6d565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b612b3a61347d565b612b426133fc565b306001600160a01b03821603612b6b57604051631b533c7560e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612bb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bd691906153bc565b905080600003612bf957604051630e3b112360e01b815260040160405180910390fd5b6000612c04836141a3565b9050612c1083826142cf565b5050610ec56001609755565b612c246133fc565b60d78190556040518181527fc3155206c3a231f7548908ce7c152e1fb064246a6eef8f45e686a51ce0b175fc90602001611935565b612c616133fc565b604051632cbd9b6d60e11b81526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063597b36da90612cb09085906004016159c2565b602060405180830381865afa158015612ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf191906153bc565b600081815260cf602052604090205490915060ff16612d235760405163c945242d60e01b815260040160405180910390fd5b6040805160018082528183019092526000916020808301908036833701905050905060c960019054906101000a90046001600160a01b031681600081518110612d6e57612d6e614fe5565b6001600160a01b03909216602092830291909101820152600083815260d5909152604081206001015460cd805491929091612daa9084906155e8565b90915550612db990508261430d565b604051630e4cc3f960e41b81526001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063e4cc3f9090612e0a90869085906001906004016159d5565b600060405180830381600087803b158015612e2457600080fd5b505af1158015612e38573d6000803e3d6000fd5b505050600083815260cf602052604090819020805460ff1916905560c95490516370a0823160e01b8152306004820152612ecc92506101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015612ea3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec791906153bc565b613a80565b507f9de94d299df82b41c8ef1c090ea1b6fc6bb0c7ac32732410eec0b58df27c57d783604051612efc91906159c2565b60405180910390a1505050565b612f116133fc565b60ca5460a082015180516001600160a01b0390921691600090612f3657612f36614fe5565b60200260200101516001600160a01b031614612f6557604051632711b74d60e11b815260040160405180910390fd5b604051632cbd9b6d60e11b81526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063597b36da90612fb49085906004016159c2565b602060405180830381865afa158015612fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff591906153bc565b600081815260ce60205260409020549091506001600160a01b031615158061302a5750600081815260db602052604090205415155b156130485760405163eb3d1dcd60e01b815260040160405180910390fd5b600081815260cf602052604090205460ff16156130785760405163eb3d1dcd60e01b815260040160405180910390fd5b604051635bf8375f60e11b8152600481018290527f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b03169063b7f06ebe90602401602060405180830381865afa1580156130dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061310191906155fb565b61311e576040516355780d0f60e11b815260040160405180910390fd5b604051630bb2ebd160e31b81526004810182905260009081906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a1690635d975e8890602401600060405180830381865afa158015613188573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526131b091908101906154d3565b915050806000815181106131c6576131c6614fe5565b602002602001015160cd60008282546131df9190614faa565b92505081905550806000815181106131f9576131f9614fe5565b602090810291909101810151600085815260d583526040808220600190810184905560cf90945290819020805460ff191690931790925590519092507f97c48b25f8fb5648d626126d6ba4b2d81315b243f41121822689297cdafff6a2906110859086906159c2565b61326a6133fc565b6001600160a01b0381166132cf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161207b565b610ec581613b67565b6001600160a01b03831661333a5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161207b565b6001600160a01b03821661339b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161207b565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6065546001600160a01b031633146118495760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161207b565b6001600160a01b038116610ec55760405163862a606760e01b815260040160405180910390fd5b6002609754036134cf5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161207b565b6002609755565b61c4e060cb546134e69190614faa565b60cc546134f390436155e8565b10156118495760405163df3e0d1960e01b815260040160405180910390fd5b6001609755565b60006135258484612b07565b9050600019811461358d57818110156135805760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161207b565b61358d84848484036132d8565b50505050565b6001600160a01b0383166135f75760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161207b565b6001600160a01b0382166136595760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161207b565b6001600160a01b038316600090815260336020526040902054818110156136d15760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161207b565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906137319086815260200190565b60405180910390a361358d565b604051631976849960e21b81523060048201526000906001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a16906365da126490602401602060405180830381865afa1580156137a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137c99190614fc8565b6001600160a01b03160361184957604051635add22c560e01b815260040160405180910390fd5b60d254600160a01b900460ff1615611849576040516336a7e2cd60e21b815260040160405180910390fd5b80600003610ec55760405163862a606760e01b815260040160405180910390fd5b60ca5460405163c540d33160e01b8152600481018390526001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a811660248301529091166044820152606090600090819081907347fbab3dbaebfcf6173b9637bb020c0ca05158e29063c540d33190606401600060405180830381865af41580156138d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526138f99190810190615a5f565b9195509250905061390a8285614359565b92509193509193565b6065546001600160a01b03163314801590613939575060da546001600160a01b03163314155b1561184957604051634e9e4da760e11b815260040160405180910390fd5b60d9546001600160a01b0316613980576040516371ffc72560e01b815260040160405180910390fd5b60d960009054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139f791906155fb565b15611849576040516319fab72b60e01b815260040160405180910390fd5b6040516001600160a01b038085166024830152831660448201526064810182905261358d9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614442565b60c954600090613abf9061010090046001600160a01b03167f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a84614517565b60ca5460c9546040516373d0285560e11b81526001600160a01b03928316600482015261010090910482166024820152604481018490527f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a9091169063e7a050aa906064016020604051808303816000875af1158015613b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9091906153bc565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b613bc1610c10565b613bcb82436155e8565b1015610ec5576040516315844b9560e11b815260040160405180910390fd5b6001600160a01b038216613c4a5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161207b565b6001600160a01b03821660009081526033602052604090205481811015613cbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161207b565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6040805160018082528183019092526000918291906020808301908036833701905050905060c960019054906101000a90046001600160a01b031681600081518110613d6c57613d6c614fe5565b6001600160a01b03909216602092830291909101820152600085815260d5909152604081206001015460cd805491929091613da89084906155e8565b90915550613db790508461430d565b60c9546040516370a0823160e01b815230600482015260009161010090046001600160a01b0316906370a0823190602401602060405180830381865afa158015613e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2991906153bc565b604051630e4cc3f960e41b81529091506001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a169063e4cc3f9090613e7d90879086906001906004016159d5565b600060405180830381600087803b158015613e9757600080fd5b505af1158015613eab573d6000803e3d6000fd5b505060c9546040516370a0823160e01b81523060048201528493506101009091046001600160a01b031691506370a0823190602401602060405180830381865afa158015613efd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f2191906153bc565b613f2b91906155e8565b95945050505050565b6040516001600160a01b0383166024820152604481018290526116e690849063a9059cbb60e01b90606401613a49565b60d95481906001600160a01b0316156113485760d954604080516374048c4760e01b815290516000926001600160a01b0316916374048c479160048083019260209291908290030181865afa158015613fc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe591906153bc565b9050801561406a576000838211613ffc5781613ffe565b835b60d95460c9549192506140239161010090046001600160a01b03908116911683613f34565b61402d81846155e8565b92507fdbdcd7ad0943924f9daa43cdc362c9f00153489e7c5edb364597f7c4b45ce8538160405161406091815260200190565b60405180910390a1505b50919050565b600054610100900460ff166140975760405162461bcd60e51b815260040161207b90615bb0565b61297982826145c4565b600054610100900460ff166140c85760405162461bcd60e51b815260040161207b90615bb0565b611849614604565b6001600160a01b0382166141265760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161207b565b80603560008282546141389190614faa565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060d65460cd54610d3291906155e8565b6040516370a0823160e01b815230600482015260009081906001600160a01b038416906370a0823190602401602060405180830381865afa1580156141ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061421091906153bc565b905060006127106142417f000000000000000000000000000000000000000000000000000000000000006484614f71565b61424b9190614f88565b90506142816001600160a01b0385167f000000000000000000000000d22fb2d2c09c108c44b622c37f6d2f4bc9f8566883613f34565b600061271060d054846142949190614f71565b61429e9190614f88565b60d1549091506142bb906001600160a01b03878116911683613f34565b6142c58183614faa565b613f2b90846155e8565b60c9546001600160a01b036101009091048116908316036142f3576116e681613a80565b60d254612979906001600160a01b03848116911683613f34565b600081815260d5602052604090205415610ec557600081815260d5602052604081205460d68054919290916143439084906155e8565b9091555050600090815260d56020526040812055565b60008260cd600082825461436d9190614faa565b90915550506040516306ec6e8160e11b81526001600160a01b037f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a1690630dd8dd02906143be908590600401615bfb565b6000604051808303816000875af11580156143dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526144059190810190615c9b565b60008151811061441757614417614fe5565b602002602001015190508260d560008381526020019081526020016000206001018190555092915050565b6000614497826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661462b9092919063ffffffff16565b90508051600014806144b85750808060200190518101906144b891906155fb565b6116e65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161207b565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015614567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061458b91906153bc565b905061358d8463095ea7b360e01b856145a48686614faa565b6040516001600160a01b0390921660248301526044820152606401613a49565b600054610100900460ff166145eb5760405162461bcd60e51b815260040161207b90615bb0565b60366145f78382615d74565b5060376116e68282615d74565b600054610100900460ff166135125760405162461bcd60e51b815260040161207b90615bb0565b606061463a8484600085614642565b949350505050565b6060824710156146a35760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161207b565b600080866001600160a01b031685876040516146bf9190615e32565b60006040518083038185875af1925050503d80600081146146fc576040519150601f19603f3d011682016040523d82523d6000602084013e614701565b606091505b50915091506147128783838761471d565b979650505050505050565b6060831561478c578251600003614785576001600160a01b0385163b6147855760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161207b565b508161463a565b61463a83838151156147a15781518083602001fd5b8060405162461bcd60e51b815260040161207b919061480b565b60005b838110156147d65781810151838201526020016147be565b50506000910152565b600081518084526147f78160208601602086016147bb565b601f01601f19169290920160200192915050565b6020815260006110b260208301846147df565b6001600160a01b0381168114610ec557600080fd5b80356113488161481e565b6000806040838503121561485157600080fd5b823561485c8161481e565b946020939093013593505050565b60006020828403121561487c57600080fd5b81356110b28161481e565b60006020828403121561489957600080fd5b5035919050565b600080600080608085870312156148b657600080fd5b843593506020850135925060408501356148cf8161481e565b915060608501356148df8161481e565b939692955090935050565b6000806000606084860312156148ff57600080fd5b833561490a8161481e565b9250602084013561491a8161481e565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156149635761496361492b565b60405290565b60405160e081016001600160401b03811182821017156149635761496361492b565b604051606081016001600160401b03811182821017156149635761496361492b565b604051601f8201601f191681016001600160401b03811182821017156149d5576149d561492b565b604052919050565b6000806001600160401b038411156149f7576149f761492b565b50601f8301601f1916602001614a0c816149ad565b915050828152838383011115614a2157600080fd5b828260208301376000602084830101529392505050565b600080600060608486031215614a4d57600080fd5b8335614a588161481e565b925060208401356001600160401b03811115614a7357600080fd5b840160408187031215614a8557600080fd5b614a8d614941565b81356001600160401b03811115614aa357600080fd5b8201601f81018813614ab457600080fd5b614ac3888235602084016149dd565b82525060209182013591810191909152929592945050506040919091013590565b600060208284031215614af657600080fd5b81356001600160401b03811115614b0c57600080fd5b820160e081850312156110b257600080fd5b60008060208385031215614b3157600080fd5b82356001600160401b03811115614b4757600080fd5b8301601f81018513614b5857600080fd5b80356001600160401b03811115614b6e57600080fd5b8560208260051b8401011115614b8357600080fd5b6020919091019590945092505050565b600082601f830112614ba457600080fd5b6110b2838335602085016149dd565b60008060008060008060008060006101208a8c031215614bd257600080fd5b89356001600160401b03811115614be857600080fd5b614bf48c828d01614b93565b99505060208a01356001600160401b03811115614c1057600080fd5b614c1c8c828d01614b93565b98505060408a0135614c2d8161481e565b9650614c3b60608b01614833565b9550614c4960808b01614833565b945060a08a0135935060c08a01359250614c6560e08b01614833565b9150614c746101008b01614833565b90509295985092959850929598565b600060208284031215614c9557600080fd5b81356001600160401b03811115614cab57600080fd5b820161010081850312156110b257600080fd5b60008060408385031215614cd157600080fd5b8235614cdc8161481e565b91506020830135614cec8161481e565b809150509250929050565b63ffffffff81168114610ec557600080fd5b803561134881614cf7565b60006001600160401b03821115614d2d57614d2d61492b565b5060051b60200190565b600082601f830112614d4857600080fd5b8135614d5b614d5682614d14565b6149ad565b8082825260208201915060208360051b860101925085831115614d7d57600080fd5b602085015b83811015614da3578035614d958161481e565b835260209283019201614d82565b5095945050505050565b600082601f830112614dbe57600080fd5b8135614dcc614d5682614d14565b8082825260208201915060208360051b860101925085831115614dee57600080fd5b602085015b83811015614da3578035835260209283019201614df3565b600060e08284031215614e1d57600080fd5b614e25614969565b9050614e3082614833565b8152614e3e60208301614833565b6020820152614e4f60408301614833565b604082015260608281013590820152614e6a60808301614d09565b608082015260a08201356001600160401b03811115614e8857600080fd5b614e9484828501614d37565b60a08301525060c08201356001600160401b03811115614eb357600080fd5b614ebf84828501614dad565b60c08301525092915050565b600060208284031215614edd57600080fd5b81356001600160401b03811115614ef357600080fd5b61463a84828501614e0b565b600181811c90821680614f1357607f821691505b60208210810361406a57634e487b7160e01b600052602260045260246000fd5b805161134881614cf7565b600060208284031215614f5057600080fd5b81516110b281614cf7565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610b9057610b90614f5b565b600082614fa557634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610b9057610b90614f5b565b80516113488161481e565b600060208284031215614fda57600080fd5b81516110b28161481e565b634e487b7160e01b600052603260045260246000fd5b600081518084526020840193506020830160005b828110156150365781516001600160a01b031686526020958601959091019060010161500f565b5093949350505050565b600081518084526020840193506020830160005b82811015615036578151865260209586019590910190600101615054565b8981526001600160a01b03898116602083015288811660408301528781166060830152861660808201526bffffffffffffffffffffffff851660a082015260c0810184905261012060e082018190526000906150d090830185614ffb565b8281036101008401526150e38185615040565b9c9b505050505050505050505050565b60018060a01b038416815260606020820152600083516040606084015261511d60a08401826147df565b602095909501516080840152505060400152919050565b6001815b600184111561516f5780850481111561515357615153614f5b565b600184161561516157908102905b60019390931c928002615138565b935093915050565b60008261518657506001610b90565b8161519357506000610b90565b81600181146151a957600281146151b3576151cf565b6001915050610b90565b60ff8411156151c4576151c4614f5b565b50506001821b610b90565b5060208310610133831016604e8410600b84101617156151f2575081810a610b90565b6151ff6000198484615134565b806000190482111561521357615213614f5b565b029392505050565b60006110b260ff841683615177565b6000808335601e1984360301811261524157600080fd5b83016020810192503590506001600160401b0381111561526057600080fd5b8060051b360382131561527257600080fd5b9250929050565b81835260208301925060008160005b8481101561503657813561529b8161481e565b6001600160a01b031686526020958601959190910190600101615288565b81835260006001600160fb1b038311156152d257600080fd5b8260051b80836020870137939093016020019392505050565b600081356152f88161481e565b6001600160a01b0316835260208201356153118161481e565b6001600160a01b0316602084015261532b60408301614833565b6001600160a01b031660408401526060828101359084015261534f60808301614d09565b63ffffffff16608084015261536760a083018361522a565b60e060a086015261537c60e086018284615279565b91505061538c60c084018461522a565b85830360c087015261539f8382846152b9565b9695505050505050565b6020815260006110b260208301846152eb565b6000602082840312156153ce57600080fd5b5051919050565b6000610b903683614e0b565b84815260018060a01b038416602082015282604082015260806060820152600061539f60808301846152eb565b600082601f83011261541f57600080fd5b815161542d614d5682614d14565b8082825260208201915060208360051b86010192508583111561544f57600080fd5b602085015b83811015614da35780516154678161481e565b835260209283019201615454565b600082601f83011261548657600080fd5b8151615494614d5682614d14565b8082825260208201915060208360051b8601019250858311156154b657600080fd5b602085015b83811015614da35780518352602092830192016154bb565b600080604083850312156154e657600080fd5b82516001600160401b038111156154fc57600080fd5b830160e0818603121561550e57600080fd5b615516614969565b61551f82614fbd565b815261552d60208301614fbd565b602082015261553e60408301614fbd565b60408201526060828101519082015261555960808301614f33565b608082015260a08201516001600160401b0381111561557757600080fd5b6155838782850161540e565b60a08301525060c08201516001600160401b038111156155a257600080fd5b6155ae87828501615475565b60c083015250809350505060208301516001600160401b038111156155d257600080fd5b6155de85828601615475565b9150509250929050565b81810381811115610b9057610b90614f5b565b60006020828403121561560d57600080fd5b815180151581146110b257600080fd5b60006020828403121561562f57600080fd5b815160ff811681146110b257600080fd5b6000808335601e1984360301811261565757600080fd5b83016020810192503590506001600160401b0381111561567657600080fd5b80360382131561527257600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b80356156b98161481e565b6001600160a01b03168252602090810135910152565b81835260208301925060008160005b848110156150365781356156f181614cf7565b63ffffffff16865260209586019591909101906001016156de565b60008383855260208501945060208460051b8201018360005b8681101561576357838303601f190188526157408287615640565b61574b858284615685565b60209a8b019a90955093909301925050600101615725565b50909695505050505050565b6000808335601e1984360301811261578657600080fd5b83016020810192503590506001600160401b038111156157a557600080fd5b8060061b360382131561527257600080fd5b81835260208301925060008160005b848110156150365781356157d98161481e565b6001600160a01b0316865260208281013590870152604095860195909101906001016157c6565b604081526000833561581181614cf7565b63ffffffff16604083015261582860208501614d09565b63ffffffff1660608301526158406040850185615640565b610100608085015261585761014085018284615685565b91505061586a60a08401606087016156ae565b61587760a086018661522a565b848303603f190160e086015261588e8382846156cf565b9250505061589f60c086018661522a565b848303603f19016101008601526158b783828461570c565b925050506158c860e086018661576f565b848303603f19016101208601526158e08382846157b7565b93505050506110b260208301846001600160a01b03169052565b6000808335601e1984360301811261591157600080fd5b8301803591506001600160401b0382111561592b57600080fd5b6020019150600681901b360382131561527257600080fd5b80516001600160a01b039081168352602080830151821690840152604080830151909116908301526060808201519083015260808082015160009161598f9085018263ffffffff169052565b5060a082015160e060a08501526159a960e0850182614ffb565b905060c083015184820360c0860152613f2b8282615040565b6020815260006110b26020830184615943565b6060815260006159e86060830186615943565b828103602084015280855180835260208301915060208701925060005b81811015615a2c5783516001600160a01b0316835260209384019390920191600101615a05565b505080925050508215156040830152949350505050565b80516bffffffffffffffffffffffff8116811461134857600080fd5b600080600060608486031215615a7457600080fd5b83516001600160401b03811115615a8a57600080fd5b8401601f81018613615a9b57600080fd5b8051615aa9614d5682614d14565b8082825260208201915060208360051b850101925088831115615acb57600080fd5b602084015b83811015615b8b5780516001600160401b03811115615aee57600080fd5b85016060818c03601f19011215615b0457600080fd5b615b0c61498b565b60208201516001600160401b03811115615b2557600080fd5b615b348d60208386010161540e565b82525060408201516001600160401b03811115615b5057600080fd5b615b5f8d602083860101615475565b60208301525060608201519150615b758261481e565b6040810191909152835260209283019201615ad0565b5060208801519096509450615ba7925050604086019050615a43565b90509250925092565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b82811015615c8f57603f198786030184528151805160608752615c496060880182614ffb565b905060208201518782036020890152615c628282615040565b6040938401516001600160a01b031698909301979097525094506020938401939190910190600101615c23565b50929695505050505050565b600060208284031215615cad57600080fd5b81516001600160401b03811115615cc357600080fd5b8201601f81018413615cd457600080fd5b8051615ce2614d5682614d14565b8082825260208201915060208360051b850101925086831115615d0457600080fd5b6020840193505b8284101561539f578351825260209384019390910190615d0b565b601f8211156116e657806000526020600020601f840160051c81016020851015615d4d5750805b601f840160051c820191505b81811015615d6d5760008155600101615d59565b5050505050565b81516001600160401b03811115615d8d57615d8d61492b565b615da181615d9b8454614eff565b84615d26565b6020601f821160018114615dd55760008315615dbd5750848201515b600019600385901b1c1916600184901b178455615d6d565b600084815260208120601f198516915b82811015615e055787850151825560209485019460019092019101615de5565b5084821015615e235786840151600019600387901b60f8161c191681555b50505050600190811b01905550565b60008251615e448184602087016147bb565b919091019291505056fea26469706673582212203373db8eb7aa6c4b5020b3a0deb19229b99b69a0bba50f76582bd1c19bc923d964736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda000000000000000000000000ec53bf9167f50cdeb3ae105f56099aaab9061f8300000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e750000000000000000000000000000000000000000000000000000000000000064000000000000000000000000d22fb2d2c09c108c44b622c37f6d2f4bc9f85668000000000000000000000000000000000000000000000000000000000000138800000000000000000000000018efef04f525a9bf0c6440b12ebb71bfa2ab5982
-----Decoded View---------------
Arg [0] : _strategyManager (address): 0x858646372CC42E1A627fcE94aa7A7033e7CF075A
Arg [1] : _delegationManager (address): 0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A
Arg [2] : _rewardsCoordinator (address): 0x7750d328b314EfFa365A0402CcfD489B80B0adda
Arg [3] : _eigen (address): 0xec53bF9167f50cDEB3Ae105f56099aaaB9061F83
Arg [4] : _bEigen (address): 0x83E9115d334D248Ce39a6f36144aEaB5b3456e75
Arg [5] : _protocolFee (uint256): 100
Arg [6] : _protocolTreasury (address): 0xD22FB2d2c09C108c44b622c37F6d2f4Bc9f85668
Arg [7] : _maxCooldownBlocksBasisPoints (uint256): 5000
Arg [8] : _withdrawBufferBeacon (address): 0x18EfEf04F525a9BF0c6440b12ebb71BfA2aB5982
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
Arg [1] : 00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a
Arg [2] : 0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda
Arg [3] : 000000000000000000000000ec53bf9167f50cdeb3ae105f56099aaab9061f83
Arg [4] : 00000000000000000000000083e9115d334d248ce39a6f36144aeab5b3456e75
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [6] : 000000000000000000000000d22fb2d2c09c108c44b622c37f6d2f4bc9f85668
Arg [7] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [8] : 00000000000000000000000018efef04f525a9bf0c6440b12ebb71bfa2ab5982
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.