Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AlephAVS
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAlephAVS} from "./IAlephAVS.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IStrategyFactory} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyFactory.sol";
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20 as IERC20Eigen} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {IAlephVaultDeposit} from "Aleph/src/interfaces/IAlephVaultDeposit.sol";
import {IAlephVaultFactory} from "Aleph/src/interfaces/IAlephVaultFactory.sol";
import {IAlephVault} from "Aleph/src/interfaces/IAlephVault.sol";
import {IAlephVaultRedeem} from "Aleph/src/interfaces/IAlephVaultRedeem.sol";
import {IAccountant} from "Aleph/src/interfaces/IAccountant.sol";
import {IERC20Factory} from "./interfaces/IERC20Factory.sol";
import {ERC20Factory} from "./ERC20Factory.sol";
import {AlephAVSPausable} from "./AlephAVSPausable.sol";
import {IMintableBurnableERC20} from "./interfaces/IMintableBurnableERC20.sol";
import {AlephSlashing} from "./libraries/AlephSlashing.sol";
import {AlephVaultManagement} from "./libraries/AlephVaultManagement.sol";
import {RewardsManagement} from "./libraries/RewardsManagement.sol";
import {UnallocateManagement} from "./libraries/UnallocateManagement.sol";
import {AlephValidation} from "./libraries/AlephValidation.sol";
contract AlephAVS is IAlephAVS, AlephAVSPausable, ReentrancyGuard {
using SafeERC20 for IERC20;
bytes32 public constant OWNER = keccak256("OWNER");
uint32 private constant LST_STRATEGIES_OPERATOR_SET_ID = 0;
IAllocationManager public immutable ALLOCATION_MANAGER;
IDelegationManager public immutable DELEGATION_MANAGER;
IStrategyManager public immutable STRATEGY_MANAGER;
IRewardsCoordinator public immutable REWARDS_COORDINATOR;
IAlephVaultFactory public immutable VAULT_FACTORY;
IStrategyFactory public immutable STRATEGY_FACTORY;
struct AVSStorage {
IERC20Factory erc20Factory;
mapping(address vault => IStrategy slashedStrategy) vaultToSlashedStrategy;
mapping(address vault => IStrategy originalStrategy) vaultToOriginalStrategy;
mapping(address vault => uint8 classId) vaultToClassId;
mapping(uint32 operatorSetId => mapping(address strategy => bool exists)) strategyExists;
mapping(address user => mapping(address vault => uint256 estAmountToRedeem)) pendingUnallocate;
mapping(address vault => uint256 totalEstAmount) totalPendingUnallocate;
mapping(address vault => uint256 withdrawnAmount) vaultWithdrawnAmount;
}
bytes32 private constant AVS_STORAGE_LOCATION = 0x032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db604100;
function _getAVSStorage() private pure returns (AVSStorage storage $) {
assembly {
$.slot := AVS_STORAGE_LOCATION
}
}
string private constant SLASH_DESCRIPTION = "";
string private constant REWARDS_DESCRIPTION = "";
function _validVault(address _vault) private view {
if (_getAVSStorage().vaultToSlashedStrategy[_vault] == IStrategy(address(0))) {
revert VaultNotInitialized(_vault);
}
}
modifier validVault(address _vault) {
_validVault(_vault);
_;
}
function _onlyOperator() private view {
if (!DELEGATION_MANAGER.isOperator(msg.sender)) revert NotRegisteredOperator();
}
modifier onlyOperator() {
_onlyOperator();
_;
}
function _validAmount(uint256 _amount) private pure {
if (_amount == 0) revert InvalidAmount();
}
modifier validAmount(uint256 _amount) {
_validAmount(_amount);
_;
}
constructor(
IAllocationManager _allocationManager,
IDelegationManager _delegationManager,
IStrategyManager _strategyManager,
IRewardsCoordinator _rewardsCoordinator,
IAlephVaultFactory _vaultFactory,
IStrategyFactory _strategyFactory
) {
if (address(_allocationManager) == address(0)) {
revert InvalidAllocationManager();
}
if (address(_delegationManager) == address(0)) revert InvalidDelegationManager();
if (address(_strategyManager) == address(0)) revert InvalidStrategyManager();
if (address(_rewardsCoordinator) == address(0)) revert InvalidRewardsCoordinator();
if (address(_vaultFactory) == address(0)) revert InvalidVaultFactory();
if (address(_strategyFactory) == address(0)) revert InvalidStrategyFactory();
ALLOCATION_MANAGER = _allocationManager;
DELEGATION_MANAGER = _delegationManager;
STRATEGY_MANAGER = _strategyManager;
REWARDS_COORDINATOR = _rewardsCoordinator;
VAULT_FACTORY = _vaultFactory;
STRATEGY_FACTORY = _strategyFactory;
_disableInitializers();
}
function initialize(address _owner, address _guardian, string memory _metadataURI) external initializer {
_initialize(_owner, _guardian, _metadataURI);
}
function _initialize(address _owner, address _guardian, string memory _metadataURI) internal onlyInitializing {
if (_owner == address(0) || _guardian == address(0)) revert InvalidAmount();
__AccessControl_init();
_pausableInit(_owner, _guardian);
_grantRole(DEFAULT_ADMIN_ROLE, _owner);
_grantRole(OWNER, _owner);
ALLOCATION_MANAGER.updateAVSMetadataURI(address(this), _metadataURI);
_initializeOperatorSet();
ERC20Factory _erc20Factory = new ERC20Factory(address(this));
_getAVSStorage().erc20Factory = IERC20Factory(address(_erc20Factory));
}
function erc20Factory() external view returns (IERC20Factory) {
return _getAVSStorage().erc20Factory;
}
function vaultToSlashedStrategy(address _vault) external view returns (IStrategy _slashedStrategy) {
_slashedStrategy = _getAVSStorage().vaultToSlashedStrategy[_vault];
}
function vaultToOriginalStrategy(address _vault) external view returns (IStrategy _originalStrategy) {
_originalStrategy = _getAVSStorage().vaultToOriginalStrategy[_vault];
}
/**
* @notice Returns the pending unallocation status for a user and vault
* @dev This view function allows users to check if they can call completeUnallocate
* @param _user The user address to check
* @param _alephVault The Aleph vault address
* @return userPendingAmount The user's pending unallocation amount
* @return totalPendingAmount The total pending unallocation amount for the vault
* @return redeemableAmount The amount currently redeemable from the vault
* @return canComplete Whether the user can complete unallocation (has pending amount and vault has redeemable amount)
*/
function getPendingUnallocateStatus(address _user, address _alephVault)
external
view
returns (uint256 userPendingAmount, uint256 totalPendingAmount, uint256 redeemableAmount, bool canComplete)
{
AVSStorage storage $ = _getAVSStorage();
userPendingAmount = $.pendingUnallocate[_user][_alephVault];
totalPendingAmount = $.totalPendingUnallocate[_alephVault];
// Get redeemable amount from vault
redeemableAmount = IAlephVault(_alephVault).redeemableAmount(address(this));
// User can complete if they have pending amount and funds are available
canComplete = userPendingAmount > 0 && (redeemableAmount > 0 || $.vaultWithdrawnAmount[_alephVault] > 0);
}
/**
* @notice Calculates the expected amount that will be withdrawn in completeUnallocate
* @dev View function to get expected amount for signature generation. See interface documentation for details.
*
* @param _user The user address to calculate for
* @param _alephVault The Aleph vault address
* @return expectedAmount The expected amount that will be withdrawn and deposited to strategy
*/
function calculateCompleteUnallocateAmount(address _user, address _alephVault)
external
view
returns (uint256 expectedAmount)
{
AVSStorage storage $ = _getAVSStorage();
uint256 _userPendingAmount = $.pendingUnallocate[_user][_alephVault];
uint256 _totalPending = $.totalPendingUnallocate[_alephVault];
uint256 _vaultRedeemableAmount = IAlephVault(_alephVault).redeemableAmount(address(this));
uint256 _withdrawnAmount = $.vaultWithdrawnAmount[_alephVault];
expectedAmount = UnallocateManagement.calculateCompleteUnallocateAmountView(
_userPendingAmount, _totalPending, _vaultRedeemableAmount, _withdrawnAmount
);
}
function registerOperator(
address _operator,
address _avs,
uint32[] calldata _operatorSetIds,
bytes calldata /* data */
)
external
{
_validateAVSRegistrarCall(_avs);
emit OperatorRegistered(_operator, _operatorSetIds);
}
function deregisterOperator(address _operator, address _avs, uint32[] calldata _operatorSetIds) external {
_validateAVSRegistrarCall(_avs);
emit OperatorDeregistered(_operator, _operatorSetIds);
}
function supportsAVS(address _avs) external view returns (bool) {
return _avs == address(this);
}
/// @notice Corrects vaultWithdrawnAmount to fix shortage
function correctWithdrawnAmount(address _v, uint256 _a) external onlyRole(OWNER) {
_getAVSStorage().vaultWithdrawnAmount[_v] += _a;
}
function initializeVault(uint8 _classId, address _vault, IStrategy _lstStrategy)
external
onlyRole(OWNER)
returns (IStrategy _slashedStrategy)
{
AVSStorage storage $ = _getAVSStorage();
if (!VAULT_FACTORY.isValidVault(_vault)) revert InvalidVault();
if ($.vaultToSlashedStrategy[_vault] != IStrategy(address(0))) revert VaultAlreadyInitialized();
// Validate the provided strategy
AlephValidation.validateStrategy(address(_lstStrategy));
// Get the original token from the LST strategy's underlying token
// This is the token that will be used to create the slashed token
// Note: underlyingToken() returns IERC20Eigen, so we use that type
IERC20Eigen _originalTokenEigen = _lstStrategy.underlyingToken();
IERC20 _originalToken = IERC20(address(_originalTokenEigen));
// Validate that the vault's underlying token matches the LST strategy's underlying token
if (address(IAlephVault(_vault).underlyingToken()) != address(_originalToken)) {
revert InvalidStrategy();
}
IERC20 _slashedToken;
(_slashedToken, _slashedStrategy) = AlephVaultManagement.createSlashedStrategyForVault(
STRATEGY_FACTORY, _vault, _originalToken, $.vaultToSlashedStrategy, $.erc20Factory
);
$.vaultToClassId[_vault] = _classId;
$.vaultToOriginalStrategy[_vault] = _lstStrategy;
_addStrategyIfNotExists(LST_STRATEGIES_OPERATOR_SET_ID, _lstStrategy);
emit VaultInitialized(
_vault, _classId, address(_originalToken), address(_slashedToken), address(_slashedStrategy)
);
}
function allocate(address _alephVault, IAlephVaultDeposit.RequestDepositParams calldata _requestDepositParams)
external
nonReentrant
onlyOperator
whenFlowNotPaused(ALLOCATE_FLOW)
validVault(_alephVault)
validAmount(_requestDepositParams.amount)
{
RewardsManagement.validateOperatorSplit(REWARDS_COORDINATOR, msg.sender, address(this));
AVSStorage storage $ = _getAVSStorage();
if ($.vaultToClassId[_alephVault] != _requestDepositParams.classId) revert InvalidClassId();
(, IStrategy _stakerStrategy) = _getVaultTokenAndStrategy(_alephVault);
IStrategy _stakerSlashedStrategy = _getSlashedStrategy(_alephVault);
uint256 _tokenAmount = _slashAndTransferInternal(
msg.sender, _requestDepositParams.amount, _stakerStrategy, LST_STRATEGIES_OPERATOR_SET_ID, address(this)
);
IERC20Eigen _slashedToken = IERC20Eigen(_stakerSlashedStrategy.underlyingToken());
uint256 _amountToMint = AlephVaultManagement.calculateAmountToMint(
_requestDepositParams.classId, _alephVault, address(_slashedToken), _tokenAmount
);
uint256 _vaultShares =
AlephVaultManagement.depositToAlephVault(_alephVault, _requestDepositParams, _tokenAmount);
IMintableBurnableERC20(address(_slashedToken)).mint(address(this), _amountToMint);
// Update operator allocations in Accountant for fee distribution
address _accountant = IAlephVault(_alephVault).accountant();
if (_accountant != address(0)) {
IAccountant(_accountant).setOperatorAllocations(_alephVault, msg.sender, _tokenAmount);
}
RewardsManagement.submitOperatorDirectedRewards(
REWARDS_COORDINATOR,
address(this),
msg.sender,
_stakerStrategy,
_slashedToken,
_amountToMint,
REWARDS_DESCRIPTION
);
emit AllocatedToAlephVault(
msg.sender,
_alephVault,
address(_stakerStrategy),
address(_stakerSlashedStrategy),
_tokenAmount,
_amountToMint,
_vaultShares,
_requestDepositParams.classId
);
}
/**
* @notice Requests to unallocate funds by redeeming slashed tokens from vault
* @dev First step of two-step unallocate flow. See interface documentation for detailed usage.
*
* @param _alephVault The Aleph vault address to unallocate from
* @param _tokenAmount The amount of slashed strategy tokens to unallocate
* @return batchId The batch ID for the redeem request
* @return estAmountToRedeem The estimated amount that will be redeemed from the vault
*/
function requestUnallocate(address _alephVault, uint256 _tokenAmount)
external
nonReentrant
whenFlowNotPaused(UNALLOCATE_FLOW)
validAmount(_tokenAmount)
validVault(_alephVault)
returns (uint48 batchId, uint256 estAmountToRedeem)
{
AVSStorage storage $ = _getAVSStorage();
uint8 _classId = $.vaultToClassId[_alephVault];
IStrategy _slashedStrategy = _getSlashedStrategy(_alephVault);
estAmountToRedeem = AlephVaultManagement.calculateAmountToRedeem(
_classId, _alephVault, address(_slashedStrategy.underlyingToken()), _tokenAmount
);
if (estAmountToRedeem == 0) revert InvalidAmount();
AlephVaultManagement.validateAndBurnSlashedTokens(msg.sender, _slashedStrategy, _tokenAmount, address(this));
IAlephVaultRedeem.RedeemRequestParams memory _p =
IAlephVaultRedeem.RedeemRequestParams({classId: _classId, estAmountToRedeem: estAmountToRedeem});
IAlephVaultRedeem(_alephVault).syncRedeem(_p);
$.vaultWithdrawnAmount[_alephVault] += estAmountToRedeem;
batchId = 0;
$.pendingUnallocate[msg.sender][_alephVault] += estAmountToRedeem;
$.totalPendingUnallocate[_alephVault] += estAmountToRedeem;
emit UnallocateRequested(
msg.sender, _alephVault, address(_slashedStrategy), _tokenAmount, estAmountToRedeem, batchId, _classId
);
return (batchId, estAmountToRedeem);
}
/**
* @notice Completes the unallocation by withdrawing redeemable amount and depositing back to strategy
* @dev Second step of two-step unallocate flow. See interface documentation for detailed usage.
*
* @param _alephVault The Aleph vault address to complete unallocation from
* @param _strategyDepositExpiry The expiry timestamp for the strategy deposit signature
* @param _strategyDepositSignature The caller's signature for depositing back into the original LST strategy
* @return _amount The amount of tokens redeemed from the vault and deposited to the strategy
* @return _shares The shares received in the original LST strategy
*/
function completeUnallocate(
address _alephVault,
uint256 _strategyDepositExpiry,
bytes calldata _strategyDepositSignature
)
external
nonReentrant
whenFlowNotPaused(UNALLOCATE_FLOW)
validVault(_alephVault)
returns (uint256 _amount, uint256 _shares)
{
AVSStorage storage $ = _getAVSStorage();
uint8 _classId = $.vaultToClassId[_alephVault];
IStrategy _slashedStrategy = _getSlashedStrategy(_alephVault);
(IERC20 _vaultToken, IStrategy _originalStrategy) = _getVaultTokenAndStrategy(_alephVault);
uint256 _userPendingAmount = $.pendingUnallocate[msg.sender][_alephVault];
if (_userPendingAmount == 0) revert NoPendingUnallocation();
// Calculate expected amount first (before withdrawing) so signature can be generated
// Use the stored estAmountToRedeem as the expected amount
uint256 _totalPending = $.totalPendingUnallocate[_alephVault];
if (_totalPending == 0 || _totalPending < _userPendingAmount) revert InvalidAmount();
uint256 _vaultRedeemableAmount = IAlephVault(_alephVault).redeemableAmount(address(this));
uint256 _withdrawnAmount = $.vaultWithdrawnAmount[_alephVault];
// Calculate expected amount using view function (before state changes)
uint256 _expectedAmount = UnallocateManagement.calculateCompleteUnallocateAmountView(
_userPendingAmount, _totalPending, _vaultRedeemableAmount, _withdrawnAmount
);
if (_expectedAmount == 0) revert InvalidAmount();
// Step 1: Withdraw redeemable amount from vault and calculate total available
uint256 _totalRedeemableAmount = UnallocateManagement.withdrawAndCalculateAvailable(
_alephVault, _vaultToken, _vaultRedeemableAmount, _withdrawnAmount
);
// Step 2: Validate expected amount but don't cap it
_amount = _expectedAmount;
if (_amount == 0) revert InvalidAmount();
if (_amount > _totalRedeemableAmount) revert InvalidAmount();
uint256 _contractBalance = _vaultToken.balanceOf(address(this));
if (_amount > _contractBalance) revert InvalidAmount();
// Step 3: Update storage
// Calculate new values using _totalRedeemableAmount directly (total available after withdrawal)
(uint256 _newVaultWithdrawnAmount, uint256 _newTotalPending) = UnallocateManagement.calculateUnallocationStorageUpdates(
_totalRedeemableAmount, _amount, _userPendingAmount, _totalPending
);
$.vaultWithdrawnAmount[_alephVault] = _newVaultWithdrawnAmount;
$.pendingUnallocate[msg.sender][_alephVault] = 0;
$.totalPendingUnallocate[_alephVault] = _newTotalPending;
// Step 4: Deposit to strategy (interaction)
_shares = AlephVaultManagement.depositToOriginalStrategy(
STRATEGY_MANAGER,
_originalStrategy,
_vaultToken,
msg.sender,
_amount,
_strategyDepositExpiry,
_strategyDepositSignature
);
emit UnallocateCompleted(
msg.sender, _alephVault, address(_originalStrategy), address(_slashedStrategy), _amount, _shares, _classId
);
}
function calculateUnallocateAmount(address _alephVault, uint256 _tokenAmount)
external
view
validVault(_alephVault)
returns (uint256 _estimatedAmount, IStrategy _strategy, IERC20 _token)
{
IStrategy _slashedStrategy = _getSlashedStrategy(_alephVault);
_estimatedAmount = AlephVaultManagement.calculateAmountToRedeem(
_getAVSStorage().vaultToClassId[_alephVault],
_alephVault,
address(_slashedStrategy.underlyingToken()),
_tokenAmount
);
(_token, _strategy) = _getVaultTokenAndStrategy(_alephVault);
}
function _addStrategyIfNotExists(uint32 _operatorSetId, IStrategy _strategy) private {
AVSStorage storage $ = _getAVSStorage();
if ($.strategyExists[_operatorSetId][address(_strategy)]) return;
IStrategy[] memory arr = new IStrategy[](1);
arr[0] = _strategy;
ALLOCATION_MANAGER.addStrategiesToOperatorSet(address(this), _operatorSetId, arr);
$.strategyExists[_operatorSetId][address(_strategy)] = true;
}
function _slashAndTransferInternal(
address _operator,
uint256 _amount,
IStrategy _strategy,
uint32 _operatorSetId,
address _recipient
) private returns (uint256 _tokenAmount) {
OperatorSet memory _operatorSet = OperatorSet(address(this), _operatorSetId);
if (!ALLOCATION_MANAGER.isOperatorSet(_operatorSet)) revert InvalidOperatorSet();
if (!ALLOCATION_MANAGER.isMemberOfOperatorSet(_operator, _operatorSet)) revert NotMemberOfOperatorSet();
uint64 _magnitudeToSlash =
AlephSlashing.calculateMagnitudeFromAmount(ALLOCATION_MANAGER, _operator, _operatorSet, _amount, _strategy);
AlephSlashing.verifyOperatorAllocation(
ALLOCATION_MANAGER, _operator, _operatorSet, _magnitudeToSlash, _strategy
);
uint256 _slashId = AlephSlashing.executeSlashAndGetId(
ALLOCATION_MANAGER,
address(this),
_operator,
_operatorSetId,
_magnitudeToSlash,
_strategy,
SLASH_DESCRIPTION
);
_tokenAmount = AlephSlashing.clearRedistributableShares(
STRATEGY_MANAGER, address(this), _operatorSetId, _slashId, _strategy
);
if (_tokenAmount == 0) revert NoTokensReceived();
IERC20 _underlyingToken = IERC20(address(_strategy.underlyingToken()));
_underlyingToken.safeTransfer(_recipient, _tokenAmount);
emit SlashExecuted(
_operator, _operatorSetId, address(_strategy), address(_underlyingToken), _tokenAmount, _slashId
);
}
function _getSlashedStrategy(address _vault) internal view returns (IStrategy _slashedStrategy) {
_slashedStrategy = _getAVSStorage().vaultToSlashedStrategy[_vault];
if (address(_slashedStrategy) == address(0)) revert InvalidStrategy();
}
function _getVaultTokenAndStrategy(address _vault) internal view returns (IERC20 _vaultToken, IStrategy _strategy) {
AVSStorage storage $ = _getAVSStorage();
_strategy = $.vaultToOriginalStrategy[_vault];
if (address(_strategy) == address(0)) revert InvalidStrategy();
_vaultToken = IERC20(IAlephVault(_vault).underlyingToken());
}
function _validateAVSRegistrarCall(address _avs) private view {
if (msg.sender != address(ALLOCATION_MANAGER) || _avs != address(this)) {
revert Unauthorized();
}
}
function _initializeOperatorSet() private {
IStrategy[] memory _lstStrategies = new IStrategy[](0);
IAllocationManagerTypes.CreateSetParams memory lstCreateParams = IAllocationManagerTypes.CreateSetParams({
operatorSetId: LST_STRATEGIES_OPERATOR_SET_ID, strategies: _lstStrategies
});
IAllocationManagerTypes.CreateSetParams[] memory _params = new IAllocationManagerTypes.CreateSetParams[](1);
_params[0] = lstCreateParams;
address[] memory recipients = new address[](1);
recipients[0] = address(this);
ALLOCATION_MANAGER.createRedistributingOperatorSets(address(this), _params, recipients);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IAlephVaultDeposit} from "Aleph/src/interfaces/IAlephVaultDeposit.sol";
import {IAlephVaultRedeem} from "Aleph/src/interfaces/IAlephVaultRedeem.sol";
import {IERC20Factory} from "./interfaces/IERC20Factory.sol";
/**
* @title IAlephAVS
* @notice Interface for the AlephAVS contract
*/
interface IAlephAVS is IAVSRegistrar {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when an operator registers for AlephAVS operator sets
* @param operator The operator address
* @param operatorSetIds The operator set IDs the operator registered for
*/
event OperatorRegistered(address indexed operator, uint32[] operatorSetIds);
/**
* @notice Emitted when an operator deregisters from AlephAVS operator sets
* @param operator The operator address
* @param operatorSetIds The operator set IDs the operator deregistered from
*/
event OperatorDeregistered(address indexed operator, uint32[] operatorSetIds);
/**
* @notice Emitted when an operator is slashed during allocation
* @param operator The operator that was slashed
* @param operatorSetId The operator set ID where the slash occurred
* @param strategy The strategy that was slashed
* @param underlyingToken The underlying token of the slashed strategy
* @param amount The amount of tokens received from the slash
* @param slashId The unique identifier for this slash event
*/
event SlashExecuted(
address indexed operator,
uint32 operatorSetId,
address indexed strategy,
address indexed underlyingToken,
uint256 amount,
uint256 slashId
);
/**
* @notice Emitted when an operator allocates funds to an Aleph vault
* @param operator The operator who allocated the funds
* @param alephVault The Aleph vault address funds were allocated to
* @param originalStrategy The original LST strategy that was slashed
* @param slashedStrategy The slashed strategy created for this vault
* @param tokenAmount The amount of tokens slashed and allocated
* @param amountToMint The amount of slashed tokens minted and distributed
* @param vaultShares The vault shares received from the deposit
* @param classId The share class ID used for the vault deposit
*/
event AllocatedToAlephVault(
address indexed operator,
address indexed alephVault,
address originalStrategy,
address slashedStrategy,
uint256 tokenAmount,
uint256 amountToMint,
uint256 vaultShares,
uint8 classId
);
/**
* @notice Emitted when a user requests to unallocate funds from an Aleph vault
* @param tokenHolder The address that held the slashed tokens and requested unallocation
* @param alephVault The Aleph vault address funds are being unallocated from
* @param slashedStrategy The slashed strategy whose tokens were burned
* @param tokenAmount The amount of slashed tokens burned
* @param estAmountToRedeem The estimated amount that will be redeemed from the vault
* @param batchId The batch ID for the redeem request
* @param classId The share class ID used for the vault redemption
*/
event UnallocateRequested(
address indexed tokenHolder,
address indexed alephVault,
address slashedStrategy,
uint256 tokenAmount,
uint256 estAmountToRedeem,
uint48 batchId,
uint8 classId
);
/**
* @notice Emitted when funds are unallocated from an Aleph vault
* @param tokenHolder The address that held the slashed tokens and called unallocate
* @param alephVault The Aleph vault address funds were unallocated from
* @param originalStrategy The original LST strategy where tokens were deposited back
* @param slashedStrategy The slashed strategy whose tokens were burned
* @param amount The amount of tokens redeemed from the vault and deposited to the strategy
* @param shares The shares received in the original LST strategy
* @param classId The share class ID used for the vault redemption
*/
event UnallocateCompleted(
address indexed tokenHolder,
address indexed alephVault,
address originalStrategy,
address slashedStrategy,
uint256 amount,
uint256 shares,
uint8 classId
);
/**
* @notice Emitted when a vault is initialized with its slashed token and strategy
* @param vault The vault address that was initialized
* @param originalToken The original token (vault's underlying token)
* @param slashedToken The slashed token created for this vault
* @param slashedStrategy The slashed strategy created for this vault
*/
event VaultInitialized(
address indexed vault,
uint8 classId,
address indexed originalToken,
address indexed slashedToken,
address slashedStrategy
);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error NotRegisteredOperator();
error InvalidAllocationManager();
error Unauthorized();
error InsufficientAllocation();
error InvalidOperatorSet();
error InvalidStrategyManager();
error InvalidStrategy();
error InvalidDelegationManager();
error InvalidRewardsCoordinator();
error InvalidVaultFactory();
error InvalidVault();
error InvalidStrategyFactory();
error NotMemberOfOperatorSet();
error AmountTooSmall();
error MagnitudeOverflow();
error InvalidAmount();
error InsufficientBalance();
error TokenAmountMismatch();
error NotAlephOperator();
error NoTokensReceived();
error InvalidAlephOperator();
error OperatorSplitNotZero();
error InvalidClassId();
error VaultAlreadyInitialized();
error InsufficientOutput(uint256 actualAmount, uint256 minAmount);
error VaultNotInitialized(address vault);
error NoPendingUnallocation();
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the ERC20 factory contract
* @return The ERC20 factory contract address
*/
function erc20Factory() external view returns (IERC20Factory);
/**
* @notice Returns the slashed strategy for a given vault
* @param vault The vault address
* @return The slashed strategy for the vault
*/
function vaultToSlashedStrategy(address vault) external view returns (IStrategy);
function vaultToOriginalStrategy(address vault) external view returns (IStrategy);
/*//////////////////////////////////////////////////////////////
PUBLIC FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Allocates funds by slashing the operator, depositing to Aleph vault, and creating rewards submission
* @param _alephVault The Aleph vault address to deposit to
* @param _requestDepositParams Parameters for vault deposit (amount, authSignature, classId)
*/
function allocate(address _alephVault, IAlephVaultDeposit.RequestDepositParams calldata _requestDepositParams)
external;
/**
* @notice Requests to unallocate funds by redeeming slashed tokens from vault
* @dev This is the first step of the two-step unallocate flow. Called by anyone who holds slashed strategy tokens.
*
* **How it works:**
* 1. Burns the slashed tokens from the caller
* 2. Calculates the estimated amount to redeem from the vault (based on current vault price per share)
* 3. Requests redemption from the vault (the vault sees only the AVS as the allocator)
* 4. Stores the estimated amount as pending unallocation for the caller
*
* **Important Notes:**
* - The caller must hold at least `_tokenAmount` of slashed strategy tokens
* - The estimated amount may differ from the actual amount redeemed due to vault price changes
* - Multiple users can request unallocation; funds are distributed proportionally when available
* - After calling this, the user must wait for the vault to process the redemption request
* - Use `getPendingUnallocateStatus()` to check when `completeUnallocate()` can be called
*
* **Edge Cases:**
* - If `_tokenAmount` is 0, reverts with `InvalidAmount`
* - If vault is not initialized, reverts with `VaultNotInitialized`
* - If calculated `estAmountToRedeem` is 0, reverts with `InvalidAmount`
*
* @param _alephVault The Aleph vault address to unallocate from (must be initialized)
* @param _tokenAmount The amount of slashed strategy tokens to unallocate (must be > 0)
* @return batchId The batch ID for the redeem request (used by the vault for tracking)
* @return estAmountToRedeem The estimated amount that will be redeemed from the vault
*
* @custom:example
* ```solidity
* // User has 100 slashed tokens and wants to unallocate
* (uint48 batchId, uint256 estAmount) = alephAVS.requestUnallocate(vaultAddress, 100e18);
* // estAmount might be 95e18 if vault price per share is 0.95
* ```
*/
function requestUnallocate(address _alephVault, uint256 _tokenAmount)
external
returns (uint48 batchId, uint256 estAmountToRedeem);
/**
* @notice Completes the unallocation by withdrawing redeemable amount and depositing back to strategy
* @dev This is the second step of the two-step unallocate flow. Called by the user who previously called `requestUnallocate`.
*
* **How it works:**
* 1. Checks that the user has pending unallocation (from `requestUnallocate`)
* 2. Calculates the expected amount based on proportional distribution (if multiple users have pending)
* 3. Withdraws redeemable amount from the vault (if available)
* 4. Caps the amount to actual available balances (vault redeemable + previously withdrawn)
* 5. Deposits the amount back into the original LST strategy using the provided signature
* 6. Clears the user's pending unallocation
*
* **Proportional Distribution:**
* If multiple users have requested unallocation, the available funds are distributed proportionally:
* - User's share = (userPendingAmount / totalPendingAmount) * totalRedeemableAmount
* - If this is the last user, they receive all remaining withdrawn amount
*
* **Signature Requirements:**
* - The signature must be generated using `calculateCompleteUnallocateAmount()` to get the exact expected amount
* - Signature is for `depositIntoStrategyWithSignature()` in StrategyManager
* - Must be signed by the caller (msg.sender) with the correct nonce
* - Expiry must be in the future
*
* **Important Notes:**
* - Call `getPendingUnallocateStatus()` first to check if unallocation can be completed
* - Call `calculateCompleteUnallocateAmount()` to get the expected amount for signature generation
* - The actual amount may be slightly less than expected due to rounding or insufficient funds
* - If vault has no redeemable amount yet, wait for the vault to process the redemption request
*
* **Edge Cases:**
* - If user has no pending unallocation, reverts with `NoPendingUnallocation`
* - If vault has no redeemable amount and no previously withdrawn amount, reverts with `InvalidAmount`
* - If signature is invalid or expired, the strategy deposit will fail
* - If calculated amount is 0, reverts with `InvalidAmount`
*
* @param _alephVault The Aleph vault address to complete unallocation from (must be initialized)
* @param _strategyDepositExpiry The expiry timestamp for the strategy deposit signature (must be in future)
* @param _strategyDepositSignature The caller's EIP-712 signature for depositing back into the original LST strategy
* @return amount The amount of tokens redeemed from the vault and deposited to the strategy
* @return shares The shares received in the original LST strategy
*
* @custom:example
* ```solidity
* // First, check status and get expected amount
* uint256 expectedAmount = alephAVS.calculateCompleteUnallocateAmount(userAddress, vaultAddress);
* // Generate signature with expectedAmount
* bytes memory sig = generateStrategyDepositSignature(expectedAmount, nonce, expiry);
* // Complete unallocation
* (uint256 amount, uint256 shares) = alephAVS.completeUnallocate(vaultAddress, expiry, sig);
* ```
*/
function completeUnallocate(
address _alephVault,
uint256 _strategyDepositExpiry,
bytes calldata _strategyDepositSignature
) external returns (uint256 amount, uint256 shares);
/**
* @notice Calculates the estimated amount that will be redeemed from the vault for unallocation
* @dev This view function allows callers to calculate the amount before calling unallocate,
* so they can create the signature for depositIntoStrategyWithSignature
* @param _alephVault The Aleph vault address to unallocate from
* @param _tokenAmount The amount of slashed strategy tokens to unallocate
* @return estimatedAmount The estimated amount of tokens that will be redeemed from the vault
* @return strategy The original LST strategy where tokens will be deposited
* @return token The vault token that will be deposited to the strategy
*/
function calculateUnallocateAmount(address _alephVault, uint256 _tokenAmount)
external
view
returns (uint256 estimatedAmount, IStrategy strategy, IERC20 token);
/**
* @notice Returns the pending unallocation status for a user and vault
* @dev This view function allows users to check if they can call completeUnallocate
* @param _user The user address to check
* @param _alephVault The Aleph vault address
* @return userPendingAmount The user's pending unallocation amount
* @return totalPendingAmount The total pending unallocation amount for the vault
* @return redeemableAmount The amount currently redeemable from the vault
* @return canComplete Whether the user can complete unallocation (has pending amount and vault has redeemable amount)
*/
function getPendingUnallocateStatus(address _user, address _alephVault)
external
view
returns (uint256 userPendingAmount, uint256 totalPendingAmount, uint256 redeemableAmount, bool canComplete);
/**
* @notice Calculates the expected amount that will be withdrawn in completeUnallocate
* @dev This view function allows users to calculate the exact amount before calling `completeUnallocate`,
* so they can generate the strategy deposit signature with the correct amount.
*
* **Use this function to:**
* 1. Get the expected amount for signature generation
* 2. Verify if unallocation can be completed
* 3. Check the amount before calling `completeUnallocate`
*
* **Calculation Logic:**
* - If user is the only one with pending unallocation: gets all available redeemable amount
* - If multiple users have pending: proportional distribution based on their pending amounts
* - Formula: (userPendingAmount / totalPendingAmount) * totalRedeemableAmount
* - Total redeemable = vault redeemable amount + previously withdrawn amount
*
* **Important:**
* - This is a view function - no state changes
* - The actual amount in `completeUnallocate` may be slightly different due to:
* - Rounding differences
* - Changes in vault redeemable amount between calls
* - Contract balance constraints
* - Always use this amount for signature generation to ensure it matches
*
* @param _user The user address to calculate for
* @param _alephVault The Aleph vault address
* @return expectedAmount The expected amount that will be withdrawn and deposited to strategy (0 if no pending or no redeemable)
*
* @custom:example
* ```solidity
* uint256 expected = alephAVS.calculateCompleteUnallocateAmount(userAddress, vaultAddress);
* if (expected > 0) {
* // Generate signature with expected amount
* bytes memory sig = generateSignature(expected, nonce, expiry);
* // Then call completeUnallocate
* }
* ```
*/
function calculateCompleteUnallocateAmount(address _user, address _alephVault)
external
view
returns (uint256 expectedAmount);
/**
* @notice Initializes a vault by creating its slashed token and strategy
* @param _classId The share class ID for the vault
* @param _vault The vault address to initialize
* @param _lstStrategy The original LST strategy for the vault's underlying token
* @return slashedStrategy The created slashed strategy address
*/
function initializeVault(uint8 _classId, address _vault, IStrategy _lstStrategy)
external
returns (IStrategy slashedStrategy);
}// 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();
/// @dev Thrown when an invalid strategy is provided.
error InvalidStrategy();
/// @dev Thrown when an invalid redistribution recipient is provided.
error InvalidRedistributionRecipient();
/// 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 redistributing operator set is created by an AVS.
event RedistributionAddressSet(OperatorSet operatorSet, address redistributionRecipient);
/// @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(
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.
*
* @return slashId The ID of the slash.
* @return shares The amount of shares that were slashed for each strategy.
*
* @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 returns (uint256 slashId, uint256[] memory shares);
/**
* @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 create new Redistribution operator sets.
* @param avs The AVS creating the new operator sets.
* @param params An array of operator set creation parameters.
* @param redistributionRecipients An array of addresses that will receive redistributed funds when operators are slashed.
* @dev Same logic as `createOperatorSets`, except `redistributionRecipients` corresponding to each operator set are stored.
* Additionally, emits `RedistributionOperatorSetCreated` event instead of `OperatorSetCreated` for each created operator set.
*/
function createRedistributingOperatorSets(
address avs,
CreateSetParams[] calldata params,
address[] calldata redistributionRecipients
) external;
/**
* @notice Allows an AVS to add strategies to an operator set
* @dev Strategies MUST NOT already exist in the operator set
* @dev If the operatorSet is redistributing, the `BEACONCHAIN_ETH_STRAT` may not be added, since redistribution is not supported for native eth
* @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 the number of blocks between an operator deallocating magnitude and the magnitude becoming
* unslashable and then being able to be reallocated to another operator set. Note that unlike the allocation delay
* which is configurable by the operator, the DEALLOCATION_DELAY is globally fixed and cannot be changed.
*/
function DEALLOCATION_DELAY() external view returns (uint32 delay);
/**
* @notice Returns a list of all operator sets the operator is registered for
* @param operator The operator address to query.
*/
function getRegisteredSets(
address operator
) external view returns (OperatorSet[] memory operatorSets);
/**
* @notice Returns whether the operator is registered for the operator set
* @param operator The operator to query
* @param operatorSet The operator set to query
*/
function isMemberOfOperatorSet(address operator, OperatorSet memory operatorSet) external view returns (bool);
/**
* @notice Returns whether the operator set exists
*/
function isOperatorSet(
OperatorSet memory operatorSet
) external view returns (bool);
/**
* @notice Returns all the operators registered to an operator set
* @param operatorSet The operatorSet to query.
*/
function getMembers(
OperatorSet memory operatorSet
) external view returns (address[] memory operators);
/**
* @notice Returns the number of operators registered to an operatorSet.
* @param operatorSet The operatorSet to get the member count for
*/
function getMemberCount(
OperatorSet memory operatorSet
) external view returns (uint256);
/**
* @notice Returns the address that handles registration/deregistration for the AVS
* If not set, defaults to the input address (`avs`)
*/
function getAVSRegistrar(
address avs
) external view returns (IAVSRegistrar);
/**
* @notice Returns an array of strategies in the operatorSet.
* @param operatorSet The operatorSet to query.
*/
function getStrategiesInOperatorSet(
OperatorSet memory operatorSet
) external view returns (IStrategy[] memory strategies);
/**
* @notice Returns the minimum amount of stake that will be slashable as of some future block,
* according to each operator's allocation from each strategy to the operator set. Note that this function
* will return 0 for the slashable stake if the operator is not slashable at the time of the call.
* @dev This method queries actual delegated stakes in the DelegationManager and applies
* each operator's allocation to the stake to produce the slashable stake each allocation
* represents. This method does not consider slashable stake in the withdrawal queue even though there could be
* slashable stake in the queue.
* @dev This minimum takes into account `futureBlock`, and will omit any pending magnitude
* diffs that will not be in effect as of `futureBlock`. NOTE that in order to get the true
* minimum slashable stake as of some future block, `futureBlock` MUST be greater than block.number
* @dev NOTE that `futureBlock` should be fewer than `DEALLOCATION_DELAY` blocks in the future,
* or the values returned from this method may not be accurate due to deallocations.
* @param operatorSet the operator set to query
* @param operators the list of operators whose slashable stakes will be returned
* @param strategies the strategies that each slashable stake corresponds to
* @param futureBlock the block at which to get allocation information. Should be a future block.
*/
function getMinimumSlashableStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies,
uint32 futureBlock
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns the current allocated stake, irrespective of the operator's slashable status for the operatorSet.
* @param operatorSet the operator set to query
* @param operators the operators to query
* @param strategies the strategies to query
*/
function getAllocatedStake(
OperatorSet memory operatorSet,
address[] memory operators,
IStrategy[] memory strategies
) external view returns (uint256[][] memory slashableStake);
/**
* @notice Returns whether an operator is slashable by an operator set.
* This returns true if the operator is registered or their slashableUntil block has not passed.
* This is because even when operators are deregistered, they still remain slashable for a period of time.
* @param operator the operator to check slashability for
* @param operatorSet the operator set to check slashability for
*/
function isOperatorSlashable(address operator, OperatorSet memory operatorSet) external view returns (bool);
/**
* @notice Returns the address where slashed funds will be sent for a given operator set.
* @param operatorSet The Operator Set to query.
* @return For redistributing Operator Sets, returns the configured redistribution address set during Operator Set creation.
* For non-redistributing operator sets, returns the `DEFAULT_BURN_ADDRESS`.
*/
function getRedistributionRecipient(
OperatorSet memory operatorSet
) external view returns (address);
/**
* @notice Returns whether a given operator set supports redistribution
* or not when funds are slashed and burned from EigenLayer.
* @param operatorSet The Operator Set to query.
* @return For redistributing Operator Sets, returns true.
* For non-redistributing Operator Sets, returns false.
*/
function isRedistributingOperatorSet(
OperatorSet memory operatorSet
) external view returns (bool);
/**
* @notice Returns the number of slashes for a given operator set.
* @param operatorSet The operator set to query.
* @return The number of slashes for the operator set.
*/
function getSlashCount(
OperatorSet memory operatorSet
) external view returns (uint256);
/**
* @notice Returns whether an operator is slashable by a redistributing operator set.
* @param operator The operator to query.
*/
function isOperatorRedistributable(
address operator
) 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";
import "../libraries/OperatorSetLib.sol";
interface IDelegationManagerErrors {
/// @dev Thrown when caller is neither the StrategyManager or EigenPodManager contract.
error OnlyStrategyManagerOrEigenPodManager();
/// @dev Thrown when msg.sender is not the EigenPodManager
error OnlyEigenPodManager();
/// @dev Throw when msg.sender is not the AllocationManager
error OnlyAllocationManager();
/// Delegation Status
/// @dev Thrown when an operator attempts to undelegate.
error OperatorsCannotUndelegate();
/// @dev Thrown when an account is actively delegated.
error ActivelyDelegated();
/// @dev Thrown when an account is not actively delegated.
error NotActivelyDelegated();
/// @dev Thrown when `operator` is not a registered operator.
error OperatorNotRegistered();
/// Invalid Inputs
/// @dev Thrown when attempting to execute an action that was not queued.
error WithdrawalNotQueued();
/// @dev Thrown when caller cannot undelegate on behalf of a staker.
error CallerCannotUndelegate();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when input arrays length is zero.
error InputArrayLengthZero();
/// Slashing
/// @dev Thrown when an operator has been fully slashed(maxMagnitude is 0) for a strategy.
/// or if the staker has had been natively slashed to the point of their beaconChainScalingFactor equalling 0.
error FullySlashed();
/// Signatures
/// @dev Thrown when attempting to spend a spent eip-712 salt.
error SaltSpent();
/// Withdrawal Processing
/// @dev Thrown when attempting to withdraw before delay has elapsed.
error WithdrawalDelayNotElapsed();
/// @dev Thrown when withdrawer is not the current caller.
error WithdrawerNotCaller();
}
interface IDelegationManagerTypes {
// @notice Struct used for storing information about a single operator who has registered with EigenLayer
struct OperatorDetails {
/// @notice DEPRECATED -- this field is no longer used, payments are handled in RewardsCoordinator.sol
address __deprecated_earningsReceiver;
/**
* @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling "forced undelegations".
* @dev Signature verification follows these rules:
* 1) If this address is left as address(0), then any staker will be free to delegate to the operator, i.e. no signature verification will be performed.
* 2) If this address is an EOA (i.e. it has no code), then we follow standard ECDSA signature verification for delegations to the operator.
* 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it returns the correct EIP-1271 "magic value".
*/
address delegationApprover;
/// @notice DEPRECATED -- this field is no longer used. An analogous field is the `allocationDelay` stored in the AllocationManager
uint32 __deprecated_stakerOptOutWindowBlocks;
}
/**
* @notice Abstract struct used in calculating an EIP712 signature for an operator's delegationApprover to approve that a specific staker delegate to the operator.
* @dev Used in computing the `DELEGATION_APPROVAL_TYPEHASH` and as a reference in the computation of the approverDigestHash in the `_delegate` function.
*/
struct DelegationApproval {
// the staker who is delegating
address staker;
// the operator being delegated to
address operator;
// the operator's provided salt
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/**
* @dev A struct representing an existing queued withdrawal. After the withdrawal delay has elapsed, this withdrawal can be completed via `completeQueuedWithdrawal`.
* A `Withdrawal` is created by the `DelegationManager` when `queueWithdrawals` is called. The `withdrawalRoots` hashes returned by `queueWithdrawals` can be used
* to fetch the corresponding `Withdrawal` from storage (via `getQueuedWithdrawal`).
*
* @param staker The address that queued the withdrawal
* @param delegatedTo The address that the staker was delegated to at the time the withdrawal was queued. Used to determine if additional slashing occurred before
* this withdrawal became completable.
* @param withdrawer The address that will call the contract to complete the withdrawal. Note that this will always equal `staker`; alternate withdrawers are not
* supported at this time.
* @param nonce The staker's `cumulativeWithdrawalsQueued` at time of queuing. Used to ensure withdrawals have unique hashes.
* @param startBlock The block number when the withdrawal was queued.
* @param strategies The strategies requested for withdrawal when the withdrawal was queued
* @param scaledShares The staker's deposit shares requested for withdrawal, scaled by the staker's `depositScalingFactor`. Upon completion, these will be
* scaled by the appropriate slashing factor as of the withdrawal's completable block. The result is what is actually withdrawable.
*/
struct Withdrawal {
address staker;
address delegatedTo;
address withdrawer;
uint256 nonce;
uint32 startBlock;
IStrategy[] strategies;
uint256[] scaledShares;
}
/**
* @param strategies The strategies to withdraw from
* @param depositShares For each strategy, the number of deposit shares to withdraw. Deposit shares can
* be queried via `getDepositedShares`.
* NOTE: The number of shares ultimately received when a withdrawal is completed may be lower depositShares
* if the staker or their delegated operator has experienced slashing.
* @param __deprecated_withdrawer This field is ignored. The only party that may complete a withdrawal
* is the staker that originally queued it. Alternate withdrawers are not supported.
*/
struct QueuedWithdrawalParams {
IStrategy[] strategies;
uint256[] depositShares;
address __deprecated_withdrawer;
}
}
interface IDelegationManagerEvents is IDelegationManagerTypes {
// @notice Emitted when a new operator registers in EigenLayer and provides their delegation approver.
event OperatorRegistered(address indexed operator, address delegationApprover);
/// @notice Emitted when an operator updates their delegation approver
event DelegationApproverUpdated(address indexed operator, address newDelegationApprover);
/**
* @notice Emitted when @param operator indicates that they are updating their MetadataURI string
* @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing
*/
event OperatorMetadataURIUpdated(address indexed operator, string metadataURI);
/// @notice Emitted whenever an operator's shares are increased for a given strategy. Note that shares is the delta in the operator's shares.
event OperatorSharesIncreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta in the operator's shares.
event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted when @param staker delegates to @param operator.
event StakerDelegated(address indexed staker, address indexed operator);
/// @notice Emitted when @param staker undelegates from @param operator.
event StakerUndelegated(address indexed staker, address indexed operator);
/// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself
event StakerForceUndelegated(address indexed staker, address indexed operator);
/// @notice Emitted when a staker's depositScalingFactor is updated
event DepositScalingFactorUpdated(address staker, IStrategy strategy, uint256 newDepositScalingFactor);
/**
* @notice Emitted when a new withdrawal is queued.
* @param withdrawalRoot Is the hash of the `withdrawal`.
* @param withdrawal Is the withdrawal itself.
* @param sharesToWithdraw Is an array of the expected shares that were queued for withdrawal corresponding to the strategies in the `withdrawal`.
*/
event SlashingWithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal, uint256[] sharesToWithdraw);
/// @notice Emitted when a queued withdrawal is completed
event SlashingWithdrawalCompleted(bytes32 withdrawalRoot);
/// @notice Emitted whenever an operator's shares are slashed for a given strategy
event OperatorSharesSlashed(address indexed operator, IStrategy strategy, uint256 totalSlashedShares);
}
/**
* @title DelegationManager
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This is the contract for delegation in EigenLayer. The main functionalities of this contract are
* - enabling anyone to register as an operator in EigenLayer
* - allowing operators to specify parameters related to stakers who delegate to them
* - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time)
* - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager)
*/
interface IDelegationManager is ISignatureUtilsMixin, IDelegationManagerErrors, IDelegationManagerEvents {
/**
* @dev Initializes the initial owner and paused status.
*/
function initialize(
uint256 initialPausedStatus
) external;
/**
* @notice Registers the caller as an operator in EigenLayer.
* @param initDelegationApprover is an address that, if set, must provide a signature when stakers delegate
* to an operator.
* @param allocationDelay The delay before allocations take effect.
* @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator.
*
* @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself".
* @dev This function will revert if the caller is already delegated to an operator.
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
*/
function registerAsOperator(
address initDelegationApprover,
uint32 allocationDelay,
string calldata metadataURI
) external;
/**
* @notice Updates an operator's stored `delegationApprover`.
* @param operator is the operator to update the delegationApprover for
* @param newDelegationApprover is the new delegationApprover for the operator
*
* @dev The caller must have previously registered as an operator in EigenLayer.
*/
function modifyOperatorDetails(address operator, address newDelegationApprover) external;
/**
* @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated.
* @param operator The operator to update metadata for
* @param metadataURI The URI for metadata associated with an operator
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
*/
function updateOperatorMetadataURI(address operator, string calldata metadataURI) external;
/**
* @notice Caller delegates their stake to an operator.
* @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer.
* @param approverSignatureAndExpiry (optional) Verifies the operator approves of this delegation
* @param approverSalt (optional) A unique single use value tied to an individual signature.
* @dev The signature/salt are used ONLY if the operator has configured a delegationApprover.
* If they have not, these params can be left empty.
*/
function delegateTo(
address operator,
SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) external;
/**
* @notice Undelegates the staker from their operator and queues a withdrawal for all of their shares
* @param staker The account to be undelegated
* @return withdrawalRoots The roots of the newly queued withdrawals, if a withdrawal was queued. Returns
* an empty array if none was queued.
*
* @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves.
* @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover"
* @dev Reverts if the `staker` is not delegated to an operator
*/
function undelegate(
address staker
) external returns (bytes32[] memory withdrawalRoots);
/**
* @notice Undelegates the staker from their current operator, and redelegates to `newOperator`
* Queues a withdrawal for all of the staker's withdrawable shares. These shares will only be
* delegated to `newOperator` AFTER the withdrawal is completed.
* @dev This method acts like a call to `undelegate`, then `delegateTo`
* @param newOperator the new operator that will be delegated all assets
* @dev NOTE: the following 2 params are ONLY checked if `newOperator` has a `delegationApprover`.
* If not, they can be left empty.
* @param newOperatorApproverSig A signature from the operator's `delegationApprover`
* @param approverSalt A unique single use value tied to the approver's signature
*/
function redelegate(
address newOperator,
SignatureWithExpiry memory newOperatorApproverSig,
bytes32 approverSalt
) external returns (bytes32[] memory withdrawalRoots);
/**
* @notice Allows a staker to queue a withdrawal of their deposit shares. The withdrawal can be
* completed after the MIN_WITHDRAWAL_DELAY_BLOCKS via either of the completeQueuedWithdrawal methods.
*
* While in the queue, these shares are removed from the staker's balance, as well as from their operator's
* delegated share balance (if applicable). Note that while in the queue, deposit shares are still subject
* to slashing. If any slashing has occurred, the shares received may be less than the queued deposit shares.
*
* @dev To view all the staker's strategies/deposit shares that can be queued for withdrawal, see `getDepositedShares`
* @dev To view the current conversion between a staker's deposit shares and withdrawable shares, see `getWithdrawableShares`
*/
function queueWithdrawals(
QueuedWithdrawalParams[] calldata params
) external returns (bytes32[] memory);
/**
* @notice Used to complete a queued withdrawal
* @param withdrawal The withdrawal to complete
* @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array.
* @param tokens For each `withdrawal.strategies`, the underlying token of the strategy
* NOTE: if `receiveAsTokens` is false, the `tokens` array is unused and can be filled with default values. However, `tokens.length` MUST still be equal to `withdrawal.strategies.length`.
* NOTE: For the `beaconChainETHStrategy`, the corresponding `tokens` value is ignored (can be 0).
* @param receiveAsTokens If true, withdrawn shares will be converted to tokens and sent to the caller. If false, the caller receives shares that can be delegated to an operator.
* NOTE: if the caller receives shares and is currently delegated to an operator, the received shares are
* automatically delegated to the caller's current operator.
*/
function completeQueuedWithdrawal(
Withdrawal calldata withdrawal,
IERC20[] calldata tokens,
bool receiveAsTokens
) external;
/**
* @notice Used to complete multiple queued withdrawals
* @param withdrawals Array of Withdrawals to complete. See `completeQueuedWithdrawal` for the usage of a single Withdrawal.
* @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
* @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean.
* @dev See `completeQueuedWithdrawal` for relevant dev tags
*/
function completeQueuedWithdrawals(
Withdrawal[] calldata withdrawals,
IERC20[][] calldata tokens,
bool[] calldata receiveAsTokens
) external;
/**
* @notice Called by a share manager when a staker's deposit share balance in a strategy increases.
* This method delegates any new shares to an operator (if applicable), and updates the staker's
* deposit scaling factor regardless.
* @param staker The address whose deposit shares have increased
* @param strategy The strategy in which shares have been deposited
* @param prevDepositShares The number of deposit shares the staker had in the strategy prior to the increase
* @param addedShares The number of deposit shares added by the staker
*
* @dev Note that if the either the staker's current operator has been slashed 100% for `strategy`, OR the
* staker has been slashed 100% on the beacon chain such that the calculated slashing factor is 0, this
* method WILL REVERT.
*/
function increaseDelegatedShares(
address staker,
IStrategy strategy,
uint256 prevDepositShares,
uint256 addedShares
) external;
/**
* @notice If the staker is delegated, decreases its operator's shares in response to
* a decrease in balance in the beaconChainETHStrategy
* @param staker the staker whose operator's balance will be decreased
* @param curDepositShares the current deposit shares held by the staker
* @param beaconChainSlashingFactorDecrease the amount that the staker's beaconChainSlashingFactor has decreased by
* @dev Note: `beaconChainSlashingFactorDecrease` are assumed to ALWAYS be < 1 WAD.
* These invariants are maintained in the EigenPodManager.
*/
function decreaseDelegatedShares(
address staker,
uint256 curDepositShares,
uint64 beaconChainSlashingFactorDecrease
) external;
/**
* @notice Decreases the operator's shares in storage after a slash and increases the burnable shares by calling
* into either the StrategyManager or EigenPodManager (if the strategy is beaconChainETH).
* @param operator The operator to decrease shares for.
* @param operatorSet The operator set to decrease shares for.
* @param slashId The slash id to decrease shares for.
* @param strategy The strategy to decrease shares for.
* @param prevMaxMagnitude The previous maxMagnitude of the operator.
* @param newMaxMagnitude The new maxMagnitude of the operator.
* @dev Callable only by the AllocationManager.
* @dev Note: Assumes `prevMaxMagnitude <= newMaxMagnitude`. This invariant is maintained in
* the AllocationManager.
* @return totalDepositSharesToSlash The total deposit shares to burn or redistribute.
*/
function slashOperatorShares(
address operator,
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) external returns (uint256 totalDepositSharesToSlash);
/**
*
* VIEW FUNCTIONS
*
*/
/**
* @notice returns the address of the operator that `staker` is delegated to.
* @notice Mapping: staker => operator whom the staker is currently delegated to.
* @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator.
*/
function delegatedTo(
address staker
) external view returns (address);
/**
* @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover.
* @dev Salts are used in the `delegateTo` function. Note that this function only processes the delegationApprover's
* signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`.
*/
function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool);
/// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated.
/// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes.
function cumulativeWithdrawalsQueued(
address staker
) external view returns (uint256);
/**
* @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
*/
function isDelegated(
address staker
) external view returns (bool);
/**
* @notice Returns true is an operator has previously registered for delegation.
*/
function isOperator(
address operator
) external view returns (bool);
/**
* @notice Returns the delegationApprover account for an operator
*/
function delegationApprover(
address operator
) external view returns (address);
/**
* @notice Returns the shares that an operator has delegated to them in a set of strategies
* @param operator the operator to get shares for
* @param strategies the strategies to get shares for
*/
function getOperatorShares(
address operator,
IStrategy[] memory strategies
) external view returns (uint256[] memory);
/**
* @notice Returns the shares that a set of operators have delegated to them in a set of strategies
* @param operators the operators to get shares for
* @param strategies the strategies to get shares for
*/
function getOperatorsShares(
address[] memory operators,
IStrategy[] memory strategies
) external view returns (uint256[][] memory);
/**
* @notice Returns amount of withdrawable shares from an operator for a strategy that is still in the queue
* and therefore slashable. Note that the *actual* slashable amount could be less than this value as this doesn't account
* for amounts that have already been slashed. This assumes that none of the shares have been slashed.
* @param operator the operator to get shares for
* @param strategy the strategy to get shares for
* @return the amount of shares that are slashable in the withdrawal queue for an operator and a strategy
*/
function getSlashableSharesInQueue(address operator, IStrategy strategy) external view returns (uint256);
/**
* @notice Given a staker and a set of strategies, return the shares they can queue for withdrawal and the
* corresponding depositShares.
* This value depends on which operator the staker is delegated to.
* The shares amount returned is the actual amount of Strategy shares the staker would receive (subject
* to each strategy's underlying shares to token ratio).
*/
function getWithdrawableShares(
address staker,
IStrategy[] memory strategies
) external view returns (uint256[] memory withdrawableShares, uint256[] memory depositShares);
/**
* @notice Returns the number of shares in storage for a staker and all their strategies
*/
function getDepositedShares(
address staker
) external view returns (IStrategy[] memory, uint256[] memory);
/**
* @notice Returns the scaling factor applied to a staker's deposits for a given strategy
*/
function depositScalingFactor(address staker, IStrategy strategy) external view returns (uint256);
/**
* @notice Returns the Withdrawal associated with a `withdrawalRoot`.
* @param withdrawalRoot The hash identifying the queued withdrawal.
* @return withdrawal The withdrawal details.
*/
function queuedWithdrawals(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal);
/**
* @notice Returns the Withdrawal and corresponding shares associated with a `withdrawalRoot`
* @param withdrawalRoot The hash identifying the queued withdrawal
* @return withdrawal The withdrawal details
* @return shares Array of shares corresponding to each strategy in the withdrawal
* @dev The shares are what a user would receive from completing a queued withdrawal, assuming all slashings are applied
* @dev Withdrawals queued before the slashing release cannot be queried with this method
*/
function getQueuedWithdrawal(
bytes32 withdrawalRoot
) external view returns (Withdrawal memory withdrawal, uint256[] memory shares);
/**
* @notice Returns all queued withdrawals and their corresponding shares for a staker.
* @param staker The address of the staker to query withdrawals for.
* @return withdrawals Array of Withdrawal structs containing details about each queued withdrawal.
* @return shares 2D array of shares, where each inner array corresponds to the strategies in the withdrawal.
* @dev The shares are what a user would receive from completing a queued withdrawal, assuming all slashings are applied.
*/
function getQueuedWithdrawals(
address staker
) external view returns (Withdrawal[] memory withdrawals, uint256[][] memory shares);
/// @notice Returns a list of queued withdrawal roots for the `staker`.
/// NOTE that this only returns withdrawals queued AFTER the slashing release.
function getQueuedWithdrawalRoots(
address staker
) external view returns (bytes32[] memory);
/**
* @notice Converts shares for a set of strategies to deposit shares, likely in order to input into `queueWithdrawals`.
* This function will revert from a division by 0 error if any of the staker's strategies have a slashing factor of 0.
* @param staker the staker to convert shares for
* @param strategies the strategies to convert shares for
* @param withdrawableShares the shares to convert
* @return the deposit shares
* @dev will be a few wei off due to rounding errors
*/
function convertToDepositShares(
address staker,
IStrategy[] memory strategies,
uint256[] memory withdrawableShares
) external view returns (uint256[] memory);
/// @notice Returns the keccak256 hash of `withdrawal`.
function calculateWithdrawalRoot(
Withdrawal memory withdrawal
) external pure returns (bytes32);
/**
* @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` function.
* @param staker The account delegating their stake
* @param operator The account receiving delegated stake
* @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general)
* @param approverSalt A unique and single use value associated with the approver signature.
* @param expiry Time after which the approver's signature becomes invalid
*/
function calculateDelegationApprovalDigestHash(
address staker,
address operator,
address _delegationApprover,
bytes32 approverSalt,
uint256 expiry
) external view returns (bytes32);
/// @notice return address of the beaconChainETHStrategy
function beaconChainETHStrategy() external view returns (IStrategy);
/**
* @notice Returns the minimum withdrawal delay in blocks to pass for withdrawals queued to be completable.
* Also applies to legacy withdrawals so any withdrawals not completed prior to the slashing upgrade will be subject
* to this longer delay.
* @dev Backwards-compatible interface to return the internal `MIN_WITHDRAWAL_DELAY_BLOCKS` value
* @dev Previous value in storage was deprecated. See `__deprecated_minWithdrawalDelayBlocks`
*/
function minWithdrawalDelayBlocks() external view returns (uint32);
/// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract
function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./IStrategy.sol";
import "./IShareManager.sol";
import "./IDelegationManager.sol";
import "./IEigenPodManager.sol";
import "./ISemVerMixin.sol";
interface IStrategyManagerErrors {
/// @dev Thrown when total strategies deployed exceeds max.
error MaxStrategiesExceeded();
/// @dev Thrown when call attempted from address that's not delegation manager.
error OnlyDelegationManager();
/// @dev Thrown when call attempted from address that's not strategy whitelister.
error OnlyStrategyWhitelister();
/// @dev Thrown when provided `shares` amount is too high.
error SharesAmountTooHigh();
/// @dev Thrown when provided `shares` amount is zero.
error SharesAmountZero();
/// @dev Thrown when provided `staker` address is null.
error StakerAddressZero();
/// @dev Thrown when provided `strategy` not found.
error StrategyNotFound();
/// @dev Thrown when attempting to deposit to a non-whitelisted strategy.
error StrategyNotWhitelisted();
/// @dev Thrown when attempting to add a strategy that is already in the operator set's burn or redistributable shares.
error StrategyAlreadyInSlash();
}
interface IStrategyManagerEvents {
/**
* @notice Emitted when a new deposit occurs on behalf of `staker`.
* @param staker Is the staker who is depositing funds into EigenLayer.
* @param strategy Is the strategy that `staker` has deposited into.
* @param shares Is the number of new shares `staker` has been granted in `strategy`.
*/
event Deposit(address staker, IStrategy strategy, uint256 shares);
/// @notice Emitted when the `strategyWhitelister` is changed
event StrategyWhitelisterChanged(address previousAddress, address newAddress);
/// @notice Emitted when a strategy is added to the approved list of strategies for deposit
event StrategyAddedToDepositWhitelist(IStrategy strategy);
/// @notice Emitted when a strategy is removed from the approved list of strategies for deposit
event StrategyRemovedFromDepositWhitelist(IStrategy strategy);
/// @notice Emitted when an operator is slashed and shares to be burned or redistributed are increased
event BurnOrRedistributableSharesIncreased(
OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
);
/// @notice Emitted when shares marked for burning or redistribution are decreased and transferred to the operator set's redistribution recipient
event BurnOrRedistributableSharesDecreased(
OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
);
/// @notice Emitted when shares are burnt
/// @dev This event is only emitted in the pre-redistribution slash path
event BurnableSharesDecreased(IStrategy strategy, uint256 shares);
}
/**
* @title Interface for the primary entrypoint for funds into EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice See the `StrategyManager` contract itself for implementation details.
*/
interface IStrategyManager is IStrategyManagerErrors, IStrategyManagerEvents, IShareManager, ISemVerMixin {
/**
* @notice Initializes the strategy manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set),
* and transfers contract ownership to the specified `initialOwner`.
* @param initialOwner Ownership of this contract is transferred to this address.
* @param initialStrategyWhitelister The initial value of `strategyWhitelister` to set.
* @param initialPausedStatus The initial value of `_paused` to set.
*/
function initialize(
address initialOwner,
address initialStrategyWhitelister,
uint256 initialPausedStatus
) external;
/**
* @notice Deposits `amount` of `token` into the specified `strategy` and credits shares to the caller
* @param strategy the strategy that handles `token`
* @param token the token from which the `amount` will be transferred
* @param amount the number of tokens to deposit
* @return depositShares the number of deposit shares credited to the caller
* @dev The caller must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
*
* WARNING: Be extremely cautious when depositing tokens that do not strictly adhere to ERC20 standards.
* Tokens that diverge significantly from ERC20 norms can cause unexpected behavior in token balances for
* that strategy, e.g. ERC-777 tokens allowing cross-contract reentrancy.
*/
function depositIntoStrategy(
IStrategy strategy,
IERC20 token,
uint256 amount
) external returns (uint256 depositShares);
/**
* @notice Deposits `amount` of `token` into the specified `strategy` and credits shares to the `staker`
* Note tokens are transferred from `msg.sender`, NOT from `staker`. This method allows the caller, using a
* signature, to deposit their tokens to another staker's balance.
* @param strategy the strategy that handles `token`
* @param token the token from which the `amount` will be transferred
* @param amount the number of tokens to transfer from the caller to the strategy
* @param staker the staker that the deposited assets will be credited to
* @param expiry the timestamp at which the signature expires
* @param signature a valid ECDSA or EIP-1271 signature from `staker`
* @return depositShares the number of deposit shares credited to `staker`
* @dev The caller must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
*
* WARNING: Be extremely cautious when depositing tokens that do not strictly adhere to ERC20 standards.
* Tokens that diverge significantly from ERC20 norms can cause unexpected behavior in token balances for
* that strategy, e.g. ERC-777 tokens allowing cross-contract reentrancy.
*/
function depositIntoStrategyWithSignature(
IStrategy strategy,
IERC20 token,
uint256 amount,
address staker,
uint256 expiry,
bytes memory signature
) external returns (uint256 depositShares);
/**
* @notice Legacy burn strategy shares for the given strategy by calling into the strategy to transfer
* to the default burn address.
* @param strategy The strategy to burn shares in.
* @dev This function will be DEPRECATED in a release after redistribution
*/
function burnShares(
IStrategy strategy
) external;
/**
* @notice Removes burned shares from storage and transfers the underlying tokens for the slashId to the redistribution recipient.
* @dev Reentrancy is checked in the `clearBurnOrRedistributableSharesByStrategy` function.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash ID to burn shares in.
* @return The amounts of tokens transferred to the redistribution recipient for each strategy
*/
function clearBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId
) external returns (uint256[] memory);
/**
* @notice Removes a single strategy's shares from storage and transfers the underlying tokens for the slashId to the redistribution recipient.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash ID to burn shares in.
* @param strategy The strategy to burn shares in.
* @return The amount of tokens transferred to the redistribution recipient for the strategy.
*/
function clearBurnOrRedistributableSharesByStrategy(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy
) external returns (uint256);
/**
* @notice Returns the strategies and shares that have NOT been sent to the redistribution recipient for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @return The strategies and shares for the given slashId.
*/
function getBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId
) external view returns (IStrategy[] memory, uint256[] memory);
/**
* @notice Returns the shares for a given strategy for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @param strategy The strategy to get the shares for.
* @return The shares for the given strategy for the given slashId.
* @dev This function will return revert if the shares have already been sent to the redistribution recipient.
*/
function getBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy
) external view returns (uint256);
/**
* @notice Returns the number of strategies that have NOT been sent to the redistribution recipient for a given slashId.
* @param operatorSet The operator set to burn or redistribute shares in.
* @param slashId The slash ID to burn or redistribute shares in.
* @return The number of strategies for the given slashId.
*/
function getBurnOrRedistributableCount(
OperatorSet calldata operatorSet,
uint256 slashId
) external view returns (uint256);
/**
* @notice Owner-only function to change the `strategyWhitelister` address.
* @param newStrategyWhitelister new address for the `strategyWhitelister`.
*/
function setStrategyWhitelister(
address newStrategyWhitelister
) external;
/**
* @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
*/
function addStrategiesToDepositWhitelist(
IStrategy[] calldata strategiesToWhitelist
) external;
/**
* @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
* @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
*/
function removeStrategiesFromDepositWhitelist(
IStrategy[] calldata strategiesToRemoveFromWhitelist
) external;
/// @notice Returns bool for whether or not `strategy` is whitelisted for deposit
function strategyIsWhitelistedForDeposit(
IStrategy strategy
) external view returns (bool);
/**
* @notice Get all details on the staker's deposits and corresponding shares
* @return (staker's strategies, shares in these strategies)
*/
function getDeposits(
address staker
) external view returns (IStrategy[] memory, uint256[] memory);
function getStakerStrategyList(
address staker
) external view returns (IStrategy[] memory);
/// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
function stakerStrategyListLength(
address staker
) external view returns (uint256);
/// @notice Returns the current shares of `user` in `strategy`
function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 shares);
/// @notice Returns the single, central Delegation contract of EigenLayer
function delegation() external view returns (IDelegationManager);
/// @notice Returns the address of the `strategyWhitelister`
function strategyWhitelister() external view returns (address);
/// @notice Returns the burnable shares of a strategy
/// @dev This function will be deprecated in a release after redistribution
function getBurnableShares(
IStrategy strategy
) external view returns (uint256);
/**
* @notice Gets every strategy with burnable shares and the amount of burnable shares in each said strategy
*
* @dev This function will be deprecated in a release after redistribution
* WARNING: This operation can copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Users should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function getStrategiesWithBurnableShares() external view returns (address[] memory, uint256[] memory);
/**
* @param staker The address of the staker.
* @param strategy The strategy to deposit into.
* @param token The token to deposit.
* @param amount The amount of `token` to deposit.
* @param nonce The nonce of the staker.
* @param expiry The expiry of the signature.
* @return The EIP-712 signable digest hash.
*/
function calculateStrategyDepositDigestHash(
address staker,
IStrategy strategy,
IERC20 token,
uint256 amount,
uint256 nonce,
uint256 expiry
) external view returns (bytes32);
/**
* @notice Returns the operator sets that have pending burn or redistributable shares.
* @return The operator sets that have pending burn or redistributable shares.
*/
function getPendingOperatorSets() external view returns (OperatorSet[] memory);
/**
* @notice Returns the slash IDs that are pending to be burned or redistributed.
* @dev This function will return revert if the operator set has no pending burn or redistributable shares.
* @param operatorSet The operator set to get the pending slash IDs for.
* @return The slash IDs that are pending to be burned or redistributed.
*/
function getPendingSlashIds(
OperatorSet calldata operatorSet
) external view returns (uint256[] memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
using OperatorSetLib for OperatorSet global;
/**
* @notice An operator set identified by the AVS address and an identifier
* @param avs The address of the AVS this operator set belongs to
* @param id The unique identifier for the operator set
*/
struct OperatorSet {
address avs;
uint32 id;
}
library OperatorSetLib {
function key(
OperatorSet memory os
) internal pure returns (bytes32) {
return bytes32(abi.encodePacked(os.avs, uint96(os.id)));
}
function decode(
bytes32 _key
) internal pure returns (OperatorSet memory) {
/// forgefmt: disable-next-item
return OperatorSet({
avs: address(uint160(uint256(_key) >> 96)),
id: uint32(uint256(_key) & type(uint96).max)
});
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/SlashingLib.sol";
import "./ISemVerMixin.sol";
interface IStrategyErrors {
/// @dev Thrown when called by an account that is not strategy manager.
error OnlyStrategyManager();
/// @dev Thrown when new shares value is zero.
error NewSharesZero();
/// @dev Thrown when total shares exceeds max.
error TotalSharesExceedsMax();
/// @dev Thrown when amount shares is greater than total shares.
error WithdrawalAmountExceedsTotalDeposits();
/// @dev Thrown when attempting an action with a token that is not accepted.
error OnlyUnderlyingToken();
/// StrategyBaseWithTVLLimits
/// @dev Thrown when `maxPerDeposit` exceeds max.
error MaxPerDepositExceedsMax();
/// @dev Thrown when balance exceeds max total deposits.
error BalanceExceedsMaxTotalDeposits();
}
interface IStrategyEvents {
/**
* @notice Used to emit an event for the exchange rate between 1 share and underlying token in a strategy contract
* @param rate is the exchange rate in wad 18 decimals
* @dev Tokens that do not have 18 decimals must have offchain services scale the exchange rate by the proper magnitude
*/
event ExchangeRateEmitted(uint256 rate);
/**
* Used to emit the underlying token and its decimals on strategy creation
* @notice token
* @param token is the ERC20 token of the strategy
* @param decimals are the decimals of the ERC20 token in the strategy
*/
event StrategyTokenSet(IERC20 token, uint8 decimals);
}
/**
* @title Minimal interface for an `Strategy` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Custom `Strategy` implementations may expand extensively on this interface.
*/
interface IStrategy is IStrategyErrors, IStrategyEvents, ISemVerMixin {
/**
* @notice Used to deposit tokens into this Strategy
* @param token is the ERC20 token being deposited
* @param amount is the amount of token being deposited
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
* @return newShares is the number of new shares issued at the current exchange ratio.
*/
function deposit(IERC20 token, uint256 amount) external returns (uint256);
/**
* @notice Used to withdraw tokens from this Strategy, to the `recipient`'s address
* @param recipient is the address to receive the withdrawn funds
* @param token is the ERC20 token being transferred out
* @param amountShares is the amount of shares being withdrawn
* @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
* other functions, and individual share balances are recorded in the strategyManager as well.
* @return amountOut is the amount of tokens being transferred out.
*/
function withdraw(address recipient, IERC20 token, uint256 amountShares) external returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlying(
uint256 amountShares
) external returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToShares(
uint256 amountUnderlying
) external returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
*/
function userUnderlying(
address user
) external returns (uint256);
/**
* @notice convenience function for fetching the current total shares of `user` in this strategy, by
* querying the `strategyManager` contract
*/
function shares(
address user
) external view returns (uint256);
/**
* @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
* For a staker using this function and trying to calculate the amount of underlying tokens they have in total they
* should input into `amountShares` their withdrawable shares read from the `DelegationManager` contract.
* @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
* @param amountShares is the amount of shares to calculate its conversion into the underlying token
* @return The amount of underlying tokens corresponding to the input `amountShares`
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function sharesToUnderlyingView(
uint256 amountShares
) external view returns (uint256);
/**
* @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
* @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
* @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
* @return The amount of shares corresponding to the input `amountUnderlying`. This is used as deposit shares
* in the `StrategyManager` contract.
* @dev Implementation for these functions in particular may vary significantly for different strategies
*/
function underlyingToSharesView(
uint256 amountUnderlying
) external view returns (uint256);
/**
* @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
* this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
*/
function userUnderlyingView(
address user
) external view returns (uint256);
/// @notice The underlying token for shares in this Strategy
function underlyingToken() external view returns (IERC20);
/// @notice The total number of extant shares in this Strategy
function totalShares() external view returns (uint256);
/// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
function explanation() external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IStrategy.sol";
import "./ISemVerMixin.sol";
/**
* @title Interface for the `StrategyFactory` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @dev This may not be compatible with non-standard ERC20 tokens. Caution is warranted.
*/
interface IStrategyFactory is ISemVerMixin {
/// @dev Thrown when attempting to deploy a strategy for a blacklisted token.
error BlacklistedToken();
/// @dev Thrown when attempting to deploy a strategy that already exists.
error StrategyAlreadyExists();
/// @dev Thrown when attempting to blacklist a token that is already blacklisted
error AlreadyBlacklisted();
event TokenBlacklisted(IERC20 token);
/// @notice Upgradeable beacon which new Strategies deployed by this contract point to
function strategyBeacon() external view returns (IBeacon);
/// @notice Mapping token => Strategy contract for the token
/// The strategies in this mapping are deployed by the StrategyFactory.
/// The factory can only deploy a single strategy per token address
/// These strategies MIGHT not be whitelisted in the StrategyManager,
/// though deployNewStrategy does whitelist by default.
/// These strategies MIGHT not be the only strategy for the underlying token
/// as additional strategies can be whitelisted by the owner of the factory.
function deployedStrategies(
IERC20 token
) external view returns (IStrategy);
/**
* @notice Deploy a new strategyBeacon contract for the ERC20 token.
* @param token the token to deploy a strategy for
* @dev A strategy contract must not yet exist for the token.
* $dev Immense caution is warranted for non-standard ERC20 tokens, particularly "reentrant" tokens
* like those that conform to ERC777.
*/
function deployNewStrategy(
IERC20 token
) external returns (IStrategy newStrategy);
/**
* @notice Owner-only function to pass through a call to `StrategyManager.addStrategiesToDepositWhitelist`
*/
function whitelistStrategies(
IStrategy[] calldata strategiesToWhitelist
) external;
/**
* @notice Owner-only function to pass through a call to `StrategyManager.removeStrategiesFromDepositWhitelist`
*/
function removeStrategiesFromWhitelist(
IStrategy[] calldata strategiesToRemoveFromWhitelist
) external;
/// @notice Emitted when the `strategyBeacon` is changed
event StrategyBeaconModified(IBeacon previousBeacon, IBeacon newBeacon);
/// @notice Emitted whenever a slot is set in the `tokenStrategy` mapping
event StrategySetForToken(IERC20 token, IStrategy strategy);
}// 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 zero.
error DurationIsZero();
/// @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. "1.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 duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
* @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 duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
* @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 duration of the `rewardsSubmission` cannot be 0 and must be a multiple of `CALCULATION_INTERVAL_SECONDS`
* @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: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// 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 v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @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 {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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 {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, 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 to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, 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 from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, 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 spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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].
*
* IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
* by the {ReentrancyGuardTransient} variant in v6.0.
*/
abstract contract ReentrancyGuard {
using StorageSlot for bytes32;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
// 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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_reentrancyGuardStorageSlot().getUint256Slot().value = 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();
}
/**
* @dev A `view` only version of {nonReentrant}. Use to block view functions
* from being called, preventing reading from inconsistent contract state.
*
* CAUTION: This is a "view" modifier and does not change the reentrancy
* status. Use it only on view functions. For payable or non-payable functions,
* use the standard {nonReentrant} modifier instead.
*/
modifier nonReentrantView() {
_nonReentrantBeforeView();
_;
}
function _nonReentrantBeforeView() private view {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
_nonReentrantBeforeView();
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_reentrancyGuardStorageSlot().getUint256Slot().value = 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 _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
}
function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}// 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: BUSL-1.1
pragma solidity ^0.8.27;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
import {AuthLibrary} from "@aleph-vault/libraries/AuthLibrary.sol";
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAlephVaultDeposit {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when a new minimum deposit amount is queued.
* @param classId The ID of the share class.
* @param minDepositAmount The new minimum deposit amount.
*/
event NewMinDepositAmountQueued(uint8 classId, uint256 minDepositAmount);
/**
* @notice Emitted when a new minimum user balance is queued.
* @param classId The ID of the share class.
* @param minUserBalance The new minimum user balance.
*/
event NewMinUserBalanceQueued(uint8 classId, uint256 minUserBalance);
/**
* @notice Emitted when a new maximum deposit cap is queued.
* @param classId The ID of the share class.
* @param maxDepositCap The new maximum deposit cap.
*/
event NewMaxDepositCapQueued(uint8 classId, uint256 maxDepositCap);
/**
* @notice Emitted when a new minimum deposit amount is set.
* @param classId The ID of the share class.
* @param minDepositAmount The new minimum deposit amount.
*/
event NewMinDepositAmountSet(uint8 classId, uint256 minDepositAmount);
/**
* @notice Emitted when a new minimum user balance is set.
* @param classId The ID of the share class.
* @param minUserBalance The new minimum user balance.
*/
event NewMinUserBalanceSet(uint8 classId, uint256 minUserBalance);
/**
* @notice Emitted when a new maximum deposit cap is set.
* @param classId The ID of the share class.
* @param maxDepositCap The new maximum deposit cap.
*/
event NewMaxDepositCapSet(uint8 classId, uint256 maxDepositCap);
/**
* @notice Emitted when a deposit request is made.
* @param classId The ID of the share class.
* @param batchId The batch ID of the deposit request.
* @param user The user making the deposit request.
* @param amount The amount of the deposit request.
*/
event DepositRequest(uint8 classId, uint48 batchId, address indexed user, uint256 amount);
/**
* @notice Emitted when a synchronous deposit is made.
* @param classId The ID of the share class.
* @param allocator The address making the deposit.
* @param amount The amount deposited.
* @param shares The number of shares minted.
* @param seriesId The series ID where shares were minted.
* @param batchId The batch ID when the deposit occurred.
* @param totalAssets The total assets in the series after the deposit.
* @param totalShares The total shares in the series after the deposit.
*/
event SyncDeposit(
uint8 indexed classId,
address indexed allocator,
uint256 amount,
uint256 shares,
uint32 seriesId,
uint48 batchId,
uint256 totalAssets,
uint256 totalShares
);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the minimum deposit amount is invalid.
*/
error InvalidMinDepositAmount();
/**
* @notice Emitted when the deposit is insufficient.
*/
error InsufficientDeposit();
/**
* @notice Emitted when the deposit is less than the minimum deposit amount.
*/
error DepositLessThanMinDepositAmount(uint256 minDepositAmount);
/**
* @notice Emitted when the deposit is less than the minimum user balance.
*/
error DepositLessThanMinUserBalance(uint256 minUserBalance);
/**
* @notice Emitted when the deposit exceeds the maximum deposit cap.
*/
error DepositExceedsMaxDepositCap(uint256 maxDepositCap);
/**
* @notice Emitted when only one request per batch is allowed for deposit.
*/
error OnlyOneRequestPerBatchAllowedForDeposit();
/**
* @notice Emitted when the deposit request fails.
*/
error DepositRequestFailed();
/**
* @notice Emitted when only async deposit is allowed (sync is not valid).
*/
error OnlyAsyncDepositAllowed();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Constructor params.
* @param minDepositAmountTimelock The timelock period for the minimum deposit amount.
* @param minUserBalanceTimelock The timelock period for the minimum user balance.
* @param maxDepositCapTimelock The timelock period for the maximum deposit cap.
*/
struct DepositConstructorParams {
uint48 minDepositAmountTimelock;
uint48 minUserBalanceTimelock;
uint48 maxDepositCapTimelock;
}
/**
* @notice Parameters for a deposit request.
* @param classId The ID of the share class.
* @param amount The amount of the deposit request.
* @param _authSignature The auth signature for the deposit request.
*/
struct RequestDepositParams {
uint8 classId;
uint256 amount;
AuthLibrary.AuthSignature authSignature;
}
/*//////////////////////////////////////////////////////////////
TIMELOCK FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Queues a new minimum deposit amount.
* @param _classId The ID of the share class to set the minimum deposit amount for.
* @param _minDepositAmount The new minimum deposit amount.
*/
function queueMinDepositAmount(uint8 _classId, uint256 _minDepositAmount) external;
/**
* @notice Queues a new minimum user balance.
* @param _classId The ID of the share class to set the minimum user balance for.
* @param _minUserBalance The new minimum user balance.
*/
function queueMinUserBalance(uint8 _classId, uint256 _minUserBalance) external;
/**
* @notice Queues a new maximum deposit cap.
* @param _classId The ID of the share class to set the maximum deposit cap for.
* @param _maxDepositCap The new maximum deposit cap.
*/
function queueMaxDepositCap(uint8 _classId, uint256 _maxDepositCap) external;
/**
* @notice Sets the minimum deposit amount.
* @param _classId The ID of the share class to set the minimum deposit amount for.
*/
function setMinDepositAmount(uint8 _classId) external;
/**
* @notice Sets the minimum user balance.
* @param _classId The ID of the share class to set the minimum user balance for.
*/
function setMinUserBalance(uint8 _classId) external;
/**
* @notice Sets the maximum deposit cap.
* @param _classId The ID of the share class to set the maximum deposit cap for.
*/
function setMaxDepositCap(uint8 _classId) external;
/*//////////////////////////////////////////////////////////////
DEPOSIT FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Requests a deposit of assets into the vault for the current batch.
* @param _requestDepositParams The parameters for the deposit request.
* @return _batchId The batch ID for the deposit.
*/
function requestDeposit(RequestDepositParams calldata _requestDepositParams) external returns (uint48 _batchId);
/**
* @notice Deposits assets synchronously into the vault, minting shares immediately.
* @param _requestDepositParams The parameters for the deposit (same as requestDeposit).
* @return _shares The number of shares minted to the caller.
* @dev Only callable when totalAssets is valid for the specified class.
*/
function syncDeposit(RequestDepositParams calldata _requestDepositParams) external returns (uint256 _shares);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
import {IAlephVault} from "@aleph-vault/interfaces/IAlephVault.sol";
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAlephVaultFactory {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when a vault is deployed.
* @param vault The address of the deployed vault.
* @param manager The address of the manager.
* @param name The name of the vault.
* @param configId The config ID of the vault.
*/
event VaultDeployed(address indexed vault, address indexed manager, string name, string configId);
/**
* @notice Emitted when the operations multisig is set.
* @param operationsMultisig The new operations multisig.
*/
event OperationsMultisigSet(address indexed operationsMultisig);
/**
* @notice Emitted when the oracle is set.
* @param oracle The new oracle.
*/
event OracleSet(address indexed oracle);
/**
* @notice Emitted when the guardian is set.
* @param guardian The new guardian.
*/
event GuardianSet(address indexed guardian);
/**
* @notice Emitted when the authentication signer is set.
* @param authSigner The new authentication signer.
*/
event AuthSignerSet(address indexed authSigner);
/**
* @notice Emitted when the management fee is set.
* @param managementFee The new management fee.
*/
event ManagementFeeSet(uint32 indexed managementFee);
/**
* @notice Emitted when the performance fee is set.
* @param performanceFee The new performance fee.
*/
event PerformanceFeeSet(uint32 indexed performanceFee);
/**
* @notice Emitted when the module implementation is set.
* @param module The module identifier.
* @param implementation The new implementation.
*/
event ModuleImplementationSet(bytes4 indexed module, address indexed implementation);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the initialization params are invalid.
*/
error InvalidInitializationParams();
/**
* @notice Emitted when the parameter is invalid.
*/
error InvalidParam();
/**
* @notice Emitted when the chain is unsupported.
*/
error UnsupportedChain();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Initialization params.
* @param beacon The beacon address of the vault.
* @param operationsMultisig The operations multisig address.
* @param oracle The oracle address.
* @param guardian The guardian address.
* @param authSigner The authentication signer address.
* @param accountant The accountant proxy address.
* @param alephVaultDepositImplementation The aleph vault deposit implementation address.
* @param alephVaultRedeemImplementation The aleph vault redeem implementation address.
* @param alephVaultSettlementImplementation The aleph vault settlement implementation address.
* @param feeManagerImplementation The fee manager implementation address.
* @param migrationManagerImplementation The migration manager implementation address.
*/
struct InitializationParams {
address beacon;
address operationsMultisig;
address oracle;
address guardian;
address authSigner;
address accountant;
address alephVaultDepositImplementation;
address alephVaultRedeemImplementation;
address alephVaultSettlementImplementation;
address feeManagerImplementation;
address migrationManagerImplementation;
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Checks if an address is a valid vault deployed by this factory
* @param _vault The address to check
* @return True if the vault was deployed by this factory, false otherwise
*/
function isValidVault(address _vault) external view returns (bool);
/*//////////////////////////////////////////////////////////////
SETTER FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Updates the operations multisig address for the factory and all deployed vaults
* @param _operationsMultisig The new operations multisig address
* @dev Only callable by OPERATIONS_MULTISIG role. Updates all deployed vaults.
*/
function setOperationsMultisig(address _operationsMultisig) external;
/**
* @notice Updates the oracle address for all deployed vaults
* @param _oracle The new oracle address
* @dev Only callable by OPERATIONS_MULTISIG role. Updates all deployed vaults.
*/
function setOracle(address _oracle) external;
/**
* @notice Updates the guardian address for all deployed vaults
* @param _guardian The new guardian address
* @dev Only callable by OPERATIONS_MULTISIG role. Updates all deployed vaults.
*/
function setGuardian(address _guardian) external;
/**
* @notice Updates the authentication signer address for vault deployment
* @param _authSigner The new authentication signer address
* @dev Only callable by OPERATIONS_MULTISIG role. Updates all deployed vaults.
*/
function setAuthSigner(address _authSigner) external;
/**
* @notice Updates a module implementation address for all deployed vaults
* @param _module The module identifier to update
* @param _implementation The new implementation address for the module
* @dev Only callable by OPERATIONS_MULTISIG role. Updates all deployed vaults.
*/
function setModuleImplementation(bytes4 _module, address _implementation) external;
/*//////////////////////////////////////////////////////////////
DEPLOY FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Deploys a new vault.
* @param _userInitializationParams Struct containing all user initialization parameters.
* @return The address of the new vault.
*/
function deployVault(IAlephVault.UserInitializationParams calldata _userInitializationParams)
external
returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
import {EnumerableSet} from "openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol";
import {AuthLibrary} from "@aleph-vault/libraries/AuthLibrary.sol";
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAlephVault {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the deposit authentication is enabled.
*/
event IsDepositAuthEnabledSet(bool isDepositAuthEnabled);
/**
* @notice Emitted when the settlement authentication is enabled.
*/
event IsSettlementAuthEnabledSet(bool isSettlementAuthEnabled);
/**
* @notice Emitted when the vault treasury is set.
*/
event VaultTreasurySet(address vaultTreasury);
/**
* @notice Emitted when the share class is created.
*/
event ShareClassCreated(uint8 classId, ShareClassParams shareClassParams);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the initialization params are invalid.
*/
error InvalidInitializationParams();
/**
* @notice Emitted when the auth signer is invalid.
*/
error InvalidAuthSigner();
/**
* @notice Emitted when the share class is invalid.
*/
error InvalidShareClass();
/**
* @notice Emitted when the share series is invalid.
*/
error InvalidShareSeries();
/**
* @notice Emitted when the share class params are invalid.
*/
error InvalidShareClassParams();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Initialization params.
* @param _operationsMultisig The operations multisig address.
* @param _vaultFactory The vault factory address.
* @param _manager The manager address.
* @param _oracle The oracle address.
* @param _guardian The guardian address.
* @param _authSigner The auth signer address.
* @param _accountant The accountant proxy address.
* @param _userInitializationParams The user initialization params.
* @param _moduleInitializationParams The module initialization params.
*/
struct InitializationParams {
address operationsMultisig;
address vaultFactory;
address manager;
address oracle;
address guardian;
address authSigner;
address accountant;
UserInitializationParams userInitializationParams;
ModuleInitializationParams moduleInitializationParams;
}
/**
* @notice Initialization params provided by the user.
* @param _name The name of the vault.
* @param _configId The config ID of the vault.
* @param _underlyingToken The underlying token address.
* @param _custodian The custodian address in which vault funds are stored.
* @param _vaultTreasury The vault treasury address in which fees are collected.
* @param _syncExpirationBatches The number of batches sync flows remain valid after valuation update.
* @param _shareClassParams The share class params for default share class.
* @param _authSignature The auth signature to deploy the vault.
*/
struct UserInitializationParams {
string name;
string configId;
address underlyingToken;
address custodian;
address vaultTreasury;
uint48 syncExpirationBatches;
ShareClassParams shareClassParams;
AuthLibrary.AuthSignature authSignature;
}
/**
* @notice Initialization params for the modules.
* @param _alephVaultDepositImplementation The aleph vault deposit implementation address.
* @param _alephVaultRedeemImplementation The aleph vault redeem implementation address.
* @param _alephVaultSettlementImplementation The aleph vault settlement implementation address.
* @param _feeManagerImplementation The fee manager implementation address.
* @param _migrationManagerImplementation The migration manager implementation address.
*/
struct ModuleInitializationParams {
address alephVaultDepositImplementation;
address alephVaultRedeemImplementation;
address alephVaultSettlementImplementation;
address feeManagerImplementation;
address migrationManagerImplementation;
}
/**
* @notice Parameters for a share class.
* @param _managementFee The management fee rate in basis points.
* @param _performanceFee The performance fee rate in basis points.
* @param _noticePeriod The notice period in batches.
* @param _lockInPeriod The lock in period in batches.
* @param _minDepositAmount The minimum deposit amount.
* @param _minUserBalance The minimum user balance.
* @param _maxDepositCap The maximum deposit cap.
* @param _minRedeemAmount The minimum redeem amount.
* @dev all amounts are denominated in underlying token decimals.
*/
struct ShareClassParams {
uint32 managementFee;
uint32 performanceFee;
uint48 noticePeriod;
uint48 lockInPeriod;
uint256 minDepositAmount;
uint256 minUserBalance;
uint256 maxDepositCap;
uint256 minRedeemAmount;
}
/**
* @notice Structure for a share class.
* @param _shareSeriesId The number of share series created for the share class.
* @param _lastConsolidatedSeriesId The ID of the last consolidated share series.
* @param _lastFeePaidId The last Batch ID in which fees were paid.
* @param _depositSettleId The last Batch ID in which deposits were settled.
* @param _redeemSettleId The last Batch ID in which redemptions were settled.
* @param _shareClassParams The parameters for the share class.
* @param _shareSeries All share series for the share class.
* @param _depositRequests The deposit requests made for the share class.
* @param _redeemRequests The redemption requests made for the share class.
* @param _userLockInPeriod The lock in period for each user in the share class.
*/
struct ShareClass {
uint32 shareSeriesId;
uint32 lastConsolidatedSeriesId;
uint48 lastFeePaidId;
uint48 depositSettleId;
uint48 redeemSettleId;
ShareClassParams shareClassParams;
mapping(uint32 => ShareSeries) shareSeries;
mapping(uint48 batchId => DepositRequests) depositRequests;
mapping(uint48 batchId => RedeemRequests) redeemRequests;
mapping(address user => uint48) userLockInPeriod;
}
/**
* @notice Structure for a share series.
* @param _totalAssets The total assets in the share series.
* @param _totalShares The total shares in the share series.
* @param _highWaterMark The high water mark of the share series.
* @param _users The users in the share series.
* @param _sharesOf The shares of each user in the share series.
* @dev assets and shares are denominated in underlying token decimals.
* @dev if a share series is consolidated, the values inside this mapping are cleared out.
*/
struct ShareSeries {
uint256 totalAssets;
uint256 totalShares;
uint256 highWaterMark;
EnumerableSet.AddressSet users;
mapping(address => uint256) sharesOf;
}
/**
* @notice Structure for the deposit requests for a share class.
* @param _totalAmountToDeposit The total amount to deposit for the share class.
* @param _usersToDeposit The users to deposit for the share class.
* @param _depositRequest The deposit request for each user in the share class.
* @dev deposit requests are amounts denominated in underlying token decimals.
* @dev deposit request values are cleared out after settlement.
*/
struct DepositRequests {
uint256 totalAmountToDeposit;
EnumerableSet.AddressSet usersToDeposit;
mapping(address => uint256) depositRequest;
}
/**
* @notice Structure for the redemption requests for a share class.
* @param _usersToRedeem The users to redeem for the share class.
* @param _redeemRequest The redemption request for each user in the share class.
* @dev redemption requests are in share units (percentage of remaining total user assets in share class)
* denominated in TOTAL_SHARE_UNITS (1e18).
* @dev redemption request values are cleared out after settlement.
*/
struct RedeemRequests {
EnumerableSet.AddressSet usersToRedeem;
mapping(address => uint256) redeemRequest;
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the start time of the vault.
* @return The start time.
*/
function startTimeStamp() external view returns (uint48);
/**
* @notice Returns the current batch ID based on the elapsed time since start.
* @return The current batch ID.
*/
function currentBatch() external view returns (uint48);
/**
* @notice Returns the number of share classes in the vault.
* @return The number of share classes.
*/
function shareClasses() external view returns (uint8);
/**
* @notice Returns the max series ID of the share class.
* @param _classId The ID of the share class.
* @return The max series ID of the share class.
*/
function shareSeriesId(uint8 _classId) external view returns (uint32);
/**
* @notice Returns the last consolidated series ID of the share class.
* @param _classId The ID of the share class.
* @return The last consolidated series ID of the share class.
*/
function lastConsolidatedSeriesId(uint8 _classId) external view returns (uint32);
/**
* @notice Returns the name of the vault.
* @return The name.
*/
function name() external view returns (string memory);
/**
* @notice Returns the manager of the vault.
* @return The manager.
*/
function manager() external view returns (address);
/**
* @notice Returns the underlying token of the vault.
* @return The underlying token.
*/
function underlyingToken() external view returns (address);
/**
* @notice Returns the custodian of the vault.
* @return The custodian.
*/
function custodian() external view returns (address);
/**
* @notice Returns the vault treasury of the vault.
* @return The vault treasury.
*/
function vaultTreasury() external view returns (address);
/**
* @notice Checks if total assets are valid for synchronous operations for a specific class.
* @param _classId The share class ID to check.
* @return true if sync flows are allowed, false otherwise.
*/
function isTotalAssetsValid(uint8 _classId) external view returns (bool);
/**
* @notice Returns the operations multisig of the vault.
* @return The operations multisig.
*/
function operationsMultisig() external view returns (address);
/**
* @notice Returns the oracle of the vault.
* @return The oracle.
*/
function oracle() external view returns (address);
/**
* @notice Returns the guardian of the vault.
* @return The guardian.
*/
function guardian() external view returns (address);
/**
* @notice Returns the KYC authentication signer of the vault.
* @return The KYC authentication signer.
*/
function authSigner() external view returns (address);
/**
* @notice Returns the accountant of the vault.
* @return The accountant.
*/
function accountant() external view returns (address);
/**
* @notice Returns the management fee of the vault.
* @param _classId The ID of the share class.
* @return The management fee.
*/
function managementFee(uint8 _classId) external view returns (uint32);
/**
* @notice Returns the performance fee of the vault.
* @param _classId The ID of the share class.
* @return The performance fee.
*/
function performanceFee(uint8 _classId) external view returns (uint32);
/**
* @notice Returns the notice period of the vault.
* @param _classId The ID of the share class.
* @return The notice period.
*/
function noticePeriod(uint8 _classId) external view returns (uint48);
/**
* @notice Returns the lock in period of the vault.
* @param _classId The ID of the share class.
* @return The lock in period.
*/
function lockInPeriod(uint8 _classId) external view returns (uint48);
/**
* @notice Returns the minimum deposit amount.
* @param _classId The ID of the share class.
* @return The minimum deposit amount of the share class.
*/
function minDepositAmount(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the minimum user balance.
* @param _classId The ID of the share class.
* @return The minimum user balance of the share class.
*/
function minUserBalance(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the maximum deposit cap.
* @param _classId The ID of the share class.
* @return The maximum deposit cap of the share class.
*/
function maxDepositCap(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the minimum redeem amount.
* @param _classId The ID of the share class.
* @return The minimum redeem amount of the share class.
*/
function minRedeemAmount(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the user lock in period.
* @param _classId The ID of the share class.
* @param _user The address of the user.
* @return The user lock in period.
*/
function userLockInPeriod(uint8 _classId, address _user) external view returns (uint48);
/**
* @notice Returns the amount of assets claimable by a user.
* @param _user The address of the user.
* @return The amount of assets claimable by the user.
*/
function redeemableAmount(address _user) external view returns (uint256);
/**
* @notice Returns whether authentication is enabled for deposits.
* @return The status of the authentication for deposits.
*/
function isDepositAuthEnabled() external view returns (bool);
/**
* @notice Returns whether authentication is enabled for settlements.
* @return The status of the authentication for settlements.
*/
function isSettlementAuthEnabled() external view returns (bool);
/**
* @notice Returns the total assets currently held by the vault.
* @return The total assets.
*/
function totalAssets() external view returns (uint256);
/**
* @notice Returns the total assets in the vault for a given class.
* @param _classId The ID of the share class.
* @return The total assets in the vault for the given class.
*/
function totalAssetsOfClass(uint8 _classId) external view returns (uint256[] memory);
/**
* @notice Returns the total assets in the vault for a given class.
* @param _classId The ID of the share class.
* @return The total assets in the vault for the given class.
*/
function totalAssetsPerClass(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the total assets in the vault for a given series.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @return The total assets in the vault for the given series.
*/
function totalAssetsPerSeries(uint8 _classId, uint32 _seriesId) external view returns (uint256);
/**
* @notice Returns the total shares in the vault for a given series.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @return The total shares in the vault for the given series.
*/
function totalSharesPerSeries(uint8 _classId, uint32 _seriesId) external view returns (uint256);
/**
* @notice Returns the total assets of a user in a given class.
* @param _classId The ID of the share class.
* @param _user The address of the user.
* @return The total assets of a user in a given class.
*/
function assetsPerClassOf(uint8 _classId, address _user) external view returns (uint256);
/**
* @notice Returns the amount of assets claimable by a user based on their shares.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @param _user The address of the user.
* @return The amount of assets claimable by the user.
*/
function assetsOf(uint8 _classId, uint32 _seriesId, address _user) external view returns (uint256);
/**
* @notice Returns the number of shares owned by a user.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @param _user The address of the user.
* @return The number of shares owned by the user.
*/
function sharesOf(uint8 _classId, uint32 _seriesId, address _user) external view returns (uint256);
/**
* @notice Returns the current price per share of the vault.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @return The current price per share.
*/
function pricePerShare(uint8 _classId, uint32 _seriesId) external view returns (uint256);
/**
* @notice Returns the current high water mark of the vault.
* @param _classId The ID of the share class.
* @param _seriesId The ID of the share series.
* @return The current high water mark.
*/
function highWaterMark(uint8 _classId, uint32 _seriesId) external view returns (uint256);
/**
* @notice Returns the total amount of unsettled deposit requests for a given class.
* @param _classId The ID of the share class.
* @return The total amount of unsettled deposit requests for the given class.
* @dev Please note that this function will return the deposit amount for all batches including the current batch.
* However, if these deposit requests are settled in this batch, the amount requested in this batch will NOT be settled.
* It will be settled in the next settlement batch. So if you're using this function to check for the deposit request for settlement,
* please be aware of this nuance.
*/
function totalAmountToDeposit(uint8 _classId) external view returns (uint256);
/**
* @notice Returns the total amount of unsettled deposit requests for a given class at a given batch.
* @param _classId The ID of the share class.
* @param _batchId The ID of the batch.
* @return The total amount of unsettled deposit requests for the given class at the given batch.
*/
function totalAmountToDepositAt(uint8 _classId, uint48 _batchId) external view returns (uint256);
/**
* @notice Returns the deposit request of a user.
* @param _classId The ID of the share class.
* @param _user The user to query.
* @return The deposit request of the user.
*/
function depositRequestOf(uint8 _classId, address _user) external view returns (uint256);
/**
* @notice Returns the deposit request of a user at a given batch.
* @param _classId The ID of the share class.
* @param _user The user to query.
* @param _batchId The ID of the batch.
* @return The deposit request of the user at the given batch.
*/
function depositRequestOfAt(uint8 _classId, address _user, uint48 _batchId) external view returns (uint256);
/**
* @notice Returns the redeem request of a user.
* @param _classId The ID of the share class.
* @param _user The user to query.
* @return The redeem request of the user.
*/
function redeemRequestOf(uint8 _classId, address _user) external view returns (uint256);
/**
* @notice Returns the redeem request of a user at a given batch.
* @param _classId The ID of the share class.
* @param _user The user to query.
* @param _batchId The ID of the batch.
* @return The redeem request of the user at the given batch.
*/
function redeemRequestOfAt(uint8 _classId, address _user, uint48 _batchId) external view returns (uint256);
/**
* @notice Returns the users to deposit at a given batch.
* @param _classId The ID of the share class.
* @param _batchId The ID of the batch.
* @return The users to deposit at the given batch.
*/
function usersToDepositAt(uint8 _classId, uint48 _batchId) external view returns (address[] memory);
/**
* @notice Returns the users to redeem at a given batch.
* @param _classId The ID of the share class.
* @param _batchId The ID of the batch.
* @return The users to redeem at the given batch.
*/
function usersToRedeemAt(uint8 _classId, uint48 _batchId) external view returns (address[] memory);
/**
* @notice Returns the total fee amount to collect.
* @return The total fee amount to collect.
*/
function totalFeeAmountToCollect() external view returns (uint256);
/*//////////////////////////////////////////////////////////////
SETTER FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Sets whether authentication is enabled for deposits.
* @param _isDepositAuthEnabled The new status of the authentication for deposits.
*/
function setIsDepositAuthEnabled(bool _isDepositAuthEnabled) external;
/**
* @notice Sets whether authentication is enabled for settlements.
* @param _isSettlementAuthEnabled The new status of the authentication for settlements.
*/
function setIsSettlementAuthEnabled(bool _isSettlementAuthEnabled) external;
/**
* @notice Sets the vault treasury.
* @param _vaultTreasury The new vault treasury.
*/
function setVaultTreasury(address _vaultTreasury) external;
/**
* @notice Creates a new share class.
* @param _shareClassParams The parameters for the share class.
*/
function createShareClass(ShareClassParams memory _shareClassParams) external returns (uint8 _classId);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAlephVaultRedeem {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when a new notice period is queued.
* @param classId The ID of the share class.
* @param noticePeriod The new notice period in batches.
*/
event NewNoticePeriodQueued(uint8 classId, uint48 noticePeriod);
/**
* @notice Emitted when a new lock in period is queued.
* @param classId The ID of the share class.
* @param lockInPeriod The new lock in period in batches.
*/
event NewLockInPeriodQueued(uint8 classId, uint48 lockInPeriod);
/**
* @notice Emitted when a new minimum redeem amount is queued.
* @param classId The ID of the share class.
* @param minRedeemAmount The new minimum redeem amount.
*/
event NewMinRedeemAmountQueued(uint8 classId, uint256 minRedeemAmount);
/**
* @notice Emitted when a new notice period is set.
* @param classId The ID of the share class.
* @param noticePeriod The new notice period in batches.
*/
event NewNoticePeriodSet(uint8 classId, uint48 noticePeriod);
/**
* @notice Emitted when a new lock in period is set.
* @param classId The ID of the share class.
* @param lockInPeriod The new lock in period in batches.
*/
event NewLockInPeriodSet(uint8 classId, uint48 lockInPeriod);
/**
* @notice Emitted when a new minimum redeem amount is set.
* @param classId The ID of the share class.
* @param minRedeemAmount The new minimum redeem amount.
*/
event NewMinRedeemAmountSet(uint8 classId, uint256 minRedeemAmount);
/**
* @notice Emitted when a redeem request is made.
* @param classId The ID of the share class.
* @param batchId The batch ID of the redeem request.
* @param user The user making the redeem request.
* @param estAmountToRedeem The estimated amount to redeem.
*/
event RedeemRequest(uint8 classId, uint48 batchId, address indexed user, uint256 estAmountToRedeem);
/**
* @notice Emitted when the redeemable amount is withdrawn.
* @param user The user withdrawing the redeemable amount.
* @param redeemableAmount The redeemable amount.
*/
event RedeemableAmountWithdrawn(address indexed user, uint256 redeemableAmount);
/**
* @notice Emitted when the excess assets are withdrawn.
* @param excessAssets The excess assets.
*/
event ExcessAssetsWithdrawn(uint256 excessAssets);
/**
* @notice Emitted when a synchronous redeem is made.
* @param classId The ID of the share class.
* @param batchId The batch ID when the redeem occurred.
* @param allocator The address making the redeem.
* @param requestedAmount The amount requested to redeem.
*/
event SyncRedeem(uint8 indexed classId, uint48 batchId, address indexed allocator, uint256 requestedAmount);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the minimum redeem amount is invalid.
*/
error InvalidMinRedeemAmount();
/**
* @notice Emitted when the redeem is less than the minimum redeem amount.
* @param minRedeemAmount The minimum redeem amount.
*/
error RedeemLessThanMinRedeemAmount(uint256 minRedeemAmount);
/**
* @notice Emitted when the user is in the lock in period.
* @param userLockInPeriod The user lock in period.
*/
error UserInLockInPeriodNotElapsed(uint48 userLockInPeriod);
/**
* @notice Emitted when the assets to redeem are insufficient.
*/
error InsufficientAssetsToRedeem();
/**
* @notice Emitted when the redeem falls below the minimum user balance.
* @param minUserBalance The minimum user balance.
*/
error RedeemFallBelowMinUserBalance(uint256 minUserBalance);
/**
* @notice Emitted when only one request per batch is allowed for redeem.
*/
error OnlyOneRequestPerBatchAllowedForRedeem();
/**
* @notice Emitted when the vault balance is insufficient.
*/
error InsufficientVaultBalance();
/**
* @notice Emitted when only async redeem is allowed (sync is not valid).
*/
error OnlyAsyncRedeemAllowed();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Constructor params.
* @param noticePeriodTimelock The timelock period for the notice period.
* @param lockInPeriodTimelock The timelock period for the lock in period.
* @param minRedeemAmountTimelock The timelock period for the minimum redeem amount.
*/
struct RedeemConstructorParams {
uint48 noticePeriodTimelock;
uint48 lockInPeriodTimelock;
uint48 minRedeemAmountTimelock;
}
/**
* @notice Parameters for a redeem request.
* @param classId The ID of the share class.
* @param estAmountToRedeem The estimated amount to redeem.
* @dev pleas note that the amount mentioned here is used to calculate the share units based on the
* PPS at the moment of request. The actual amount the users can withdraw after settlement may be
* different from the amount specified here due to change in PPS based on the pnl of the vault and fees.
*/
struct RedeemRequestParams {
uint8 classId;
uint256 estAmountToRedeem;
}
/*//////////////////////////////////////////////////////////////
TIMELOCK FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Queues a new notice period.
* @param _classId The ID of the share class to set the notice period for.
* @param _noticePeriod The new notice period in batches.
*/
function queueNoticePeriod(uint8 _classId, uint48 _noticePeriod) external;
/**
* @notice Queues a new lock in period.
* @param _classId The ID of the share class to set the lock in period for.
* @param _lockInPeriod The new lock in period in batches.
*/
function queueLockInPeriod(uint8 _classId, uint48 _lockInPeriod) external;
/**
* @notice Queues a new minimum redeem amount.
* @param _classId The ID of the share class to set the minimum redeem amount for.
* @param _minRedeemAmount The new minimum redeem amount.
*/
function queueMinRedeemAmount(uint8 _classId, uint256 _minRedeemAmount) external;
/**
* @notice Sets the notice period in batches
* @param _classId The ID of the share class to set the notice period for.
*/
function setNoticePeriod(uint8 _classId) external;
/**
* @notice Sets the lock in period in batches
* @param _classId The ID of the share class to set the lock in period for.
*/
function setLockInPeriod(uint8 _classId) external;
/**
* @notice Sets the minimum redeem amount.
* @param _classId The ID of the share class to set the minimum redeem amount for.
*/
function setMinRedeemAmount(uint8 _classId) external;
/*//////////////////////////////////////////////////////////////
REDEEM FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Requests to redeem shares from the vault for the current batch.
* @param _redeemRequestParams The parameters for the redeem request.
* @return _batchId The batch ID for the redeem request.
*/
function requestRedeem(RedeemRequestParams calldata _redeemRequestParams) external returns (uint48 _batchId);
/**
* @notice Withdraws the redeemable amount for the user.
*/
function withdrawRedeemableAmount() external;
/**
* @notice Withdraws excess assets from the vault and sends back to custodian.
*/
function withdrawExcessAssets() external;
/**
* @notice Redeems shares synchronously from the vault, transferring assets immediately.
* @param _redeemRequestParams The parameters for the redeem (same as requestRedeem).
* @return _assets The amount of assets transferred to the caller.
* @dev Only callable when totalAssets is valid. Bypasses notice period.
*/
function syncRedeem(RedeemRequestParams calldata _redeemRequestParams) external returns (uint256 _assets);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
import {EnumerableSet} from "openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol";
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAccountant {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the operations multisig is set.
* @param operationsMultisig The new operations multisig.
*/
event OperationsMultisigSet(address operationsMultisig);
/**
* @notice Emitted when the vault factory is set.
* @param vaultFactory The new vault factory.
*/
event VaultFactorySet(address vaultFactory);
/**
* @notice Emitted when the aleph treasury is set.
* @param alephTreasury The new aleph treasury.
*/
event AlephTreasurySet(address alephTreasury);
/**
* @notice Emitted when the vault treasury is set.
* @param vault The vault.
* @param vaultTreasury The new vault treasury.
*/
event VaultTreasurySet(address vault, address vaultTreasury);
/**
* @notice Emitted when the management fee cut is set.
* @param vault The vault.
* @param managementFeeCut The new management fee cut.
*/
event ManagementFeeCutSet(address vault, uint32 managementFeeCut);
/**
* @notice Emitted when the performance fee cut is set.
* @param vault The vault.
* @param performanceFeeCut The new performance fee cut.
*/
event PerformanceFeeCutSet(address vault, uint32 performanceFeeCut);
/**
* @notice Emitted when the operator fee cut is set.
* @param vault The vault.
* @param operatorFeeCut The new operator fee cut.
*/
event OperatorFeeCutSet(address vault, uint32 operatorFeeCut);
/**
* @notice Emitted when the operator allocations are set.
* @param vault The vault.
* @param operator The operator.
* @param allocatedAmount The allocated amount.
*/
event OperatorAllocationsSet(address vault, address operator, uint256 allocatedAmount);
/**
* @notice Emitted when operator fees are distributed to an operator.
* @param vault The vault.
* @param operator The operator receiving the fee.
* @param operatorFee The fee amount distributed to the operator.
*/
event OperatorFeeDistributed(address vault, address operator, uint256 operatorFee);
/**
* @notice Emitted when fees are collected.
* @param vault The vault.
* @param managementFeesToCollect The management fees to collect.
* @param performanceFeesToCollect The performance fees to collect.
* @param vaultFee The vault fee split
* @param alephFee The aleph fee split
* @param operatorsFee The fees for the operators.
*/
event FeesCollected(
address vault,
uint256 managementFeesToCollect,
uint256 performanceFeesToCollect,
uint256 vaultFee,
uint256 alephFee,
uint256[] operatorsFee
);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when the initialization params are invalid.
*/
error InvalidInitializationParams();
/**
* @notice Emitted when the vault is invalid.
*/
error InvalidVault();
/**
* @notice Emitted when the manager is invalid.
*/
error InvalidManager();
/**
* @notice Emitted when the vault treasury is invalid.
*/
error InvalidVaultTreasury();
/**
* @notice Emitted when the vault treasury is not set.
*/
error VaultTreasuryNotSet();
/**
* @notice Emitted when fees are not collected.
*/
error FeesNotCollected();
/**
* @notice Emitted when the operator fee cut is invalid.
*/
error InvalidOperatorFeeCut();
/**
* @notice Emitted when the operator allocation input is invalid.
*/
error InvalidOperatorAllocation();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Initialization params.
* @param operationsMultisig The operations multisig.
* @param alephTreasury The aleph treasury.
*/
struct InitializationParams {
address operationsMultisig;
address alephTreasury;
}
/**
* @notice Operator allocations.
* @param totalOperatorAllocations The total operator allocations.
* @param operators The operators.
* @param allocatedAmount The allocated amount by each operator.
*/
struct OperatorAllocations {
uint256 totalOperatorAllocations;
EnumerableSet.AddressSet operators;
mapping(address operator => uint256 allocatedAmount) allocatedAmount;
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the vault treasury of the caller.
* @return The vault treasury.
*/
function vaultTreasury() external view returns (address);
/*//////////////////////////////////////////////////////////////
SETTER FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the vault treasury.
* @param _vault The vault to initialize the treasury for.
* @param _vaultTreasury The new vault treasury.
*/
function initializeVaultTreasury(address _vault, address _vaultTreasury) external;
/**
* @notice Sets the operations multisig.
* @param _operationsMultisig The new operations multisig.
*/
function setOperationsMultisig(address _operationsMultisig) external;
/**
* @notice Sets the vault factory.
* @param _vaultFactory The new vault factory.
*/
function setVaultFactory(address _vaultFactory) external;
/**
* @notice Sets the aleph treasury.
* @param _alephTreasury The new aleph treasury.
*/
function setAlephTreasury(address _alephTreasury) external;
/**
* @notice Sets the vault treasury.
* @param _vaultTreasury The new vault treasury.
*/
function setVaultTreasury(address _vaultTreasury) external;
/**
* @notice Sets the aleph avs.
* @param _alephAvs The new aleph avs.
*/
function setAlephAvs(address _alephAvs) external;
/**
* @notice Sets the management fee cut.
* @param _vault The vault to set the management fee cut for.
* @param _managementFeeCut The new management fee cut.
*/
function setManagementFeeCut(address _vault, uint32 _managementFeeCut) external;
/**
* @notice Sets the performance fee cut.
* @param _vault The vault to set the performance fee cut for.
* @param _performanceFeeCut The new performance fee cut.
*/
function setPerformanceFeeCut(address _vault, uint32 _performanceFeeCut) external;
/**
* @notice Sets the operator fee cut.
* @param _vault The vault to set the operator fee cut for.
* @param _operatorFeeCut The new operator fee cut.
*/
function setOperatorFeeCut(address _vault, uint32 _operatorFeeCut) external;
/**
* @notice Sets the operator allocations.
* @param _vault The vault to set the operator allocations for.
* @param _operator The operator to set the allocations for.
* @param _allocatedAmount The new allocated amount.
*/
function setOperatorAllocations(address _vault, address _operator, uint256 _allocatedAmount) external;
/*//////////////////////////////////////////////////////////////
FEE FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Collects all pending fees from a given vault.
* @param _vault The vault to collect fees from.
*/
function collectFees(address _vault) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
/**
* @title IERC20Factory
* @notice Interface for ERC20 token factory
*/
interface IERC20Factory {
/**
* @notice Emitted when a new ERC20 token is created
* @param token The address of the newly created token
* @param name The name of the token
* @param symbol The symbol of the token
* @param creator The address that created the token (msg.sender of createToken)
*/
event TokenCreated(address indexed token, string name, string symbol, address indexed creator);
/**
* @notice Creates a new ERC20 token
* @param name The name of the token
* @param symbol The symbol of the token
* @param decimals The number of decimals for the token
* @return token The address of the newly created token
*/
function createToken(string memory name, string memory symbol, uint8 decimals) external returns (address token);
/**
* @notice Gets the number of tokens created by this factory
* @return count The number of tokens created
*/
function getTokenCount() external view returns (uint256 count);
/**
* @notice Gets the address of a token by its index
* @param index The index of the token
* @return token The address of the token
*/
function getToken(uint256 index) external view returns (address token);
/**
* @notice Checks if an address is a token created by this factory
* @param token The address to check
* @return isToken Whether the address is a token created by this factory
*/
function isToken(address token) external view returns (bool isToken);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import {IERC20Factory} from "./interfaces/IERC20Factory.sol";
import {ERC20Token} from "./ERC20Token.sol";
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
/**
* @title ERC20Factory
* @notice Factory contract for creating slashed ERC20 tokens
* @dev Creates mintable/burnable ERC20 tokens for representing vault shares
*/
contract ERC20Factory is IERC20Factory, Ownable {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error EmptyString();
error IndexOutOfBounds();
/*//////////////////////////////////////////////////////////////
NAMESPACED STORAGE (ERC-7201)
//////////////////////////////////////////////////////////////*/
/// @custom:storage-location erc7201:erc20.factory.storage
struct FactoryStorage {
/// @dev Array of all tokens created by this factory
address[] tokens;
/// @dev Mapping from token address to creation status
mapping(address => bool) isToken;
}
// keccak256(abi.encode(uint256(keccak256("erc20.factory.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant FACTORY_STORAGE_LOCATION =
0x5c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b900;
function _getFactoryStorage() private pure returns (FactoryStorage storage $) {
assembly {
$.slot := FACTORY_STORAGE_LOCATION
}
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Modifier to ensure the string is not empty
* @param _str The string to check
*/
modifier nonEmptyString(string memory _str) {
if (bytes(_str).length == 0) revert EmptyString();
_;
}
/**
* @notice Modifier to ensure the index is within bounds
* @param _index The index to check
*/
modifier validIndex(uint256 _index) {
if (_index >= _getFactoryStorage().tokens.length) revert IndexOutOfBounds();
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Constructs the ERC20Factory contract
* @param _owner The owner of the contract
*/
constructor(address _owner) Ownable(_owner) {}
/*//////////////////////////////////////////////////////////////
PUBLIC FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Creates a new ERC20 token
* @param name The name of the token
* @param symbol The symbol of the token
* @param decimals The number of decimals for the token (typically 18)
* @return token The address of the newly created token
*/
function createToken(string memory name, string memory symbol, uint8 decimals)
external
override
onlyOwner
nonEmptyString(name)
nonEmptyString(symbol)
returns (address token)
{
// Deploy new token
ERC20Token newToken = new ERC20Token(name, symbol, decimals, msg.sender);
token = address(newToken);
// Track the token
FactoryStorage storage $ = _getFactoryStorage();
$.tokens.push(token);
$.isToken[token] = true;
// Emit event
emit TokenCreated(token, name, symbol, msg.sender);
return token;
}
/**
* @notice Gets the number of tokens created by this factory
* @return count The number of tokens created
*/
function getTokenCount() external view override returns (uint256 count) {
return _getFactoryStorage().tokens.length;
}
/**
* @notice Gets the address of a token by its index
* @param index The index of the token
* @return token The address of the token
*/
function getToken(uint256 index) external view override validIndex(index) returns (address token) {
return _getFactoryStorage().tokens[index];
}
/**
* @notice Gets all tokens created by this factory
* @return tokens Array of all token addresses
*/
function getAllTokens() external view returns (address[] memory tokens) {
return _getFactoryStorage().tokens;
}
/**
* @notice Checks if an address is a token created by this factory
* @param token The address to check
* @return Whether the address is a token created by this factory
*/
function isToken(address token) external view override returns (bool) {
return _getFactoryStorage().isToken[token];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAlephAVSPausable} from "./interfaces/IAlephAVSPausable.sol";
import {AccessControlUpgradeable} from "@openzeppelin-upgrades/contracts/access/AccessControlUpgradeable.sol";
contract AlephAVSPausable is IAlephAVSPausable, AccessControlUpgradeable {
bytes4 public constant ALLOCATE_FLOW = bytes4(keccak256("ALLOCATE_FLOW"));
bytes4 public constant UNALLOCATE_FLOW = bytes4(keccak256("UNALLOCATE_FLOW"));
/*//////////////////////////////////////////////////////////////
NAMESPACED STORAGE (ERC-7201)
//////////////////////////////////////////////////////////////*/
/// @custom:storage-location erc7201:aleph.avs.storage
struct PausableStorage {
// Mapping of pausable flow to its pause state
mapping(bytes4 pausableFlow => bool isPaused) flowsPauseStates;
}
// keccak256(abi.encode(uint256(keccak256("pausable.avs.storage")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant PAUSABLE_STORAGE_LOCATION =
0xf8131bc7f7376b7d8d09601d142eed8304a0dce3fa238f43875ec194c35e4400;
function _getPausableStorage() private pure returns (PausableStorage storage $) {
assembly {
$.slot := PAUSABLE_STORAGE_LOCATION
}
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Modifier to check if a flow is not paused
* @param _pausableFlow The flow identifier
*/
modifier whenFlowNotPaused(bytes4 _pausableFlow) {
_revertIfFlowPaused(_pausableFlow);
_;
}
/**
* @notice Modifier to check if a flow is paused
* @param _pausableFlow The flow identifier
*/
modifier whenFlowPaused(bytes4 _pausableFlow) {
_revertIfFlowUnpaused(_pausableFlow);
_;
}
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
function isFlowPaused(bytes4 _pausableFlow) external view returns (bool _isPaused) {
return _getPausableStorage().flowsPauseStates[_pausableFlow];
}
/*//////////////////////////////////////////////////////////////
PAUSING FUNCTIONS
//////////////////////////////////////////////////////////////*/
function pause(bytes4 _pausableFlow) external onlyRole(_pausableFlow) {
_pause(_pausableFlow);
}
function unpause(bytes4 _pausableFlow) external onlyRole(_pausableFlow) {
_unpause(_pausableFlow);
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @dev Internal function to pause a flow
* @param _pausableFlow The flow identifier
*/
function _pause(bytes4 _pausableFlow) internal {
PausableStorage storage _sd = _getPausableStorage();
if (_sd.flowsPauseStates[_pausableFlow]) revert FlowIsCurrentlyPaused();
_sd.flowsPauseStates[_pausableFlow] = true;
emit FlowPaused(_pausableFlow, msg.sender);
}
/**
* @dev Internal function to unpause a flow
* @param _pausableFlow The flow identifier
*/
function _unpause(bytes4 _pausableFlow) internal {
PausableStorage storage _sd = _getPausableStorage();
if (!_sd.flowsPauseStates[_pausableFlow]) revert FlowIsCurrentlyUnpaused();
_sd.flowsPauseStates[_pausableFlow] = false;
emit FlowUnpaused(_pausableFlow, msg.sender);
}
/**
* @dev Internal function to revert if a flow is paused
* @param _pausableFlow The flow identifier
*/
function _revertIfFlowPaused(bytes4 _pausableFlow) internal view {
if (_getPausableStorage().flowsPauseStates[_pausableFlow]) revert FlowIsCurrentlyPaused();
}
/**
* @dev Internal function to revert if a flow is unpaused
* @param _pausableFlow The flow identifier
*/
function _revertIfFlowUnpaused(bytes4 _pausableFlow) internal view {
if (!_getPausableStorage().flowsPauseStates[_pausableFlow]) revert FlowIsCurrentlyUnpaused();
}
/**
* @dev Internal function to initialize the pausable storage
* @param _owner The owner address
* @param _guardian The guardian address
*/
function _pausableInit(address _owner, address _guardian) internal {
_grantRole(ALLOCATE_FLOW, _owner);
_grantRole(ALLOCATE_FLOW, _guardian);
_grantRole(UNALLOCATE_FLOW, _owner);
_grantRole(UNALLOCATE_FLOW, _guardian);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
/**
* @title IMintableBurnableERC20
* @notice Interface for ERC20 tokens that support minting and burning
*/
interface IMintableBurnableERC20 {
/**
* @notice Mints new tokens to the specified address
* @param to The address to receive the tokens
* @param amount The amount of tokens to mint
*/
function mint(address to, uint256 amount) external;
/**
* @notice Burns tokens from the specified address
* @param from The address to burn tokens from
* @param amount The amount of tokens to burn
*/
function burn(address from, uint256 amount) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";
import {AlephUtils} from "./AlephUtils.sol";
/**
* @title AlephSlashing
* @notice Library for slashing-related calculations and operations
* @dev Provides functions for calculating magnitudes, wads, and executing slashes
*/
library AlephSlashing {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error AmountTooSmall();
error InsufficientAllocation();
error MagnitudeOverflow();
/*//////////////////////////////////////////////////////////////
MAGNITUDE CALCULATION FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Calculate magnitude to slash from underlying token amount
* @param _allocationManager The AllocationManager contract
* @param _operator The operator address
* @param _operatorSet The operator set
* @param _amount The underlying token amount
* @param _strategy The strategy
* @return magnitudeToSlash The magnitude to slash
*/
function calculateMagnitudeFromAmount(
IAllocationManager _allocationManager,
address _operator,
OperatorSet memory _operatorSet,
uint256 _amount,
IStrategy _strategy
) internal view returns (uint64 magnitudeToSlash) {
uint256 sharesNeeded = _strategy.underlyingToSharesView(_amount);
if (sharesNeeded == 0) revert AmountTooSmall();
uint256 allocatedShares = getAllocatedShares(_allocationManager, _operator, _operatorSet, _strategy);
if (allocatedShares < sharesNeeded) revert InsufficientAllocation();
IAllocationManagerTypes.Allocation memory allocation =
_allocationManager.getAllocation(_operator, _operatorSet, _strategy);
uint256 magnitudeUint = Math.mulDiv(uint256(allocation.currentMagnitude), sharesNeeded, allocatedShares);
if (magnitudeUint > uint256(allocation.currentMagnitude)) {
magnitudeUint = uint256(allocation.currentMagnitude);
}
if (magnitudeUint > type(uint64).max) revert MagnitudeOverflow();
// casting to 'uint64' is safe because we check magnitudeUint <= type(uint64).max above
// forge-lint: disable-next-line(unsafe-typecast)
magnitudeToSlash = uint64(magnitudeUint);
}
/**
* @notice Get allocated shares for an operator in an operator set
* @param _allocationManager The AllocationManager contract
* @param _operator The operator address
* @param _operatorSet The operator set
* @param _strategy The strategy
* @return The allocated shares
*/
function getAllocatedShares(
IAllocationManager _allocationManager,
address _operator,
OperatorSet memory _operatorSet,
IStrategy _strategy
) internal view returns (uint256) {
address[] memory operators = new address[](1);
operators[0] = _operator;
IStrategy[] memory strategyArray = AlephUtils.asStrategyArray(_strategy);
uint256[][] memory allocatedStakes =
_allocationManager.getAllocatedStake(_operatorSet, operators, strategyArray);
return allocatedStakes[0][0];
}
/**
* @notice Verify operator has allocated magnitude to the operator set
* @param _allocationManager The AllocationManager contract
* @param _operator The operator address
* @param _operatorSet The operator set
* @param _magnitudeToSlash The magnitude to slash
* @param _strategy The strategy
*/
function verifyOperatorAllocation(
IAllocationManager _allocationManager,
address _operator,
OperatorSet memory _operatorSet,
uint64 _magnitudeToSlash,
IStrategy _strategy
) internal view {
IAllocationManagerTypes.Allocation memory allocation =
_allocationManager.getAllocation(_operator, _operatorSet, _strategy);
if (allocation.currentMagnitude < _magnitudeToSlash) revert InsufficientAllocation();
}
/*//////////////////////////////////////////////////////////////
SLASHING EXECUTION FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Execute slash of operator to redistribute shares
* @param _allocationManager The AllocationManager contract
* @param _avsAddress The AVS address (slash caller)
* @param _operator The operator to slash
* @param _operatorSetId The operator set ID
* @param _magnitudeToSlash The magnitude to slash
* @param _strategy The strategy being slashed
* @param _slashDescription The description for the slash
* @return slashId The ID of the slash
*/
function executeSlashAndGetId(
IAllocationManager _allocationManager,
address _avsAddress,
address _operator,
uint32 _operatorSetId,
uint64 _magnitudeToSlash,
IStrategy _strategy,
string memory _slashDescription
) internal returns (uint256 slashId) {
OperatorSet memory operatorSet = AlephUtils.getOperatorSet(_avsAddress, _operatorSetId);
IAllocationManagerTypes.Allocation memory allocation =
_allocationManager.getAllocation(_operator, operatorSet, _strategy);
uint256 wadToSlash = calculateWadToSlash(_magnitudeToSlash, allocation.currentMagnitude);
IStrategy[] memory strategyArray = AlephUtils.asStrategyArray(_strategy);
uint256[] memory wadsToSlash = new uint256[](1);
wadsToSlash[0] = wadToSlash;
IAllocationManagerTypes.SlashingParams memory slashingParams = IAllocationManagerTypes.SlashingParams({
operator: _operator,
operatorSetId: _operatorSetId,
strategies: strategyArray,
wadsToSlash: wadsToSlash,
description: _slashDescription
});
(slashId,) = _allocationManager.slashOperator(_avsAddress, slashingParams);
return slashId;
}
/**
* @notice Calculate wad to slash from magnitude and current magnitude
* @param _magnitudeToSlash The magnitude to slash
* @param _currentMagnitude The current magnitude of the allocation
* @return The wad (proportion) to slash, capped at 1e18 (100%)
*/
function calculateWadToSlash(uint64 _magnitudeToSlash, uint64 _currentMagnitude) internal pure returns (uint256) {
if (_currentMagnitude == 0 || _magnitudeToSlash == 0) return 0;
uint64 _magnitudeToSlashAdjusted = _magnitudeToSlash > _currentMagnitude ? _currentMagnitude : _magnitudeToSlash;
uint256 _wad = Math.mulDiv(uint256(_magnitudeToSlashAdjusted), AlephUtils.WAD, uint256(_currentMagnitude));
return _wad > AlephUtils.WAD ? AlephUtils.WAD : _wad;
}
/**
* @notice Clear redistributable shares and receive tokens
* @param _strategyManager The StrategyManager contract
* @param _avsAddress The AVS address
* @param _operatorSetId The operator set ID
* @param _slashId The slash ID
* @param _strategy The strategy
* @return The token amount received
*/
function clearRedistributableShares(
IStrategyManager _strategyManager,
address _avsAddress,
uint32 _operatorSetId,
uint256 _slashId,
IStrategy _strategy
) internal returns (uint256) {
OperatorSet memory operatorSet = AlephUtils.getOperatorSet(_avsAddress, _operatorSetId);
return _strategyManager.clearBurnOrRedistributableSharesByStrategy(operatorSet, _slashId, _strategy);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20 as IERC20Eigen} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {ERC4626Math} from "Aleph/src/libraries/ERC4626Math.sol";
import {IAlephVault} from "Aleph/src/interfaces/IAlephVault.sol";
import {IAlephVaultDeposit} from "Aleph/src/interfaces/IAlephVaultDeposit.sol";
import {IAlephVaultRedeem} from "Aleph/src/interfaces/IAlephVaultRedeem.sol";
import {IAlephVaultFactory} from "Aleph/src/interfaces/IAlephVaultFactory.sol";
import {IStrategyFactory} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyFactory.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {IERC20Factory} from "../interfaces/IERC20Factory.sol";
import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol";
import {IMintableBurnableERC20} from "../interfaces/IMintableBurnableERC20.sol";
import {AlephUtils} from "./AlephUtils.sol";
import {AlephValidation} from "./AlephValidation.sol";
/**
* @title AlephVaultManagement
* @notice Library for vault management operations
* @dev Provides functions for vault interactions, slashed token/strategy creation, deposits, withdrawals, and calculations
*/
library AlephVaultManagement {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error InvalidAlephVault();
/*//////////////////////////////////////////////////////////////
VAULT TOKEN/STRATEGY HELPERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Gets the vault token
* @param _vaultFactory The Aleph Vault Factory
* @param _vault The vault address
* @return vaultToken The vault's underlying token
*/
function getVaultToken(IAlephVaultFactory _vaultFactory, address _vault) internal view returns (IERC20 vaultToken) {
AlephValidation.validateVault(_vaultFactory, _vault);
vaultToken = IERC20(address(IAlephVault(_vault).underlyingToken()));
}
/**
* @notice Gets the vault token and validates the provided strategy
* @param _vaultFactory The Aleph Vault Factory
* @param _vault The vault address
* @param _strategy The strategy to validate (must match vault's underlying token)
* @return vaultToken The vault's underlying token
*/
function getVaultTokenAndStrategy(IAlephVaultFactory _vaultFactory, address _vault, IStrategy _strategy)
internal
view
returns (IERC20 vaultToken)
{
vaultToken = getVaultToken(_vaultFactory, _vault);
AlephValidation.validateStrategy(address(_strategy));
if (address(_strategy.underlyingToken()) != address(vaultToken)) {
revert AlephValidation.InvalidStrategy();
}
}
/**
* @notice Creates or gets the slashed token for a vault
* @param _erc20Factory The ERC20 Factory
* @param _vault The vault address
* @param _originalToken The original token (vault's underlying token)
* @return slashedToken The slashed token address
*/
function createSlashedTokenForVault(IERC20Factory _erc20Factory, address _vault, IERC20 _originalToken)
internal
returns (IERC20 slashedToken)
{
// Create new slashed token
// Naming convention: "al" prefix stands for "Aleph"
// Format: "al<OriginalTokenName>-<VaultName>"
string memory _vaultName = IAlephVault(_vault).name();
string memory _originalName = IERC20Metadata(address(_originalToken)).name();
string memory _originalSymbol = IERC20Metadata(address(_originalToken)).symbol();
string memory _tokenName = string.concat("al", _originalName, "-", _vaultName);
string memory _tokenSymbol = string.concat("al", _originalSymbol, "-", _vaultName);
address _slashedTokenAddress =
_erc20Factory.createToken(_tokenName, _tokenSymbol, IERC20Metadata(address(_originalToken)).decimals());
slashedToken = IERC20(_slashedTokenAddress);
}
/**
* @notice Creates or gets the slashed strategy for a vault
* @param _strategyFactory The Strategy Factory
* @param _vault The vault address
* @param _originalToken The original token (vault's underlying token)
* @param _erc20Factory The ERC20 Factory
* @return slashedToken The slashed token
* @return slashedStrategy The slashed strategy
*/
function createSlashedStrategyForVault(
IStrategyFactory _strategyFactory,
address _vault,
IERC20 _originalToken,
mapping(address => IStrategy) storage _vaultToSlashedStrategy,
IERC20Factory _erc20Factory
) internal returns (IERC20 slashedToken, IStrategy slashedStrategy) {
slashedToken = createSlashedTokenForVault(_erc20Factory, _vault, _originalToken);
// Convert to IERC20Eigen for StrategyFactory (uses @openzeppelin/contracts IERC20)
// Note: StrategyFactory expects IERC20 from @openzeppelin/contracts, which is IERC20Eigen
IERC20Eigen _slashedTokenEigen = IERC20Eigen(address(slashedToken));
// Check if a strategy already exists for this token (edge case: partial transaction)
// This should never happen with CREATE, but we handle it gracefully
IStrategy _existingStrategy = _strategyFactory.deployedStrategies(_slashedTokenEigen);
if (address(_existingStrategy) != address(0)) {
// Strategy already exists - reuse it (this handles edge cases from partial transactions)
slashedStrategy = _existingStrategy;
} else {
// Deploy a new strategy for the newly created slashed token
slashedStrategy = _strategyFactory.deployNewStrategy(_slashedTokenEigen);
}
// Store in mapping for easy querying
_vaultToSlashedStrategy[_vault] = slashedStrategy;
}
/*//////////////////////////////////////////////////////////////
VAULT OPERATIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Deposits tokens to an Aleph vault synchronously
* @param _vault The vault address
* @param _requestDepositParams The deposit parameters
* @param _tokenAmount The token amount to deposit (may differ from _requestDepositParams.amount due to rounding)
* @return shares The number of shares minted
*/
function depositToAlephVault(
address _vault,
IAlephVaultDeposit.RequestDepositParams calldata _requestDepositParams,
uint256 _tokenAmount
) internal returns (uint256 shares) {
IERC20 _vaultToken = IERC20(IAlephVault(_vault).underlyingToken());
SafeERC20.forceApprove(_vaultToken, _vault, _tokenAmount);
IAlephVaultDeposit.RequestDepositParams memory adjustedParams = IAlephVaultDeposit.RequestDepositParams({
classId: _requestDepositParams.classId,
amount: _tokenAmount,
authSignature: _requestDepositParams.authSignature
});
if (!IAlephVault(_vault).isTotalAssetsValid(_requestDepositParams.classId)) {
IAlephVaultDeposit(_vault).requestDeposit(adjustedParams);
shares = 0;
} else {
shares = IAlephVaultDeposit(_vault).syncDeposit(adjustedParams);
}
SafeERC20.forceApprove(_vaultToken, _vault, 0);
}
/**
* @notice Calculates the amount of slashed tokens to mint based on the amount to deposit
* @param _classId The share class ID
* @param _vault The vault address
* @param _slashedToken The slashed token address
* @param _amount The amount deposited to the vault
* @return The amount of slashed tokens to mint
*/
function calculateAmountToMint(uint8 _classId, address _vault, address _slashedToken, uint256 _amount)
internal
view
returns (uint256)
{
return ERC4626Math.previewDeposit(
_amount, IERC20(_slashedToken).totalSupply(), IAlephVault(_vault).assetsPerClassOf(_classId, address(this))
);
}
/**
* @notice Calculates the amount of tokens to redeem based on the amount of slashed tokens to burn
* @param _classId The share class ID
* @param _vault The vault address
* @param _slashedToken The slashed token address
* @param _amount The amount of slashed tokens to burn
* @return The amount of tokens to redeem
*/
function calculateAmountToRedeem(uint8 _classId, address _vault, address _slashedToken, uint256 _amount)
internal
view
returns (uint256)
{
return ERC4626Math.previewRedeem(
_amount, IAlephVault(_vault).assetsPerClassOf(_classId, address(this)), IERC20(_slashedToken).totalSupply()
);
}
/**
* @notice Redeems tokens from the vault with calculated parameters
* @param _vault The vault address
* @param _slashedStrategy The slashed strategy
* @param _amount The amount of slashed tokens to redeem
* @param _classId The share class ID
* @return amount The amount of tokens redeemed
*/
function redeemFromVault(address _vault, IStrategy _slashedStrategy, uint256 _amount, uint8 _classId)
internal
returns (uint256 amount)
{
uint256 _estAmountToRedeem =
calculateAmountToRedeem(_classId, _vault, address(_slashedStrategy.underlyingToken()), _amount);
IAlephVaultRedeem.RedeemRequestParams memory _redeemParams =
IAlephVaultRedeem.RedeemRequestParams({classId: _classId, estAmountToRedeem: _estAmountToRedeem});
return IAlephVaultRedeem(_vault).syncRedeem(_redeemParams);
}
/*//////////////////////////////////////////////////////////////
SLASHED TOKEN OPERATIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Validates balance and burns slashed tokens
* @param _tokenHolder The token holder address
* @param _slashedStrategy The slashed strategy
* @param _tokenAmount The amount to burn
* @param _contractAddress The contract address to transfer tokens to
*/
function validateAndBurnSlashedTokens(
address _tokenHolder,
IStrategy _slashedStrategy,
uint256 _tokenAmount,
address _contractAddress
) internal {
IMintableBurnableERC20 _slashedToken = IMintableBurnableERC20(address(_slashedStrategy.underlyingToken()));
IERC20 _token = IERC20(address(_slashedToken));
if (_token.balanceOf(_tokenHolder) < _tokenAmount) revert InsufficientBalance();
_token.safeTransferFrom(_tokenHolder, _contractAddress, _tokenAmount);
_slashedToken.burn(_contractAddress, _tokenAmount);
}
error InsufficientBalance();
/*//////////////////////////////////////////////////////////////
STRATEGY DEPOSIT OPERATIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Deposits tokens back into the original strategy on behalf of a staker
* @param _strategyManager The StrategyManager contract
* @param _targetStrategy The target strategy to deposit to (from initializeVault)
* @param _token The token to deposit
* @param _staker The staker address
* @param _tokenAmount The token amount to deposit
* @param _expiry The expiry timestamp for the signature
* @param _signature The staker's signature
* @return shares The shares received in the strategy
*/
function depositToOriginalStrategy(
IStrategyManager _strategyManager,
IStrategy _targetStrategy,
IERC20 _token,
address _staker,
uint256 _tokenAmount,
uint256 _expiry,
bytes calldata _signature
) internal returns (uint256 shares) {
AlephValidation.validateStrategy(address(_targetStrategy));
SafeERC20.forceApprove(_token, address(_strategyManager), _tokenAmount);
shares = _strategyManager.depositIntoStrategyWithSignature(
_targetStrategy, IERC20Eigen(address(_token)), _tokenAmount, _staker, _expiry, _signature
);
SafeERC20.forceApprove(_token, address(_strategyManager), 0);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20 as IERC20Eigen} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IRewardsCoordinatorTypes} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {AlephUtils} from "./AlephUtils.sol";
/**
* @title RewardsManagement
* @notice Library for managing rewards submissions to EigenLayer's RewardsCoordinator
* @dev Handles operator-directed rewards for vault allocations
*/
library RewardsManagement {
using SafeERC20 for IERC20;
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/// @dev Number of intervals to look back for retroactive rewards (EigenLayer requirement)
uint256 private constant RETROACTIVE_INTERVALS = 2;
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error OperatorSplitNotZero();
/**
* @notice Submits operator-directed rewards to RewardsCoordinator
* @param _rewardsCoordinator The RewardsCoordinator contract
* @param _avsAddress The AVS address submitting rewards
* @param _operator The operator receiving rewards
* @param _stakerStrategy The strategy used for reward calculation
* @param _rewardToken The token to distribute as rewards
* @param _rewardAmount The amount of rewards to distribute
* @param _rewardsDescription The description for the rewards submission
* @dev Creates a retroactive rewards submission that covers the previous calculation interval
*/
function submitOperatorDirectedRewards(
IRewardsCoordinator _rewardsCoordinator,
address _avsAddress,
address _operator,
IStrategy _stakerStrategy,
IERC20Eigen _rewardToken,
uint256 _rewardAmount,
string memory _rewardsDescription
) internal {
IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory strategiesAndMultipliers =
createStrategyAndMultiplierArray(_stakerStrategy);
IRewardsCoordinatorTypes.OperatorReward[] memory operatorRewards =
createOperatorRewardArray(_operator, _rewardAmount);
(uint32 _startTimestamp, uint32 _duration) = calculateRetroactiveRewardsWindow(_rewardsCoordinator);
IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[] memory rewardsSubmissions =
createRewardsSubmissionArray(
strategiesAndMultipliers, _rewardToken, operatorRewards, _startTimestamp, _duration, _rewardsDescription
);
// Approve RewardsCoordinator to spend tokens using SafeERC20
SafeERC20.forceApprove(IERC20(address(_rewardToken)), address(_rewardsCoordinator), _rewardAmount);
_rewardsCoordinator.createOperatorDirectedAVSRewardsSubmission(_avsAddress, rewardsSubmissions);
// Reset approval to 0 after use
SafeERC20.forceApprove(IERC20(address(_rewardToken)), address(_rewardsCoordinator), 0);
}
/**
* @notice Creates a single-element StrategyAndMultiplier array
* @param _strategy The strategy
* @return Array containing the strategy with default multiplier
*/
function createStrategyAndMultiplierArray(IStrategy _strategy)
internal
pure
returns (IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory)
{
IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory arr =
new IRewardsCoordinatorTypes.StrategyAndMultiplier[](1);
arr[0] = IRewardsCoordinatorTypes.StrategyAndMultiplier({
strategy: _strategy, multiplier: AlephUtils.REWARD_MULTIPLIER
});
return arr;
}
/**
* @notice Creates a single-element OperatorReward array
* @param _operator The operator
* @param _amount The reward amount
* @return Array containing the operator reward
*/
function createOperatorRewardArray(address _operator, uint256 _amount)
internal
pure
returns (IRewardsCoordinatorTypes.OperatorReward[] memory)
{
IRewardsCoordinatorTypes.OperatorReward[] memory arr = new IRewardsCoordinatorTypes.OperatorReward[](1);
arr[0] = IRewardsCoordinatorTypes.OperatorReward({operator: _operator, amount: _amount});
return arr;
}
/**
* @notice Creates a single-element OperatorDirectedRewardsSubmission array
* @param _strategiesAndMultipliers The strategies and multipliers
* @param _token The reward token
* @param _operatorRewards The operator rewards
* @param _startTimestamp The start timestamp
* @param _duration The duration
* @param _description The description
* @return Array containing the rewards submission
*/
function createRewardsSubmissionArray(
IRewardsCoordinatorTypes.StrategyAndMultiplier[] memory _strategiesAndMultipliers,
IERC20Eigen _token,
IRewardsCoordinatorTypes.OperatorReward[] memory _operatorRewards,
uint32 _startTimestamp,
uint32 _duration,
string memory _description
) internal pure returns (IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[] memory) {
IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[] memory arr =
new IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission[](1);
arr[0] = IRewardsCoordinatorTypes.OperatorDirectedRewardsSubmission({
strategiesAndMultipliers: _strategiesAndMultipliers,
token: _token,
operatorRewards: _operatorRewards,
startTimestamp: _startTimestamp,
duration: _duration,
description: _description
});
return arr;
}
/**
* @notice Calculates retroactive rewards window for EigenLayer submission
* @param _rewardsCoordinator The RewardsCoordinator contract
* @return startTimestamp The start timestamp for the rewards window
* @return duration The duration of the rewards window (one interval)
* @dev Uses RETROACTIVE_INTERVALS to ensure rewards are based on pre-slash share amounts
*/
function calculateRetroactiveRewardsWindow(IRewardsCoordinator _rewardsCoordinator)
internal
view
returns (uint32 startTimestamp, uint32 duration)
{
uint32 interval = _rewardsCoordinator.CALCULATION_INTERVAL_SECONDS();
startTimestamp = uint32(((block.timestamp / interval) - RETROACTIVE_INTERVALS) * interval);
duration = interval;
}
/**
* @notice Validates that operator's AVS split is 0 (100% to stakers)
* @param _rewardsCoordinator The RewardsCoordinator contract
* @param _operator The operator address
* @param _avsAddress The AVS address
* @dev getOperatorAVSSplit returns a uint16 value in basis points (bips):
* - Range: 0 to 10,000 (inclusive)
* - 0 = 0% to operator, 100% to stakers (required)
* - 10,000 = 100% to operator, 0% to stakers
* - If operator hasn't set a custom split, returns defaultOperatorSplitBips (typically 1000 = 10%)
* - Reverts if the split is not 0, ensuring all rewards go to stakers
*/
function validateOperatorSplit(IRewardsCoordinator _rewardsCoordinator, address _operator, address _avsAddress)
internal
view
{
uint16 operatorSplit = _rewardsCoordinator.getOperatorAVSSplit(_operator, _avsAddress);
if (operatorSplit != 0) {
revert OperatorSplitNotZero();
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAlephVaultRedeem} from "Aleph/src/interfaces/IAlephVaultRedeem.sol";
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
/**
* @title UnallocateManagement
* @notice Library for managing unallocate operations
* @dev Handles calculation logic for unallocate operations to reduce contract size
*/
library UnallocateManagement {
/**
* @notice Calculates the user's proportional share for complete unallocate
* @dev Calculates share based on proportional distribution. If user is the last one or calculated
* share exceeds available, they receive all remaining withdrawn amount.
* @param _userPendingAmount The user's pending unallocation amount
* @param _totalPending The total pending unallocation amount across all users
* @param _totalRedeemableAmount The total redeemable amount (vault redeemable + previously withdrawn)
* @param _withdrawnAmount The currently withdrawn amount stored in contract
* @return _userShare The user's calculated share amount
*/
function calculateUserShare(
uint256 _userPendingAmount,
uint256 _totalPending,
uint256 _totalRedeemableAmount,
uint256 _withdrawnAmount
) internal pure returns (uint256 _userShare) {
if (_totalPending == 0 || _userPendingAmount == 0) {
return 0;
}
// Calculate user's share: (userPending / totalPending) * totalRedeemable
_userShare = (_userPendingAmount * _totalRedeemableAmount) / _totalPending;
// If this is the last user (or only user), they get all remaining withdrawn amount
if (_totalPending == _userPendingAmount || _userShare > _withdrawnAmount) {
_userShare = _withdrawnAmount > 0 ? _withdrawnAmount : _totalRedeemableAmount;
}
}
/**
* @notice Calculates the expected amount for complete unallocate (pure view function)
* @dev This is a pure function that calculates the expected amount before any state changes.
* Used for signature generation. Handles proportional distribution and edge cases.
* @param _userPendingAmount The user's pending unallocation amount
* @param _totalPending The total pending unallocation amount across all users
* @param _vaultRedeemableAmount The current redeemable amount available in the vault
* @param _withdrawnAmount The amount previously withdrawn and stored in contract
* @return _expectedAmount The expected amount the user will receive (0 if no pending or no redeemable)
*/
function calculateCompleteUnallocateAmountView(
uint256 _userPendingAmount,
uint256 _totalPending,
uint256 _vaultRedeemableAmount,
uint256 _withdrawnAmount
) internal pure returns (uint256 _expectedAmount) {
if (_userPendingAmount == 0) {
return 0;
}
uint256 _totalRedeemableAmount = _vaultRedeemableAmount + _withdrawnAmount;
if (_totalRedeemableAmount == 0 || _totalPending == 0) {
return 0;
}
// Calculate expected share: (userPending / totalPending) * totalRedeemable
_expectedAmount = (_userPendingAmount * _totalRedeemableAmount) / _totalPending;
// Available amount is what can actually be withdrawn:
// - If vault has new redeemable: available = vaultRedeemable + withdrawn (will be withdrawn in completeUnallocate)
// - If vault has no new redeemable: available = withdrawn (already withdrawn)
uint256 _availableAmount = _vaultRedeemableAmount > 0 ? _totalRedeemableAmount : _withdrawnAmount;
// If this is the last user (or only user), they get all remaining available amount
// Also if calculated share exceeds available, cap to available (last user gets remainder)
if (_totalPending == _userPendingAmount) {
// Last user gets all available
_expectedAmount = _availableAmount;
} else if (_expectedAmount > _availableAmount) {
// Calculated share exceeds available, cap to available
_expectedAmount = _availableAmount;
}
}
/**
* @notice Withdraws redeemable amount from vault and calculates total available
* @dev Withdraws new redeemable funds if available, otherwise uses previously withdrawn amount.
* Verifies actual contract balance when using previously withdrawn funds.
* @param _alephVault The vault address to withdraw from
* @param _vaultToken The vault token contract
* @param _vaultRedeemableAmount The current redeemable amount available in the vault
* @param _withdrawnAmount The amount previously withdrawn and stored in contract state
* @return _totalRedeemableAmount The total amount available (newly withdrawn + previously withdrawn)
* @custom:reverts If no funds are available (should be checked before calling)
*/
function withdrawAndCalculateAvailable(
address _alephVault,
IERC20 _vaultToken,
uint256 _vaultRedeemableAmount,
uint256 _withdrawnAmount
) internal returns (uint256 _totalRedeemableAmount) {
if (_vaultRedeemableAmount > 0) {
// Withdraw new redeemable amount from vault
IAlephVaultRedeem(_alephVault).withdrawRedeemableAmount();
_totalRedeemableAmount = _vaultRedeemableAmount + _withdrawnAmount;
} else if (_withdrawnAmount > 0) {
// Use previously withdrawn amount, but check actual contract balance
uint256 _contractBalance = _vaultToken.balanceOf(address(this));
_totalRedeemableAmount = _contractBalance < _withdrawnAmount ? _contractBalance : _withdrawnAmount;
} else {
// No funds available - this should be caught before calling this function
revert();
}
}
/**
* @notice Calculates the final amount to withdraw, capping to available balances
* @dev Caps the calculated share to both available amount and contract balance to ensure
* we never attempt to withdraw more than what's actually available.
* @param _calculatedShare The user's calculated proportional share
* @param _availableAmount The amount available for withdrawal (vault-specific)
* @param _contractBalance The contract's current token balance (global safety check)
* @return _finalAmount The final amount to withdraw (capped to minimum of share, available, and balance)
* @custom:reverts If final amount is zero after capping
*/
function calculateFinalAmount(uint256 _calculatedShare, uint256 _availableAmount, uint256 _contractBalance)
internal
pure
returns (uint256 _finalAmount)
{
_finalAmount = _calculatedShare;
// Cap to available amount
if (_finalAmount > _availableAmount) {
_finalAmount = _availableAmount;
}
// Cap to contract balance
if (_finalAmount > _contractBalance) {
_finalAmount = _contractBalance;
}
if (_finalAmount == 0) {
revert();
}
}
/**
* @notice Calculates new storage values after processing unallocation
* @dev Pure function that calculates what storage values should be after completing an unallocation.
* Reduces withdrawn amount by the amount used, reduces total pending by user's pending amount.
* Clears withdrawn amount if no more pending unallocations remain.
* @param _currentVaultWithdrawnAmount Current total withdrawn amount stored for this vault
* @param _amount The amount being withdrawn and used in this unallocation
* @param _userPendingAmount The user's pending unallocation amount being processed
* @param _totalPending The total pending unallocation amount across all users
* @return _newVaultWithdrawnAmount New vault withdrawn amount (current - amount used, or 0 if no pending left)
* @return _newTotalPending New total pending amount (total - user's pending, or 0 if invalid)
*/
function calculateUnallocationStorageUpdates(
uint256 _currentVaultWithdrawnAmount,
uint256 _amount,
uint256 _userPendingAmount,
uint256 _totalPending
) internal pure returns (uint256 _newVaultWithdrawnAmount, uint256 _newTotalPending) {
// Update vault withdrawn amount: subtract the amount being used
_newVaultWithdrawnAmount = _currentVaultWithdrawnAmount - _amount;
// Update total pending: subtract user's pending amount
if (_userPendingAmount > _totalPending) {
_newTotalPending = 0;
} else {
_newTotalPending = _totalPending - _userPendingAmount;
}
// If no more pending unallocations, clear withdrawn amount
if (_newTotalPending == 0 && _newVaultWithdrawnAmount > 0) {
_newVaultWithdrawnAmount = 0;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol";
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
import {IAlephVaultFactory} from "Aleph/src/interfaces/IAlephVaultFactory.sol";
import {AlephUtils} from "./AlephUtils.sol";
/**
* @title AlephValidation
* @notice Library for validation logic across Aleph contracts
* @dev Provides validation functions for operator sets, vaults, and strategies
*/
library AlephValidation {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error InvalidOperatorSet();
error NotMemberOfOperatorSet();
error InvalidAlephVault();
error InvalidStrategy();
/**
* @notice Validates operator set and membership
* @param _allocationManager The AllocationManager contract
* @param _operator The operator address
* @param _operatorSet The operator set
*/
function validateOperatorSetAndMembership(
IAllocationManager _allocationManager,
address _operator,
OperatorSet memory _operatorSet
) internal view {
if (!_allocationManager.isOperatorSet(_operatorSet)) revert InvalidOperatorSet();
if (!_allocationManager.isMemberOfOperatorSet(_operator, _operatorSet)) revert NotMemberOfOperatorSet();
}
/*//////////////////////////////////////////////////////////////
VAULT VALIDATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Validates that an address is a valid Aleph vault
* @param _vaultFactory The Aleph Vault Factory contract
* @param _alephVault The vault address to validate
*/
function validateVault(IAlephVaultFactory _vaultFactory, address _alephVault) internal view {
if (!_vaultFactory.isValidVault(_alephVault)) {
revert InvalidAlephVault();
}
}
/*//////////////////////////////////////////////////////////////
STRATEGY VALIDATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Validates that a strategy address is not zero
* @param _strategy The strategy address
*/
function validateStrategy(address _strategy) internal pure {
if (_strategy == address(0)) {
revert InvalidStrategy();
}
}
}// 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
* @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;
/**
* @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.0;
/// @title ISemVerMixin
/// @notice A mixin interface that provides semantic versioning functionality.
/// @dev Follows SemVer 2.0.0 specification (https://semver.org/)
interface ISemVerMixin {
/// @notice Returns the semantic version string of the contract.
/// @return The version string in SemVer format (e.g., "1.1.1")
function version() external view returns (string memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "./ISemVerMixin.sol";
interface ISignatureUtilsMixinErrors {
/// @notice Thrown when a signature is invalid.
error InvalidSignature();
/// @notice Thrown when a signature has expired.
error SignatureExpired();
}
interface ISignatureUtilsMixinTypes {
/// @notice Struct that bundles together a signature and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
/// @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature.
/// @dev Used primarily for stack management.
struct SignatureWithSaltAndExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the salt used to generate the signature
bytes32 salt;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
}
/**
* @title The interface for common signature utilities.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface ISignatureUtilsMixin is ISignatureUtilsMixinErrors, ISignatureUtilsMixinTypes, ISemVerMixin {
/// @notice Computes the EIP-712 domain separator used for signature validation.
/// @dev The domain separator is computed according to EIP-712 specification, using:
/// - The hardcoded name "EigenLayer"
/// - The contract's version string
/// - The current chain ID
/// - This contract's address
/// @return The 32-byte domain separator hash used in EIP-712 structured data signing.
/// @dev See https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator.
function domainSeparator() external view returns (bytes32);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin-upgrades/contracts/utils/math/SafeCastUpgradeable.sol";
/// @dev All scaling factors have `1e18` as an initial/default value. This value is represented
/// by the constant `WAD`, which is used to preserve precision with uint256 math.
///
/// When applying scaling factors, they are typically multiplied/divided by `WAD`, allowing this
/// constant to act as a "1" in mathematical formulae.
uint64 constant WAD = 1e18;
/*
* There are 2 types of shares:
* 1. deposit shares
* - These can be converted to an amount of tokens given a strategy
* - by calling `sharesToUnderlying` on the strategy address (they're already tokens
* in the case of EigenPods)
* - These live in the storage of the EigenPodManager and individual StrategyManager strategies
* 2. withdrawable shares
* - For a staker, this is the amount of shares that they can withdraw
* - For an operator, the shares delegated to them are equal to the sum of their stakers'
* withdrawable shares
*
* Along with a slashing factor, the DepositScalingFactor is used to convert between the two share types.
*/
struct DepositScalingFactor {
uint256 _scalingFactor;
}
using SlashingLib for DepositScalingFactor global;
library SlashingLib {
using Math for uint256;
using SlashingLib for uint256;
using SafeCastUpgradeable for uint256;
/// @dev Thrown if an updated deposit scaling factor is 0 to avoid underflow.
error InvalidDepositScalingFactor();
// WAD MATH
function mulWad(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(y, WAD);
}
function divWad(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(WAD, y);
}
/**
* @notice Used explicitly for calculating slashed magnitude, we want to ensure even in the
* situation where an operator is slashed several times and precision has been lost over time,
* an incoming slashing request isn't rounded down to 0 and an operator is able to avoid slashing penalties.
*/
function mulWadRoundUp(uint256 x, uint256 y) internal pure returns (uint256) {
return x.mulDiv(y, WAD, Math.Rounding.Up);
}
// GETTERS
function scalingFactor(
DepositScalingFactor memory dsf
) internal pure returns (uint256) {
return dsf._scalingFactor == 0 ? WAD : dsf._scalingFactor;
}
function scaleForQueueWithdrawal(
DepositScalingFactor memory dsf,
uint256 depositSharesToWithdraw
) internal pure returns (uint256) {
return depositSharesToWithdraw.mulWad(dsf.scalingFactor());
}
function scaleForCompleteWithdrawal(uint256 scaledShares, uint256 slashingFactor) internal pure returns (uint256) {
return scaledShares.mulWad(slashingFactor);
}
/**
* @notice Scales shares according to the difference in an operator's magnitude before and
* after being slashed. This is used to calculate the number of slashable shares in the
* withdrawal queue.
* NOTE: max magnitude is guaranteed to only ever decrease.
*/
function scaleForBurning(
uint256 scaledShares,
uint64 prevMaxMagnitude,
uint64 newMaxMagnitude
) internal pure returns (uint256) {
return scaledShares.mulWad(prevMaxMagnitude - newMaxMagnitude);
}
function update(
DepositScalingFactor storage dsf,
uint256 prevDepositShares,
uint256 addedShares,
uint256 slashingFactor
) internal {
if (prevDepositShares == 0) {
// If this is the staker's first deposit or they are delegating to an operator,
// the slashing factor is inverted and applied to the existing DSF. This has the
// effect of "forgiving" prior slashing for any subsequent deposits.
dsf._scalingFactor = dsf.scalingFactor().divWad(slashingFactor);
return;
}
/**
* Base Equations:
* (1) newShares = currentShares + addedShares
* (2) newDepositShares = prevDepositShares + addedShares
* (3) newShares = newDepositShares * newDepositScalingFactor * slashingFactor
*
* Plugging (1) into (3):
* (4) newDepositShares * newDepositScalingFactor * slashingFactor = currentShares + addedShares
*
* Solving for newDepositScalingFactor
* (5) newDepositScalingFactor = (currentShares + addedShares) / (newDepositShares * slashingFactor)
*
* Plugging in (2) into (5):
* (7) newDepositScalingFactor = (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor)
* Note that magnitudes must be divided by WAD for precision. Thus,
*
* (8) newDepositScalingFactor = WAD * (currentShares + addedShares) / ((prevDepositShares + addedShares) * slashingFactor / WAD)
* (9) newDepositScalingFactor = (currentShares + addedShares) * WAD / (prevDepositShares + addedShares) * WAD / slashingFactor
*/
// Step 1: Calculate Numerator
uint256 currentShares = dsf.calcWithdrawable(prevDepositShares, slashingFactor);
// Step 2: Compute currentShares + addedShares
uint256 newShares = currentShares + addedShares;
// Step 3: Calculate newDepositScalingFactor
/// forgefmt: disable-next-item
uint256 newDepositScalingFactor = newShares
.divWad(prevDepositShares + addedShares)
.divWad(slashingFactor);
dsf._scalingFactor = newDepositScalingFactor;
// Avoid potential underflow.
require(newDepositScalingFactor != 0, InvalidDepositScalingFactor());
}
/// @dev Reset the staker's DSF for a strategy by setting it to 0. This is the same
/// as setting it to WAD (see the `scalingFactor` getter above).
///
/// A DSF is reset when a staker reduces their deposit shares to 0, either by queueing
/// a withdrawal, or undelegating from their operator. This ensures that subsequent
/// delegations/deposits do not use a stale DSF (e.g. from a prior operator).
function reset(
DepositScalingFactor storage dsf
) internal {
dsf._scalingFactor = 0;
}
// CONVERSION
function calcWithdrawable(
DepositScalingFactor memory dsf,
uint256 depositShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return depositShares
.mulWad(dsf.scalingFactor())
.mulWad(slashingFactor);
}
function calcDepositShares(
DepositScalingFactor memory dsf,
uint256 withdrawableShares,
uint256 slashingFactor
) internal pure returns (uint256) {
/// forgefmt: disable-next-item
return withdrawableShares
.divWad(dsf.scalingFactor())
.divWad(slashingFactor);
}
function calcSlashedAmount(
uint256 operatorShares,
uint256 prevMaxMagnitude,
uint256 newMaxMagnitude
) internal pure returns (uint256) {
// round up mulDiv so we don't overslash
return operatorShares - operatorShares.mulDiv(newMaxMagnitude, prevMaxMagnitude, Math.Rounding.Up);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "../libraries/SlashingLib.sol";
import "./IStrategy.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/OperatorSetLib.sol";
/**
* @title Interface for a `IShareManager` contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice This contract is used by the DelegationManager as a unified interface to interact with the EigenPodManager and StrategyManager
*/
interface IShareManager {
/// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @return updatedShares the staker's deposit shares after decrement
function removeDepositShares(
address staker,
IStrategy strategy,
uint256 depositSharesToRemove
) external returns (uint256);
/// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @return existingDepositShares the shares the staker had before any were added
/// @return addedShares the new shares added to the staker's balance
function addShares(address staker, IStrategy strategy, uint256 shares) external returns (uint256, uint256);
/// @notice Used by the DelegationManager to convert deposit shares to tokens and send them to a staker
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @dev token is not validated when talking to the EigenPodManager
function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external;
/// @notice Returns the current shares of `user` in `strategy`
/// @dev strategy must be beaconChainETH when talking to the EigenPodManager
/// @dev returns 0 if the user has negative shares
function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares);
/**
* @notice Increase the amount of burnable/redistributable shares for a given Strategy. This is called by the DelegationManager
* when an operator is slashed in EigenLayer.
* @param operatorSet The operator set to burn shares in.
* @param slashId The slash id to burn shares in.
* @param strategy The strategy to burn shares in.
* @param addedSharesToBurn The amount of added shares to burn.
* @dev This function is only called by the DelegationManager when an operator is slashed.
*/
function increaseBurnOrRedistributableShares(
OperatorSet calldata operatorSet,
uint256 slashId,
IStrategy strategy,
uint256 addedSharesToBurn
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import "./IETHPOSDeposit.sol";
import "./IStrategyManager.sol";
import "./IEigenPod.sol";
import "./IShareManager.sol";
import "./IPausable.sol";
import "./IStrategy.sol";
import "./ISemVerMixin.sol";
interface IEigenPodManagerErrors {
/// @dev Thrown when caller is not a EigenPod.
error OnlyEigenPod();
/// @dev Thrown when caller is not DelegationManager.
error OnlyDelegationManager();
/// @dev Thrown when caller already has an EigenPod.
error EigenPodAlreadyExists();
/// @dev Thrown when shares is not a multiple of gwei.
error SharesNotMultipleOfGwei();
/// @dev Thrown when shares would result in a negative integer.
error SharesNegative();
/// @dev Thrown when the strategy is not the beaconChainETH strategy.
error InvalidStrategy();
/// @dev Thrown when the pods shares are negative and a beacon chain balance update is attempted.
/// The podOwner should complete legacy withdrawal first.
error LegacyWithdrawalsNotCompleted();
/// @dev Thrown when caller is not the proof timestamp setter
error OnlyProofTimestampSetter();
}
interface IEigenPodManagerEvents {
/// @notice Emitted to notify the deployment of an EigenPod
event PodDeployed(address indexed eigenPod, address indexed podOwner);
/// @notice Emitted to notify a deposit of beacon chain ETH recorded in the strategy manager
event BeaconChainETHDeposited(address indexed podOwner, uint256 amount);
/// @notice Emitted when the balance of an EigenPod is updated
event PodSharesUpdated(address indexed podOwner, int256 sharesDelta);
/// @notice Emitted every time the total shares of a pod are updated
event NewTotalShares(address indexed podOwner, int256 newTotalShares);
/// @notice Emitted when a withdrawal of beacon chain ETH is completed
event BeaconChainETHWithdrawalCompleted(
address indexed podOwner,
uint256 shares,
uint96 nonce,
address delegatedAddress,
address withdrawer,
bytes32 withdrawalRoot
);
/// @notice Emitted when a staker's beaconChainSlashingFactor is updated
event BeaconChainSlashingFactorDecreased(
address staker, uint64 prevBeaconChainSlashingFactor, uint64 newBeaconChainSlashingFactor
);
/// @notice Emitted when an operator is slashed and shares to be burned are increased
event BurnableETHSharesIncreased(uint256 shares);
/// @notice Emitted when the Pectra fork timestamp is updated
event PectraForkTimestampSet(uint64 newPectraForkTimestamp);
/// @notice Emitted when the proof timestamp setter is updated
event ProofTimestampSetterSet(address newProofTimestampSetter);
}
interface IEigenPodManagerTypes {
/**
* @notice The amount of beacon chain slashing experienced by a pod owner as a proportion of WAD
* @param isSet whether the slashingFactor has ever been updated. Used to distinguish between
* a value of "0" and an uninitialized value.
* @param slashingFactor the proportion of the pod owner's balance that has been decreased due to
* slashing or other beacon chain balance decreases.
* @dev NOTE: if !isSet, `slashingFactor` should be treated as WAD. `slashingFactor` is monotonically
* decreasing and can hit 0 if fully slashed.
*/
struct BeaconChainSlashingFactor {
bool isSet;
uint64 slashingFactor;
}
}
/**
* @title Interface for factory that creates and manages solo staking pods that have their withdrawal credentials pointed to EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
*/
interface IEigenPodManager is
IEigenPodManagerErrors,
IEigenPodManagerEvents,
IEigenPodManagerTypes,
IShareManager,
IPausable,
ISemVerMixin
{
/**
* @notice Creates an EigenPod for the sender.
* @dev Function will revert if the `msg.sender` already has an EigenPod.
* @dev Returns EigenPod address
*/
function createPod() external returns (address);
/**
* @notice Stakes for a new beacon chain validator on the sender's EigenPod.
* Also creates an EigenPod for the sender if they don't have one already.
* @param pubkey The 48 bytes public key of the beacon chain validator.
* @param signature The validator's signature of the deposit data.
* @param depositDataRoot The root/hash of the deposit data for the validator's deposit.
*/
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;
/**
* @notice Adds any positive share delta to the pod owner's deposit shares, and delegates them to the pod
* owner's operator (if applicable). A negative share delta does NOT impact the pod owner's deposit shares,
* but will reduce their beacon chain slashing factor and delegated shares accordingly.
* @param podOwner is the pod owner whose balance is being updated.
* @param prevRestakedBalanceWei is the total amount restaked through the pod before the balance update, including
* any amount currently in the withdrawal queue.
* @param balanceDeltaWei is the amount the balance changed
* @dev Callable only by the podOwner's EigenPod contract.
* @dev Reverts if `sharesDelta` is not a whole Gwei amount
*/
function recordBeaconChainETHBalanceUpdate(
address podOwner,
uint256 prevRestakedBalanceWei,
int256 balanceDeltaWei
) external;
/// @notice Sets the address that can set proof timestamps
function setProofTimestampSetter(
address newProofTimestampSetter
) external;
/// @notice Sets the Pectra fork timestamp, only callable by `proofTimestampSetter`
function setPectraForkTimestamp(
uint64 timestamp
) external;
/// @notice Returns the address of the `podOwner`'s EigenPod if it has been deployed.
function ownerToPod(
address podOwner
) external view returns (IEigenPod);
/// @notice Returns the address of the `podOwner`'s EigenPod (whether it is deployed yet or not).
function getPod(
address podOwner
) external view returns (IEigenPod);
/// @notice The ETH2 Deposit Contract
function ethPOS() external view returns (IETHPOSDeposit);
/// @notice Beacon proxy to which the EigenPods point
function eigenPodBeacon() external view returns (IBeacon);
/// @notice Returns 'true' if the `podOwner` has created an EigenPod, and 'false' otherwise.
function hasPod(
address podOwner
) external view returns (bool);
/// @notice Returns the number of EigenPods that have been created
function numPods() external view returns (uint256);
/**
* @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy.
* @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can
* decrease between the pod owner queuing and completing a withdrawal.
* When the pod owner's shares would otherwise increase, this "deficit" is decreased first _instead_.
* Likewise, when a withdrawal is completed, this "deficit" is decreased and the withdrawal amount is decreased; We can think of this
* as the withdrawal "paying off the deficit".
*/
function podOwnerDepositShares(
address podOwner
) external view returns (int256);
/// @notice returns canonical, virtual beaconChainETH strategy
function beaconChainETHStrategy() external view returns (IStrategy);
/**
* @notice Returns the historical sum of proportional balance decreases a pod owner has experienced when
* updating their pod's balance.
*/
function beaconChainSlashingFactor(
address staker
) external view returns (uint64);
/// @notice Returns the accumulated amount of beacon chain ETH Strategy shares
function burnableETHShares() external view returns (uint256);
/// @notice Returns the timestamp of the Pectra hard fork
/// @dev Specifically, this returns the timestamp of the first non-missed slot at or after the Pectra hard fork
function pectraForkTimestamp() external view returns (uint64);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.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: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-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: BUSL-1.1
pragma solidity ^0.8.0;
/*
______ __ __
/ \ / | / |
/$$$$$$ |$$ | ______ ______ $$ |____
$$ |__$$ |$$ | / \ / \ $$ \
$$ $$ |$$ |/$$$$$$ |/$$$$$$ |$$$$$$$ |
$$$$$$$$ |$$ |$$ $$ |$$ | $$ |$$ | $$ |
$$ | $$ |$$ |$$$$$$$$/ $$ |__$$ |$$ | $$ |
$$ | $$ |$$ |$$ |$$ $$/ $$ | $$ |
$$/ $$/ $$/ $$$$$$$/ $$$$$$$/ $$/ $$/
$$ |
$$ |
$$/
*/
import {ECDSA} from "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol";
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
library AuthLibrary {
using ECDSA for bytes32;
using MessageHashUtils for bytes32;
/**
* @notice The flow for the settle deposit.
*/
bytes4 internal constant SETTLE_DEPOSIT = bytes4(keccak256("SETTLE_DEPOSIT"));
/**
* @notice The flow for the settle redeem.
*/
bytes4 internal constant SETTLE_REDEEM = bytes4(keccak256("SETTLE_REDEEM"));
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice The error thrown when the auth signature is expired.
*/
error AuthSignatureExpired();
/**
* @notice The error thrown when the auth signature is invalid.
*/
error InvalidAuthSignature();
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice The auth signature.
* @param authSignature The auth signature.
* @param expiryBlock The expiry block.
*/
struct AuthSignature {
bytes authSignature;
uint256 expiryBlock;
}
/*//////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Verifies the vault deployment auth signature.
* @param _vaultFactory The vault factory.
* @param _name The name of the vault.
* @param _configId The config ID of the vault.
* @param _authSigner The auth signer.
* @param _authSignature The auth signature.
*/
function verifyVaultDeploymentAuthSignature(
address _vaultFactory,
string memory _name,
string memory _configId,
address _authSigner,
AuthSignature memory _authSignature
) internal view {
bytes32 _hash = keccak256(
abi.encode(msg.sender, _vaultFactory, _name, _configId, block.chainid, _authSignature.expiryBlock)
);
_verifyAuthSignature(_hash, _authSigner, _authSignature);
}
/**
* @notice Verifies the deposit request auth signature.
* @param _classId The class ID of the deposit request.
* @param _authSigner The auth signer.
* @param _authSignature The auth signature.
*/
function verifyDepositRequestAuthSignature(uint8 _classId, address _authSigner, AuthSignature memory _authSignature)
internal
view
{
bytes32 _hash =
keccak256(abi.encode(msg.sender, address(this), block.chainid, _classId, _authSignature.expiryBlock));
_verifyAuthSignature(_hash, _authSigner, _authSignature);
}
/**
* @notice Verifies the settlement auth signature.
* @param _flow The flow of the settlement.
* @param _classId The class ID of the settlement.
* @param _toBatchId The batch ID of the settlement.
* @param _manager The manager of the settlement.
* @param _newTotalAssets The new total assets of the settlement.
* @param _authSigner The auth signer.
* @param _authSignature The auth signature.
*/
function verifySettlementAuthSignature(
bytes4 _flow,
uint8 _classId,
uint48 _toBatchId,
address _manager,
uint256[] calldata _newTotalAssets,
address _authSigner,
AuthSignature memory _authSignature
) internal view {
bytes32 _hash = keccak256(
abi.encode(
_flow,
_manager,
address(this),
block.chainid,
_classId,
_toBatchId,
_newTotalAssets,
_authSignature.expiryBlock
)
);
_verifyAuthSignature(_hash, _authSigner, _authSignature);
}
/**
* @notice Verifies the auth signature.
* @param _hash The hash of the auth signature.
* @param _authSigner The auth signer.
* @param _authSignature The auth signature.
*/
function _verifyAuthSignature(bytes32 _hash, address _authSigner, AuthSignature memory _authSignature)
internal
view
{
if (_authSignature.expiryBlock < block.number) {
revert AuthSignatureExpired();
}
address _signer = _hash.toEthSignedMessageHash().recover(_authSignature.authSignature);
if (_signer != _authSigner) {
revert InvalidAuthSignature();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
import {Arrays} from "../Arrays.sol";
import {Math} from "../math/Math.sol";
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* The following types are supported:
*
* - `bytes32` (`Bytes32Set`) since v3.3.0
* - `address` (`AddressSet`) since v3.3.0
* - `uint256` (`UintSet`) since v3.3.0
* - `string` (`StringSet`) since v5.4.0
* - `bytes` (`BytesSet`) since v5.4.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: This function has an unbounded cost that scales with set size. Developers should keep in mind that
* using it may render the function uncallable if the set grows to the point where clearing it consumes too much
* gas to fit in a block.
*/
function _clear(Set storage set) private {
uint256 len = _length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set, uint256 start, uint256 end) private view returns (bytes32[] memory) {
unchecked {
end = Math.min(end, _length(set));
start = Math.min(start, end);
uint256 len = end - start;
bytes32[] memory result = new bytes32[](len);
for (uint256 i = 0; i < len; ++i) {
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
}
return result;
}
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(Bytes32Set storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set, uint256 start, uint256 end) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner, start, end);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(AddressSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set, uint256 start, uint256 end) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner, start, end);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(UintSet storage set) internal {
_clear(set._inner);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set, uint256 start, uint256 end) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner, start, end);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
struct StringSet {
// Storage of set values
string[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(string value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(StringSet storage set, string memory value) internal returns (bool) {
if (!contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(StringSet storage set, string memory value) internal returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
string memory lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(StringSet storage set) internal {
uint256 len = length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(StringSet storage set, string memory value) internal view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(StringSet storage set) internal view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(StringSet storage set, uint256 index) internal view returns (string memory) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(StringSet storage set) internal view returns (string[] memory) {
return set._values;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(StringSet storage set, uint256 start, uint256 end) internal view returns (string[] memory) {
unchecked {
end = Math.min(end, length(set));
start = Math.min(start, end);
uint256 len = end - start;
string[] memory result = new string[](len);
for (uint256 i = 0; i < len; ++i) {
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
}
return result;
}
}
struct BytesSet {
// Storage of set values
bytes[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(BytesSet storage set, bytes memory value) internal returns (bool) {
if (!contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(BytesSet storage set, bytes memory value) internal returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes memory lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Removes all the values from a set. O(n).
*
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
*/
function clear(BytesSet storage set) internal {
uint256 len = length(set);
for (uint256 i = 0; i < len; ++i) {
delete set._positions[set._values[i]];
}
Arrays.unsafeSetLength(set._values, 0);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(BytesSet storage set, bytes memory value) internal view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(BytesSet storage set) internal view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(BytesSet storage set, uint256 index) internal view returns (bytes memory) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(BytesSet storage set) internal view returns (bytes[] memory) {
return set._values;
}
/**
* @dev Return a slice of the set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(BytesSet storage set, uint256 start, uint256 end) internal view returns (bytes[] memory) {
unchecked {
end = Math.min(end, length(set));
start = Math.min(start, end);
uint256 len = end - start;
bytes[] memory result = new bytes[](len);
for (uint256 i = 0; i < len; ++i) {
result[i] = Arrays.unsafeAccess(set._values, start + i).value;
}
return result;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol";
import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
/**
* @title ERC20Token
* @notice Mintable/burnable ERC20 token for representing slashed vault shares
* @dev On Sepolia testnet, anyone can mint and burn tokens for testing purposes.
* On all other chains (including mainnet), only the owner (AlephAVS) can mint and burn tokens.
*/
contract ERC20Token is ERC20, Ownable {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when tokens are minted
* @param to The address receiving the minted tokens
* @param amount The amount of tokens minted
*/
event SlashedTokenMinted(address indexed to, uint256 amount);
/**
* @notice Emitted when tokens are burned
* @param from The address whose tokens are burned
* @param amount The amount of tokens burned
*/
event SlashedTokenBurned(address indexed from, uint256 amount);
uint8 private immutable DECIMALS;
/// @dev Mainnet chain ID (1)
uint256 private constant MAINNET_CHAIN_ID = 1;
/// @dev Sepolia testnet chain ID (11155111)
uint256 private constant SEPOLIA_CHAIN_ID = 11155111;
/**
* @notice Constructs the ERC20Token contract
* @param _name The name of the token
* @param _symbol The symbol of the token
* @param _decimals The number of decimals for the token
* @param _owner The owner of the contract
*/
constructor(string memory _name, string memory _symbol, uint8 _decimals, address _owner)
ERC20(_name, _symbol)
Ownable(_owner)
{
DECIMALS = _decimals;
}
/**
* @notice Returns the number of decimals for the token
* @return The number of decimals
*/
function decimals() public view virtual override returns (uint8) {
return DECIMALS;
}
/**
* @notice Mints new tokens to the specified address
* @param to The address to receive the tokens
* @param amount The amount of tokens to mint
* @dev On Sepolia testnet, anyone can mint. On other chains, only the owner can mint.
*/
function mint(address to, uint256 amount) external {
// On Sepolia testnet, allow anyone to mint. On other chains, require owner.
if (block.chainid == SEPOLIA_CHAIN_ID) {
// Sepolia testnet - allow anyone, no owner check needed
} else {
_checkOwner();
}
_mint(to, amount);
emit SlashedTokenMinted(to, amount);
}
/**
* @notice Burns tokens from the specified address
* @param from The address to burn tokens from
* @param amount The amount of tokens to burn
* @dev On Sepolia testnet, anyone can burn. On other chains, only the owner can burn.
*/
function burn(address from, uint256 amount) external {
// On Sepolia testnet, allow anyone to burn. On other chains, require owner.
if (block.chainid == SEPOLIA_CHAIN_ID) {
// Sepolia testnet - allow anyone, no owner check needed
} else {
_checkOwner();
}
_burn(from, amount);
emit SlashedTokenBurned(from, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
/**
* @author Othentic Labs LTD.
* @notice Terms of Service: https://aleph.finance/terms-of-service
*/
interface IAlephAVSPausable {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when a flow is paused
* @param _pausableFlow The flow identifier
* @param _pauser The address that paused the flow
*/
event FlowPaused(bytes4 _pausableFlow, address _pauser);
/**
* @notice Emitted when a flow is unpaused
* @param _pausableFlow The flow identifier
* @param _unpauser The address that unpaused the flow
*/
event FlowUnpaused(bytes4 _pausableFlow, address _unpauser);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted when a flow is currently paused
*/
error FlowIsCurrentlyPaused();
/**
* @notice Emitted when a flow is currently unpaused
*/
error FlowIsCurrentlyUnpaused();
/*//////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Checks if a specific flow is currently paused
* @param _pausableFlow The flow identifier to check
* @return True if the flow is paused, false otherwise
*/
function isFlowPaused(bytes4 _pausableFlow) external view returns (bool);
/*//////////////////////////////////////////////////////////////
PAUSING FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Pauses a specific flow to prevent its execution
* @param _pausableFlow The flow identifier to pause
* @dev Only callable by users with the flow-specific role. Reverts if flow is already paused.
*/
function pause(bytes4 _pausableFlow) external;
/**
* @notice Unpauses a specific flow to allow its execution
* @param _pausableFlow The flow identifier to unpause
* @dev Only callable by users with the flow-specific role. Reverts if flow is not paused.
*/
function unpause(bytes4 _pausableFlow) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(account),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* @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 v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* 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 {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 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 low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, 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.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
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⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// 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²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev 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) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @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 + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
/**
* @dev Counts the number of leading zero bits in a uint256.
*/
function clz(uint256 x) internal pure returns (uint256) {
return ternary(x == 0, 256, 255 - log2(x));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.30;
import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol";
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
/**
* @title AlephUtils
* @notice Utility library for common functions used across Aleph contracts
* @dev This library provides reusable utility functions to reduce code duplication
*/
library AlephUtils {
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
uint32 public constant LST_STRATEGIES_OPERATOR_SET_ID = 0;
uint32 public constant SLASHED_STRATEGIES_OPERATOR_SET_ID = 1;
uint64 public constant OPERATOR_SET_MAGNITUDE = 1e18;
uint256 public constant WAD = 1e18;
uint96 public constant REWARD_MULTIPLIER = uint96(1e18);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
error InvalidAddress();
/*//////////////////////////////////////////////////////////////
VALIDATION FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Validates that an address is not the zero address
* @param _address The address to validate
* @dev Reverts with InvalidAddress if the address is zero
*/
function validateAddress(address _address) internal pure {
if (_address == address(0)) {
revert InvalidAddress();
}
}
/**
* @notice Validates that an address is not the zero address with custom error selector
* @param _address The address to validate
* @param _errorSelector The error selector to use if validation fails
* @dev Uses assembly to revert with the provided error selector
*/
function validateAddressWithSelector(address _address, bytes4 _errorSelector) internal pure {
if (_address == address(0)) {
assembly {
mstore(0x00, _errorSelector)
revert(0x00, 0x04)
}
}
}
/*//////////////////////////////////////////////////////////////
STRATEGY FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Converts a single strategy to an array
* @param _strategy The strategy to convert
* @return An array containing the single strategy
*/
function asStrategyArray(IStrategy _strategy) internal pure returns (IStrategy[] memory) {
IStrategy[] memory arr = new IStrategy[](1);
arr[0] = _strategy;
return arr;
}
/**
* @notice Creates a single-element strategy array with magnitude
* @param _strategy The strategy
* @param _magnitude The magnitude
* @return strategies Array of strategies
* @return magnitudes Array of magnitudes
*/
function createStrategyAllocationParams(IStrategy _strategy, uint64 _magnitude)
internal
pure
returns (IStrategy[] memory strategies, uint64[] memory magnitudes)
{
strategies = new IStrategy[](1);
strategies[0] = _strategy;
magnitudes = new uint64[](1);
magnitudes[0] = _magnitude;
}
/*//////////////////////////////////////////////////////////////
OPERATOR SET FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Gets an operator set for a given AVS address
* @param _avsAddress The AVS contract address
* @param _operatorSetId The operator set ID
* @return The operator set
*/
function getOperatorSet(address _avsAddress, uint32 _operatorSetId) internal pure returns (OperatorSet memory) {
return OperatorSet(_avsAddress, _operatorSetId);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
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: BUSL-1.1
pragma solidity ^0.8.0;
import {Math} from "openzeppelin-contracts/contracts/utils/math/Math.sol";
/**
* @dev This library adds helper functions for ERC4626 math operations.
*/
library ERC4626Math {
using Math for uint256;
/**
* @notice The total number of share units alloted to any user in a given class.
*/
uint256 public constant TOTAL_SHARE_UNITS = 1e18;
function previewDeposit(uint256 assets, uint256 totalShares, uint256 totalAssets) internal pure returns (uint256) {
return convertToShares(assets, totalShares, totalAssets, Math.Rounding.Floor);
}
function previewMint(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return convertToAssets(shares, totalAssets, totalShares, Math.Rounding.Ceil);
}
function previewWithdraw(uint256 assets, uint256 totalShares, uint256 totalAssets) internal pure returns (uint256) {
return convertToShares(assets, totalShares, totalAssets, Math.Rounding.Ceil);
}
function previewRedeem(uint256 shares, uint256 totalAssets, uint256 totalShares) internal pure returns (uint256) {
return convertToAssets(shares, totalAssets, totalShares, Math.Rounding.Floor);
}
/**
* @notice Preview the amount of assets to redeem based on the number of share units.
* @param shareUnits The number of share units to redeem.
* @param totalAssets The total amount of assets.
* @return The amount of assets to redeem.
*/
function previewMintUnits(uint256 shareUnits, uint256 totalAssets) internal pure returns (uint256) {
return convertToAssets(shareUnits, totalAssets);
}
/**
* @notice Preview the number of share units to redeem based on the amount of assets.
* @param assets The amount of assets to withdraw.
* @param totalAssets The total amount of assets.
* @return The number of share units to redeem.
*/
function previewWithdrawUnits(uint256 assets, uint256 totalAssets) internal pure returns (uint256) {
return convertToShareUnits(assets, totalAssets);
}
/**
* @dev Internal conversion function (from assets to shares) with support for rounding direction.
*/
function convertToShares(uint256 assets, uint256 totalShares, uint256 totalAssets, Math.Rounding rounding)
internal
pure
returns (uint256)
{
return assets.mulDiv(totalShares + 10 ** _decimalsOffset(), totalAssets + 1, rounding);
}
/**
* @dev Internal conversion function (from shares to assets) with support for rounding direction.
*/
function convertToAssets(uint256 shares, uint256 totalAssets, uint256 totalShares, Math.Rounding rounding)
internal
pure
returns (uint256)
{
return shares.mulDiv(totalAssets + 1, totalShares + 10 ** _decimalsOffset(), rounding);
}
/**
* @dev Internal conversion function (from assets to share units) with support for rounding direction.
*/
function convertToShareUnits(uint256 assets, uint256 totalAssets) internal pure returns (uint256) {
return assets.mulDiv(TOTAL_SHARE_UNITS, totalAssets, Math.Rounding.Floor);
}
/**
* @dev Internal conversion function (from share units to assets) with support for rounding direction.
*/
function convertToAssets(uint256 shareUnits, uint256 totalAssets) internal pure returns (uint256) {
return shareUnits.mulDiv(totalAssets, TOTAL_SHARE_UNITS, Math.Rounding.Ceil);
}
function _decimalsOffset() private pure returns (uint8) {
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.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: CC0-1.0
pragma solidity >=0.5.0;
// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IETHPOSDeposit {
/// @notice A processed deposit event.
event DepositEvent(bytes pubkey, bytes withdrawal_credentials, bytes amount, bytes signature, bytes index);
/// @notice Submit a Phase 0 DepositData object.
/// @param pubkey A BLS12-381 public key.
/// @param withdrawal_credentials Commitment to a public key for withdrawals.
/// @param signature A BLS12-381 signature.
/// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
/// Used as a protection against malformed input.
function deposit(
bytes calldata pubkey,
bytes calldata withdrawal_credentials,
bytes calldata signature,
bytes32 deposit_data_root
) external payable;
/// @notice Query the current deposit root hash.
/// @return The deposit root hash.
function get_deposit_root() external view returns (bytes32);
/// @notice Query the current deposit count.
/// @return The deposit count encoded as a little endian 64-bit number.
function get_deposit_count() external view returns (bytes memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../libraries/BeaconChainProofs.sol";
import "./ISemVerMixin.sol";
import "./IEigenPodManager.sol";
interface IEigenPodErrors {
/// @dev Thrown when msg.sender is not the EPM.
error OnlyEigenPodManager();
/// @dev Thrown when msg.sender is not the pod owner.
error OnlyEigenPodOwner();
/// @dev Thrown when msg.sender is not owner or the proof submitter.
error OnlyEigenPodOwnerOrProofSubmitter();
/// @dev Thrown when attempting an action that is currently paused.
error CurrentlyPaused();
/// Invalid Inputs
/// @dev Thrown when an address of zero is provided.
error InputAddressZero();
/// @dev Thrown when two array parameters have mismatching lengths.
error InputArrayLengthMismatch();
/// @dev Thrown when `validatorPubKey` length is not equal to 48-bytes.
error InvalidPubKeyLength();
/// @dev Thrown when provided timestamp is out of range.
error TimestampOutOfRange();
/// Checkpoints
/// @dev Thrown when no active checkpoints are found.
error NoActiveCheckpoint();
/// @dev Thrown if an uncompleted checkpoint exists.
error CheckpointAlreadyActive();
/// @dev Thrown if there's not a balance available to checkpoint.
error NoBalanceToCheckpoint();
/// @dev Thrown when attempting to create a checkpoint twice within a given block.
error CannotCheckpointTwiceInSingleBlock();
/// Withdrawing
/// @dev Thrown when amount exceeds `restakedExecutionLayerGwei`.
error InsufficientWithdrawableBalance();
/// Validator Status
/// @dev Thrown when a validator's withdrawal credentials have already been verified.
error CredentialsAlreadyVerified();
/// @dev Thrown if the provided proof is not valid for this EigenPod.
error WithdrawalCredentialsNotForEigenPod();
/// @dev Thrown when a validator is not in the ACTIVE status in the pod.
error ValidatorNotActiveInPod();
/// @dev Thrown when validator is not active yet on the beacon chain.
error ValidatorInactiveOnBeaconChain();
/// @dev Thrown if a validator is exiting the beacon chain.
error ValidatorIsExitingBeaconChain();
/// @dev Thrown when a validator has not been slashed on the beacon chain.
error ValidatorNotSlashedOnBeaconChain();
/// Consolidation and Withdrawal Requests
/// @dev Thrown when a predeploy request is initiated with insufficient msg.value
error InsufficientFunds();
/// @dev Thrown when calling the predeploy fails
error PredeployFailed();
/// @dev Thrown when querying a predeploy for its current fee fails
error FeeQueryFailed();
/// Misc
/// @dev Thrown when an invalid block root is returned by the EIP-4788 oracle.
error InvalidEIP4788Response();
/// @dev Thrown when attempting to send an invalid amount to the beacon deposit contract.
error MsgValueNot32ETH();
/// @dev Thrown when provided `beaconTimestamp` is too far in the past.
error BeaconTimestampTooFarInPast();
/// @dev Thrown when provided `beaconTimestamp` is before the last checkpoint
error BeaconTimestampBeforeLatestCheckpoint();
/// @dev Thrown when the pectraForkTimestamp returned from the EigenPodManager is zero
error ForkTimestampZero();
}
interface IEigenPodTypes {
enum VALIDATOR_STATUS {
INACTIVE, // doesnt exist
ACTIVE, // staked on ethpos and withdrawal credentials are pointed to the EigenPod
WITHDRAWN // withdrawn from the Beacon Chain
}
/**
* @param validatorIndex index of the validator on the beacon chain
* @param restakedBalanceGwei amount of beacon chain ETH restaked on EigenLayer in gwei
* @param lastCheckpointedAt timestamp of the validator's most recent balance update
* @param status last recorded status of the validator
*/
struct ValidatorInfo {
uint64 validatorIndex;
uint64 restakedBalanceGwei;
uint64 lastCheckpointedAt;
VALIDATOR_STATUS status;
}
struct Checkpoint {
bytes32 beaconBlockRoot;
uint24 proofsRemaining;
uint64 podBalanceGwei;
int64 balanceDeltasGwei;
uint64 prevBeaconBalanceGwei;
}
/**
* @param srcPubkey the pubkey of the source validator for the consolidation
* @param targetPubkey the pubkey of the target validator for the consolidation
* @dev Note that if srcPubkey == targetPubkey, this is a "switch request," and will
* change the validator's withdrawal credential type from 0x01 to 0x02.
* For more notes on usage, see `requestConsolidation`
*/
struct ConsolidationRequest {
bytes srcPubkey;
bytes targetPubkey;
}
/**
* @param pubkey the pubkey of the validator to withdraw from
* @param amountGwei the amount (in gwei) to withdraw from the beacon chain to the pod
* @dev Note that if amountGwei == 0, this is a "full exit request," and will fully exit
* the validator to the pod.
* For more notes on usage, see `requestWithdrawal`
*/
struct WithdrawalRequest {
bytes pubkey;
uint64 amountGwei;
}
}
interface IEigenPodEvents is IEigenPodTypes {
/// @notice Emitted when an ETH validator stakes via this eigenPod
event EigenPodStaked(bytes32 pubkeyHash);
/// @notice Emitted when a pod owner updates the proof submitter address
event ProofSubmitterUpdated(address prevProofSubmitter, address newProofSubmitter);
/// @notice Emitted when an ETH validator's withdrawal credentials are successfully verified to be pointed to this eigenPod
event ValidatorRestaked(bytes32 pubkeyHash);
/// @notice Emitted when an ETH validator's balance is proven to be updated. Here newValidatorBalanceGwei
// is the validator's balance that is credited on EigenLayer.
event ValidatorBalanceUpdated(bytes32 pubkeyHash, uint64 balanceTimestamp, uint64 newValidatorBalanceGwei);
/// @notice Emitted when restaked beacon chain ETH is withdrawn from the eigenPod.
event RestakedBeaconChainETHWithdrawn(address indexed recipient, uint256 amount);
/// @notice Emitted when ETH is received via the `receive` fallback
event NonBeaconChainETHReceived(uint256 amountReceived);
/// @notice Emitted when a checkpoint is created
event CheckpointCreated(
uint64 indexed checkpointTimestamp, bytes32 indexed beaconBlockRoot, uint256 validatorCount
);
/// @notice Emitted when a checkpoint is finalized
event CheckpointFinalized(uint64 indexed checkpointTimestamp, int256 totalShareDeltaWei);
/// @notice Emitted when a validator is proven for a given checkpoint
event ValidatorCheckpointed(uint64 indexed checkpointTimestamp, bytes32 indexed pubkeyHash);
/// @notice Emitted when a validator is proven to have 0 balance at a given checkpoint
event ValidatorWithdrawn(uint64 indexed checkpointTimestamp, bytes32 indexed pubkeyHash);
/// @notice Emitted when a consolidation request is initiated where source == target
event SwitchToCompoundingRequested(bytes32 indexed validatorPubkeyHash);
/// @notice Emitted when a standard consolidation request is initiated
event ConsolidationRequested(bytes32 indexed sourcePubkeyHash, bytes32 indexed targetPubkeyHash);
/// @notice Emitted when a withdrawal request is initiated where request.amountGwei == 0
event ExitRequested(bytes32 indexed validatorPubkeyHash);
/// @notice Emitted when a partial withdrawal request is initiated
event WithdrawalRequested(bytes32 indexed validatorPubkeyHash, uint64 withdrawalAmountGwei);
}
/**
* @title The implementation contract used for restaking beacon chain ETH on EigenLayer
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @dev Note that all beacon chain balances are stored as gwei within the beacon chain datastructures. We choose
* to account balances in terms of gwei in the EigenPod contract and convert to wei when making calls to other contracts
*/
interface IEigenPod is IEigenPodErrors, IEigenPodEvents, ISemVerMixin {
/// @notice Used to initialize the pointers to contracts crucial to the pod's functionality, in beacon proxy construction from EigenPodManager
function initialize(
address owner
) external;
/// @notice Called by EigenPodManager when the owner wants to create another ETH validator.
/// @dev This function only supports staking to a 0x01 validator. For compounding validators, please interact directly with the deposit contract.
function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable;
/**
* @notice Transfers `amountWei` from this contract to the `recipient`. Only callable by the EigenPodManager as part
* of the DelegationManager's withdrawal flow.
* @dev `amountWei` is not required to be a whole Gwei amount. Amounts less than a Gwei multiple may be unrecoverable due to Gwei conversion.
*/
function withdrawRestakedBeaconChainETH(address recipient, uint256 amount) external;
/**
* @dev Create a checkpoint used to prove this pod's active validator set. Checkpoints are completed
* by submitting one checkpoint proof per ACTIVE validator. During the checkpoint process, the total
* change in ACTIVE validator balance is tracked, and any validators with 0 balance are marked `WITHDRAWN`.
* @dev Once finalized, the pod owner is awarded shares corresponding to:
* - the total change in their ACTIVE validator balances
* - any ETH in the pod not already awarded shares
* @dev A checkpoint cannot be created if the pod already has an outstanding checkpoint. If
* this is the case, the pod owner MUST complete the existing checkpoint before starting a new one.
* @param revertIfNoBalance Forces a revert if the pod ETH balance is 0. This allows the pod owner
* to prevent accidentally starting a checkpoint that will not increase their shares
*/
function startCheckpoint(
bool revertIfNoBalance
) external;
/**
* @dev Progress the current checkpoint towards completion by submitting one or more validator
* checkpoint proofs. Anyone can call this method to submit proofs towards the current checkpoint.
* For each validator proven, the current checkpoint's `proofsRemaining` decreases.
* @dev If the checkpoint's `proofsRemaining` reaches 0, the checkpoint is finalized.
* (see `_updateCheckpoint` for more details)
* @dev This method can only be called when there is a currently-active checkpoint.
* @param balanceContainerProof proves the beacon's current balance container root against a checkpoint's `beaconBlockRoot`
* @param proofs Proofs for one or more validator current balances against the `balanceContainerRoot`
*/
function verifyCheckpointProofs(
BeaconChainProofs.BalanceContainerProof calldata balanceContainerProof,
BeaconChainProofs.BalanceProof[] calldata proofs
) external;
/**
* @dev Verify one or more validators have their withdrawal credentials pointed at this EigenPod, and award
* shares based on their effective balance. Proven validators are marked `ACTIVE` within the EigenPod, and
* future checkpoint proofs will need to include them.
* @dev Withdrawal credential proofs MUST NOT be older than `currentCheckpointTimestamp`.
* @dev Validators proven via this method MUST NOT have an exit epoch set already.
* @param beaconTimestamp the beacon chain timestamp sent to the 4788 oracle contract. Corresponds
* to the parent beacon block root against which the proof is verified.
* @param stateRootProof proves a beacon state root against a beacon block root
* @param validatorIndices a list of validator indices being proven
* @param validatorFieldsProofs proofs of each validator's `validatorFields` against the beacon state root
* @param validatorFields the fields of the beacon chain "Validator" container. See consensus specs for
* details: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
*/
function verifyWithdrawalCredentials(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
uint40[] calldata validatorIndices,
bytes[] calldata validatorFieldsProofs,
bytes32[][] calldata validatorFields
) external;
/**
* @dev Prove that one of this pod's active validators was slashed on the beacon chain. A successful
* staleness proof allows the caller to start a checkpoint.
*
* @dev Note that in order to start a checkpoint, any existing checkpoint must already be completed!
* (See `_startCheckpoint` for details)
*
* @dev Note that this method allows anyone to start a checkpoint as soon as a slashing occurs on the beacon
* chain. This is intended to make it easier to external watchers to keep a pod's balance up to date.
*
* @dev Note too that beacon chain slashings are not instant. There is a delay between the initial slashing event
* and the validator's final exit back to the execution layer. During this time, the validator's balance may or
* may not drop further due to a correlation penalty. This method allows proof of a slashed validator
* to initiate a checkpoint for as long as the validator remains on the beacon chain. Once the validator
* has exited and been checkpointed at 0 balance, they are no longer "checkpoint-able" and cannot be proven
* "stale" via this method.
* See https://eth2book.info/capella/part3/transition/epoch/#slashings for more info.
*
* @param beaconTimestamp the beacon chain timestamp sent to the 4788 oracle contract. Corresponds
* to the parent beacon block root against which the proof is verified.
* @param stateRootProof proves a beacon state root against a beacon block root
* @param proof the fields of the beacon chain "Validator" container, along with a merkle proof against
* the beacon state root. See the consensus specs for more details:
* https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator
*
* @dev Staleness conditions:
* - Validator's last checkpoint is older than `beaconTimestamp`
* - Validator MUST be in `ACTIVE` status in the pod
* - Validator MUST be slashed on the beacon chain
*/
function verifyStaleBalance(
uint64 beaconTimestamp,
BeaconChainProofs.StateRootProof calldata stateRootProof,
BeaconChainProofs.ValidatorProof calldata proof
) external;
/// @notice Allows the owner or proof submitter to initiate one or more requests to
/// consolidate their validators on the beacon chain.
/// @param requests An array of requests consisting of the source and target pubkeys
/// of the validators to be consolidated
/// @dev The target validator MUST have ACTIVE (proven) withdrawal credentials pointed at
/// the pod. This prevents cross-pod consolidations.
/// @dev The consolidation request predeploy requires a fee is sent with each request;
/// this is pulled from msg.value. After submitting all requests, any remaining fee is
/// refunded to the caller by calling its fallback function.
/// @dev This contract exposes `getConsolidationRequestFee` to query the current fee for
/// a single request. If submitting multiple requests in a single block, the total fee
/// is equal to (fee * requests.length). This fee is updated at the end of each block.
///
/// (See https://eips.ethereum.org/EIPS/eip-7251#fee-calculation for details)
///
/// @dev Note on beacon chain behavior:
/// - If request.srcPubkey == request.targetPubkey, this is a "switch" consolidation. Once
/// processed on the beacon chain, the validator's withdrawal credentials will be changed
/// to compounding (0x02).
/// - The rest of the notes assume src != target.
/// - The target validator MUST already have 0x02 credentials. The source validator can have either.
/// - Consolidation sets the source validator's exit_epoch and withdrawable_epoch, similar to an exit.
/// When the exit epoch is reached, an epoch sweep will process the consolidation and transfer balance
/// from the source to the target validator.
/// - Consolidation transfers min(srcValidator.effective_balance, state.balance[srcIndex]) to the target.
/// This may not be the entirety of the source validator's balance; any remainder will be moved to the
/// pod when hit by a subsequent withdrawal sweep.
///
/// @dev Note that consolidation requests CAN FAIL for a variety of reasons. Failures occur when the request
/// is processed on the beacon chain, and are invisible to the pod. The pod and predeploy cannot guarantee
/// a request will succeed; it's up to the pod owner to determine this for themselves. If your request fails,
/// you can retry by initiating another request via this method.
///
/// Some requirements that are NOT checked by the pod:
/// - If request.srcPubkey == request.targetPubkey, the validator MUST have 0x01 credentials
/// - If request.srcPubkey != request.targetPubkey, the target validator MUST have 0x02 credentials
/// - Both the source and target validators MUST be active on the beacon chain and MUST NOT have
/// initiated exits
/// - The source validator MUST NOT have pending partial withdrawal requests (via `requestWithdrawal`)
/// - If the source validator is slashed after requesting consolidation (but before processing),
/// the consolidation will be skipped.
///
/// For further reference, see consolidation processing at block and epoch boundaries:
/// - Block: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_consolidation_request
/// - Epoch: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_pending_consolidations
function requestConsolidation(
ConsolidationRequest[] calldata requests
) external payable;
/// @notice Allows the owner or proof submitter to initiate one or more requests to
/// withdraw funds from validators on the beacon chain.
/// @param requests An array of requests consisting of the source validator and an
/// amount to withdraw
/// @dev The withdrawal request predeploy requires a fee is sent with each request;
/// this is pulled from msg.value. After submitting all requests, any remaining fee is
/// refunded to the caller by calling its fallback function.
/// @dev This contract exposes `getWithdrawalRequestFee` to query the current fee for
/// a single request. If submitting multiple requests in a single block, the total fee
/// is equal to (fee * requests.length). This fee is updated at the end of each block.
///
/// (See https://eips.ethereum.org/EIPS/eip-7002#fee-update-rule for details)
///
/// @dev Note on beacon chain behavior:
/// - Withdrawal requests have two types: full exit requests, and partial exit requests.
/// Partial exit requests will be skipped if the validator has 0x01 withdrawal credentials.
/// If you want your validators to have access to partial exits, use `requestConsolidation`
/// to change their withdrawal credentials to compounding (0x02).
/// - If request.amount == 0, this is a FULL exit request. A full exit request initiates a
/// standard validator exit.
/// - Other amounts are treated as PARTIAL exit requests. A partial exit request will NOT result
/// in a validator with less than 32 ETH balance. Any requested amount above this is ignored.
/// - The actual amount withdrawn for a partial exit is given by the formula:
/// min(request.amount, state.balances[vIdx] - 32 ETH - pending_balance_to_withdraw)
/// (where `pending_balance_to_withdraw` is the sum of any outstanding partial exit requests)
/// (Note that this means you may request more than is actually withdrawn!)
///
/// @dev Note that withdrawal requests CAN FAIL for a variety of reasons. Failures occur when the request
/// is processed on the beacon chain, and are invisible to the pod. The pod and predeploy cannot guarantee
/// a request will succeed; it's up to the pod owner to determine this for themselves. If your request fails,
/// you can retry by initiating another request via this method.
///
/// Some requirements that are NOT checked by the pod:
/// - request.pubkey MUST be a valid validator pubkey
/// - request.pubkey MUST belong to a validator whose withdrawal credentials are this pod
/// - If request.amount is for a partial exit, the validator MUST have 0x02 withdrawal credentials
/// - If request.amount is for a full exit, the validator MUST NOT have any pending partial exits
/// - The validator MUST be active and MUST NOT have initiated exit
///
/// For further reference: https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-process_withdrawal_request
function requestWithdrawal(
WithdrawalRequest[] calldata requests
) external payable;
/// @notice called by owner of a pod to remove any ERC20s deposited in the pod
function recoverTokens(IERC20[] memory tokenList, uint256[] memory amountsToWithdraw, address recipient) external;
/// @notice Allows the owner of a pod to update the proof submitter, a permissioned
/// address that can call various EigenPod methods, but cannot trigger asset withdrawals
/// from the DelegationManager.
/// @dev Note that EITHER the podOwner OR proofSubmitter can access these methods,
/// so it's fine to set your proofSubmitter to 0 if you want the podOwner to be the
/// only address that can call these methods.
/// @param newProofSubmitter The new proof submitter address. If set to 0, only the
/// pod owner will be able to call EigenPod methods.
function setProofSubmitter(
address newProofSubmitter
) external;
/**
*
* VIEW METHODS
*
*/
/// @notice An address with permissions to call `startCheckpoint` and `verifyWithdrawalCredentials`, set
/// by the podOwner. This role exists to allow a podOwner to designate a hot wallet that can call
/// these methods, allowing the podOwner to remain a cold wallet that is only used to manage funds.
/// @dev If this address is NOT set, only the podOwner can call `startCheckpoint` and `verifyWithdrawalCredentials`
function proofSubmitter() external view returns (address);
/// @notice Native ETH in the pod that has been accounted for in a checkpoint (denominated in gwei).
/// This amount is withdrawable from the pod via the DelegationManager withdrawal flow.
function withdrawableRestakedExecutionLayerGwei() external view returns (uint64);
/// @notice The single EigenPodManager for EigenLayer
function eigenPodManager() external view returns (IEigenPodManager);
/// @notice The owner of this EigenPod
function podOwner() external view returns (address);
/// @notice Returns the validatorInfo struct for the provided pubkeyHash
function validatorPubkeyHashToInfo(
bytes32 validatorPubkeyHash
) external view returns (ValidatorInfo memory);
/// @notice Returns the validatorInfo struct for the provided pubkey
function validatorPubkeyToInfo(
bytes calldata validatorPubkey
) external view returns (ValidatorInfo memory);
/// @notice Returns the validator status for a given validator pubkey hash
function validatorStatus(
bytes32 pubkeyHash
) external view returns (VALIDATOR_STATUS);
/// @notice Returns the validator status for a given validator pubkey
function validatorStatus(
bytes calldata validatorPubkey
) external view returns (VALIDATOR_STATUS);
/// @notice Number of validators with proven withdrawal credentials, who do not have proven full withdrawals
function activeValidatorCount() external view returns (uint256);
/// @notice The timestamp of the last checkpoint finalized
function lastCheckpointTimestamp() external view returns (uint64);
/// @notice The timestamp of the currently-active checkpoint. Will be 0 if there is not active checkpoint
function currentCheckpointTimestamp() external view returns (uint64);
/// @notice Returns the currently-active checkpoint
/// If there's not an active checkpoint, this method returns the checkpoint that was last active.
function currentCheckpoint() external view returns (Checkpoint memory);
/// @notice For each checkpoint, the total balance attributed to exited validators, in gwei
///
/// NOTE that the values added to this mapping are NOT guaranteed to capture the entirety of a validator's
/// exit - rather, they capture the total change in a validator's balance when a checkpoint shows their
/// balance change from nonzero to zero. While a change from nonzero to zero DOES guarantee that a validator
/// has been fully exited, it is possible that the magnitude of this change does not capture what is
/// typically thought of as a "full exit."
///
/// For example:
/// 1. Consider a validator was last checkpointed at 32 ETH before exiting. Once the exit has been processed,
/// it is expected that the validator's exited balance is calculated to be `32 ETH`.
/// 2. However, before `startCheckpoint` is called, a deposit is made to the validator for 1 ETH. The beacon
/// chain will automatically withdraw this ETH, but not until the withdrawal sweep passes over the validator
/// again. Until this occurs, the validator's current balance (used for checkpointing) is 1 ETH.
/// 3. If `startCheckpoint` is called at this point, the balance delta calculated for this validator will be
/// `-31 ETH`, and because the validator has a nonzero balance, it is not marked WITHDRAWN.
/// 4. After the exit is processed by the beacon chain, a subsequent `startCheckpoint` and checkpoint proof
/// will calculate a balance delta of `-1 ETH` and attribute a 1 ETH exit to the validator.
///
/// If this edge case impacts your usecase, it should be possible to mitigate this by monitoring for deposits
/// to your exited validators, and waiting to call `startCheckpoint` until those deposits have been automatically
/// exited.
///
/// Additional edge cases this mapping does not cover:
/// - If a validator is slashed, their balance exited will reflect their original balance rather than the slashed amount
/// - The final partial withdrawal for an exited validator will be likely be included in this mapping.
/// i.e. if a validator was last checkpointed at 32.1 ETH before exiting, the next checkpoint will calculate their
/// "exited" amount to be 32.1 ETH rather than 32 ETH.
function checkpointBalanceExitedGwei(
uint64
) external view returns (uint64);
/// @notice Query the 4788 oracle to get the parent block root of the slot with the given `timestamp`
/// @param timestamp of the block for which the parent block root will be returned. MUST correspond
/// to an existing slot within the last 24 hours. If the slot at `timestamp` was skipped, this method
/// will revert.
function getParentBlockRoot(
uint64 timestamp
) external view returns (bytes32);
/// @notice Returns the fee required to add a consolidation request to the EIP-7251 predeploy this block.
/// @dev Note that the predeploy updates its fee every block according to https://eips.ethereum.org/EIPS/eip-7251#fee-calculation
/// Consider overestimating the amount sent to ensure the fee does not update before your transaction.
function getConsolidationRequestFee() external view returns (uint256);
/// @notice Returns the current fee required to add a withdrawal request to the EIP-7002 predeploy.
/// @dev Note that the predeploy updates its fee every block according to https://eips.ethereum.org/EIPS/eip-7002#fee-update-rule
/// Consider overestimating the amount sent to ensure the fee does not update before your transaction.
function getWithdrawalRequestFee() external view returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import "../interfaces/IPauserRegistry.sol";
/**
* @title Adds pausability to a contract, with pausing & unpausing controlled by the `pauser` and `unpauser` of a PauserRegistry contract.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contracts that inherit from this contract may define their own `pause` and `unpause` (and/or related) functions.
* These functions should be permissioned as "onlyPauser" which defers to a `PauserRegistry` for determining access control.
* @dev Pausability is implemented using a uint256, which allows up to 256 different single bit-flags; each bit can potentially pause different functionality.
* Inspiration for this was taken from the NearBridge design here https://etherscan.io/address/0x3FEFc5A4B1c02f21cBc8D3613643ba0635b9a873#code.
* For the `pause` and `unpause` functions we've implemented, if you pause, you can only flip (any number of) switches to on/1 (aka "paused"), and if you unpause,
* you can only flip (any number of) switches to off/0 (aka "paused").
* If you want a pauseXYZ function that just flips a single bit / "pausing flag", it will:
* 1) 'bit-wise and' (aka `&`) a flag with the current paused state (as a uint256)
* 2) update the paused state to this new value
* @dev We note as well that we have chosen to identify flags by their *bit index* as opposed to their numerical value, so, e.g. defining `DEPOSITS_PAUSED = 3`
* indicates specifically that if the *third bit* of `_paused` is flipped -- i.e. it is a '1' -- then deposits should be paused
*/
interface IPausable {
/// @dev Thrown when caller is not pauser.
error OnlyPauser();
/// @dev Thrown when caller is not unpauser.
error OnlyUnpauser();
/// @dev Thrown when currently paused.
error CurrentlyPaused();
/// @dev Thrown when invalid `newPausedStatus` is provided.
error InvalidNewPausedStatus();
/// @dev Thrown when a null address input is provided.
error InputAddressZero();
/// @notice Emitted when the pause is triggered by `account`, and changed to `newPausedStatus`.
event Paused(address indexed account, uint256 newPausedStatus);
/// @notice Emitted when the pause is lifted by `account`, and changed to `newPausedStatus`.
event Unpaused(address indexed account, uint256 newPausedStatus);
/// @notice Address of the `PauserRegistry` contract that this contract defers to for determining access control (for pausing).
function pauserRegistry() external view returns (IPauserRegistry);
/**
* @notice This function is used to pause an EigenLayer contract's functionality.
* It is permissioned to the `pauser` address, which is expected to be a low threshold multisig.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only pause functionality, and thus cannot 'unflip' any bit in `_paused` from 1 to 0.
*/
function pause(
uint256 newPausedStatus
) external;
/**
* @notice Alias for `pause(type(uint256).max)`.
*/
function pauseAll() external;
/**
* @notice This function is used to unpause an EigenLayer contract's functionality.
* It is permissioned to the `unpauser` address, which is expected to be a high threshold multisig or governance contract.
* @param newPausedStatus represents the new value for `_paused` to take, which means it may flip several bits at once.
* @dev This function can only unpause functionality, and thus cannot 'flip' any bit in `_paused` from 0 to 1.
*/
function unpause(
uint256 newPausedStatus
) external;
/// @notice Returns the current paused status as a uint256.
function paused() external view returns (uint256);
/// @notice Returns 'true' if the `indexed`th bit of `_paused` is 1, and 'false' otherwise
function paused(
uint8 index
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction
* is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash
* invalidation or nonces for replay protection.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Variant of {tryRecover} that takes a signature in calldata
*/
function tryRecoverCalldata(
bytes32 hash,
bytes calldata signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, calldata slices would work here, but are
// significantly more expensive (length check) than using calldataload in assembly.
assembly ("memory-safe") {
r := calldataload(signature.offset)
s := calldataload(add(signature.offset, 0x20))
v := byte(0, calldataload(add(signature.offset, 0x40)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction
* is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash
* invalidation or nonces for replay protection.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Variant of {recover} that takes a signature in calldata
*/
function recoverCalldata(bytes32 hash, bytes calldata signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecoverCalldata(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Parse a signature into its `v`, `r` and `s` components. Supports 65-byte and 64-byte (ERC-2098)
* formats. Returns (0,0,0) for invalid signatures. Consider skipping {tryRecover} or {recover} if so.
*/
function parse(bytes memory signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
assembly ("memory-safe") {
// Check the signature length
switch mload(signature)
// - case 65: r,s,v signature (standard)
case 65 {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)
case 64 {
let vs := mload(add(signature, 0x40))
r := mload(add(signature, 0x20))
s := and(vs, shr(1, not(0)))
v := add(shr(255, vs), 27)
}
default {
r := 0
s := 0
v := 0
}
}
}
/**
* @dev Variant of {parse} that takes a signature in calldata
*/
function parseCalldata(bytes calldata signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
assembly ("memory-safe") {
// Check the signature length
switch signature.length
// - case 65: r,s,v signature (standard)
case 65 {
r := calldataload(signature.offset)
s := calldataload(add(signature.offset, 0x20))
v := byte(0, calldataload(add(signature.offset, 0x40)))
}
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
r := calldataload(signature.offset)
s := and(vs, shr(1, not(0)))
v := add(shr(255, vs), 27)
}
default {
r := 0
s := 0
v := 0
}
}
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.24;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.
*/
function toDataWithIntendedValidatorHash(
address validator,
bytes32 messageHash
) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, hex"19_00")
mstore(0x02, shl(96, validator))
mstore(0x16, messageHash)
digest := keccak256(0x00, 0x36)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol)
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
pragma solidity ^0.8.20;
import {Comparators} from "./Comparators.sol";
import {SlotDerivation} from "./SlotDerivation.sol";
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using SlotDerivation for bytes32;
using StorageSlot for bytes32;
/**
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
uint256[] memory array,
function(uint256, uint256) pure returns (bool) comp
) internal pure returns (uint256[] memory) {
_quickSort(_begin(array), _end(array), comp);
return array;
}
/**
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
*/
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
sort(array, Comparators.lt);
return array;
}
/**
* @dev Sort an array of address (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
address[] memory array,
function(address, address) pure returns (bool) comp
) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of address in increasing order.
*/
function sort(address[] memory array) internal pure returns (address[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
*
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
*
* NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the
* array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may
* consume more gas than is available in a block, leading to potential DoS.
*
* IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way.
*/
function sort(
bytes32[] memory array,
function(bytes32, bytes32) pure returns (bool) comp
) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), _castToUint256Comp(comp));
return array;
}
/**
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
*/
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
sort(_castToUint256Array(array), Comparators.lt);
return array;
}
/**
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops
* at end (exclusive). Sorting follows the `comp` comparator.
*
* Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls.
*
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
* be used only if the limits are within a memory array.
*/
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
unchecked {
if (end - begin < 0x40) return;
// Use first element as pivot
uint256 pivot = _mload(begin);
// Position where the pivot should be at the end of the loop
uint256 pos = begin;
for (uint256 it = begin + 0x20; it < end; it += 0x20) {
if (comp(_mload(it), pivot)) {
// If the value stored at the iterator's position comes before the pivot, we increment the
// position of the pivot and move the value there.
pos += 0x20;
_swap(pos, it);
}
}
_swap(begin, pos); // Swap pivot into place
_quickSort(begin, pos, comp); // Sort the left side of the pivot
_quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot
}
}
/**
* @dev Pointer to the memory location of the first element of `array`.
*/
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
assembly ("memory-safe") {
ptr := add(array, 0x20)
}
}
/**
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
* that comes just after the last element of the array.
*/
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
unchecked {
return _begin(array) + array.length * 0x20;
}
}
/**
* @dev Load memory word (as a uint256) at location `ptr`.
*/
function _mload(uint256 ptr) private pure returns (uint256 value) {
assembly {
value := mload(ptr)
}
}
/**
* @dev Swaps the elements memory location `ptr1` and `ptr2`.
*/
function _swap(uint256 ptr1, uint256 ptr2) private pure {
assembly {
let value1 := mload(ptr1)
let value2 := mload(ptr2)
mstore(ptr1, value2)
mstore(ptr2, value1)
}
}
/// @dev Helper: low level cast address memory array to uint256 memory array
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast address comp function to uint256 comp function
function _castToUint256Comp(
function(address, address) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
function _castToUint256Comp(
function(bytes32, bytes32) pure returns (bool) input
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
assembly {
output := input
}
}
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* NOTE: The `array` is expected to be sorted in ascending order, and to
* contain no repeated elements.
*
* IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks
* support for repeated elements in the array. The {lowerBound} function should
* be used instead.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value greater or equal than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound].
*/
function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Searches an `array` sorted in ascending order and returns the first
* index that contains a value strictly greater than `element`. If no such index
* exists (i.e. all values in the array are strictly less than `element`), the array
* length is returned. Time complexity O(log n).
*
* See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound].
*/
function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Same as {lowerBound}, but with an array in memory.
*/
function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) < element) {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
} else {
high = mid;
}
}
return low;
}
/**
* @dev Same as {upperBound}, but with an array in memory.
*/
function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeMemoryAccess(array, mid) > element) {
high = mid;
} else {
// this cannot overflow because mid < high
unchecked {
low = mid + 1;
}
}
}
return low;
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getBytesSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) {
bytes32 slot;
assembly ("memory-safe") {
slot := arr.slot
}
return slot.deriveArray().offset(pos).getStringSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(address[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes32[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(uint256[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(bytes[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
/**
* @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden.
*
* WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased.
*/
function unsafeSetLength(string[] storage array, uint256 len) internal {
assembly ("memory-safe") {
sstore(array.slot, len)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.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}.
*
* 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 ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* Both 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 returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual 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 returns (uint8) {
return 18;
}
/// @inheritdoc IERC20
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/// @inheritdoc IERC20
function balanceOf(address account) public view virtual 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 `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/// @inheritdoc IERC20
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` 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 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* 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 `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` 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.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` 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.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @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 v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool 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.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @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
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
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
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
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
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
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
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
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
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
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
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
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
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
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
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
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
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
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
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
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
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
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
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
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
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
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
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
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
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
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
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
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
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
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
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
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
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
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
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
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
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
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
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
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
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
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
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
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
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
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
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
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
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
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
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
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
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
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
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
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
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
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
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @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
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @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
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @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
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @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
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @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
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @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
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @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
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @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
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @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
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @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
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @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
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @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
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @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
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @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
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @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
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @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
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @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
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @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
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @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
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @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
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @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
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @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
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @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
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @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
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @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
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @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
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @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
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @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
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @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
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @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
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
import "./Merkle.sol";
import "../libraries/Endian.sol";
//Utility library for parsing and PHASE0 beacon chain block headers
//SSZ Spec: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization
//BeaconBlockHeader Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader
//BeaconState Spec: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconstate
library BeaconChainProofs {
/// @dev Thrown when a proof is invalid.
error InvalidProof();
/// @dev Thrown when a proof with an invalid length is provided.
error InvalidProofLength();
/// @dev Thrown when a validator fields length is invalid.
error InvalidValidatorFieldsLength();
/// @notice Heights of various merkle trees in the beacon chain
/// beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// beaconStateRoot
/// / \ HEIGHT: BEACON_STATE_TREE_HEIGHT
/// validatorContainerRoot, balanceContainerRoot
/// | | HEIGHT: BALANCE_TREE_HEIGHT
/// | individual balances
/// | HEIGHT: VALIDATOR_TREE_HEIGHT
/// individual validators
uint256 internal constant BEACON_BLOCK_HEADER_TREE_HEIGHT = 3;
uint256 internal constant DENEB_BEACON_STATE_TREE_HEIGHT = 5;
uint256 internal constant PECTRA_BEACON_STATE_TREE_HEIGHT = 6;
uint256 internal constant BALANCE_TREE_HEIGHT = 38;
uint256 internal constant VALIDATOR_TREE_HEIGHT = 40;
/// @notice Index of the beaconStateRoot in the `BeaconBlockHeader` container
///
/// BeaconBlockHeader = [..., state_root, ...]
/// 0... 3
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblockheader)
uint256 internal constant STATE_ROOT_INDEX = 3;
/// @notice Indices for fields in the `BeaconState` container
///
/// BeaconState = [..., validators, balances, ...]
/// 0... 11 12
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#beaconstate)
uint256 internal constant VALIDATOR_CONTAINER_INDEX = 11;
uint256 internal constant BALANCE_CONTAINER_INDEX = 12;
/// @notice Number of fields in the `Validator` container
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator)
uint256 internal constant VALIDATOR_FIELDS_LENGTH = 8;
/// @notice Indices for fields in the `Validator` container
uint256 internal constant VALIDATOR_PUBKEY_INDEX = 0;
uint256 internal constant VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX = 1;
uint256 internal constant VALIDATOR_BALANCE_INDEX = 2;
uint256 internal constant VALIDATOR_SLASHED_INDEX = 3;
uint256 internal constant VALIDATOR_ACTIVATION_EPOCH_INDEX = 5;
uint256 internal constant VALIDATOR_EXIT_EPOCH_INDEX = 6;
/// @notice Slot/Epoch timings
uint64 internal constant SECONDS_PER_SLOT = 12;
uint64 internal constant SLOTS_PER_EPOCH = 32;
uint64 internal constant SECONDS_PER_EPOCH = SLOTS_PER_EPOCH * SECONDS_PER_SLOT;
/// @notice `FAR_FUTURE_EPOCH` is used as the default value for certain `Validator`
/// fields when a `Validator` is first created on the beacon chain
uint64 internal constant FAR_FUTURE_EPOCH = type(uint64).max;
bytes8 internal constant UINT64_MASK = 0xffffffffffffffff;
/// @notice The beacon chain version to validate against
enum ProofVersion {
DENEB,
PECTRA
}
/// @notice Contains a beacon state root and a merkle proof verifying its inclusion under a beacon block root
struct StateRootProof {
bytes32 beaconStateRoot;
bytes proof;
}
/// @notice Contains a validator's fields and a merkle proof of their inclusion under a beacon state root
struct ValidatorProof {
bytes32[] validatorFields;
bytes proof;
}
/// @notice Contains a beacon balance container root and a proof of this root under a beacon block root
struct BalanceContainerProof {
bytes32 balanceContainerRoot;
bytes proof;
}
/// @notice Contains a validator balance root and a proof of its inclusion under a balance container root
struct BalanceProof {
bytes32 pubkeyHash;
bytes32 balanceRoot;
bytes proof;
}
/**
*
* VALIDATOR FIELDS -> BEACON STATE ROOT -> BEACON BLOCK ROOT
*
*/
/// @notice Verify a merkle proof of the beacon state root against a beacon block root
/// @param beaconBlockRoot merkle root of the beacon block
/// @param proof the beacon state root and merkle proof of its inclusion under `beaconBlockRoot`
function verifyStateRoot(bytes32 beaconBlockRoot, StateRootProof calldata proof) internal view {
require(proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT), InvalidProofLength());
/// This merkle proof verifies the `beaconStateRoot` under the `beaconBlockRoot`
/// - beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// -- beaconStateRoot
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: beaconBlockRoot,
leaf: proof.beaconStateRoot,
index: STATE_ROOT_INDEX
}),
InvalidProof()
);
}
/// @notice Verify a merkle proof of a validator container against a `beaconStateRoot`
/// @dev This proof starts at a validator's container root, proves through the validator container root,
/// and continues proving to the root of the `BeaconState`
/// @dev See https://eth2book.info/capella/part3/containers/dependencies/#validator for info on `Validator` containers
/// @dev See https://eth2book.info/capella/part3/containers/state/#beaconstate for info on `BeaconState` containers
/// @param beaconStateRoot merkle root of the `BeaconState` container
/// @param validatorFields an individual validator's fields. These are merklized to form a `validatorRoot`,
/// which is used as the leaf to prove against `beaconStateRoot`
/// @param validatorFieldsProof a merkle proof of inclusion of `validatorFields` under `beaconStateRoot`
/// @param validatorIndex the validator's unique index
function verifyValidatorFields(
ProofVersion proofVersion,
bytes32 beaconStateRoot,
bytes32[] calldata validatorFields,
bytes calldata validatorFieldsProof,
uint40 validatorIndex
) internal view {
require(validatorFields.length == VALIDATOR_FIELDS_LENGTH, InvalidValidatorFieldsLength());
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofVersion);
/// Note: the reason we use `VALIDATOR_TREE_HEIGHT + 1` here is because the merklization process for
/// this container includes hashing the root of the validator tree with the length of the validator list
require(
validatorFieldsProof.length == 32 * ((VALIDATOR_TREE_HEIGHT + 1) + beaconStateTreeHeight),
InvalidProofLength()
);
// Merkleize `validatorFields` to get the leaf to prove
bytes32 validatorRoot = Merkle.merkleizeSha256(validatorFields);
/// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees:
/// - beaconStateRoot
/// | HEIGHT: BEACON_STATE_TREE_HEIGHT
/// -- validatorContainerRoot
/// | HEIGHT: VALIDATOR_TREE_HEIGHT + 1
/// ---- validatorRoot
uint256 index = (VALIDATOR_CONTAINER_INDEX << (VALIDATOR_TREE_HEIGHT + 1)) | uint256(validatorIndex);
require(
Merkle.verifyInclusionSha256({
proof: validatorFieldsProof,
root: beaconStateRoot,
leaf: validatorRoot,
index: index
}),
InvalidProof()
);
}
/**
*
* VALIDATOR BALANCE -> BALANCE CONTAINER ROOT -> BEACON BLOCK ROOT
*
*/
/// @notice Verify a merkle proof of the beacon state's balances container against the beacon block root
/// @dev This proof starts at the balance container root, proves through the beacon state root, and
/// continues proving through the beacon block root. As a result, this proof will contain elements
/// of a `StateRootProof` under the same block root, with the addition of proving the balances field
/// within the beacon state.
/// @dev This is used to make checkpoint proofs more efficient, as a checkpoint will verify multiple balances
/// against the same balance container root.
/// @param beaconBlockRoot merkle root of the beacon block
/// @param proof a beacon balance container root and merkle proof of its inclusion under `beaconBlockRoot`
function verifyBalanceContainer(
ProofVersion proofVersion,
bytes32 beaconBlockRoot,
BalanceContainerProof calldata proof
) internal view {
uint256 beaconStateTreeHeight = getBeaconStateTreeHeight(proofVersion);
require(
proof.proof.length == 32 * (BEACON_BLOCK_HEADER_TREE_HEIGHT + beaconStateTreeHeight), InvalidProofLength()
);
/// This proof combines two proofs, so its index accounts for the relative position of leaves in two trees:
/// - beaconBlockRoot
/// | HEIGHT: BEACON_BLOCK_HEADER_TREE_HEIGHT
/// -- beaconStateRoot
/// | HEIGHT: BEACON_STATE_TREE_HEIGHT
/// ---- balancesContainerRoot
uint256 index = (STATE_ROOT_INDEX << (beaconStateTreeHeight)) | BALANCE_CONTAINER_INDEX;
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: beaconBlockRoot,
leaf: proof.balanceContainerRoot,
index: index
}),
InvalidProof()
);
}
/// @notice Verify a merkle proof of a validator's balance against the beacon state's `balanceContainerRoot`
/// @param balanceContainerRoot the merkle root of all validators' current balances
/// @param validatorIndex the index of the validator whose balance we are proving
/// @param proof the validator's associated balance root and a merkle proof of inclusion under `balanceContainerRoot`
/// @return validatorBalanceGwei the validator's current balance (in gwei)
function verifyValidatorBalance(
bytes32 balanceContainerRoot,
uint40 validatorIndex,
BalanceProof calldata proof
) internal view returns (uint64 validatorBalanceGwei) {
/// Note: the reason we use `BALANCE_TREE_HEIGHT + 1` here is because the merklization process for
/// this container includes hashing the root of the balances tree with the length of the balances list
require(proof.proof.length == 32 * (BALANCE_TREE_HEIGHT + 1), InvalidProofLength());
/// When merkleized, beacon chain balances are combined into groups of 4 called a `balanceRoot`. The merkle
/// proof here verifies that this validator's `balanceRoot` is included in the `balanceContainerRoot`
/// - balanceContainerRoot
/// | HEIGHT: BALANCE_TREE_HEIGHT
/// -- balanceRoot
uint256 balanceIndex = uint256(validatorIndex / 4);
require(
Merkle.verifyInclusionSha256({
proof: proof.proof,
root: balanceContainerRoot,
leaf: proof.balanceRoot,
index: balanceIndex
}),
InvalidProof()
);
/// Extract the individual validator's balance from the `balanceRoot`
return getBalanceAtIndex(proof.balanceRoot, validatorIndex);
}
/**
* @notice Parses a balanceRoot to get the uint64 balance of a validator.
* @dev During merkleization of the beacon state balance tree, four uint64 values are treated as a single
* leaf in the merkle tree. We use validatorIndex % 4 to determine which of the four uint64 values to
* extract from the balanceRoot.
* @param balanceRoot is the combination of 4 validator balances being proven for
* @param validatorIndex is the index of the validator being proven for
* @return The validator's balance, in Gwei
*/
function getBalanceAtIndex(bytes32 balanceRoot, uint40 validatorIndex) internal pure returns (uint64) {
uint256 bitShiftAmount = (validatorIndex % 4) * 64;
return Endian.fromLittleEndianUint64(bytes32((uint256(balanceRoot) << bitShiftAmount)));
}
/// @notice Indices for fields in the `Validator` container:
/// 0: pubkey
/// 1: withdrawal credentials
/// 2: effective balance
/// 3: slashed?
/// 4: activation eligibility epoch
/// 5: activation epoch
/// 6: exit epoch
/// 7: withdrawable epoch
///
/// (See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator)
/// @dev Retrieves a validator's pubkey hash
function getPubkeyHash(
bytes32[] memory validatorFields
) internal pure returns (bytes32) {
return validatorFields[VALIDATOR_PUBKEY_INDEX];
}
/// @dev Retrieves a validator's withdrawal credentials
function getWithdrawalCredentials(
bytes32[] memory validatorFields
) internal pure returns (bytes32) {
return validatorFields[VALIDATOR_WITHDRAWAL_CREDENTIALS_INDEX];
}
/// @dev Retrieves a validator's effective balance (in gwei)
function getEffectiveBalanceGwei(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_BALANCE_INDEX]);
}
/// @dev Retrieves a validator's activation epoch
function getActivationEpoch(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_ACTIVATION_EPOCH_INDEX]);
}
/// @dev Retrieves true IFF a validator is marked slashed
function isValidatorSlashed(
bytes32[] memory validatorFields
) internal pure returns (bool) {
return validatorFields[VALIDATOR_SLASHED_INDEX] != 0;
}
/// @dev Retrieves a validator's exit epoch
function getExitEpoch(
bytes32[] memory validatorFields
) internal pure returns (uint64) {
return Endian.fromLittleEndianUint64(validatorFields[VALIDATOR_EXIT_EPOCH_INDEX]);
}
/// @dev We check if the proofTimestamp is <= pectraForkTimestamp because a `proofTimestamp` at the `pectraForkTimestamp`
/// is considered to be Pre-Pectra given the EIP-4788 oracle returns the parent block.
function getBeaconStateTreeHeight(
ProofVersion proofVersion
) internal pure returns (uint256) {
return proofVersion == ProofVersion.DENEB ? DENEB_BEACON_STATE_TREE_HEIGHT : PECTRA_BEACON_STATE_TREE_HEIGHT;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Strings.sol)
pragma solidity ^0.8.24;
import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";
import {Bytes} from "./Bytes.sol";
/**
* @dev String operations.
*/
library Strings {
using SafeCast for *;
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
uint256 private constant SPECIAL_CHARS_LOOKUP =
(1 << 0x08) | // backspace
(1 << 0x09) | // tab
(1 << 0x0a) | // newline
(1 << 0x0c) | // form feed
(1 << 0x0d) | // carriage return
(1 << 0x22) | // double quote
(1 << 0x5c); // backslash
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev The string being parsed contains characters that are not in scope of the given base.
*/
error StringsInvalidChar();
/**
* @dev The string being parsed is not a properly formatted address.
*/
error StringsInvalidAddressFormat();
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly ("memory-safe") {
ptr := add(add(buffer, 0x20), length)
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Converts a `bytes` buffer to its ASCII `string` hexadecimal representation.
*/
function toHexString(bytes memory input) internal pure returns (string memory) {
unchecked {
bytes memory buffer = new bytes(2 * input.length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 0; i < input.length; ++i) {
uint8 v = uint8(input[i]);
buffer[2 * i + 2] = HEX_DIGITS[v >> 4];
buffer[2 * i + 3] = HEX_DIGITS[v & 0xf];
}
return string(buffer);
}
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return Bytes.equal(bytes(a), bytes(b));
}
/**
* @dev Parse a decimal string and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input) internal pure returns (uint256) {
return parseUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
uint256 result = 0;
for (uint256 i = begin; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 9) return (false, 0);
result *= 10;
result += chr;
}
return (true, result);
}
/**
* @dev Parse a decimal string and returns the value as a `int256`.
*
* Requirements:
* - The string must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input) internal pure returns (int256) {
return parseInt(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
(bool success, int256 value) = tryParseInt(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
* the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
}
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
/**
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character or if the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, int256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseIntUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseIntUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, int256 value) {
bytes memory buffer = bytes(input);
// Check presence of a negative sign.
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
bool positiveSign = sign == bytes1("+");
bool negativeSign = sign == bytes1("-");
uint256 offset = (positiveSign || negativeSign).toUint();
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
if (absSuccess && absValue < ABS_MIN_INT256) {
return (true, negativeSign ? -int256(absValue) : int256(absValue));
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
return (true, type(int256).min);
} else return (false, 0);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input) internal pure returns (uint256) {
return parseHexUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
* invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseHexUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseHexUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
// skip 0x prefix if present
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 offset = hasPrefix.toUint() * 2;
uint256 result = 0;
for (uint256 i = begin + offset; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 15) return (false, 0);
result *= 16;
unchecked {
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
// This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.
result += chr;
}
}
return (true, result);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input) internal pure returns (address) {
return parseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
(bool success, address value) = tryParseAddress(input, begin, end);
if (!success) revert StringsInvalidAddressFormat();
return value;
}
/**
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
* formatted address. See {parseAddress-string} requirements.
*/
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
return tryParseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
* formatted address. See {parseAddress-string-uint256-uint256} requirements.
*/
function tryParseAddress(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, address value) {
if (end > bytes(input).length || begin > end) return (false, address(0));
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
// check that input is the correct length
if (end - begin == expectedLength) {
// length guarantees that this does not overflow, and value is at most type(uint160).max
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
return (s, address(uint160(v)));
} else {
return (false, address(0));
}
}
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
uint8 value = uint8(chr);
// Try to parse `chr`:
// - Case 1: [0-9]
// - Case 2: [a-f]
// - Case 3: [A-F]
// - otherwise not supported
unchecked {
if (value > 47 && value < 58) value -= 48;
else if (value > 96 && value < 103) value -= 87;
else if (value > 64 && value < 71) value -= 55;
else return type(uint8).max;
}
return value;
}
/**
* @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
*
* WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
*
* NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of
* RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode
* characters that are not in this range, but other tooling may provide different results.
*/
function escapeJSON(string memory input) internal pure returns (string memory) {
bytes memory buffer = bytes(input);
bytes memory output = new bytes(2 * buffer.length); // worst case scenario
uint256 outputLength = 0;
for (uint256 i; i < buffer.length; ++i) {
bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));
if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {
output[outputLength++] = "\\";
if (char == 0x08) output[outputLength++] = "b";
else if (char == 0x09) output[outputLength++] = "t";
else if (char == 0x0a) output[outputLength++] = "n";
else if (char == 0x0c) output[outputLength++] = "f";
else if (char == 0x0d) output[outputLength++] = "r";
else if (char == 0x5c) output[outputLength++] = "\\";
else if (char == 0x22) {
// solhint-disable-next-line quotes
output[outputLength++] = '"';
}
} else {
output[outputLength++] = char;
}
}
// write the actual length and deallocate unused memory
assembly ("memory-safe") {
mstore(output, outputLength)
mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))
}
return string(output);
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(add(buffer, 0x20), offset))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides a set of functions to compare values.
*
* _Available since v5.1._
*/
library Comparators {
function lt(uint256 a, uint256 b) internal pure returns (bool) {
return a < b;
}
function gt(uint256 a, uint256 b) internal pure returns (bool) {
return a > b;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol)
// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js.
pragma solidity ^0.8.20;
/**
* @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots
* corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by
* the solidity language / compiler.
*
* See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.].
*
* Example usage:
* ```solidity
* contract Example {
* // Add the library methods
* using StorageSlot for bytes32;
* using SlotDerivation for bytes32;
*
* // Declare a namespace
* string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot
*
* function setValueInNamespace(uint256 key, address newValue) internal {
* _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue;
* }
*
* function getValueInNamespace(uint256 key) internal view returns (address) {
* return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value;
* }
* }
* ```
*
* TIP: Consider using this library along with {StorageSlot}.
*
* NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking
* upgrade safety will ignore the slots accessed through this library.
*
* _Available since v5.1._
*/
library SlotDerivation {
/**
* @dev Derive an ERC-7201 slot from a string (namespace).
*/
function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) {
assembly ("memory-safe") {
mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1))
slot := and(keccak256(0x00, 0x20), not(0xff))
}
}
/**
* @dev Add an offset to a slot to get the n-th element of a structure or an array.
*/
function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) {
unchecked {
return bytes32(uint256(slot) + pos);
}
}
/**
* @dev Derive the location of the first element in an array from the slot where the length is stored.
*/
function deriveArray(bytes32 slot) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, slot)
result := keccak256(0x00, 0x20)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, and(key, shr(96, not(0))))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, iszero(iszero(key)))
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
mstore(0x00, key)
mstore(0x20, slot)
result := keccak256(0x00, 0x40)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
/**
* @dev Derive the location of a mapping element from the key.
*/
function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) {
assembly ("memory-safe") {
let length := mload(key)
let begin := add(key, 0x20)
let end := add(begin, length)
let cache := mload(end)
mstore(end, slot)
result := keccak256(begin, add(length, 0x20))
mstore(end, cache)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol)
pragma solidity >=0.8.4;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// 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.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, salt the leaves, or hash the leaves with a hash function other than
* what is used for the Merkle tree's internal nodes. This is because the
* concatenation of a sorted pair of internal nodes in the Merkle tree could
* be reinterpreted as a leaf value.
*/
library Merkle {
/// @notice Thrown when the provided proof was not a multiple of 32, or was empty for SHA256.
/// @dev Error code: 0x4dc5f6a4
error InvalidProofLength();
/// @notice Thrown when the provided index was outside the max index for the tree.
/// @dev Error code: 0x63df8171
error InvalidIndex();
/// @notice Thrown when the provided leaves' length was not a power of two.
/// @dev Error code: 0xf6558f51
error LeavesNotPowerOfTwo();
/// @notice Thrown when the provided leaves' length was 0.
/// @dev Error code: 0xbaec3d9a
error NoLeaves();
/// @notice Thrown when the provided leaves' length was insufficient.
/// @dev Error code: 0xf8ef0367
/// @dev This is used for the SHA256 Merkle tree, where the tree must have more than 1 leaf.
error NotEnoughLeaves();
/// @notice Thrown when the root is empty.
/// @dev Error code: 0x53ce4ece
/// @dev Empty roots should never be valid. We prevent them to avoid issues like the Nomad bridge attack: <https://medium.com/nomad-xyz-blog/nomad-bridge-hack-root-cause-analysis-875ad2e5aacd>
error EmptyRoot();
/**
* @notice Verifies that a given leaf is included in a Merkle tree
* @param proof The proof of inclusion for the leaf
* @param root The root of the Merkle tree
* @param leaf The leaf to verify
* @param index The index of the leaf in the Merkle tree
* @return True if the leaf is included in the Merkle tree, false otherwise
* @dev A `proof` is valid if and only if the rebuilt hash matches the root of the tree.
* @dev Reverts for:
* - InvalidProofLength: proof.length is not a multiple of 32.
* - InvalidIndex: index is not 0 at conclusion of computation (implying outside the max index for the tree).
*/
function verifyInclusionKeccak(
bytes memory proof,
bytes32 root,
bytes32 leaf,
uint256 index
) internal pure returns (bool) {
require(root != bytes32(0), EmptyRoot());
return processInclusionProofKeccak(proof, leaf, index) == root;
}
/**
* @notice Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`.
* @param proof The proof of inclusion for the leaf
* @param leaf The leaf to verify
* @param index The index of the leaf in the Merkle tree
* @return The rebuilt hash
* @dev Reverts for:
* - InvalidProofLength: proof.length is not a multiple of 32.
* - InvalidIndex: index is not 0 at conclusion of computation (implying outside the max index for the tree).
* @dev The tree is built assuming `leaf` is the 0 indexed `index`'th leaf from the bottom left of the tree.
*/
function processInclusionProofKeccak(
bytes memory proof,
bytes32 leaf,
uint256 index
) internal pure returns (bytes32) {
if (proof.length == 0) {
return leaf;
}
require(proof.length % 32 == 0, InvalidProofLength());
bytes32 computedHash = leaf;
for (uint256 i = 32; i <= proof.length; i += 32) {
if (index % 2 == 0) {
// if index is even, 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 index is odd, then computedHash is a right sibling
assembly {
mstore(0x00, mload(add(proof, i)))
mstore(0x20, computedHash)
computedHash := keccak256(0x00, 0x40)
index := div(index, 2)
}
}
}
// Confirm proof was fully consumed by end of computation
require(index == 0, InvalidIndex());
return computedHash;
}
/**
* @notice Verifies that a given leaf is included in a Merkle tree
* @param proof The proof of inclusion for the leaf
* @param root The root of the Merkle tree
* @param leaf The leaf to verify
* @param index The index of the leaf in the Merkle tree
* @return True if the leaf is included in the Merkle tree, false otherwise
* @dev A `proof` is valid if and only if the rebuilt hash matches the root of the tree.
* @dev Reverts for:
* - InvalidProofLength: proof.length is 0 or not a multiple of 32.
* - InvalidIndex: index is not 0 at conclusion of computation (implying outside the max index for the tree).
*/
function verifyInclusionSha256(
bytes memory proof,
bytes32 root,
bytes32 leaf,
uint256 index
) internal view returns (bool) {
require(root != bytes32(0), EmptyRoot());
return processInclusionProofSha256(proof, leaf, index) == root;
}
/**
* @notice Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`.
* @param proof The proof of inclusion for the leaf
* @param leaf The leaf to verify
* @param index The index of the leaf in the Merkle tree
* @return The rebuilt hash
* @dev Reverts for:
* - InvalidProofLength: proof.length is 0 or not a multiple of 32.
* - InvalidIndex: index is not 0 at conclusion of computation (implying outside the max index for the tree).
* @dev The tree is built assuming `leaf` is the 0 indexed `index`'th leaf from the bottom left of the tree.
*/
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 index is even, 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 index is odd, 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)
}
}
}
// Confirm proof was fully consumed by end of computation
require(index == 0, InvalidIndex());
return computedHash[0];
}
/**
* @notice Returns the Merkle root of a tree created from a set of leaves using SHA-256 as its hash function
* @param leaves the leaves of the Merkle tree
* @return The computed Merkle root of the tree.
* @dev Reverts for:
* - NotEnoughLeaves: leaves.length is less than 2.
* - LeavesNotPowerOfTwo: leaves.length is not a power of two.
* @dev Unlike the Keccak version, this function does not allow a single-leaf tree.
*/
function merkleizeSha256(
bytes32[] memory leaves
) internal pure returns (bytes32) {
require(leaves.length > 1, NotEnoughLeaves());
require(isPowerOfTwo(leaves.length), LeavesNotPowerOfTwo());
// 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]));
}
// While we haven't computed the root
while (numNodesInLayer != 1) {
// The next layer above has half as many nodes
numNodesInLayer /= 2;
// 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 first node in the layer is the root
return layer[0];
}
/**
* @notice Returns the Merkle root of a tree created from a set of leaves using Keccak as its hash function
* @param leaves the leaves of the Merkle tree
* @return The computed Merkle root of the tree.
* @dev Reverts for:
* - NoLeaves: leaves.length is 0.
*/
function merkleizeKeccak(
bytes32[] memory leaves
) internal pure returns (bytes32) {
require(leaves.length > 0, NoLeaves());
uint256 numNodesInLayer;
if (!isPowerOfTwo(leaves.length)) {
// Pad to the next power of 2
numNodesInLayer = 1;
while (numNodesInLayer < leaves.length) {
numNodesInLayer *= 2;
}
} else {
numNodesInLayer = leaves.length;
}
// Create a layer to store the internal nodes
bytes32[] memory layer = new bytes32[](numNodesInLayer);
for (uint256 i = 0; i < leaves.length; i++) {
layer[i] = leaves[i];
}
// While we haven't computed the root
while (numNodesInLayer != 1) {
// The next layer above has half as many nodes
numNodesInLayer /= 2;
// Overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < numNodesInLayer; i++) {
layer[i] = keccak256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
}
}
// The first node in the layer is the root
return layer[0];
}
/**
* @notice Returns the Merkle proof for a given index in a tree created from a set of leaves using Keccak as its hash function
* @param leaves the leaves of the Merkle tree
* @param index the index of the leaf to get the proof for
* @return proof The computed Merkle proof for the leaf at index.
* @dev Reverts for:
* - InvalidIndex: index is outside the max index for the tree.
*/
function getProofKeccak(bytes32[] memory leaves, uint256 index) internal pure returns (bytes memory proof) {
require(leaves.length > 0, NoLeaves());
// TODO: very inefficient, use ZERO_HASHES
// pad to the next power of 2
uint256 numNodesInLayer = 1;
while (numNodesInLayer < leaves.length) {
numNodesInLayer *= 2;
}
bytes32[] memory layer = new bytes32[](numNodesInLayer);
for (uint256 i = 0; i < leaves.length; i++) {
layer[i] = leaves[i];
}
if (index >= layer.length) revert InvalidIndex();
// While we haven't computed the root
while (numNodesInLayer != 1) {
// Flip the least significant bit of index to get the sibling index
uint256 siblingIndex = index ^ 1;
// Add the sibling to the proof
proof = abi.encodePacked(proof, layer[siblingIndex]);
index /= 2;
// The next layer above has half as many nodes
numNodesInLayer /= 2;
// Overwrite the first numNodesInLayer nodes in layer with the pairwise hashes of their children
for (uint256 i = 0; i < numNodesInLayer; i++) {
layer[i] = keccak256(abi.encodePacked(layer[2 * i], layer[2 * i + 1]));
}
}
}
/**
* @notice Returns the Merkle proof for a given index in a tree created from a set of leaves using SHA-256 as its hash function
* @param leaves the leaves of the Merkle tree
* @param index the index of the leaf to get the proof for
* @return proof The computed Merkle proof for the leaf at index.
* @dev Reverts for:
* - NotEnoughLeaves: leaves.length is less than 2.
* @dev Unlike the Keccak version, this function does not allow a single-leaf proof.
*/
function getProofSha256(bytes32[] memory leaves, uint256 index) internal pure returns (bytes memory proof) {
require(leaves.length > 1, NotEnoughLeaves());
// TODO: very inefficient, use ZERO_HASHES
// pad to the next power of 2
uint256 numNodesInLayer = 1;
while (numNodesInLayer < leaves.length) {
numNodesInLayer *= 2;
}
bytes32[] memory layer = new bytes32[](numNodesInLayer);
for (uint256 i = 0; i < leaves.length; i++) {
layer[i] = leaves[i];
}
if (index >= layer.length) revert InvalidIndex();
// While we haven't computed the root
while (numNodesInLayer != 1) {
// Flip the least significant bit of index to get the sibling index
uint256 siblingIndex = index ^ 1;
// Add the sibling to the proof
proof = abi.encodePacked(proof, layer[siblingIndex]);
index /= 2;
// The next layer above has half as many nodes
numNodesInLayer /= 2;
// 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]));
}
}
}
/**
* @notice Returns whether the input is a power of two
* @param value the value to check
* @return True if the input is a power of two, false otherwise
*/
function isPowerOfTwo(
uint256 value
) internal pure returns (bool) {
return value != 0 && (value & (value - 1)) == 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
library Endian {
/**
* @notice Converts a little endian-formatted uint64 to a big endian-formatted uint64
* @param lenum little endian-formatted uint64 input, provided as 'bytes32' type
* @return n The big endian-formatted uint64
* @dev Note that the input is formatted as a 'bytes32' type (i.e. 256 bits), but it is immediately truncated to a uint64 (i.e. 64 bits)
* through a right-shift/shr operation.
*/
function fromLittleEndianUint64(
bytes32 lenum
) internal pure returns (uint64 n) {
// the number needs to be stored in little-endian encoding (ie in bytes 0-8)
n = uint64(uint256(lenum >> 192));
// forgefmt: disable-next-item
return (n >> 56) |
((0x00FF000000000000 & n) >> 40) |
((0x0000FF0000000000 & n) >> 24) |
((0x000000FF00000000 & n) >> 8) |
((0x00000000FF000000 & n) << 8) |
((0x0000000000FF0000 & n) << 24) |
((0x000000000000FF00 & n) << 40) |
((0x00000000000000FF & n) << 56);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Bytes.sol)
pragma solidity ^0.8.24;
import {Math} from "./math/Math.sol";
/**
* @dev Bytes operations.
*/
library Bytes {
/**
* @dev Forward search for `s` in `buffer`
* * If `s` is present in the buffer, returns the index of the first instance
* * If `s` is not present in the buffer, returns type(uint256).max
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]
*/
function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {
return indexOf(buffer, s, 0);
}
/**
* @dev Forward search for `s` in `buffer` starting at position `pos`
* * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance
* * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]
*/
function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
uint256 length = buffer.length;
for (uint256 i = pos; i < length; ++i) {
if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) {
return i;
}
}
return type(uint256).max;
}
/**
* @dev Backward search for `s` in `buffer`
* * If `s` is present in the buffer, returns the index of the last instance
* * If `s` is not present in the buffer, returns type(uint256).max
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]
*/
function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {
return lastIndexOf(buffer, s, type(uint256).max);
}
/**
* @dev Backward search for `s` in `buffer` starting at position `pos`
* * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance
* * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]
*/
function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {
unchecked {
uint256 length = buffer.length;
for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) {
if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) {
return i - 1;
}
}
return type(uint256).max;
}
}
/**
* @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in
* memory.
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
*/
function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {
return slice(buffer, start, buffer.length);
}
/**
* @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in
* memory. The `end` argument is truncated to the length of the `buffer`.
*
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
*/
function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
// sanitize
uint256 length = buffer.length;
end = Math.min(end, length);
start = Math.min(start, end);
// allocate and copy
bytes memory result = new bytes(end - start);
assembly ("memory-safe") {
mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start))
}
return result;
}
/**
* @dev Moves the content of `buffer`, from `start` (included) to the end of `buffer` to the start of that buffer.
*
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
*/
function splice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {
return splice(buffer, start, buffer.length);
}
/**
* @dev Moves the content of `buffer`, from `start` (included) to end (excluded) to the start of that buffer. The
* `end` argument is truncated to the length of the `buffer`.
*
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
*/
function splice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
// sanitize
uint256 length = buffer.length;
end = Math.min(end, length);
start = Math.min(start, end);
// allocate and copy
assembly ("memory-safe") {
mcopy(add(buffer, 0x20), add(add(buffer, 0x20), start), sub(end, start))
mstore(buffer, sub(end, start))
}
return buffer;
}
/**
* @dev Concatenate an array of bytes into a single bytes object.
*
* For fixed bytes types, we recommend using the solidity built-in `bytes.concat` or (equivalent)
* `abi.encodePacked`.
*
* NOTE: this could be done in assembly with a single loop that expands starting at the FMP, but that would be
* significantly less readable. It might be worth benchmarking the savings of the full-assembly approach.
*/
function concat(bytes[] memory buffers) internal pure returns (bytes memory) {
uint256 length = 0;
for (uint256 i = 0; i < buffers.length; ++i) {
length += buffers[i].length;
}
bytes memory result = new bytes(length);
uint256 offset = 0x20;
for (uint256 i = 0; i < buffers.length; ++i) {
bytes memory input = buffers[i];
assembly ("memory-safe") {
mcopy(add(result, offset), add(input, 0x20), mload(input))
}
unchecked {
offset += input.length;
}
}
return result;
}
/**
* @dev Returns true if the two byte buffers are equal.
*/
function equal(bytes memory a, bytes memory b) internal pure returns (bool) {
return a.length == b.length && keccak256(a) == keccak256(b);
}
/**
* @dev Reverses the byte order of a bytes32 value, converting between little-endian and big-endian.
* Inspired in https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel[Reverse Parallel]
*/
function reverseBytes32(bytes32 value) internal pure returns (bytes32) {
value = // swap bytes
((value >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |
((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
value = // swap 2-byte long pairs
((value >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |
((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
value = // swap 4-byte long pairs
((value >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |
((value & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
value = // swap 8-byte long pairs
((value >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |
((value & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
return (value >> 128) | (value << 128); // swap 16-byte long pairs
}
/// @dev Same as {reverseBytes32} but optimized for 128-bit values.
function reverseBytes16(bytes16 value) internal pure returns (bytes16) {
value = // swap bytes
((value & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
value = // swap 2-byte long pairs
((value & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
value = // swap 4-byte long pairs
((value & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) |
((value & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32);
return (value >> 64) | (value << 64); // swap 8-byte long pairs
}
/// @dev Same as {reverseBytes32} but optimized for 64-bit values.
function reverseBytes8(bytes8 value) internal pure returns (bytes8) {
value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8); // swap bytes
value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16); // swap 2-byte long pairs
return (value >> 32) | (value << 32); // swap 4-byte long pairs
}
/// @dev Same as {reverseBytes32} but optimized for 32-bit values.
function reverseBytes4(bytes4 value) internal pure returns (bytes4) {
value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); // swap bytes
return (value >> 16) | (value << 16); // swap 2-byte long pairs
}
/// @dev Same as {reverseBytes32} but optimized for 16-bit values.
function reverseBytes2(bytes2 value) internal pure returns (bytes2) {
return (value >> 8) | (value << 8);
}
/**
* @dev Counts the number of leading zero bits a bytes array. Returns `8 * buffer.length`
* if the buffer is all zeros.
*/
function clz(bytes memory buffer) internal pure returns (uint256) {
for (uint256 i = 0; i < buffer.length; i += 0x20) {
bytes32 chunk = _unsafeReadBytesOffset(buffer, i);
if (chunk != bytes32(0)) {
return Math.min(8 * i + Math.clz(uint256(chunk)), 8 * buffer.length);
}
}
return 8 * buffer.length;
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(add(buffer, 0x20), offset))
}
}
}{
"remappings": [
"openzeppelin-contracts/=lib/Aleph/lib/openzeppelin-contracts/",
"@openzeppelin/contracts/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/",
"@openzeppelin-upgrades/contracts/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/",
"@aleph-script/=lib/Aleph/script/",
"@aleph-test/=lib/Aleph/test/",
"@aleph-vault/=lib/Aleph/src/",
"@openzeppelin/contracts-upgradeable/=lib/Aleph/lib/openzeppelin-contracts-upgradeable/contracts/",
"Aleph/=lib/Aleph/",
"ds-test/=lib/eigenlayer-contracts/lib/ds-test/src/",
"eigenlayer-contracts/=lib/eigenlayer-contracts/",
"erc4626-tests/=lib/Aleph/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/Aleph/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/",
"openzeppelin-contracts-upgradeable/=lib/Aleph/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts-v4.9.0/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/",
"openzeppelin/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/",
"zeus-templates/=lib/eigenlayer-contracts/lib/zeus-templates/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IAllocationManager","name":"_allocationManager","type":"address"},{"internalType":"contract IDelegationManager","name":"_delegationManager","type":"address"},{"internalType":"contract IStrategyManager","name":"_strategyManager","type":"address"},{"internalType":"contract IRewardsCoordinator","name":"_rewardsCoordinator","type":"address"},{"internalType":"contract IAlephVaultFactory","name":"_vaultFactory","type":"address"},{"internalType":"contract IStrategyFactory","name":"_strategyFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountTooSmall","type":"error"},{"inputs":[],"name":"AmountTooSmall","type":"error"},{"inputs":[],"name":"FlowIsCurrentlyPaused","type":"error"},{"inputs":[],"name":"FlowIsCurrentlyUnpaused","type":"error"},{"inputs":[],"name":"InsufficientAllocation","type":"error"},{"inputs":[],"name":"InsufficientAllocation","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualAmount","type":"uint256"},{"internalType":"uint256","name":"minAmount","type":"uint256"}],"name":"InsufficientOutput","type":"error"},{"inputs":[],"name":"InvalidAlephOperator","type":"error"},{"inputs":[],"name":"InvalidAllocationManager","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidClassId","type":"error"},{"inputs":[],"name":"InvalidDelegationManager","type":"error"},{"inputs":[],"name":"InvalidOperatorSet","type":"error"},{"inputs":[],"name":"InvalidRewardsCoordinator","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidStrategy","type":"error"},{"inputs":[],"name":"InvalidStrategyFactory","type":"error"},{"inputs":[],"name":"InvalidStrategyManager","type":"error"},{"inputs":[],"name":"InvalidVault","type":"error"},{"inputs":[],"name":"InvalidVaultFactory","type":"error"},{"inputs":[],"name":"MagnitudeOverflow","type":"error"},{"inputs":[],"name":"MagnitudeOverflow","type":"error"},{"inputs":[],"name":"NoPendingUnallocation","type":"error"},{"inputs":[],"name":"NoTokensReceived","type":"error"},{"inputs":[],"name":"NotAlephOperator","type":"error"},{"inputs":[],"name":"NotMemberOfOperatorSet","type":"error"},{"inputs":[],"name":"NotRegisteredOperator","type":"error"},{"inputs":[],"name":"OperatorSplitNotZero","type":"error"},{"inputs":[],"name":"OperatorSplitNotZero","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenAmountMismatch","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"VaultAlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"VaultNotInitialized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"alephVault","type":"address"},{"indexed":false,"internalType":"address","name":"originalStrategy","type":"address"},{"indexed":false,"internalType":"address","name":"slashedStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToMint","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"vaultShares","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"classId","type":"uint8"}],"name":"AllocatedToAlephVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"_pausableFlow","type":"bytes4"},{"indexed":false,"internalType":"address","name":"_pauser","type":"address"}],"name":"FlowPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"_pausableFlow","type":"bytes4"},{"indexed":false,"internalType":"address","name":"_unpauser","type":"address"}],"name":"FlowUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint32[]","name":"operatorSetIds","type":"uint32[]"}],"name":"OperatorDeregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint32[]","name":"operatorSetIds","type":"uint32[]"}],"name":"OperatorRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint32","name":"operatorSetId","type":"uint32"},{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":true,"internalType":"address","name":"underlyingToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"slashId","type":"uint256"}],"name":"SlashExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenHolder","type":"address"},{"indexed":true,"internalType":"address","name":"alephVault","type":"address"},{"indexed":false,"internalType":"address","name":"originalStrategy","type":"address"},{"indexed":false,"internalType":"address","name":"slashedStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"classId","type":"uint8"}],"name":"UnallocateCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenHolder","type":"address"},{"indexed":true,"internalType":"address","name":"alephVault","type":"address"},{"indexed":false,"internalType":"address","name":"slashedStrategy","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"estAmountToRedeem","type":"uint256"},{"indexed":false,"internalType":"uint48","name":"batchId","type":"uint48"},{"indexed":false,"internalType":"uint8","name":"classId","type":"uint8"}],"name":"UnallocateRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint8","name":"classId","type":"uint8"},{"indexed":true,"internalType":"address","name":"originalToken","type":"address"},{"indexed":true,"internalType":"address","name":"slashedToken","type":"address"},{"indexed":false,"internalType":"address","name":"slashedStrategy","type":"address"}],"name":"VaultInitialized","type":"event"},{"inputs":[],"name":"ALLOCATE_FLOW","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ALLOCATION_MANAGER","outputs":[{"internalType":"contract IAllocationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATION_MANAGER","outputs":[{"internalType":"contract IDelegationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OWNER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_COORDINATOR","outputs":[{"internalType":"contract IRewardsCoordinator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGY_FACTORY","outputs":[{"internalType":"contract IStrategyFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGY_MANAGER","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNALLOCATE_FLOW","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT_FACTORY","outputs":[{"internalType":"contract IAlephVaultFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_alephVault","type":"address"},{"components":[{"internalType":"uint8","name":"classId","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"bytes","name":"authSignature","type":"bytes"},{"internalType":"uint256","name":"expiryBlock","type":"uint256"}],"internalType":"struct AuthLibrary.AuthSignature","name":"authSignature","type":"tuple"}],"internalType":"struct IAlephVaultDeposit.RequestDepositParams","name":"_requestDepositParams","type":"tuple"}],"name":"allocate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_alephVault","type":"address"}],"name":"calculateCompleteUnallocateAmount","outputs":[{"internalType":"uint256","name":"expectedAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_alephVault","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"calculateUnallocateAmount","outputs":[{"internalType":"uint256","name":"_estimatedAmount","type":"uint256"},{"internalType":"contract IStrategy","name":"_strategy","type":"address"},{"internalType":"contract IERC20","name":"_token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_alephVault","type":"address"},{"internalType":"uint256","name":"_strategyDepositExpiry","type":"uint256"},{"internalType":"bytes","name":"_strategyDepositSignature","type":"bytes"}],"name":"completeUnallocate","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_v","type":"address"},{"internalType":"uint256","name":"_a","type":"uint256"}],"name":"correctWithdrawnAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_avs","type":"address"},{"internalType":"uint32[]","name":"_operatorSetIds","type":"uint32[]"}],"name":"deregisterOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"erc20Factory","outputs":[{"internalType":"contract IERC20Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_alephVault","type":"address"}],"name":"getPendingUnallocateStatus","outputs":[{"internalType":"uint256","name":"userPendingAmount","type":"uint256"},{"internalType":"uint256","name":"totalPendingAmount","type":"uint256"},{"internalType":"uint256","name":"redeemableAmount","type":"uint256"},{"internalType":"bool","name":"canComplete","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_classId","type":"uint8"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"contract IStrategy","name":"_lstStrategy","type":"address"}],"name":"initializeVault","outputs":[{"internalType":"contract IStrategy","name":"_slashedStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_pausableFlow","type":"bytes4"}],"name":"isFlowPaused","outputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_pausableFlow","type":"bytes4"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_avs","type":"address"},{"internalType":"uint32[]","name":"_operatorSetIds","type":"uint32[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"registerOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_alephVault","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"requestUnallocate","outputs":[{"internalType":"uint48","name":"batchId","type":"uint48"},{"internalType":"uint256","name":"estAmountToRedeem","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_avs","type":"address"}],"name":"supportsAVS","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_pausableFlow","type":"bytes4"}],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"vaultToOriginalStrategy","outputs":[{"internalType":"contract IStrategy","name":"_originalStrategy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"vaultToSlashedStrategy","outputs":[{"internalType":"contract IStrategy","name":"_slashedStrategy","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610140346102d357601f61629638819003918201601f19168301916001600160401b038311848410176102d75780849260c0946040528339810103126102d3578051906001600160a01b038216908183036102d35760208101516001600160a01b03811693908481036102d35760408301516001600160a01b038116949092908584036102d3576060850151946001600160a01b0386168087036102d3576080820151976001600160a01b03891692838a036102d35760a00151996001600160a01b038b1694858c036102d35760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055156102c457156102b557156102a65715610297571561028857156102795760805260a05260c05260e05261010052610120525f5460ff8160081c166102245760ff808216036101ea575b604051615faa90816102ec82396080518181816107ed0152818161219901528181612c2701528181613e8a01526140b1015260a0518181816102650152610678015260c05181818161055401528181610c4701526127e4015260e0518181816105ea0152818161071e015281816111520152818161124701528181611271015281816112f3015261133e015261010051818181612f30015261352b0152610120518181816104ed015261312f0152f35b60ff90811916175f557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a15f61013a565b60405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b632f9b373360e11b5f5260045ffd5b63770f64bf60e11b5f5260045ffd5b63f8480a7560e01b5f5260045ffd5b6368b6c4bb60e01b5f5260045ffd5b63165cd34760e31b5f5260045ffd5b6307fb89e960e31b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe610160806040526004361015610013575f80fd5b5f610140525f3560e01c90816301ffc9a71461364a57508063049d4c1b14613585578063084727b11461355a578063103f290714613516578063117803e3146134ef57806313ce83c61461341e57806317f24c0f14612ebc5780631ac71d9614612dba578063248a9ca314612d875780632f2ff15d14612ce1578063303ca95614612c5657806331232bc914612c1257806336568abe14612b7e57806338b1b34e14612b495780633aa83ec714612a885780633ab22ff2146125f157806344260ff4146125cc5780634571e3a61461205c5780634cef3daf14611cb157806357b53c8f1461061957806371e2c264146105d257806391d14854146105835780639fc2c4761461053c578063a217fddf1461051c578063ae501345146104d5578063aed753c914610496578063b526578714610467578063bac1e94b1461038d578063c63fd502146102de578063d547741f14610294578063d5c1c20a1461024d578063efd96978146101fb578063f4c3066f146101c45763f5beff1014610198575f80fd5b346101bd57610140513660031901126101bd576040516340e1896760e01b8152602090f35b6101405180fd5b346101bd57610140513660031901126101bd575f516020615ef55f395f51905f52546040516001600160a01b039091168152602090f35b346101bd5760203660031901126101bd5760043563ffffffff60e01b81168091036101bd5761014051525f516020615f555f395f51905f52602052602060ff6040610140512054166040519015158152f35b346101bd57610140513660031901126101bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101bd5760403660031901126101bd576102d76004356102b36136b3565b906102d26102cd825f526065602052600160405f20015490565b613d57565b61410c565b6101405180f35b346101bd5760803660031901126101bd576102f761369d565b6102ff6136b3565b6044356001600160401b0381116101bd5761031e9036906004016136c9565b90926064356001600160401b0381116101bd577f9efdc3d07eb312e06bf36ea85db02aec96817d7c7421f919027b240eaf34035d9361036461036b9236906004016136f9565b50506140ae565b61038360405192839260018060a01b03169583613984565b0390a26101405180f35b346101bd5760203660031901126101bd576004356001600160e01b031981168082036101bd576103bc81613d57565b8061014051525f516020615f555f395f51905f5260205260ff60406101405120541615610452576101408051919091525f516020615f555f395f51905f5260209081529051604090819020805460ff1916905580516001600160e01b031993909316835233918301919091527fc7e56e17b0a6c4b467df6495e1eda1baecd7ba20604e80c1058ac06f4578d85e91a16101405180f35b6368c87f3360e11b6101405152600461014051fd5b346101bd5760203660031901126101bd57602061048261369d565b6040516001600160a01b0390911630148152f35b346101bd5760403660031901126101bd576104bf6104b261369d565b6104ba613c5d565b61386d565b6104cc60243582546139ca565b90556101405180f35b346101bd57610140513660031901126101bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101bd57610140513660031901126101bd576020604051610140518152f35b346101bd57610140513660031901126101bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101bd5760403660031901126101bd5761059c6136b3565b60043561014051526065602052604061014051209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b346101bd57610140513660031901126101bd576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101bd5760403660031901126101bd5761063261369d565b60e0526001600160401b03602435116101bd576060602435360360031901126101bd5761065d61418d565b6040516336b87bd760e11b81523360048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115611b74576101405191611c92575b5015611c7d5763099b4ac360e31b61014051525f516020615f555f395f51905f5260205260ff604061014051205416611c68576106f160e051613a8c565b6024803501358015611c535760405163e063f81f60e01b81523360048201523060248201526020816044817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa8015611b74576101405190611c14575b61ffff915016611bff5760ff61076f60e0516138dd565b541660ff6107816024356004016139d7565b1603611bea5761079260e051613be6565b61010052506107a260e051613ac7565b60a0526040516107b181613726565b30815261014051602082019081526040516304c1b8eb60e31b815282516001600160a01b039081166004830152915163ffffffff1660248201527f00000000000000000000000000000000000000000000000000000000000000009091169290602081604481875afa908115611b74576101405191611bcb575b5015611bb6576040516333869dd160e11b815233600482015282516001600160a01b03166024820152602083015163ffffffff166044820152602081606481875afa908115611b74576101405191611b97575b5015611b8257604051906338f6b94760e21b8252600482015260208160248160018060a01b0361010051165afa908115611b74576101405191611b42575b508015611b2d5760409061095982516108d5848261378b565b60018152601f198401366020830137336108ee82613dc2565b526109436108fe610100516149e8565b85516315a29d4d60e11b815287516001600160a01b03166004820152602088015163ffffffff1660248201529390928492839291608060448501526084840190613de3565b8281036003190160648401526101405194613de3565b0381885afa908115611412576101405191611a78575b5061097c61098291613dc2565b51613dc2565b518181106119f75782519163021c373760e31b8352606083806109ad610100518933600485016144c7565b0381895afa928315611721576101405193611a48575b506001600160401b03916109da91838551166148ac565b915116808211611a40575b506001600160401b038111611a2b5760606001600160401b03610a2392169383518093819263021c373760e31b8352610100519033600485016144c7565b0381875afa9081156118995783916001600160401b03916101405191611a0c575b505116106119f757602092815192610a5c858561378b565b610140518452610a8f6060610a703061494a565b85518093819263021c373760e31b8352610100519033600485016144c7565b0381865afa90811561172157610abc92916001600160401b039161014051916119c8575b50511690614974565b90610ac9610100516149e8565b835192610ad6858561378b565b60018452601f1985013688860137610aed84613dc2565b5283519060a08201908282106001600160401b038311176119ae57908552338252610140518783019081528583019182526060830194855260808301969096528451633635205760e01b81523060048201526024810186905282516001600160a01b03166044820152955163ffffffff1660648701525160a0608487015285929190610b7d9060e4850190613de3565b93518385036043190160a485015280518086526101405195890195918901915b89828210611997575050505082610bca608082930151956043198382030160c48401526101405196614278565b039161014051905af191821561198a576101405192611942575b50610bee3061494a565b81516316a26f7b60e11b815281516001600160a01b0316600482015260209091015163ffffffff1660248201529160448301819052610100516001600160a01b03908116606485015261014051859185916084918391907f0000000000000000000000000000000000000000000000000000000000000000165af1928315611899576101405193611913575b5082156118fe578151632495a59960e01b8152610100518590829060049082906001600160a01b03165afa9081156114125761014051916118e1575b506101408051845163a9059cbb60e01b90915230600452602486905290516001600160a01b0392909216929091869060448180875af160016101405151148116156118bf575b828552156118a65761014051825285820185905283820152610100516001600160a01b03169033907f3c011840976564fcc4559f75e69f8a0a69ebb3a374148ab6358c306c33dd41fa90606090a48051632495a59960e01b815260a0518490829060049082906001600160a01b03165afa8015611899576101405160c05261187a575b50610d8e6024356004016139d7565b8151906318160ddd60e01b8252848260048160018060a01b0360c051165afa9081156114125785906101405192611849575b8451632e35e48960e11b815260ff909116600482015230602482015292508280604481015b038160018060a01b0360e051165afa91821561141257610140519261181a575b50600161012081905281019081106118065761012051820180921161159457610e3c91610e3291856148ac565b61014051906139ca565b610140516080528151632495a59960e01b815260e0518590829060049082906001600160a01b03165afa9081156114125761014051916117e9575b5060e051610e909085906001600160a01b038416614413565b610e9e6024356004016139d7565b906024356044810135903603604219018112156101bd5760ff855193610ec385613755565b1683528587840152846003198260243501360301126101bd57845190610ee882613726565b600481602435010135906001600160401b0382116101bd57366023602435830184010112156101bd57602491610f2e9036908435840101600481810135918d01016137c7565b835281350101358782015284830152610f4b6024356004016139d7565b60ff855191630bdf607b60e41b8352166004820152868160248160018060a01b0360e051165afa9081156117dc5790879161014051916117af575b5061172e578451631fb96acd60e01b8152919282908190610faa906004830161429c565b03816101405160018060a01b0360e051165af18015611721576116e2575b50610fe790610140516080525b60e051906001600160a01b031661439b565b60c0516001600160a01b03163b156101bd5781516340c10f1960e01b8152610140805130600484015260248301849052905160c05183916044918391906001600160a01b03165af18015611412576116c7575b508151634fb3ccc560e01b815260e0518590829060049082906001600160a01b03165afa90811561141257610140519161169a575b506001600160a01b031680611632575b50815161108c858261378b565b610140518152825161109e848261378b565b61012051815285610140515b601f198601811061161157505083516110c281613726565b610100516001600160a01b03168152670de0b6b3a7640000878201526110e782613dc2565b526110f181613dc2565b508351916110ff858461378b565b61012051835286610140515b601f19870181106115f0575050845161112381613726565b338152848882015261113484613dc2565b5261113e83613dc2565b508451639d45c28160e01b815287816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156115e35761014051916115ae575b5061119e63ffffffff8216426139f8565b80600119810111611594576111bf63ffffffff9182841690600119016139e5565b168651946111cd888761378b565b61012051865289610140515b601f198a0181106115505750509063ffffffff92918851956111fa87613770565b865260c0516001600160a01b03168b87015288860152606085015216608083015260a082015261122982613dc2565b5261123381613dc2565b5060c05161126f9083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116614413565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b156101bd57825190634e5cd2fd60e11b825260448201306004840152846024840152815180915260648301908760648260051b86010193019161014051905b82821061141f5750506101405192849250829003905081837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af18015611412576113f7575b5060c05160ff9390611366906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116911661439b565b6113746024356004016139d7565b9280519560018060a01b036101005116875260018060a01b0360a0511690870152850152606084015260805160808401521660a082015260018060a01b0360e05116907ffaf66257bc51b727241377e1a40ac926a99e5955fa479671239fd77ebb72082560c03392a3610120515f516020615f355f395f51905f52556101405180f35b610140516114049161378b565b610140516101bd5784611328565b83513d61014051823e3d90fd5b90919293899060631987820301835285519060c081019180519260c0835283518091528460e0840194019061014051905b8d8183106115125750505050808401516001600160a01b0316828501528a8101518284038c8401528051808552610140519486019491860191905b8d8183106114e25750505050916114d09160a08463ffffffff60608897015116606084015263ffffffff608082015116608084015201519060a0818403910152614278565b950191019161012051019092916112d9565b9092969193949582885160018060a01b0381511683520151838201520195019161012051018e959493929161148b565b909296919394956bffffffffffffffffffffffff83895160018060a01b038151168452015116838201520195019161012051018e9594939291611450565b895161155b81613770565b60608152610140518382015260608b820152610140516060820152610140516080820152606060a082015282828a010152018a906111d9565b634e487b7160e01b61014051526011600452602461014051fd5b90508781813d83116115dc575b6115c5818361378b565b810103126101bd576115d690614462565b8861118d565b503d6115bb565b86513d61014051823e3d90fd5b86516115fb81613726565b5f81525f8382015282828701015201879061110b565b855161161c81613726565b5f81525f838201528282850101520186906110aa565b803b156101bd57825163569ebf3560e11b815260e0516001600160a01b03166004820152336024820152604481018590526101405190918290606490829084905af18015611412571561107f576101405161168c9161378b565b610140516101bd578461107f565b6116ba9150853d87116116c0575b6116b2818361378b565b81019061394d565b8561106f565b503d6116a8565b610140516116d49161378b565b610140516101bd578461103a565b8581813d831161171a575b6116f7818361378b565b810103126101bd57519065ffffffffffff821682036101bd579050610fe7610fc8565b503d6116ed565b84513d61014051823e3d90fd5b84516355ef454960e11b8152928390819061174c906004830161429c565b03816101405160018060a01b0360e051165af1801561172157610140519061177c575b610fe79250608052610fd5565b508582813d83116117a8575b611792818361378b565b810103126117a457610fe7915161176f565b5f80fd5b503d611788565b6117cf9150823d84116117d5575b6117c7818361378b565b81019061396c565b88610f86565b503d6117bd565b85513d61014051823e3d90fd5b6118009150853d87116116c0576116b2818361378b565b85610e77565b634e487b7160e01b5f52601160045260245ffd5b9091508481813d8311611842575b611832818361378b565b810103126117a457519085610e05565b503d611828565b915082813d8311611873575b61185f818361378b565b810103126117a45784610de5925191610dc0565b503d611855565b61189090843d86116116c0576116b2818361378b565b60c05283610d7f565b82513d61014051823e3d90fd5b82635274afe760e01b6101405152600452602461014051fd5b60018115166118d557833b15153d151616610cfc565b823d61014051823e3d90fd5b6118f89150853d87116116c0576116b2818361378b565b85610cb6565b639671a89f60e01b6101405152600461014051fd5b9092508381813d831161193b575b61192b818361378b565b810103126117a457519184610c7a565b503d611921565b9091503d8061014051833e611957818361378b565b81019082818303126101bd57805191848201516001600160401b0381116101bd5761198292016144ff565b509083610be4565b50513d61014051823e3d90fd5b835188529687019689965090920191600101610b9d565b634e487b7160e01b61014051526041600452602461014051fd5b6119ea915060603d6060116119f0575b6119e2818361378b565b810190614473565b88610ab3565b503d6119d8565b6337cb51dd60e21b6101405152600461014051fd5b611a25915060603d6060116119f0576119e2818361378b565b86610a44565b63125a110760e21b6101405152600461014051fd5b9050846109e5565b6109da91935091611a6f6001600160401b039360603d6060116119f0576119e2818361378b565b939150916109c3565b90503d8061014051833e611a8c818361378b565b8101906020818303126101bd578051906001600160401b0382116101bd57019080601f830112156101bd578151611ac281613dab565b92611acf8651948561378b565b81845260208085019260051b820101918383116101bd5760208201905b838210611b0057505050505061097c61096f565b81516001600160401b0381116101bd57602091611b22878480948801016144ff565b815201910190611aec565b63617ab12d60e11b6101405152600461014051fd5b90506020813d602011611b6c575b81611b5d6020938361378b565b810103126117a45751836108bc565b3d9150611b50565b6040513d61014051823e3d90fd5b631caa993f60e31b6101405152600461014051fd5b611bb0915060203d6020116117d5576117c7818361378b565b8461087e565b631fb1705560e21b6101405152600461014051fd5b611be4915060203d6020116117d5576117c7818361378b565b8461082b565b632f20e08d60e21b6101405152600461014051fd5b6315f1e15d60e21b6101405152600461014051fd5b506020813d602011611c4b575b81611c2e6020938361378b565b810103126101bd575161ffff811681036101bd5761ffff90610758565b3d9150611c21565b63162908e360e11b6101405152600461014051fd5b63722fdba960e01b6101405152600461014051fd5b6303fa1eaf60e41b6101405152600461014051fd5b611cab915060203d6020116117d5576117c7818361378b565b816106b3565b346101bd5760403660031901126101bd57611cca61369d565b602435611cd561418d565b611cdd6141c5565b8015611c5357611cec82613a8c565b60ff611cf7836138dd565b5416906001600160a01b03611d0b84613ac7565b16604051632495a59960e01b8152602081600481855afa908115611b7457611d4a918491610140519161203d575b506001600160a01b03168686613ae4565b928315611c5357604051632495a59960e01b8152602081600481865afa908115611b7457610140519161201e575b506040516370a0823160e01b81523360048201526001600160a01b039190911690602081602481855afa8015611b745785916101405191611fe9575b5010611fd4576101405150604051906323b872dd60e01b610140515233600452306024528460445260206101405160646101405161014051855af16001610140515114811615611fbe575b826040526101405160605215611fa657803b156101bd57632770a7eb60e21b82526101408051306004850152602484018790529051909183916044918391905af18015611b7457611f8b575b5060405192611e5984613726565b81845260208085018681526040516328c0104d60e21b8152955160ff166004870152516024860152610140516001600160a01b03881695919082906044908290895af18015611b7457611f59575b50611ee886611eb760409861386d565b611ec28882546139ca565b9055611ecd336137fd565b865f52602052875f20611ee18882546139ca565b9055613835565b611ef38682546139ca565b905585519283526020830152838583015261014051606083015260808201527fb70df16af75ac670505ba4838560ffb3b81c9e17013cf90d28a49ba89aa92bbf60a03392a360015f516020615f355f395f51905f52558151906101405182526020820152f35b6020813d602011611f83575b81611f726020938361378b565b810103126117a45750611ee8611ea7565b3d9150611f65565b61014051611f989161378b565b610140516101bd5785611e4b565b635274afe760e01b6101405152600452602461014051fd5b60018115166118d557813b15153d151616611dff565b631e9acf1760e31b6101405152600461014051fd5b9150506020813d602011612016575b816120056020938361378b565b810103126117a45784905188611db4565b3d9150611ff8565b612037915060203d6020116116c0576116b2818361378b565b86611d78565b612056915060203d6020116116c0576116b2818361378b565b87611d39565b346101bd5760603660031901126101bd5761207561369d565b61207d6136b3565b906044356001600160401b0381116101bd57366023820112156101bd576120ae9036906024816004013591016137c7565b9161014051549160ff8360081c1615928380946125bf575b80156125a8575b1561254c5783600160ff198316176101405155612537575b5060ff610140515460081c16916120fb83614218565b6001600160a01b0382169283158015612526575b611c535761213a9261212361213592614218565b61212c81613f6c565b61213583613f6c565b61400d565b610140516101405152606560205260406101405120815f5260205260ff60405f205416156124da575b5f516020615f155f395f51905f526101405152606560205260406101405120815f5260205260ff60405f20541615612479575b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691823b156101bd576040519063a982182160e01b82523060048301526040602483015281806121f861014051936044830190614278565b038161014051875af18015611b745761245e575b50604051916020919061221f838561378b565b6101405184525f3681376040519361223685613726565b61014051855283850152604093845191612250868461378b565b60018352601f1986019185610140515b84811061243957505061227284613dc2565b5261227c83613dc2565b5085519161228a878461378b565b6001835236868401373061229d83613dc2565b52803b156101bd57918551928391630caa1e7960e21b83526064830130600485015260606024850152815180915260848401908860848260051b87010193019161014051905b8a8c8484106123f4575050505050508261230e81926003198382030160448401526101405196613de3565b039161014051905af18015611721576123d9575b5082516114b9808201908282106001600160401b038311176119ae5784918391614a1c833930815203019061014051f080156114125760018060a01b03166bffffffffffffffffffffffff60a01b5f516020615ef55f395f51905f525416175f516020615ef55f395f51905f525561239b576101405180f35b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001961014051541661014051555160018152a180806102d7565b610140516123e69161378b565b610140516101bd5783612322565b6001939597985081929496612428916083198d8303018752838a5163ffffffff815116845201519181858201520190613de3565b9601920192018795949391926122e3565b885161244481613726565b610140518152606083820152828288010152018690612260565b6101405161246b9161378b565b610140516101bd578261220c565b5f516020615f155f395f51905f526101405152606560205260406101405120815f5260205260405f20600160ff1982541617905533905f516020615f155f395f51905f525f516020615ed55f395f51905f526101405161014051a482612196565b610140516101405152606560205260406101405120815f5260205260405f20600160ff198254161790553381610140515f516020615ed55f395f51905f526101405161014051a4612163565b506001600160a01b0382161561210f565b6101019061ffff1916176101405155846120e5565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156120cd5750600160ff8216146120cd565b50600160ff8216106120c6565b346101bd57610140513660031901126101bd5760405163099b4ac360e31b8152602090f35b346117a45760603660031901126117a45761260a61369d565b6044356001600160401b0381116117a4576126299036906004016136f9565b61263161418d565b6126396141c5565b61264283613a8c565b60ff61264d846138dd565b541661265884613ac7565b9261266285613be6565b92909461266e336137fd565b60018060a01b0388165f5260205260405f2054958615612a795761269188613835565b5480158015612a70575b612a2d57604051631344d22360e21b8152306004820152976001600160a01b038a16969060208a6024818b5afa998a1561299c575f9a612a3c575b506126e08b61386d565b54996126ee8b828685613a16565b9a8b15612a2d5781156129a757893b156117a457604051636b7f4ea560e11b8152915f83600481838f5af192831561299c5761272f93612987575b506139ca565b808b11611c535760209b602460018060a01b0387169d8e604051928380926370a0823160e01b82523060048301525afa908115611b74576101405191612955575b508c11611c53576020946127ce92612789908e9061420b565b938181111561294657505061014051925b83158061293d575b612933575b6127b08261386d565b556127ba336137fd565b8a5f52855260405f20610140519055613835565b556001600160a01b0316946127e286613d9b565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169960e49061281b8b8d87614413565b896040519a8b9485936319744d6760e11b85528b600486015260248501528d6044850152336064850152602435608485015260c060a48501528160c48501528484013761014051838284010152601f80199101168101030181610140518c5af1958615611b745761014051966128fe575b506040976128999161439b565b865192835260018060a01b03166020830152848683015283606083015260808201527f08ff66ecb49dae546cb0e627ae91149487467cce83755083bb0e1ad9ac59315160a03392a360015f516020615f355f395f51905f525582519182526020820152f35b9095506020813d60201161292b575b8161291a6020938361378b565b810103126117a4575194604061288c565b3d915061290d565b50610140516127a7565b508015156127a2565b61294f9161420b565b9261279a565b90506020813d60201161297f575b816129706020938361378b565b810103126117a457518e612770565b3d9150612963565b5f6129919161378b565b5f610140528e612729565b6040513d5f823e3d90fd5b905080156117a4576040516370a0823160e01b8152306004820152906020826024816001600160a01b038a165afa91821561299c575f926129f9575b50808210156129f2575061272f565b905061272f565b9091506020813d602011612a25575b81612a156020938361378b565b810103126117a45751908d6129e3565b3d9150612a08565b63162908e360e11b5f5260045ffd5b9099506020813d602011612a68575b81612a586020938361378b565b810103126117a45751988b6126d6565b3d9150612a4b565b5087811061269b565b63487192dd60e01b5f5260045ffd5b346117a45760203660031901126117a4576004356001600160e01b031981168082036117a457612ab781613d57565b805f525f516020615f555f395f51905f5260205260ff60405f205416612b3a575f9081525f516020615f555f395f51905f526020908152604091829020805460ff1916600117905581516001600160e01b031993909316835233908301527f95c3658c5e0c74e20cf12db371b9b67d26e97a1937f6d2284f88cc44d036b4f691a1005b63722fdba960e01b5f5260045ffd5b346117a45760203660031901126117a45760206001600160a01b03612b74612b6f61369d565b613915565b5416604051908152f35b346117a45760403660031901126117a457612b976136b3565b336001600160a01b03821603612bb557612bb39060043561410c565b005b60405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608490fd5b346117a4575f3660031901126117a4576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346117a45760603660031901126117a457612c6f61369d565b612c776136b3565b906044356001600160401b0381116117a4577ff8aaad08ee23b49c9bb44e3bca6c7efa43442fc4281245a7f2475aa2632718d191612cbc612cc49236906004016136c9565b9290946140ae565b612cdc60405192839260018060a01b03169583613984565b0390a2005b346117a45760403660031901126117a457600435612cfd6136b3565b90612d176102cd825f526065602052600160405f20015490565b805f52606560205260405f2060018060a01b0383165f5260205260ff60405f20541615612d4057005b5f8181526065602090815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291905f516020615ed55f395f51905f529080a4005b346117a45760203660031901126117a4576020612db26004355f526065602052600160405f20015490565b604051908152f35b346117a45760403660031901126117a457612dd361369d565b612de4612dde6136b3565b916137fd565b60018060a01b0382165f5260205260405f2054612e0082613835565b54604051631344d22360e21b815230600482015292906020846024816001600160a01b0386165afa90811561299c575f91612e87575b608094508315159283612e5e575b506040519384526020840152604083015215156060820152f35b909250811590811591612e74575b509185612e44565b612e7e915061386d565b54151585612e6c565b90506020843d602011612eb4575b81612ea26020938361378b565b810103126117a4576080935190612e36565b3d9150612e95565b346117a45760603660031901126117a45760043560ff8116908181036117a457612ee46136b3565b916044356001600160a01b038116918282036117a457612f02613c5d565b604051630642194560e41b81526001600160a01b0386811660048301819052929190602090829060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa90811561299c575f916133ff575b50156133f0576001600160a01b03612f77876138a5565b54166133e157612f8684613d9b565b604051632495a59960e01b8152602081600481885afa90811561299c575f916133c2575b50604051632495a59960e01b81526001600160a01b03919091169390602081600481875afa801561299c5785915f916133a3575b506001600160a01b031603613394575f516020615ef55f395f51905f52546040516306fdde0360e01b8152906001600160a01b03165f82600481885afa91821561299c575f92613378575b506040516306fdde0360e01b8152915f836004818a5afa92831561299c575f9361335c575b506040516395d89b4160e01b8152925f846004818b5afa93841561299c575f9461332c575b50906130828161308893614345565b93614345565b9160405163313ce56760e01b81526020816004818b5afa90811561299c575f916132e6575b50916130e25f6130f4959360209560ff6040519889978896879563e8a0aed360e01b8752606060048801526064870190614278565b85810360031901602487015290614278565b9116604483015203925af190811561299c575f916132c7575b5060405163581dfd6560e01b81526001600160a01b03918216600482018190527f000000000000000000000000000000000000000000000000000000000000000090921698919691906020816024818d5afa90811561299c575f916132a8575b506001600160a01b038116156132285760209950916131e97f2840f76158e444c1d697cef892b963f173b7dd782e0e1887a5521b40f9841b079594926131ff94955b6131b8826138a5565b80546001600160a01b0319166001600160a01b0389161790556131da826138dd565b9060ff19825416179055613915565b80546001600160a01b0319169091179055613e1f565b6040805160ff9790971687526001600160a01b03919091166020870181905295a4604051908152f35b50929160205f996024604051809c8193636b9b622960e01b83528c60048401525af191821561299c576131e97f2840f76158e444c1d697cef892b963f173b7dd782e0e1887a5521b40f9841b07956131ff9460209c5f9161328b575b50956131af565b6132a291508d3d8f116116c0576116b2818361378b565b8d613284565b6132c1915060203d6020116116c0576116b2818361378b565b8a61316d565b6132e0915060203d6020116116c0576116b2818361378b565b8861310d565b90506020939193813d602011613324575b816133046020938361378b565b810103126117a457519160ff831683036117a457909290916130e26130ad565b3d91506132f7565b8261308893929550613352613082923d805f833e61334a818361378b565b8101906142e3565b9592509250613073565b6133719193503d805f833e61334a818361378b565b918a61304e565b61338d9192503d805f833e61334a818361378b565b9089613029565b632711b74d60e11b5f5260045ffd5b6133bc915060203d6020116116c0576116b2818361378b565b89612fde565b6133db915060203d6020116116c0576116b2818361378b565b87612faa565b63abd5ec5d60e01b5f5260045ffd5b630681d31960e51b5f5260045ffd5b613418915060203d6020116117d5576117c7818361378b565b87612f60565b346117a45760403660031901126117a457600461343961369d565b61344281613a8c565b61344b81613ac7565b602060ff613458846138dd565b54604051632495a59960e01b81529591169285919082906001600160a01b03165afa92831561299c576060936134af926134a9925f926134ce575b50602435916001600160a01b0316908590613ae4565b91613be6565b604080519384526001600160a01b039182166020850152911690820152f35b6134e891925060203d6020116116c0576116b2818361378b565b9086613493565b346117a4575f3660031901126117a45760206040515f516020615f155f395f51905f528152f35b346117a4575f3660031901126117a4576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346117a45760203660031901126117a45760206001600160a01b03612b7461358061369d565b6138a5565b346117a45760403660031901126117a45761359e61369d565b6135a9612dde6136b3565b60018060a01b0382165f5260205260405f20546135c582613835565b54604051631344d22360e21b815230600482015290926020826024816001600160a01b0385165afa91821561299c575f92613613575b6020612db285858861360c8761386d565b5492613a16565b9291506020833d602011613642575b8161362f6020938361378b565b810103126117a4579151909160206135fb565b3d9150613622565b346117a45760203660031901126117a4576004359063ffffffff60e01b82168092036117a457602091637965db0b60e01b811490811561368c575b5015158152f35b6301ffc9a760e01b14905083613685565b600435906001600160a01b03821682036117a457565b602435906001600160a01b03821682036117a457565b9181601f840112156117a4578235916001600160401b0383116117a4576020808501948460051b0101116117a457565b9181601f840112156117a4578235916001600160401b0383116117a457602083818601950101116117a457565b604081019081106001600160401b0382111761374157604052565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b0382111761374157604052565b60c081019081106001600160401b0382111761374157604052565b90601f801991011681019081106001600160401b0382111761374157604052565b6001600160401b03811161374157601f01601f191660200190565b9291926137d3826137ac565b916137e1604051938461378b565b8294818452818301116117a4578281602093845f960137010152565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041056020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041066020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041076020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041016020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041036020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041026020526040902090565b908160209103126117a457516001600160a01b03811681036117a45790565b908160209103126117a4575180151581036117a45790565b60208082528101839052604001915f905b8082106139a25750505090565b90919283359063ffffffff82168092036117a457602081600193829352019401920190613995565b9190820180921161180657565b3560ff811681036117a45790565b8181029291811591840414171561180657565b8115613a02570490565b634e487b7160e01b5f52601260045260245ffd5b90928115613a8457613a2881846139ca565b9081158015613a7c575b613a7357613a4985613a4484866139e5565b6139f8565b9315613a6b5750925b03613a5b575090565b9190808311613a675750565b9150565b905092613a52565b50505050505f90565b508415613a32565b505050505f90565b6001600160a01b03613a9d826138a5565b541615613aa75750565b636315b1a360e01b5f9081526001600160a01b0391909116600452602490fd5b6001600160a01b0390613ad9906138a5565b541690811561339457565b604051632e35e48960e11b815260ff9190911660048201523060248201529190602090839060449082906001600160a01b03165afa91821561299c575f92613bb1575b506040516318160ddd60e01b81529190602090839060049082906001600160a01b03165afa91821561299c575f92613b7d575b5060018101809111611806576001820180921161180657613b7a926148ac565b90565b9091506020813d602011613ba9575b81613b996020938361378b565b810103126117a45751905f613b5a565b3d9150613b8c565b91506020823d602011613bde575b81613bcc6020938361378b565b810103126117a4579051906020613b27565b3d9150613bbf565b6001600160a01b03613bf782613915565b541690811561339457604051632495a59960e01b815290602090829060049082906001600160a01b03165afa90811561299c575f91613c3e575b506001600160a01b031691565b613c57915060203d6020116116c0576116b2818361378b565b5f613c31565b335f9081527f077c9007150f571447365d3bd382bfccc7ce27caa9a880faf975f29f5cafcb79602052604090205460ff1615613c9557565b613d536020613d336011613ca833614585565b603784613cc15f516020615f155f395f51905f5261466b565b6040519687947f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000828701528051918291018587015e8401907001034b99036b4b9b9b4b733903937b6329607d1b84830152805192839101604883015e01015f838201520301601f19810183528261378b565b60405162461bcd60e51b8152602060048201529182916024830190614278565b0390fd5b5f81815260656020908152604080832033845290915290205460ff1615613d7b5750565b6020613d336011613d5393603784613cc1613d9533614585565b9361466b565b6001600160a01b03161561339457565b6001600160401b0381116137415760051b60200190565b805115613dcf5760200190565b634e487b7160e01b5f52603260045260245ffd5b90602080835192838152019201905f5b818110613e005750505090565b82516001600160a01b0316845260209384019390920191600101613df3565b6001600160a01b03165f8181527f9bc6362768ab7acc6d678440e313110dcbcf1f3bce0a546779127863e2b88a09602052604081205490919060ff16613f68576040918251613e6e848261378b565b60018152601f19840136602083013782613e8782613dc2565b527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156117a457613ef05f929183928751948580948193630287f75160e51b8352306004840152836024840152606060448401526064830190613de3565b03925af18015613f5e5790849291613f49575b508080527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db604104602052209060018060a01b03165f526020525f20600160ff19825416179055565b613f5692505f915061378b565b815f5f613f03565b84513d5f823e3d90fd5b5050565b6001600160a01b0381165f9081527f714e2b715aba5871ce4d05fd99bd94a36ff2fc47fdbc62c5c1bc08b10a64682e602052604090205460ff1615613fae5750565b6001600160a01b03165f8181527f714e2b715aba5871ce4d05fd99bd94a36ff2fc47fdbc62c5c1bc08b10a64682e60205260408120805460ff1916600117905533919063099b4ac360e31b905f516020615ed55f395f51905f529080a4565b6001600160a01b0381165f9081527f9a824e0a361d4dc38210d8d46718f5a024fcd5426c72be95b98894eaa9f84758602052604090205460ff161561404f5750565b6001600160a01b03165f8181527f9a824e0a361d4dc38210d8d46718f5a024fcd5426c72be95b98894eaa9f8475860205260408120805460ff191660011790553391906340e1896760e01b905f516020615ed55f395f51905f529080a4565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614801591906140f8575b506140ea57565b6282b42960e81b5f5260045ffd5b6001600160a01b031630141590505f6140e3565b805f52606560205260405f2060018060a01b0383165f5260205260ff60405f205416614136575050565b5f8181526065602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4565b60025f516020615f355f395f51905f5254146141b65760025f516020615f355f395f51905f5255565b633ee5aeb560e01b5f5260045ffd5b6340e1896760e01b5f525f516020615f555f395f51905f526020527f3663686bcf2d729d4855c41e87932887789108353c8318329b1f901b652c7a495460ff16612b3a57565b9190820391821161180657565b1561421f57565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906040906020835260ff815116602084015260208101518284015201519060608082015260a060206142da84516040608086015260c0850190614278565b93015191015290565b6020818303126117a4578051906001600160401b0382116117a4570181601f820112156117a457805190614316826137ac565b92614324604051948561378b565b828452602083830101116117a457815f9260208093018386015e8301015290565b6001614399916022602080969560405197889461185b60f21b828701528051918291018587015e840190602d60f81b84830152805192839101602383015e01015f838201520301601f19810184528361378b565b565b906143a75f828461470d565b156143b0575050565b6143ba818361475a565b156143f2575f6143ca91836147be565b156143d25750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b50635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b919061442082828561470d565b1561442a57505050565b614434818461475a565b1561444457906143ca91836147be565b635274afe760e01b5f9081526001600160a01b038416600452602490fd5b519063ffffffff821682036117a457565b908160609103126117a4576040519061448b82613755565b80516001600160401b03811681036117a4578252602081015180600f0b81036117a45760208301526144bf90604001614462565b604082015290565b6001600160a01b039182168152825182166020808301919091529092015163ffffffff16604083015291909116606082015260800190565b9080601f830112156117a457815161451681613dab565b92614524604051948561378b565b81845260208085019260051b8201019283116117a457602001905b82821061454c5750505090565b815181526020918201910161453f565b6040519061456982613726565b5f6020838281520152565b908151811015613dcf570160200190565b61458f602a6137ac565b9061459d604051928361378b565b602a82526145ab602a6137ac565b6020830190601f1901368237825115613dcf5760309053815160011015613dcf576078602183015360295b6001811161462a57506145e65790565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f81166010811015613dcf576f181899199a1a9b1b9c1cb0b131b232b360811b901a6146588385614574565b5360041c908015611806575f19016145d6565b61467560426137ac565b90614683604051928361378b565b6042825261469160426137ac565b6020830190601f1901368237825115613dcf5760309053815160011015613dcf576078602183015360415b600181116146cc57506145e65790565b90600f81166010811015613dcf576f181899199a1a9b1b9c1cb0b131b232b360811b901a6146fa8385614574565b5360041c908015611806575f19016146bc565b92916040519163095ea7b360e01b5f5260018060a01b031660045260245260205f60448180875af19260015f5114841615614749575b50604052565b3d15903b151516909216915f614743565b60405163095ea7b360e01b5f9081526001600160a01b03909316600452602483905290929160209060448180875af19260015f511484161561479c5750604052565b600184929415166147b5573b15153d151616915f614743565b833d5f823e3d90fd5b92916040519163095ea7b360e01b5f5260018060a01b031660045260245260205f60448180875af19260015f511484161561479c5750604052565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146148a0578382111561488857670de0b6b3a7640000829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b50634e487b715f52156003026011186020526024601cfd5b5090613b7a92506139f8565b90915f19838309928083029283808610950394808603951461493d57848311156149255790829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b82634e487b715f52156003026011186020526024601cfd5b505090613b7a92506139f8565b61495261455c565b506040519061496082613726565b6001600160a01b031681525f602082015290565b6001600160401b03821690811580156149d7575b6149d0576149ac926001600160401b039183838216115f146149c957505b166147f9565b670de0b6b3a7640000811115613b7a5750670de0b6b3a764000090565b90506149a6565b5050505f90565b506001600160401b03811615614988565b604051906149f760408361378b565b6001825260203681840137614a0b82613dc2565b6001600160a01b0390911690529056fe60803460b857601f6114b938819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36113e890816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806319f37361146104d75780632a5c792a146103f7578063715018a6146103a057806378a89567146103775780638da5cb5b14610350578063e4b50cb8146102f3578063e8a0aed3146100fe5763f2fde38b14610071575f80fd5b346100fa5760203660031901126100fa576004356001600160a01b038116908190036100fa5761009f610622565b80156100e7575f80546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b346100fa5760603660031901126100fa5760043567ffffffffffffffff81116100fa5761012f903690600401610564565b60243567ffffffffffffffff81116100fa5761014f903690600401610564565b60443560ff81168091036100fa57610165610622565b8251156102e4578151156102e45760405190610d4a9081830183811067ffffffffffffffff8211176102c55783926106498439608081526101ba6101ac60808301886105fe565b8281036020840152866105fe565b91604082015260603391015203905ff080156102d95760018060a01b0316905f5160206113935f395f51905f5254680100000000000000008110156102c5577f6596c1670eb3390048d23721809c3da5d3f531375ac0e2cab0f77a808ed643316102ac60209561023d8460018896015f5160206113935f395f51905f52556105ba565b81546001600160a01b0360039290921b82811b199091169087901b1790915584165f9081527f5c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b90160205260409020600160ff198254161790556102ba6040519283926040845260408401906105fe565b8281038984015233966105fe565b0390a3604051908152f35b634e487b7160e01b5f52604160045260245ffd5b6040513d5f823e3d90fd5b63ecd7b0d160e01b5f5260045ffd5b346100fa5760203660031901126100fa576004355f5160206113935f395f51905f5254811015610341576103286020916105ba565b905460405160039290921b1c6001600160a01b03168152f35b634e23d03560e01b5f5260045ffd5b346100fa575f3660031901126100fa575f546040516001600160a01b039091168152602090f35b346100fa575f3660031901126100fa5760205f5160206113935f395f51905f5254604051908152f35b346100fa575f3660031901126100fa576103b8610622565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100fa575f3660031901126100fa576040518060205f5160206113935f395f51905f5254928381520180925f5160206113935f395f51905f525f527f941c1986f49ec6ae940eac60cb4772d232cf98b87e67237c4199544bd2b0123d905f5b8181106104b8575050508161046d910382610542565b604051918291602083019060208452518091526040830191905f5b818110610496575050500390f35b82516001600160a01b0316845285945060209384019390920191600101610488565b82546001600160a01b0316845260209093019260019283019201610457565b346100fa5760203660031901126100fa576004356001600160a01b03811681036100fa576001600160a01b03165f9081527f5c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b9016020908152604090912060ff9054166040519015158152f35b90601f8019910116810190811067ffffffffffffffff8211176102c557604052565b81601f820112156100fa5780359067ffffffffffffffff82116102c55760405192610599601f8401601f191660200185610542565b828452602083830101116100fa57815f926020809301838601378301015290565b5f5160206113935f395f51905f52548110156105ea575f5160206113935f395f51905f525f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b5f546001600160a01b0316330361063557565b63118cdaa760e01b5f523360045260245ffdfe60a0604052346103a757610d4a80380380610019816103ab565b9283398101906080818303126103a75780516001600160401b0381116103a757826100459183016103d0565b602082015190926001600160401b0382116103a7576100659183016103d0565b9060408101519060ff821682036103a757606001516001600160a01b03811691908290036103a75783516001600160401b0381116102b857600354600181811c9116801561039d575b602082101461029a57601f811161033a575b50602094601f82116001146102d7579481929394955f926102cc575b50508160011b915f199060031b1c1916176003555b82516001600160401b0381116102b857600454600181811c911680156102ae575b602082101461029a57601f8111610237575b506020601f82116001146101d457819293945f926101c9575b50508160011b915f199060031b1c1916176004555b81156101b657600580546001600160a01b03198116841790915560405192906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a360805261092890816104228239608051816105860152f35b631e4fbdf760e01b5f525f60045260245ffd5b015190505f8061013d565b601f1982169060045f52805f20915f5b81811061021f57509583600195969710610207575b505050811b01600455610152565b01515f1960f88460031b161c191690555f80806101f9565b9192602060018192868b0151815501940192016101e4565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610290575b601f0160051c01905b8181106102855750610124565b5f8155600101610278565b909150819061026f565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610112565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100dc565b601f1982169560035f52805f20915f5b8881106103225750836001959697981061030a575b505050811b016003556100f1565b01515f1960f88460031b161c191690555f80806102fc565b919260206001819286850151815501940192016102e7565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610393575b601f0160051c01905b81811061038857506100c0565b5f815560010161037b565b9091508190610372565b90607f16906100ae565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102b857604052565b81601f820112156103a7578051906001600160401b0382116102b8576103ff601f8301601f19166020016103ab565b92828452602083830101116103a757815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461072857508063095ea7b3146106a657806318160ddd1461068957806323b872dd146105aa578063313ce5671461056d57806340c10f191461048857806370a0823114610451578063715018a6146103f65780638da5cb5b146103ce57806395d89b41146102b35780639dc29fac146101c1578063a9059cbb14610190578063dd62ed3e146101405763f2fde38b146100b6575f80fd5b3461013c57602036600319011261013c576100cf610821565b6100d76108cb565b6001600160a01b0316801561012957600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b3461013c57604036600319011261013c57610159610821565b610161610837565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b3461013c57604036600319011261013c576101b66101ac610821565b602435903361084d565b602060405160018152f35b3461013c57604036600319011261013c576101da610821565b6024359062aa36a746036102a6575b6001600160a01b031690811561029357815f525f60205260405f205481811061027a57817f8e396d76882ec446db350fff179713730a08f97b6f7ed47a2d265e25d1be97df92602092855f525f84520360405f205580600254036002555f847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051858152a3604051908152a2005b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd5b6102ae6108cb565b6101e9565b3461013c575f36600319011261013c576040515f6004548060011c906001811680156103c4575b6020831081146103b057828552908115610394575060011461033f575b50819003601f01601f191681019067ffffffffffffffff82118183101761032b57610327829182604052826107f7565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b82821061037e575060209150820101826102f7565b6001816020925483858801015201910190610369565b90506020925060ff191682840152151560051b820101826102f7565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102da565b3461013c575f36600319011261013c576005546040516001600160a01b039091168152602090f35b3461013c575f36600319011261013c5761040e6108cb565b600580546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461013c57602036600319011261013c576001600160a01b03610472610821565b165f525f602052602060405f2054604051908152f35b3461013c57604036600319011261013c576104a1610821565b6024359062aa36a74603610560575b6001600160a01b031690811561054d57600254818101809111610539577ff1d77337c6a221f354c5cb0cb43e4cb10ed777c3be30497bfc625e280ceaae6991602091600255835f525f825260405f20818154019055835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051858152a3604051908152a2005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b6105686108cb565b6104b0565b3461013c575f36600319011261013c57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461013c57606036600319011261013c576105c3610821565b6105cb610837565b6001600160a01b0382165f818152600160209081526040808320338452909152902054909260443592915f198110610609575b506101b6935061084d565b83811061066e57841561065b573315610648576101b6945f52600160205260405f2060018060a01b0333165f526020528360405f2091039055846105fe565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b3461013c575f36600319011261013c576020600254604051908152f35b3461013c57604036600319011261013c576106bf610821565b60243590331561065b576001600160a01b031690811561064857335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461013c575f36600319011261013c575f6003548060011c906001811680156107ed575b6020831081146103b05782855290811561039457506001146107985750819003601f01601f191681019067ffffffffffffffff82118183101761032b57610327829182604052826107f7565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b8282106107d7575060209150820101826102f7565b60018160209254838588010152019101906107c2565b91607f169161074c565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361013c57565b602435906001600160a01b038216820361013c57565b6001600160a01b0316908115610293576001600160a01b031691821561054d57815f525f60205260405f205481811061027a57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b6005546001600160a01b031633036108df57565b63118cdaa760e01b5f523360045260245ffdfea2646970667358221220b01ff437261f6cb2053cee001897173d6ec615564db68650687e059d06b6e85c64736f6c634300081e00335c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b900a2646970667358221220c6ba4ad719ad846d0f942f83fdbb0030855d3fc7f16efed5aa679ee68a7ab0d864736f6c634300081e00332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041006270edb7c868f86fda4adedba75108201087268ea345934db8bad688e1feb91b9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f8131bc7f7376b7d8d09601d142eed8304a0dce3fa238f43875ec194c35e4400a2646970667358221220ce2da5b17cd79d831d46f2767954350f0a32b356e59274731e8bb80baf9c67b364736f6c634300081e0033000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc3900000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda0000000000000000000000007a9aa939261fb51ddc9491c929224417a84592290000000000000000000000005e4c39ad7a3e881585e383db9827eb4811f6f647
Deployed Bytecode
0x610160806040526004361015610013575f80fd5b5f610140525f3560e01c90816301ffc9a71461364a57508063049d4c1b14613585578063084727b11461355a578063103f290714613516578063117803e3146134ef57806313ce83c61461341e57806317f24c0f14612ebc5780631ac71d9614612dba578063248a9ca314612d875780632f2ff15d14612ce1578063303ca95614612c5657806331232bc914612c1257806336568abe14612b7e57806338b1b34e14612b495780633aa83ec714612a885780633ab22ff2146125f157806344260ff4146125cc5780634571e3a61461205c5780634cef3daf14611cb157806357b53c8f1461061957806371e2c264146105d257806391d14854146105835780639fc2c4761461053c578063a217fddf1461051c578063ae501345146104d5578063aed753c914610496578063b526578714610467578063bac1e94b1461038d578063c63fd502146102de578063d547741f14610294578063d5c1c20a1461024d578063efd96978146101fb578063f4c3066f146101c45763f5beff1014610198575f80fd5b346101bd57610140513660031901126101bd576040516340e1896760e01b8152602090f35b6101405180fd5b346101bd57610140513660031901126101bd575f516020615ef55f395f51905f52546040516001600160a01b039091168152602090f35b346101bd5760203660031901126101bd5760043563ffffffff60e01b81168091036101bd5761014051525f516020615f555f395f51905f52602052602060ff6040610140512054166040519015158152f35b346101bd57610140513660031901126101bd576040517f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b03168152602090f35b346101bd5760403660031901126101bd576102d76004356102b36136b3565b906102d26102cd825f526065602052600160405f20015490565b613d57565b61410c565b6101405180f35b346101bd5760803660031901126101bd576102f761369d565b6102ff6136b3565b6044356001600160401b0381116101bd5761031e9036906004016136c9565b90926064356001600160401b0381116101bd577f9efdc3d07eb312e06bf36ea85db02aec96817d7c7421f919027b240eaf34035d9361036461036b9236906004016136f9565b50506140ae565b61038360405192839260018060a01b03169583613984565b0390a26101405180f35b346101bd5760203660031901126101bd576004356001600160e01b031981168082036101bd576103bc81613d57565b8061014051525f516020615f555f395f51905f5260205260ff60406101405120541615610452576101408051919091525f516020615f555f395f51905f5260209081529051604090819020805460ff1916905580516001600160e01b031993909316835233918301919091527fc7e56e17b0a6c4b467df6495e1eda1baecd7ba20604e80c1058ac06f4578d85e91a16101405180f35b6368c87f3360e11b6101405152600461014051fd5b346101bd5760203660031901126101bd57602061048261369d565b6040516001600160a01b0390911630148152f35b346101bd5760403660031901126101bd576104bf6104b261369d565b6104ba613c5d565b61386d565b6104cc60243582546139ca565b90556101405180f35b346101bd57610140513660031901126101bd576040517f0000000000000000000000005e4c39ad7a3e881585e383db9827eb4811f6f6476001600160a01b03168152602090f35b346101bd57610140513660031901126101bd576020604051610140518152f35b346101bd57610140513660031901126101bd576040517f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a6001600160a01b03168152602090f35b346101bd5760403660031901126101bd5761059c6136b3565b60043561014051526065602052604061014051209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b346101bd57610140513660031901126101bd576040517f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda6001600160a01b03168152602090f35b346101bd5760403660031901126101bd5761063261369d565b60e0526001600160401b03602435116101bd576060602435360360031901126101bd5761065d61418d565b6040516336b87bd760e11b81523360048201526020816024817f00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a6001600160a01b03165afa908115611b74576101405191611c92575b5015611c7d5763099b4ac360e31b61014051525f516020615f555f395f51905f5260205260ff604061014051205416611c68576106f160e051613a8c565b6024803501358015611c535760405163e063f81f60e01b81523360048201523060248201526020816044817f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda6001600160a01b03165afa8015611b74576101405190611c14575b61ffff915016611bff5760ff61076f60e0516138dd565b541660ff6107816024356004016139d7565b1603611bea5761079260e051613be6565b61010052506107a260e051613ac7565b60a0526040516107b181613726565b30815261014051602082019081526040516304c1b8eb60e31b815282516001600160a01b039081166004830152915163ffffffff1660248201527f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc399091169290602081604481875afa908115611b74576101405191611bcb575b5015611bb6576040516333869dd160e11b815233600482015282516001600160a01b03166024820152602083015163ffffffff166044820152602081606481875afa908115611b74576101405191611b97575b5015611b8257604051906338f6b94760e21b8252600482015260208160248160018060a01b0361010051165afa908115611b74576101405191611b42575b508015611b2d5760409061095982516108d5848261378b565b60018152601f198401366020830137336108ee82613dc2565b526109436108fe610100516149e8565b85516315a29d4d60e11b815287516001600160a01b03166004820152602088015163ffffffff1660248201529390928492839291608060448501526084840190613de3565b8281036003190160648401526101405194613de3565b0381885afa908115611412576101405191611a78575b5061097c61098291613dc2565b51613dc2565b518181106119f75782519163021c373760e31b8352606083806109ad610100518933600485016144c7565b0381895afa928315611721576101405193611a48575b506001600160401b03916109da91838551166148ac565b915116808211611a40575b506001600160401b038111611a2b5760606001600160401b03610a2392169383518093819263021c373760e31b8352610100519033600485016144c7565b0381875afa9081156118995783916001600160401b03916101405191611a0c575b505116106119f757602092815192610a5c858561378b565b610140518452610a8f6060610a703061494a565b85518093819263021c373760e31b8352610100519033600485016144c7565b0381865afa90811561172157610abc92916001600160401b039161014051916119c8575b50511690614974565b90610ac9610100516149e8565b835192610ad6858561378b565b60018452601f1985013688860137610aed84613dc2565b5283519060a08201908282106001600160401b038311176119ae57908552338252610140518783019081528583019182526060830194855260808301969096528451633635205760e01b81523060048201526024810186905282516001600160a01b03166044820152955163ffffffff1660648701525160a0608487015285929190610b7d9060e4850190613de3565b93518385036043190160a485015280518086526101405195890195918901915b89828210611997575050505082610bca608082930151956043198382030160c48401526101405196614278565b039161014051905af191821561198a576101405192611942575b50610bee3061494a565b81516316a26f7b60e11b815281516001600160a01b0316600482015260209091015163ffffffff1660248201529160448301819052610100516001600160a01b03908116606485015261014051859185916084918391907f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a165af1928315611899576101405193611913575b5082156118fe578151632495a59960e01b8152610100518590829060049082906001600160a01b03165afa9081156114125761014051916118e1575b506101408051845163a9059cbb60e01b90915230600452602486905290516001600160a01b0392909216929091869060448180875af160016101405151148116156118bf575b828552156118a65761014051825285820185905283820152610100516001600160a01b03169033907f3c011840976564fcc4559f75e69f8a0a69ebb3a374148ab6358c306c33dd41fa90606090a48051632495a59960e01b815260a0518490829060049082906001600160a01b03165afa8015611899576101405160c05261187a575b50610d8e6024356004016139d7565b8151906318160ddd60e01b8252848260048160018060a01b0360c051165afa9081156114125785906101405192611849575b8451632e35e48960e11b815260ff909116600482015230602482015292508280604481015b038160018060a01b0360e051165afa91821561141257610140519261181a575b50600161012081905281019081106118065761012051820180921161159457610e3c91610e3291856148ac565b61014051906139ca565b610140516080528151632495a59960e01b815260e0518590829060049082906001600160a01b03165afa9081156114125761014051916117e9575b5060e051610e909085906001600160a01b038416614413565b610e9e6024356004016139d7565b906024356044810135903603604219018112156101bd5760ff855193610ec385613755565b1683528587840152846003198260243501360301126101bd57845190610ee882613726565b600481602435010135906001600160401b0382116101bd57366023602435830184010112156101bd57602491610f2e9036908435840101600481810135918d01016137c7565b835281350101358782015284830152610f4b6024356004016139d7565b60ff855191630bdf607b60e41b8352166004820152868160248160018060a01b0360e051165afa9081156117dc5790879161014051916117af575b5061172e578451631fb96acd60e01b8152919282908190610faa906004830161429c565b03816101405160018060a01b0360e051165af18015611721576116e2575b50610fe790610140516080525b60e051906001600160a01b031661439b565b60c0516001600160a01b03163b156101bd5781516340c10f1960e01b8152610140805130600484015260248301849052905160c05183916044918391906001600160a01b03165af18015611412576116c7575b508151634fb3ccc560e01b815260e0518590829060049082906001600160a01b03165afa90811561141257610140519161169a575b506001600160a01b031680611632575b50815161108c858261378b565b610140518152825161109e848261378b565b61012051815285610140515b601f198601811061161157505083516110c281613726565b610100516001600160a01b03168152670de0b6b3a7640000878201526110e782613dc2565b526110f181613dc2565b508351916110ff858461378b565b61012051835286610140515b601f19870181106115f0575050845161112381613726565b338152848882015261113484613dc2565b5261113e83613dc2565b508451639d45c28160e01b815287816004817f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda6001600160a01b03165afa9081156115e35761014051916115ae575b5061119e63ffffffff8216426139f8565b80600119810111611594576111bf63ffffffff9182841690600119016139e5565b168651946111cd888761378b565b61012051865289610140515b601f198a0181106115505750509063ffffffff92918851956111fa87613770565b865260c0516001600160a01b03168b87015288860152606085015216608083015260a082015261122982613dc2565b5261123381613dc2565b5060c05161126f9083906001600160a01b037f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda81169116614413565b7f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda6001600160a01b03163b156101bd57825190634e5cd2fd60e11b825260448201306004840152846024840152815180915260648301908760648260051b86010193019161014051905b82821061141f5750506101405192849250829003905081837f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda6001600160a01b03165af18015611412576113f7575b5060c05160ff9390611366906001600160a01b037f0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda8116911661439b565b6113746024356004016139d7565b9280519560018060a01b036101005116875260018060a01b0360a0511690870152850152606084015260805160808401521660a082015260018060a01b0360e05116907ffaf66257bc51b727241377e1a40ac926a99e5955fa479671239fd77ebb72082560c03392a3610120515f516020615f355f395f51905f52556101405180f35b610140516114049161378b565b610140516101bd5784611328565b83513d61014051823e3d90fd5b90919293899060631987820301835285519060c081019180519260c0835283518091528460e0840194019061014051905b8d8183106115125750505050808401516001600160a01b0316828501528a8101518284038c8401528051808552610140519486019491860191905b8d8183106114e25750505050916114d09160a08463ffffffff60608897015116606084015263ffffffff608082015116608084015201519060a0818403910152614278565b950191019161012051019092916112d9565b9092969193949582885160018060a01b0381511683520151838201520195019161012051018e959493929161148b565b909296919394956bffffffffffffffffffffffff83895160018060a01b038151168452015116838201520195019161012051018e9594939291611450565b895161155b81613770565b60608152610140518382015260608b820152610140516060820152610140516080820152606060a082015282828a010152018a906111d9565b634e487b7160e01b61014051526011600452602461014051fd5b90508781813d83116115dc575b6115c5818361378b565b810103126101bd576115d690614462565b8861118d565b503d6115bb565b86513d61014051823e3d90fd5b86516115fb81613726565b5f81525f8382015282828701015201879061110b565b855161161c81613726565b5f81525f838201528282850101520186906110aa565b803b156101bd57825163569ebf3560e11b815260e0516001600160a01b03166004820152336024820152604481018590526101405190918290606490829084905af18015611412571561107f576101405161168c9161378b565b610140516101bd578461107f565b6116ba9150853d87116116c0575b6116b2818361378b565b81019061394d565b8561106f565b503d6116a8565b610140516116d49161378b565b610140516101bd578461103a565b8581813d831161171a575b6116f7818361378b565b810103126101bd57519065ffffffffffff821682036101bd579050610fe7610fc8565b503d6116ed565b84513d61014051823e3d90fd5b84516355ef454960e11b8152928390819061174c906004830161429c565b03816101405160018060a01b0360e051165af1801561172157610140519061177c575b610fe79250608052610fd5565b508582813d83116117a8575b611792818361378b565b810103126117a457610fe7915161176f565b5f80fd5b503d611788565b6117cf9150823d84116117d5575b6117c7818361378b565b81019061396c565b88610f86565b503d6117bd565b85513d61014051823e3d90fd5b6118009150853d87116116c0576116b2818361378b565b85610e77565b634e487b7160e01b5f52601160045260245ffd5b9091508481813d8311611842575b611832818361378b565b810103126117a457519085610e05565b503d611828565b915082813d8311611873575b61185f818361378b565b810103126117a45784610de5925191610dc0565b503d611855565b61189090843d86116116c0576116b2818361378b565b60c05283610d7f565b82513d61014051823e3d90fd5b82635274afe760e01b6101405152600452602461014051fd5b60018115166118d557833b15153d151616610cfc565b823d61014051823e3d90fd5b6118f89150853d87116116c0576116b2818361378b565b85610cb6565b639671a89f60e01b6101405152600461014051fd5b9092508381813d831161193b575b61192b818361378b565b810103126117a457519184610c7a565b503d611921565b9091503d8061014051833e611957818361378b565b81019082818303126101bd57805191848201516001600160401b0381116101bd5761198292016144ff565b509083610be4565b50513d61014051823e3d90fd5b835188529687019689965090920191600101610b9d565b634e487b7160e01b61014051526041600452602461014051fd5b6119ea915060603d6060116119f0575b6119e2818361378b565b810190614473565b88610ab3565b503d6119d8565b6337cb51dd60e21b6101405152600461014051fd5b611a25915060603d6060116119f0576119e2818361378b565b86610a44565b63125a110760e21b6101405152600461014051fd5b9050846109e5565b6109da91935091611a6f6001600160401b039360603d6060116119f0576119e2818361378b565b939150916109c3565b90503d8061014051833e611a8c818361378b565b8101906020818303126101bd578051906001600160401b0382116101bd57019080601f830112156101bd578151611ac281613dab565b92611acf8651948561378b565b81845260208085019260051b820101918383116101bd5760208201905b838210611b0057505050505061097c61096f565b81516001600160401b0381116101bd57602091611b22878480948801016144ff565b815201910190611aec565b63617ab12d60e11b6101405152600461014051fd5b90506020813d602011611b6c575b81611b5d6020938361378b565b810103126117a45751836108bc565b3d9150611b50565b6040513d61014051823e3d90fd5b631caa993f60e31b6101405152600461014051fd5b611bb0915060203d6020116117d5576117c7818361378b565b8461087e565b631fb1705560e21b6101405152600461014051fd5b611be4915060203d6020116117d5576117c7818361378b565b8461082b565b632f20e08d60e21b6101405152600461014051fd5b6315f1e15d60e21b6101405152600461014051fd5b506020813d602011611c4b575b81611c2e6020938361378b565b810103126101bd575161ffff811681036101bd5761ffff90610758565b3d9150611c21565b63162908e360e11b6101405152600461014051fd5b63722fdba960e01b6101405152600461014051fd5b6303fa1eaf60e41b6101405152600461014051fd5b611cab915060203d6020116117d5576117c7818361378b565b816106b3565b346101bd5760403660031901126101bd57611cca61369d565b602435611cd561418d565b611cdd6141c5565b8015611c5357611cec82613a8c565b60ff611cf7836138dd565b5416906001600160a01b03611d0b84613ac7565b16604051632495a59960e01b8152602081600481855afa908115611b7457611d4a918491610140519161203d575b506001600160a01b03168686613ae4565b928315611c5357604051632495a59960e01b8152602081600481865afa908115611b7457610140519161201e575b506040516370a0823160e01b81523360048201526001600160a01b039190911690602081602481855afa8015611b745785916101405191611fe9575b5010611fd4576101405150604051906323b872dd60e01b610140515233600452306024528460445260206101405160646101405161014051855af16001610140515114811615611fbe575b826040526101405160605215611fa657803b156101bd57632770a7eb60e21b82526101408051306004850152602484018790529051909183916044918391905af18015611b7457611f8b575b5060405192611e5984613726565b81845260208085018681526040516328c0104d60e21b8152955160ff166004870152516024860152610140516001600160a01b03881695919082906044908290895af18015611b7457611f59575b50611ee886611eb760409861386d565b611ec28882546139ca565b9055611ecd336137fd565b865f52602052875f20611ee18882546139ca565b9055613835565b611ef38682546139ca565b905585519283526020830152838583015261014051606083015260808201527fb70df16af75ac670505ba4838560ffb3b81c9e17013cf90d28a49ba89aa92bbf60a03392a360015f516020615f355f395f51905f52558151906101405182526020820152f35b6020813d602011611f83575b81611f726020938361378b565b810103126117a45750611ee8611ea7565b3d9150611f65565b61014051611f989161378b565b610140516101bd5785611e4b565b635274afe760e01b6101405152600452602461014051fd5b60018115166118d557813b15153d151616611dff565b631e9acf1760e31b6101405152600461014051fd5b9150506020813d602011612016575b816120056020938361378b565b810103126117a45784905188611db4565b3d9150611ff8565b612037915060203d6020116116c0576116b2818361378b565b86611d78565b612056915060203d6020116116c0576116b2818361378b565b87611d39565b346101bd5760603660031901126101bd5761207561369d565b61207d6136b3565b906044356001600160401b0381116101bd57366023820112156101bd576120ae9036906024816004013591016137c7565b9161014051549160ff8360081c1615928380946125bf575b80156125a8575b1561254c5783600160ff198316176101405155612537575b5060ff610140515460081c16916120fb83614218565b6001600160a01b0382169283158015612526575b611c535761213a9261212361213592614218565b61212c81613f6c565b61213583613f6c565b61400d565b610140516101405152606560205260406101405120815f5260205260ff60405f205416156124da575b5f516020615f155f395f51905f526101405152606560205260406101405120815f5260205260ff60405f20541615612479575b507f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b031691823b156101bd576040519063a982182160e01b82523060048301526040602483015281806121f861014051936044830190614278565b038161014051875af18015611b745761245e575b50604051916020919061221f838561378b565b6101405184525f3681376040519361223685613726565b61014051855283850152604093845191612250868461378b565b60018352601f1986019185610140515b84811061243957505061227284613dc2565b5261227c83613dc2565b5085519161228a878461378b565b6001835236868401373061229d83613dc2565b52803b156101bd57918551928391630caa1e7960e21b83526064830130600485015260606024850152815180915260848401908860848260051b87010193019161014051905b8a8c8484106123f4575050505050508261230e81926003198382030160448401526101405196613de3565b039161014051905af18015611721576123d9575b5082516114b9808201908282106001600160401b038311176119ae5784918391614a1c833930815203019061014051f080156114125760018060a01b03166bffffffffffffffffffffffff60a01b5f516020615ef55f395f51905f525416175f516020615ef55f395f51905f525561239b576101405180f35b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989161ff001961014051541661014051555160018152a180806102d7565b610140516123e69161378b565b610140516101bd5783612322565b6001939597985081929496612428916083198d8303018752838a5163ffffffff815116845201519181858201520190613de3565b9601920192018795949391926122e3565b885161244481613726565b610140518152606083820152828288010152018690612260565b6101405161246b9161378b565b610140516101bd578261220c565b5f516020615f155f395f51905f526101405152606560205260406101405120815f5260205260405f20600160ff1982541617905533905f516020615f155f395f51905f525f516020615ed55f395f51905f526101405161014051a482612196565b610140516101405152606560205260406101405120815f5260205260405f20600160ff198254161790553381610140515f516020615ed55f395f51905f526101405161014051a4612163565b506001600160a01b0382161561210f565b6101019061ffff1916176101405155846120e5565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156120cd5750600160ff8216146120cd565b50600160ff8216106120c6565b346101bd57610140513660031901126101bd5760405163099b4ac360e31b8152602090f35b346117a45760603660031901126117a45761260a61369d565b6044356001600160401b0381116117a4576126299036906004016136f9565b61263161418d565b6126396141c5565b61264283613a8c565b60ff61264d846138dd565b541661265884613ac7565b9261266285613be6565b92909461266e336137fd565b60018060a01b0388165f5260205260405f2054958615612a795761269188613835565b5480158015612a70575b612a2d57604051631344d22360e21b8152306004820152976001600160a01b038a16969060208a6024818b5afa998a1561299c575f9a612a3c575b506126e08b61386d565b54996126ee8b828685613a16565b9a8b15612a2d5781156129a757893b156117a457604051636b7f4ea560e11b8152915f83600481838f5af192831561299c5761272f93612987575b506139ca565b808b11611c535760209b602460018060a01b0387169d8e604051928380926370a0823160e01b82523060048301525afa908115611b74576101405191612955575b508c11611c53576020946127ce92612789908e9061420b565b938181111561294657505061014051925b83158061293d575b612933575b6127b08261386d565b556127ba336137fd565b8a5f52855260405f20610140519055613835565b556001600160a01b0316946127e286613d9b565b7f000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a6001600160a01b03169960e49061281b8b8d87614413565b896040519a8b9485936319744d6760e11b85528b600486015260248501528d6044850152336064850152602435608485015260c060a48501528160c48501528484013761014051838284010152601f80199101168101030181610140518c5af1958615611b745761014051966128fe575b506040976128999161439b565b865192835260018060a01b03166020830152848683015283606083015260808201527f08ff66ecb49dae546cb0e627ae91149487467cce83755083bb0e1ad9ac59315160a03392a360015f516020615f355f395f51905f525582519182526020820152f35b9095506020813d60201161292b575b8161291a6020938361378b565b810103126117a4575194604061288c565b3d915061290d565b50610140516127a7565b508015156127a2565b61294f9161420b565b9261279a565b90506020813d60201161297f575b816129706020938361378b565b810103126117a457518e612770565b3d9150612963565b5f6129919161378b565b5f610140528e612729565b6040513d5f823e3d90fd5b905080156117a4576040516370a0823160e01b8152306004820152906020826024816001600160a01b038a165afa91821561299c575f926129f9575b50808210156129f2575061272f565b905061272f565b9091506020813d602011612a25575b81612a156020938361378b565b810103126117a45751908d6129e3565b3d9150612a08565b63162908e360e11b5f5260045ffd5b9099506020813d602011612a68575b81612a586020938361378b565b810103126117a45751988b6126d6565b3d9150612a4b565b5087811061269b565b63487192dd60e01b5f5260045ffd5b346117a45760203660031901126117a4576004356001600160e01b031981168082036117a457612ab781613d57565b805f525f516020615f555f395f51905f5260205260ff60405f205416612b3a575f9081525f516020615f555f395f51905f526020908152604091829020805460ff1916600117905581516001600160e01b031993909316835233908301527f95c3658c5e0c74e20cf12db371b9b67d26e97a1937f6d2284f88cc44d036b4f691a1005b63722fdba960e01b5f5260045ffd5b346117a45760203660031901126117a45760206001600160a01b03612b74612b6f61369d565b613915565b5416604051908152f35b346117a45760403660031901126117a457612b976136b3565b336001600160a01b03821603612bb557612bb39060043561410c565b005b60405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608490fd5b346117a4575f3660031901126117a4576040517f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b03168152602090f35b346117a45760603660031901126117a457612c6f61369d565b612c776136b3565b906044356001600160401b0381116117a4577ff8aaad08ee23b49c9bb44e3bca6c7efa43442fc4281245a7f2475aa2632718d191612cbc612cc49236906004016136c9565b9290946140ae565b612cdc60405192839260018060a01b03169583613984565b0390a2005b346117a45760403660031901126117a457600435612cfd6136b3565b90612d176102cd825f526065602052600160405f20015490565b805f52606560205260405f2060018060a01b0383165f5260205260ff60405f20541615612d4057005b5f8181526065602090815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291905f516020615ed55f395f51905f529080a4005b346117a45760203660031901126117a4576020612db26004355f526065602052600160405f20015490565b604051908152f35b346117a45760403660031901126117a457612dd361369d565b612de4612dde6136b3565b916137fd565b60018060a01b0382165f5260205260405f2054612e0082613835565b54604051631344d22360e21b815230600482015292906020846024816001600160a01b0386165afa90811561299c575f91612e87575b608094508315159283612e5e575b506040519384526020840152604083015215156060820152f35b909250811590811591612e74575b509185612e44565b612e7e915061386d565b54151585612e6c565b90506020843d602011612eb4575b81612ea26020938361378b565b810103126117a4576080935190612e36565b3d9150612e95565b346117a45760603660031901126117a45760043560ff8116908181036117a457612ee46136b3565b916044356001600160a01b038116918282036117a457612f02613c5d565b604051630642194560e41b81526001600160a01b0386811660048301819052929190602090829060249082907f0000000000000000000000007a9aa939261fb51ddc9491c929224417a8459229165afa90811561299c575f916133ff575b50156133f0576001600160a01b03612f77876138a5565b54166133e157612f8684613d9b565b604051632495a59960e01b8152602081600481885afa90811561299c575f916133c2575b50604051632495a59960e01b81526001600160a01b03919091169390602081600481875afa801561299c5785915f916133a3575b506001600160a01b031603613394575f516020615ef55f395f51905f52546040516306fdde0360e01b8152906001600160a01b03165f82600481885afa91821561299c575f92613378575b506040516306fdde0360e01b8152915f836004818a5afa92831561299c575f9361335c575b506040516395d89b4160e01b8152925f846004818b5afa93841561299c575f9461332c575b50906130828161308893614345565b93614345565b9160405163313ce56760e01b81526020816004818b5afa90811561299c575f916132e6575b50916130e25f6130f4959360209560ff6040519889978896879563e8a0aed360e01b8752606060048801526064870190614278565b85810360031901602487015290614278565b9116604483015203925af190811561299c575f916132c7575b5060405163581dfd6560e01b81526001600160a01b03918216600482018190527f0000000000000000000000005e4c39ad7a3e881585e383db9827eb4811f6f64790921698919691906020816024818d5afa90811561299c575f916132a8575b506001600160a01b038116156132285760209950916131e97f2840f76158e444c1d697cef892b963f173b7dd782e0e1887a5521b40f9841b079594926131ff94955b6131b8826138a5565b80546001600160a01b0319166001600160a01b0389161790556131da826138dd565b9060ff19825416179055613915565b80546001600160a01b0319169091179055613e1f565b6040805160ff9790971687526001600160a01b03919091166020870181905295a4604051908152f35b50929160205f996024604051809c8193636b9b622960e01b83528c60048401525af191821561299c576131e97f2840f76158e444c1d697cef892b963f173b7dd782e0e1887a5521b40f9841b07956131ff9460209c5f9161328b575b50956131af565b6132a291508d3d8f116116c0576116b2818361378b565b8d613284565b6132c1915060203d6020116116c0576116b2818361378b565b8a61316d565b6132e0915060203d6020116116c0576116b2818361378b565b8861310d565b90506020939193813d602011613324575b816133046020938361378b565b810103126117a457519160ff831683036117a457909290916130e26130ad565b3d91506132f7565b8261308893929550613352613082923d805f833e61334a818361378b565b8101906142e3565b9592509250613073565b6133719193503d805f833e61334a818361378b565b918a61304e565b61338d9192503d805f833e61334a818361378b565b9089613029565b632711b74d60e11b5f5260045ffd5b6133bc915060203d6020116116c0576116b2818361378b565b89612fde565b6133db915060203d6020116116c0576116b2818361378b565b87612faa565b63abd5ec5d60e01b5f5260045ffd5b630681d31960e51b5f5260045ffd5b613418915060203d6020116117d5576117c7818361378b565b87612f60565b346117a45760403660031901126117a457600461343961369d565b61344281613a8c565b61344b81613ac7565b602060ff613458846138dd565b54604051632495a59960e01b81529591169285919082906001600160a01b03165afa92831561299c576060936134af926134a9925f926134ce575b50602435916001600160a01b0316908590613ae4565b91613be6565b604080519384526001600160a01b039182166020850152911690820152f35b6134e891925060203d6020116116c0576116b2818361378b565b9086613493565b346117a4575f3660031901126117a45760206040515f516020615f155f395f51905f528152f35b346117a4575f3660031901126117a4576040517f0000000000000000000000007a9aa939261fb51ddc9491c929224417a84592296001600160a01b03168152602090f35b346117a45760203660031901126117a45760206001600160a01b03612b7461358061369d565b6138a5565b346117a45760403660031901126117a45761359e61369d565b6135a9612dde6136b3565b60018060a01b0382165f5260205260405f20546135c582613835565b54604051631344d22360e21b815230600482015290926020826024816001600160a01b0385165afa91821561299c575f92613613575b6020612db285858861360c8761386d565b5492613a16565b9291506020833d602011613642575b8161362f6020938361378b565b810103126117a4579151909160206135fb565b3d9150613622565b346117a45760203660031901126117a4576004359063ffffffff60e01b82168092036117a457602091637965db0b60e01b811490811561368c575b5015158152f35b6301ffc9a760e01b14905083613685565b600435906001600160a01b03821682036117a457565b602435906001600160a01b03821682036117a457565b9181601f840112156117a4578235916001600160401b0383116117a4576020808501948460051b0101116117a457565b9181601f840112156117a4578235916001600160401b0383116117a457602083818601950101116117a457565b604081019081106001600160401b0382111761374157604052565b634e487b7160e01b5f52604160045260245ffd5b606081019081106001600160401b0382111761374157604052565b60c081019081106001600160401b0382111761374157604052565b90601f801991011681019081106001600160401b0382111761374157604052565b6001600160401b03811161374157601f01601f191660200190565b9291926137d3826137ac565b916137e1604051938461378b565b8294818452818301116117a4578281602093845f960137010152565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041056020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041066020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041076020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041016020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041036020526040902090565b6001600160a01b03165f9081527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041026020526040902090565b908160209103126117a457516001600160a01b03811681036117a45790565b908160209103126117a4575180151581036117a45790565b60208082528101839052604001915f905b8082106139a25750505090565b90919283359063ffffffff82168092036117a457602081600193829352019401920190613995565b9190820180921161180657565b3560ff811681036117a45790565b8181029291811591840414171561180657565b8115613a02570490565b634e487b7160e01b5f52601260045260245ffd5b90928115613a8457613a2881846139ca565b9081158015613a7c575b613a7357613a4985613a4484866139e5565b6139f8565b9315613a6b5750925b03613a5b575090565b9190808311613a675750565b9150565b905092613a52565b50505050505f90565b508415613a32565b505050505f90565b6001600160a01b03613a9d826138a5565b541615613aa75750565b636315b1a360e01b5f9081526001600160a01b0391909116600452602490fd5b6001600160a01b0390613ad9906138a5565b541690811561339457565b604051632e35e48960e11b815260ff9190911660048201523060248201529190602090839060449082906001600160a01b03165afa91821561299c575f92613bb1575b506040516318160ddd60e01b81529190602090839060049082906001600160a01b03165afa91821561299c575f92613b7d575b5060018101809111611806576001820180921161180657613b7a926148ac565b90565b9091506020813d602011613ba9575b81613b996020938361378b565b810103126117a45751905f613b5a565b3d9150613b8c565b91506020823d602011613bde575b81613bcc6020938361378b565b810103126117a4579051906020613b27565b3d9150613bbf565b6001600160a01b03613bf782613915565b541690811561339457604051632495a59960e01b815290602090829060049082906001600160a01b03165afa90811561299c575f91613c3e575b506001600160a01b031691565b613c57915060203d6020116116c0576116b2818361378b565b5f613c31565b335f9081527f077c9007150f571447365d3bd382bfccc7ce27caa9a880faf975f29f5cafcb79602052604090205460ff1615613c9557565b613d536020613d336011613ca833614585565b603784613cc15f516020615f155f395f51905f5261466b565b6040519687947f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000828701528051918291018587015e8401907001034b99036b4b9b9b4b733903937b6329607d1b84830152805192839101604883015e01015f838201520301601f19810183528261378b565b60405162461bcd60e51b8152602060048201529182916024830190614278565b0390fd5b5f81815260656020908152604080832033845290915290205460ff1615613d7b5750565b6020613d336011613d5393603784613cc1613d9533614585565b9361466b565b6001600160a01b03161561339457565b6001600160401b0381116137415760051b60200190565b805115613dcf5760200190565b634e487b7160e01b5f52603260045260245ffd5b90602080835192838152019201905f5b818110613e005750505090565b82516001600160a01b0316845260209384019390920191600101613df3565b6001600160a01b03165f8181527f9bc6362768ab7acc6d678440e313110dcbcf1f3bce0a546779127863e2b88a09602052604081205490919060ff16613f68576040918251613e6e848261378b565b60018152601f19840136602083013782613e8782613dc2565b527f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b0316803b156117a457613ef05f929183928751948580948193630287f75160e51b8352306004840152836024840152606060448401526064830190613de3565b03925af18015613f5e5790849291613f49575b508080527f032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db604104602052209060018060a01b03165f526020525f20600160ff19825416179055565b613f5692505f915061378b565b815f5f613f03565b84513d5f823e3d90fd5b5050565b6001600160a01b0381165f9081527f714e2b715aba5871ce4d05fd99bd94a36ff2fc47fdbc62c5c1bc08b10a64682e602052604090205460ff1615613fae5750565b6001600160a01b03165f8181527f714e2b715aba5871ce4d05fd99bd94a36ff2fc47fdbc62c5c1bc08b10a64682e60205260408120805460ff1916600117905533919063099b4ac360e31b905f516020615ed55f395f51905f529080a4565b6001600160a01b0381165f9081527f9a824e0a361d4dc38210d8d46718f5a024fcd5426c72be95b98894eaa9f84758602052604090205460ff161561404f5750565b6001600160a01b03165f8181527f9a824e0a361d4dc38210d8d46718f5a024fcd5426c72be95b98894eaa9f8475860205260408120805460ff191660011790553391906340e1896760e01b905f516020615ed55f395f51905f529080a4565b337f000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc396001600160a01b031614801591906140f8575b506140ea57565b6282b42960e81b5f5260045ffd5b6001600160a01b031630141590505f6140e3565b805f52606560205260405f2060018060a01b0383165f5260205260ff60405f205416614136575050565b5f8181526065602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4565b60025f516020615f355f395f51905f5254146141b65760025f516020615f355f395f51905f5255565b633ee5aeb560e01b5f5260045ffd5b6340e1896760e01b5f525f516020615f555f395f51905f526020527f3663686bcf2d729d4855c41e87932887789108353c8318329b1f901b652c7a495460ff16612b3a57565b9190820391821161180657565b1561421f57565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b906040906020835260ff815116602084015260208101518284015201519060608082015260a060206142da84516040608086015260c0850190614278565b93015191015290565b6020818303126117a4578051906001600160401b0382116117a4570181601f820112156117a457805190614316826137ac565b92614324604051948561378b565b828452602083830101116117a457815f9260208093018386015e8301015290565b6001614399916022602080969560405197889461185b60f21b828701528051918291018587015e840190602d60f81b84830152805192839101602383015e01015f838201520301601f19810184528361378b565b565b906143a75f828461470d565b156143b0575050565b6143ba818361475a565b156143f2575f6143ca91836147be565b156143d25750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b50635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b919061442082828561470d565b1561442a57505050565b614434818461475a565b1561444457906143ca91836147be565b635274afe760e01b5f9081526001600160a01b038416600452602490fd5b519063ffffffff821682036117a457565b908160609103126117a4576040519061448b82613755565b80516001600160401b03811681036117a4578252602081015180600f0b81036117a45760208301526144bf90604001614462565b604082015290565b6001600160a01b039182168152825182166020808301919091529092015163ffffffff16604083015291909116606082015260800190565b9080601f830112156117a457815161451681613dab565b92614524604051948561378b565b81845260208085019260051b8201019283116117a457602001905b82821061454c5750505090565b815181526020918201910161453f565b6040519061456982613726565b5f6020838281520152565b908151811015613dcf570160200190565b61458f602a6137ac565b9061459d604051928361378b565b602a82526145ab602a6137ac565b6020830190601f1901368237825115613dcf5760309053815160011015613dcf576078602183015360295b6001811161462a57506145e65790565b606460405162461bcd60e51b815260206004820152602060248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f81166010811015613dcf576f181899199a1a9b1b9c1cb0b131b232b360811b901a6146588385614574565b5360041c908015611806575f19016145d6565b61467560426137ac565b90614683604051928361378b565b6042825261469160426137ac565b6020830190601f1901368237825115613dcf5760309053815160011015613dcf576078602183015360415b600181116146cc57506145e65790565b90600f81166010811015613dcf576f181899199a1a9b1b9c1cb0b131b232b360811b901a6146fa8385614574565b5360041c908015611806575f19016146bc565b92916040519163095ea7b360e01b5f5260018060a01b031660045260245260205f60448180875af19260015f5114841615614749575b50604052565b3d15903b151516909216915f614743565b60405163095ea7b360e01b5f9081526001600160a01b03909316600452602483905290929160209060448180875af19260015f511484161561479c5750604052565b600184929415166147b5573b15153d151616915f614743565b833d5f823e3d90fd5b92916040519163095ea7b360e01b5f5260018060a01b031660045260245260205f60448180875af19260015f511484161561479c5750604052565b5f19670de0b6b3a7640000820991670de0b6b3a76400008202918280851094039380850394146148a0578382111561488857670de0b6b3a7640000829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b50634e487b715f52156003026011186020526024601cfd5b5090613b7a92506139f8565b90915f19838309928083029283808610950394808603951461493d57848311156149255790829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b82634e487b715f52156003026011186020526024601cfd5b505090613b7a92506139f8565b61495261455c565b506040519061496082613726565b6001600160a01b031681525f602082015290565b6001600160401b03821690811580156149d7575b6149d0576149ac926001600160401b039183838216115f146149c957505b166147f9565b670de0b6b3a7640000811115613b7a5750670de0b6b3a764000090565b90506149a6565b5050505f90565b506001600160401b03811615614988565b604051906149f760408361378b565b6001825260203681840137614a0b82613dc2565b6001600160a01b0390911690529056fe60803460b857601f6114b938819003918201601f19168301916001600160401b0383118484101760bc5780849260209460405283398101031260b857516001600160a01b0381169081900360b857801560a5575f80546001600160a01b031981168317825560405192916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36113e890816100d18239f35b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806319f37361146104d75780632a5c792a146103f7578063715018a6146103a057806378a89567146103775780638da5cb5b14610350578063e4b50cb8146102f3578063e8a0aed3146100fe5763f2fde38b14610071575f80fd5b346100fa5760203660031901126100fa576004356001600160a01b038116908190036100fa5761009f610622565b80156100e7575f80546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b346100fa5760603660031901126100fa5760043567ffffffffffffffff81116100fa5761012f903690600401610564565b60243567ffffffffffffffff81116100fa5761014f903690600401610564565b60443560ff81168091036100fa57610165610622565b8251156102e4578151156102e45760405190610d4a9081830183811067ffffffffffffffff8211176102c55783926106498439608081526101ba6101ac60808301886105fe565b8281036020840152866105fe565b91604082015260603391015203905ff080156102d95760018060a01b0316905f5160206113935f395f51905f5254680100000000000000008110156102c5577f6596c1670eb3390048d23721809c3da5d3f531375ac0e2cab0f77a808ed643316102ac60209561023d8460018896015f5160206113935f395f51905f52556105ba565b81546001600160a01b0360039290921b82811b199091169087901b1790915584165f9081527f5c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b90160205260409020600160ff198254161790556102ba6040519283926040845260408401906105fe565b8281038984015233966105fe565b0390a3604051908152f35b634e487b7160e01b5f52604160045260245ffd5b6040513d5f823e3d90fd5b63ecd7b0d160e01b5f5260045ffd5b346100fa5760203660031901126100fa576004355f5160206113935f395f51905f5254811015610341576103286020916105ba565b905460405160039290921b1c6001600160a01b03168152f35b634e23d03560e01b5f5260045ffd5b346100fa575f3660031901126100fa575f546040516001600160a01b039091168152602090f35b346100fa575f3660031901126100fa5760205f5160206113935f395f51905f5254604051908152f35b346100fa575f3660031901126100fa576103b8610622565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346100fa575f3660031901126100fa576040518060205f5160206113935f395f51905f5254928381520180925f5160206113935f395f51905f525f527f941c1986f49ec6ae940eac60cb4772d232cf98b87e67237c4199544bd2b0123d905f5b8181106104b8575050508161046d910382610542565b604051918291602083019060208452518091526040830191905f5b818110610496575050500390f35b82516001600160a01b0316845285945060209384019390920191600101610488565b82546001600160a01b0316845260209093019260019283019201610457565b346100fa5760203660031901126100fa576004356001600160a01b03811681036100fa576001600160a01b03165f9081527f5c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b9016020908152604090912060ff9054166040519015158152f35b90601f8019910116810190811067ffffffffffffffff8211176102c557604052565b81601f820112156100fa5780359067ffffffffffffffff82116102c55760405192610599601f8401601f191660200185610542565b828452602083830101116100fa57815f926020809301838601378301015290565b5f5160206113935f395f51905f52548110156105ea575f5160206113935f395f51905f525f5260205f2001905f90565b634e487b7160e01b5f52603260045260245ffd5b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b5f546001600160a01b0316330361063557565b63118cdaa760e01b5f523360045260245ffdfe60a0604052346103a757610d4a80380380610019816103ab565b9283398101906080818303126103a75780516001600160401b0381116103a757826100459183016103d0565b602082015190926001600160401b0382116103a7576100659183016103d0565b9060408101519060ff821682036103a757606001516001600160a01b03811691908290036103a75783516001600160401b0381116102b857600354600181811c9116801561039d575b602082101461029a57601f811161033a575b50602094601f82116001146102d7579481929394955f926102cc575b50508160011b915f199060031b1c1916176003555b82516001600160401b0381116102b857600454600181811c911680156102ae575b602082101461029a57601f8111610237575b506020601f82116001146101d457819293945f926101c9575b50508160011b915f199060031b1c1916176004555b81156101b657600580546001600160a01b03198116841790915560405192906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a360805261092890816104228239608051816105860152f35b631e4fbdf760e01b5f525f60045260245ffd5b015190505f8061013d565b601f1982169060045f52805f20915f5b81811061021f57509583600195969710610207575b505050811b01600455610152565b01515f1960f88460031b161c191690555f80806101f9565b9192602060018192868b0151815501940192016101e4565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610290575b601f0160051c01905b8181106102855750610124565b5f8155600101610278565b909150819061026f565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610112565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100dc565b601f1982169560035f52805f20915f5b8881106103225750836001959697981061030a575b505050811b016003556100f1565b01515f1960f88460031b161c191690555f80806102fc565b919260206001819286850151815501940192016102e7565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c81019160208410610393575b601f0160051c01905b81811061038857506100c0565b5f815560010161037b565b9091508190610372565b90607f16906100ae565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102b857604052565b81601f820112156103a7578051906001600160401b0382116102b8576103ff601f8301601f19166020016103ab565b92828452602083830101116103a757815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde031461072857508063095ea7b3146106a657806318160ddd1461068957806323b872dd146105aa578063313ce5671461056d57806340c10f191461048857806370a0823114610451578063715018a6146103f65780638da5cb5b146103ce57806395d89b41146102b35780639dc29fac146101c1578063a9059cbb14610190578063dd62ed3e146101405763f2fde38b146100b6575f80fd5b3461013c57602036600319011261013c576100cf610821565b6100d76108cb565b6001600160a01b0316801561012957600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b3461013c57604036600319011261013c57610159610821565b610161610837565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b3461013c57604036600319011261013c576101b66101ac610821565b602435903361084d565b602060405160018152f35b3461013c57604036600319011261013c576101da610821565b6024359062aa36a746036102a6575b6001600160a01b031690811561029357815f525f60205260405f205481811061027a57817f8e396d76882ec446db350fff179713730a08f97b6f7ed47a2d265e25d1be97df92602092855f525f84520360405f205580600254036002555f847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051858152a3604051908152a2005b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd5b6102ae6108cb565b6101e9565b3461013c575f36600319011261013c576040515f6004548060011c906001811680156103c4575b6020831081146103b057828552908115610394575060011461033f575b50819003601f01601f191681019067ffffffffffffffff82118183101761032b57610327829182604052826107f7565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b82821061037e575060209150820101826102f7565b6001816020925483858801015201910190610369565b90506020925060ff191682840152151560051b820101826102f7565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102da565b3461013c575f36600319011261013c576005546040516001600160a01b039091168152602090f35b3461013c575f36600319011261013c5761040e6108cb565b600580546001600160a01b031981169091555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461013c57602036600319011261013c576001600160a01b03610472610821565b165f525f602052602060405f2054604051908152f35b3461013c57604036600319011261013c576104a1610821565b6024359062aa36a74603610560575b6001600160a01b031690811561054d57600254818101809111610539577ff1d77337c6a221f354c5cb0cb43e4cb10ed777c3be30497bfc625e280ceaae6991602091600255835f525f825260405f20818154019055835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051858152a3604051908152a2005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b6105686108cb565b6104b0565b3461013c575f36600319011261013c57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461013c57606036600319011261013c576105c3610821565b6105cb610837565b6001600160a01b0382165f818152600160209081526040808320338452909152902054909260443592915f198110610609575b506101b6935061084d565b83811061066e57841561065b573315610648576101b6945f52600160205260405f2060018060a01b0333165f526020528360405f2091039055846105fe565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b3461013c575f36600319011261013c576020600254604051908152f35b3461013c57604036600319011261013c576106bf610821565b60243590331561065b576001600160a01b031690811561064857335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461013c575f36600319011261013c575f6003548060011c906001811680156107ed575b6020831081146103b05782855290811561039457506001146107985750819003601f01601f191681019067ffffffffffffffff82118183101761032b57610327829182604052826107f7565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b8282106107d7575060209150820101826102f7565b60018160209254838588010152019101906107c2565b91607f169161074c565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b038216820361013c57565b602435906001600160a01b038216820361013c57565b6001600160a01b0316908115610293576001600160a01b031691821561054d57815f525f60205260405f205481811061027a57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b6005546001600160a01b031633036108df57565b63118cdaa760e01b5f523360045260245ffdfea2646970667358221220b01ff437261f6cb2053cee001897173d6ec615564db68650687e059d06b6e85c64736f6c634300081e00335c57fc7b6bf6ceeaa106d807cc261837d3f0a0c5e72fcba25c00753c6ce2b900a2646970667358221220c6ba4ad719ad846d0f942f83fdbb0030855d3fc7f16efed5aa679ee68a7ab0d864736f6c634300081e00332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d032f19bc7820640f5c22e33241af744bedc756ef7c75496e1c948383db6041006270edb7c868f86fda4adedba75108201087268ea345934db8bad688e1feb91b9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f8131bc7f7376b7d8d09601d142eed8304a0dce3fa238f43875ec194c35e4400a2646970667358221220ce2da5b17cd79d831d46f2767954350f0a32b356e59274731e8bb80baf9c67b364736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc3900000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda0000000000000000000000007a9aa939261fb51ddc9491c929224417a84592290000000000000000000000005e4c39ad7a3e881585e383db9827eb4811f6f647
-----Decoded View---------------
Arg [0] : _allocationManager (address): 0x948a420b8CC1d6BFd0B6087C2E7c344a2CD0bc39
Arg [1] : _delegationManager (address): 0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A
Arg [2] : _strategyManager (address): 0x858646372CC42E1A627fcE94aa7A7033e7CF075A
Arg [3] : _rewardsCoordinator (address): 0x7750d328b314EfFa365A0402CcfD489B80B0adda
Arg [4] : _vaultFactory (address): 0x7a9aA939261fb51Ddc9491C929224417a8459229
Arg [5] : _strategyFactory (address): 0x5e4C39Ad7A3E881585e383dB9827EB4811f6F647
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000948a420b8cc1d6bfd0b6087c2e7c344a2cd0bc39
Arg [1] : 00000000000000000000000039053d51b77dc0d36036fc1fcc8cb819df8ef37a
Arg [2] : 000000000000000000000000858646372cc42e1a627fce94aa7a7033e7cf075a
Arg [3] : 0000000000000000000000007750d328b314effa365a0402ccfd489b80b0adda
Arg [4] : 0000000000000000000000007a9aa939261fb51ddc9491c929224417a8459229
Arg [5] : 0000000000000000000000005e4c39ad7a3e881585e383db9827eb4811f6f647
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 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.