HYPE Price: $22.20 (+0.26%)
 

Overview

HYPE Balance

HyperEVM LogoHyperEVM LogoHyperEVM Logo0 HYPE

HYPE Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ValidatorManager

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;

import {AccessControlEnumerableUpgradeable} from
    "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {IValidatorManager} from "./interfaces/IValidatorManager.sol";
import {IPauserRegistry} from "./interfaces/IPauserRegistry.sol";
import {IStakingManager} from "./interfaces/IStakingManager.sol";

/**
 * @title ValidatorManager
 * @notice Manages validator registration, performance tracking, and rebalancing
 * @dev This contract handles validator lifecycle and stake rebalancing
 */
contract ValidatorManager is
    IValidatorManager,
    Initializable,
    AccessControlEnumerableUpgradeable,
    ReentrancyGuardUpgradeable
{
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /* ========== LIBRARIES ========== */

    using EnumerableSet for EnumerableSet.AddressSet;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableMap for EnumerableMap.AddressToUintMap;

    /* ========== CONSTANTS ========== */

    /// @notice Basis points denominator (100%)
    uint256 public constant BASIS_POINTS = 10000;

    /* ========== ROLES ========== */

    /// @notice Role that can manage validators and operational parameters
    bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE");

    /// @notice Role that can update validator performance
    bytes32 public constant ORACLE_MANAGER_ROLE = keccak256("ORACLE_MANAGER_ROLE");

    /* ========== STATE VARIABLES ========== */

    /// @notice Registry for pausing functionality
    IPauserRegistry public pauserRegistry;

    /// @notice Total amount slashed across all validators
    uint256 public totalSlashing; // In 18 decimals

    /// @notice Total rewards across all validators
    uint256 public totalRewards; // In 18 decimals

    /// @notice Mapping of staking manager to delegation target
    mapping(address => address) public delegations;

    /// @notice Mapping of validator to rebalance request
    mapping(address => RebalanceRequest) public validatorRebalanceRequests;

    /// @notice Mapping of validator to performance report
    mapping(address => PerformanceReport) public validatorPerformance;

    /// @notice Mapping of validator to total slashing amount
    mapping(address => uint256) public validatorSlashing;

    /// @notice Mapping of validator to total rewards
    mapping(address => uint256) public validatorRewards;

    /// @dev Array of all validators
    Validator[] internal _validators;

    /// @dev Mapping of validator address to index in _validators array
    EnumerableMap.AddressToUintMap internal _validatorIndexes;

    /// @dev Set of validators with pending rebalance
    EnumerableSet.AddressSet internal _validatorsWithPendingRebalance;

    /* ========== MODIFIERS ========== */

    modifier whenNotPaused() {
        require(!pauserRegistry.isPaused(address(this)), "Contract is paused");
        _;
    }

    modifier validatorExists(address validator) {
        require(_validatorIndexes.contains(validator), "Validator does not exist");
        _;
    }

    modifier validatorActive(address validator) {
        require(validatorActiveState(validator), "Validator not active");
        _;
    }

    /* ========== INITIALIZATION ========== */

    /**
     * @notice Initialize the contract with initial configuration
     * @param admin Address that will have admin role
     * @param manager Address that will have manager role
     * @param _oracle Address that will have oracle role
     * @param _pauserRegistry Address of the pauser registry contract
     */
    function initialize(address admin, address manager, address _oracle, address _pauserRegistry)
        external
        initializer
    {
        require(admin != address(0), "Invalid admin address");
        require(manager != address(0), "Invalid manager address");
        require(_oracle != address(0), "Invalid oracle address");
        require(_pauserRegistry != address(0), "Invalid pauser registry");

        __AccessControlEnumerable_init();
        __ReentrancyGuard_init();

        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(MANAGER_ROLE, manager);
        _grantRole(ORACLE_MANAGER_ROLE, _oracle);

        pauserRegistry = IPauserRegistry(_pauserRegistry);
    }

    /* ========== VALIDATOR MANAGEMENT ========== */

    /**
     * @notice Activate a new validator in the system
     * @param validator Address of the validator to activate
     */
    function activateValidator(address validator) external whenNotPaused onlyRole(MANAGER_ROLE) {
        require(validator != address(0), "Invalid validator address");
        require(!_validatorIndexes.contains(validator), "Validator already exists");

        Validator memory newValidator =
            Validator({balance: 0, performanceScore: 0, lastUpdateTime: block.timestamp, active: true});

        _validators.push(newValidator);
        _validatorIndexes.set(validator, _validators.length - 1);

        emit ValidatorActivated(validator);
    }

    /**
     * @notice Deactivate a validator
     * @param validator Address of the validator to deactivate
     */
    function deactivateValidator(address validator) external whenNotPaused nonReentrant validatorExists(validator) {
        // limit the msg.sender to MANAGER_ROLE
        require(hasRole(MANAGER_ROLE, msg.sender), "Not authorized");

        (bool exists, uint256 index) = _validatorIndexes.tryGet(validator);
        require(exists, "Validator does not exist");

        Validator storage validatorData = _validators[index];
        require(validatorData.active, "Validator already inactive");

        // Update state after withdrawal request
        validatorData.active = false;

        emit ValidatorDeactivated(validator);
    }

    /**
     * @notice Reactivate a previously deactivated validator
     * @param validator Address of the validator to reactivate
     */
    function reactivateValidator(address validator)
        external
        whenNotPaused
        nonReentrant
        onlyRole(MANAGER_ROLE)
        validatorExists(validator)
    {
        (bool exists, uint256 index) = _validatorIndexes.tryGet(validator);
        require(exists, "Validator does not exist");

        Validator storage validatorData = _validators[index];
        require(!validatorData.active, "Validator already active");
        require(!_validatorsWithPendingRebalance.contains(validator), "Validator has pending rebalance");

        // Reactivate the validator
        validatorData.active = true;

        emit ValidatorReactivated(validator);
    }

    /* ========== REBALANCING ========== */

    /**
     * @notice Request withdrawals for multiple validators
     * @param stakingManager Address of the staking manager contract
     * @param validators Array of validator addresses
     * @param withdrawalAmounts Array of amounts to withdraw
     */
    function rebalanceWithdrawal(
        address stakingManager,
        address[] calldata validators,
        uint256[] calldata withdrawalAmounts
    ) external whenNotPaused nonReentrant onlyRole(MANAGER_ROLE) {
        require(validators.length == withdrawalAmounts.length, "Length mismatch");
        require(validators.length > 0, "Empty arrays");

        for (uint256 i = 0; i < validators.length;) {
            require(validators[i] != address(0), "Invalid validator address");

            // Add rebalance request (this will check for duplicates)
            _addRebalanceRequest(stakingManager, validators[i], withdrawalAmounts[i]);

            unchecked {
                ++i;
            }
        }

        // Trigger withdrawals through StakingManager
        IStakingManager(stakingManager).processValidatorWithdrawals(validators, withdrawalAmounts);
    }

    /**
     * @dev Internal function to add a rebalance request
     * @param validator Address of the validator
     * @param withdrawalAmount Amount to withdraw
     */
    function _addRebalanceRequest(address staking, address validator, uint256 withdrawalAmount) internal {
        require(!_validatorsWithPendingRebalance.contains(validator), "Validator has pending rebalance");
        require(withdrawalAmount > 0, "Invalid withdrawal amount");

        (bool exists, /* uint256 index */ ) = _validatorIndexes.tryGet(validator);
        require(exists, "Validator does not exist");

        validatorRebalanceRequests[validator] =
            RebalanceRequest({staking: staking, validator: validator, amount: withdrawalAmount});
        _validatorsWithPendingRebalance.add(validator);

        emit RebalanceRequestAdded(validator, withdrawalAmount);
    }

    /**
     * @notice Close multiple rebalance requests and redelegate
     * @param stakingManager Address of the staking manager contract
     * @param validators Array of validator addresses
     * @dev Clears the rebalance requests and triggers redelegation through stakingManager
     */
    function closeRebalanceRequests(address stakingManager, address[] calldata validators)
        external
        whenNotPaused
        nonReentrant
        onlyRole(MANAGER_ROLE)
    {
        require(_validatorsWithPendingRebalance.length() > 0, "No pending requests");
        require(validators.length > 0, "Empty array");

        uint256 totalAmount = 0;

        for (uint256 i = 0; i < validators.length;) {
            address validator = validators[i];
            require(_validatorsWithPendingRebalance.contains(validator), "No pending request");

            // Add amount to total for redelegation
            RebalanceRequest memory request = validatorRebalanceRequests[validator];
            require(request.staking == stakingManager, "Invalid staking manager for rebalance");

            totalAmount += request.amount;

            // Clear the rebalance request
            delete validatorRebalanceRequests[validator];
            _validatorsWithPendingRebalance.remove(validator);

            emit RebalanceRequestClosed(validator, request.amount);

            unchecked {
                ++i;
            }
        }

        // Trigger redelegation through StakingManager if there's an amount to delegate
        if (totalAmount > 0) {
            IStakingManager(stakingManager).processValidatorRedelegation(totalAmount);
        }
    }

    /**
     * @notice Check if a validator has a pending rebalance request
     * @param validator Address of the validator to check
     * @return bool True if the validator has a pending rebalance request
     */
    function hasPendingRebalance(address validator) external view returns (bool) {
        return _validatorsWithPendingRebalance.contains(validator);
    }

    /* ========== PERFORMANCE MONITORING ========== */

    /// @notice Updates performance scores for a validator
    /// @param validator Address of validator
    /// @param balance Current balance of the validator
    /// @param performanceScore New performance score (0-10000)
    function updateValidatorPerformance(address validator, uint256 balance, uint256 performanceScore)
        external
        whenNotPaused
        onlyRole(ORACLE_MANAGER_ROLE)
        validatorActive(validator)
    {
        // Much simpler validation
        require(performanceScore <= BASIS_POINTS, "Score exceeds maximum");

        uint256 index = _validatorIndexes.get(validator);

        // Update validator struct
        _validators[index].balance = balance;
        _validators[index].performanceScore = performanceScore;
        _validators[index].lastUpdateTime = block.timestamp;

        // Update performance report in one storage write
        validatorPerformance[validator] =
            PerformanceReport({balance: balance, performanceScore: performanceScore, timestamp: block.timestamp});

        emit ValidatorPerformanceUpdated(validator, block.timestamp, block.number);
    }

    /* ========== PERFORMANCE QUERIES ========== */

    function validatorScores(address validator)
        external
        view
        validatorExists(validator)
        returns (uint256 performanceScore)
    {
        Validator memory val = _validators[_validatorIndexes.get(validator)];
        return val.performanceScore;
    }

    function validatorLastUpdateTime(address validator) external view validatorExists(validator) returns (uint256) {
        return _validators[_validatorIndexes.get(validator)].lastUpdateTime;
    }

    function validatorBalance(address validator) external view validatorExists(validator) returns (uint256) {
        return _validators[_validatorIndexes.get(validator)].balance;
    }

    function validatorActiveState(address validator) public view validatorExists(validator) returns (bool) {
        return _validators[_validatorIndexes.get(validator)].active;
    }

    function activeValidatorsCount() external view returns (uint256) {
        uint256 count;
        uint256 length = _validators.length;
        for (uint256 i; i < length;) {
            if (_validators[i].active) {
                count++;
            }
            unchecked {
                ++i;
            }
        }
        return count;
    }

    function validatorCount() public view returns (uint256) {
        return _validators.length;
    }

    function validatorAt(uint256 index) public view returns (address validator, Validator memory data) {
        uint256 length = _validators.length;
        require(index < length, "Index out of bounds");

        (validator,) = _validatorIndexes.at(index);
        data = _validators[index];
        return (validator, data);
    }

    function validatorInfo(address validator) public view validatorExists(validator) returns (Validator memory) {
        return _validators[_validatorIndexes.get(validator)];
    }

    /* ========== REWARDS ========== */

    /// @notice Report a reward event for a validator
    /// @param validator Address of the validator to be rewarded
    /// @param amount Amount of rewards for the validator
    function reportRewardEvent(address validator, uint256 amount)
        external
        onlyRole(ORACLE_MANAGER_ROLE)
        validatorActive(validator)
    {
        require(amount > 0, "Invalid reward amount");

        // Update reward amounts
        totalRewards += amount;
        validatorRewards[validator] += amount;

        emit RewardEventReported(validator, amount);
    }

    /* ========== SLASHING ========== */

    /// @notice Report a slashing event for a validator
    /// @param validator Address of the validator to be slashed
    /// @param amount Amount to slash from the validator
    function reportSlashingEvent(address validator, uint256 amount)
        external
        onlyRole(ORACLE_MANAGER_ROLE)
        validatorActive(validator)
    {
        require(amount > 0, "Invalid slash amount");

        // Update slashing amounts
        totalSlashing += amount;
        validatorSlashing[validator] += amount;

        emit SlashingEventReported(validator, amount);
    }

    /* ========== DELEGATION MANAGEMENT ========== */

    /**
     * @notice Set delegation target for a staking manager
     * @param stakingManager Address of the staking manager
     * @param validator Address of the validator to delegate to
     */
    function setDelegation(address stakingManager, address validator)
        external
        whenNotPaused
        onlyRole(MANAGER_ROLE)
        validatorActive(validator)
    {
        require(stakingManager != address(0), "Invalid staking manager");
        address oldDelegation = delegations[stakingManager];
        delegations[stakingManager] = validator;

        emit DelegationUpdated(stakingManager, oldDelegation, validator);
    }

    /**
     * @notice Get delegation target for a staking manager
     * @param stakingManager Address of the staking manager
     * @return Address of the validator to delegate to
     */
    function getDelegation(address stakingManager) external view returns (address) {
        address validator = delegations[stakingManager];
        require(validator != address(0), "No delegation set");
        require(validatorActiveState(validator), "Delegated validator not active");
        return validator;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/AccessControlEnumerable.sol)

pragma solidity ^0.8.20;

import {IAccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/IAccessControlEnumerable.sol";
import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerable, AccessControlUpgradeable {
    using EnumerableSet for EnumerableSet.AddressSet;

    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlEnumerable
    struct AccessControlEnumerableStorage {
        mapping(bytes32 role => EnumerableSet.AddressSet) _roleMembers;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlEnumerable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlEnumerableStorageLocation = 0xc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000;

    function _getAccessControlEnumerableStorage() private pure returns (AccessControlEnumerableStorage storage $) {
        assembly {
            $.slot := AccessControlEnumerableStorageLocation
        }
    }

    function __AccessControlEnumerable_init() internal onlyInitializing {
    }

    function __AccessControlEnumerable_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].length();
    }

    /**
     * @dev Return all accounts that have `role`
     *
     * 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 getRoleMembers(bytes32 role) public view virtual returns (address[] memory) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        return $._roleMembers[role].values();
    }

    /**
     * @dev Overload {AccessControl-_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        bool granted = super._grantRole(role, account);
        if (granted) {
            $._roleMembers[role].add(account);
        }
        return granted;
    }

    /**
     * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
        AccessControlEnumerableStorage storage $ = _getAccessControlEnumerableStorage();
        bool revoked = super._revokeRole(role, account);
        if (revoked) {
            $._roleMembers[role].remove(account);
        }
        return revoked;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If 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].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

File 5 of 15 : EnumerableMap.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.

pragma solidity ^0.8.20;

import {EnumerableSet} from "./EnumerableSet.sol";

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * The following map types are supported:
 *
 * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
 * - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0
 * - `address -> address` (`AddressToAddressMap`) since v5.1.0
 * - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0
 * - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableMap.
 * ====
 */
library EnumerableMap {
    using EnumerableSet for EnumerableSet.Bytes32Set;

    // To implement this library for multiple types with as little code repetition as possible, we write it in
    // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
    // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
    // This means that we can only create new EnumerableMaps for types that fit in bytes32.

    /**
     * @dev Query for a nonexistent map key.
     */
    error EnumerableMapNonexistentKey(bytes32 key);

    struct Bytes32ToBytes32Map {
        // Storage of keys
        EnumerableSet.Bytes32Set _keys;
        mapping(bytes32 key => bytes32) _values;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
        map._values[key] = value;
        return map._keys.add(key);
    }

    /**
     * @dev Removes a key-value pair from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
        delete map._values[key];
        return map._keys.remove(key);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
        return map._keys.contains(key);
    }

    /**
     * @dev Returns the number of key-value pairs in the map. O(1).
     */
    function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
        return map._keys.length();
    }

    /**
     * @dev Returns the key-value pair stored at position `index` in the map. O(1).
     *
     * Note that there are no guarantees on the ordering of entries inside the
     * array, and it may change when more entries are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32 key, bytes32 value) {
        bytes32 atKey = map._keys.at(index);
        return (atKey, map._values[atKey]);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) {
        bytes32 val = map._values[key];
        if (val == bytes32(0)) {
            return (contains(map, key), bytes32(0));
        } else {
            return (true, val);
        }
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
        bytes32 value = map._values[key];
        if (value == 0 && !contains(map, key)) {
            revert EnumerableMapNonexistentKey(key);
        }
        return value;
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
        return map._keys.values();
    }

    // UintToUintMap

    struct UintToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(UintToUintMap storage map, uint256 index) internal view returns (uint256 key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(key)));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintToAddressMap

    struct UintToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
        return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256 key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(key)))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // UintToBytes32Map

    struct UintToBytes32Map {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {
        return set(map._inner, bytes32(key), value);
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(UintToBytes32Map storage map, uint256 key) internal returns (bool) {
        return remove(map._inner, bytes32(key));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(UintToBytes32Map storage map, uint256 key) internal view returns (bool) {
        return contains(map._inner, bytes32(key));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(UintToBytes32Map storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (uint256(atKey), val);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
        return (success, val);
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {
        return get(map._inner, bytes32(key));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {
        bytes32[] memory store = keys(map._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToUintMap

    struct AddressToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToUintMap storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(AddressToUintMap storage map, uint256 index) internal view returns (address key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
        return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToAddressMap

    struct AddressToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToAddressMap storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToAddressMap storage map, address key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // AddressToBytes32Map

    struct AddressToBytes32Map {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {
        return set(map._inner, bytes32(uint256(uint160(key))), value);
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(AddressToBytes32Map storage map, address key) internal returns (bool) {
        return remove(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) {
        return contains(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(AddressToBytes32Map storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (address(uint160(uint256(atKey))), val);
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) {
        (bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
        return (success, val);
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
        return get(map._inner, bytes32(uint256(uint160(key))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {
        bytes32[] memory store = keys(map._inner);
        address[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // Bytes32ToUintMap

    struct Bytes32ToUintMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
        return set(map._inner, key, bytes32(value));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
        return remove(map._inner, key);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
        return contains(map._inner, key);
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32 key, uint256 value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (atKey, uint256(val));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) {
        (bool success, bytes32 val) = tryGet(map._inner, key);
        return (success, uint256(val));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
        return uint256(get(map._inner, key));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
        bytes32[] memory store = keys(map._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }

    // Bytes32ToAddressMap

    struct Bytes32ToAddressMap {
        Bytes32ToBytes32Map _inner;
    }

    /**
     * @dev Adds a key-value pair to a map, or updates the value for an existing
     * key. O(1).
     *
     * Returns true if the key was added to the map, that is if it was not
     * already present.
     */
    function set(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {
        return set(map._inner, key, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a map. O(1).
     *
     * Returns true if the key was removed from the map, that is if it was present.
     */
    function remove(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) {
        return remove(map._inner, key);
    }

    /**
     * @dev Returns true if the key is in the map. O(1).
     */
    function contains(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool) {
        return contains(map._inner, key);
    }

    /**
     * @dev Returns the number of elements in the map. O(1).
     */
    function length(Bytes32ToAddressMap storage map) internal view returns (uint256) {
        return length(map._inner);
    }

    /**
     * @dev Returns the element stored at position `index` in the map. 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(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) {
        (bytes32 atKey, bytes32 val) = at(map._inner, index);
        return (atKey, address(uint160(uint256(val))));
    }

    /**
     * @dev Tries to returns the value associated with `key`. O(1).
     * Does not revert if `key` is not in the map.
     */
    function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) {
        (bool success, bytes32 val) = tryGet(map._inner, key);
        return (success, address(uint160(uint256(val))));
    }

    /**
     * @dev Returns the value associated with `key`. O(1).
     *
     * Requirements:
     *
     * - `key` must be in the map.
     */
    function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {
        return address(uint160(uint256(get(map._inner, key))));
    }

    /**
     * @dev Return the an array containing all the keys
     *
     * 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 map grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {
        bytes32[] memory store = keys(map._inner);
        bytes32[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position 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 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;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        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 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;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title IValidatorManager
 * @notice Interface for the ValidatorManager contract that manages validator operations
 */
interface IValidatorManager {
    /* ========== STRUCTS ========== */

    /// @notice Struct containing validator information and performance metrics
    struct Validator {
        uint256 balance; // Current balance/stake of the validator
        uint256 performanceScore; // Single aggregated performance score (0-10000)
        uint256 lastUpdateTime; // Timestamp of last score update
        bool active; // Whether the validator is currently active
    }

    struct RebalanceRequest {
        address staking; // Staking that initiated the request's belonging
        address validator; // Validator being rebalanced
        uint256 amount; // Amount to move
    }

    struct PerformanceReport {
        uint256 balance;
        uint256 performanceScore; // Single aggregated performance score
        uint256 timestamp;
    }

    /* ========== EVENTS ========== */

    event EmergencyWithdrawalLimitUpdated(uint256 newLimit);
    event ValidatorAdded(address indexed validator);
    event ValidatorRemoved(address indexed validator);
    event ValidatorScoreUpdated(address indexed validator, uint256 performanceScore);
    event StakeRebalanced(address indexed validator, uint256 newStake);
    event StakeLimitsUpdated(uint256 minLimit, uint256 maxLimit);
    event EmergencyWithdrawalRequested(address indexed validator, uint256 amount);
    event EmergencyWithdrawalProcessed(address indexed validator, uint256 amount);
    event SlashingEventReported(address indexed validator, uint256 amount);
    event PerformanceReportGenerated(address indexed validator, uint256 timestamp);
    event RebalanceRequestAdded(address indexed validator, uint256 amount);
    event RebalanceBatchProcessed(uint256 startIndex, uint256 endIndex, uint256 timestamp);
    event RebalanceRequestClosed(address indexed validator, uint256 amount);
    event AllRebalanceRequestsClosed(uint256 count, uint256 timestamp);
    event EmergencyCooldownUpdated(uint256 cooldown);
    event RebalanceCooldownUpdated(uint256 cooldown);
    event ValidatorActivated(address indexed validator);
    event ValidatorDeactivated(address indexed validator);
    event ValidatorReactivated(address indexed validator);
    event ValidatorPerformanceUpdated(address indexed validator, uint256 timestamp, uint256 blockNumber);
    event RewardEventReported(address indexed validator, uint256 amount);
    event DelegationUpdated(
        address indexed stakingManager, address indexed oldDelegation, address indexed newDelegation
    );

    /* ========== VIEW FUNCTIONS ========== */

    /// @notice Gets the total number of validators
    function validatorCount() external view returns (uint256);

    /// @notice Gets validator info at a specific index
    function validatorAt(uint256 index) external view returns (address, Validator memory);

    /// @notice Gets validator info for a specific address
    function validatorInfo(address validator) external view returns (Validator memory);

    /// @notice Gets validator performance score
    function validatorScores(address validator) external view returns (uint256 performanceScore);

    /// @notice Gets validator balance
    function validatorBalance(address validator) external view returns (uint256);

    /// @notice Gets validator active state
    function validatorActiveState(address validator) external view returns (bool);

    /// @notice Gets total slashing amount
    function totalSlashing() external view returns (uint256);

    /// @notice Get validator's last update time
    function validatorLastUpdateTime(address validator) external view returns (uint256);

    /// @notice Check if validator has pending rebalance
    function hasPendingRebalance(address validator) external view returns (bool);

    /// @notice Get total rewards across all validators
    function totalRewards() external view returns (uint256);

    /// @notice Get the total rewards earned by a validator
    function validatorRewards(address validator) external view returns (uint256);

    /// @notice Get the total amount slashed from a validator
    function validatorSlashing(address validator) external view returns (uint256);

    /// @notice Get the delegation address for the staking
    function getDelegation(address stakingManager) external view returns (address);

    /* ========== MUTATIVE FUNCTIONS ========== */

    /// @notice Activates a validator
    function activateValidator(address validator) external;

    /// @notice Deactivates a validator
    function deactivateValidator(address validator) external;

    /// @notice Updates validator performance metrics with single aggregated score
    function updateValidatorPerformance(address validator, uint256 balance, uint256 performanceScore) external;

    /// @notice Reports a slashing event for a validator
    function reportSlashingEvent(address validator, uint256 slashAmount) external;

    /// @notice Report a reward event for a validator
    function reportRewardEvent(address validator, uint256 amount) external;

    /// @notice Request withdrawals for multiple validators
    function rebalanceWithdrawal(
        address stakingManager,
        address[] calldata validators,
        uint256[] calldata withdrawalAmounts
    ) external;

    /// @notice Close multiple rebalance requests
    function closeRebalanceRequests(address stakingManager, address[] calldata validators) external;

    /// @notice Set the delegation address for the staking
    function setDelegation(address stakingManager, address validator) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title IPauserRegistry
 * @notice Interface for the PauserRegistry contract that manages protocol pause states
 */
interface IPauserRegistry {
    /* ========== EVENTS ========== */

    event ContractPaused(address indexed contractAddress);
    event ContractUnpaused(address indexed contractAddress);
    event ContractAuthorized(address indexed contractAddress);
    event ContractDeauthorized(address indexed contractAddress);

    /* ========== VIEW FUNCTIONS ========== */

    /**
     * @notice Checks if a contract is paused
     * @param contractAddress The address of the contract to check
     * @return bool True if the contract is paused
     */
    function isPaused(address contractAddress) external view returns (bool);

    /**
     * @notice Checks if a contract is authorized
     * @param contractAddress The address of the contract to check
     * @return bool True if the contract is authorized
     */
    function isAuthorizedContract(address contractAddress) external view returns (bool);

    /**
     * @notice Gets all authorized contracts
     * @return address[] Array of authorized contract addresses
     */
    function getAuthorizedContracts() external view returns (address[] memory);

    /**
     * @notice Gets the count of authorized contracts
     * @return uint256 Number of authorized contracts
     */
    function getAuthorizedContractCount() external view returns (uint256);

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Pauses a specific contract
     * @param contractAddress The address of the contract to pause
     */
    function pauseContract(address contractAddress) external;

    /**
     * @notice Unpauses a specific contract
     * @param contractAddress The address of the contract to unpause
     */
    function unpauseContract(address contractAddress) external;

    /**
     * @notice Pauses all authorized contracts
     */
    function emergencyPauseAll() external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IStakingManager {
    /* ========== STRUCTS ========== */

    struct WithdrawalRequest {
        uint256 hypeAmount; // Amount in HYPE to withdraw
        uint256 kHYPEAmount; // Amount in kHYPE to burn (excluding fee)
        uint256 kHYPEFee; // Fee amount in kHYPE tokens
        uint256 bufferUsed; // Amount fulfilled from hypeBuffer
        uint256 timestamp; // Request timestamp
    }

    // Define the enum on operation type
    enum OperationType {
        UserDeposit, // 0: User deposit operation; from EVM to Validator
        SpotDeposit, // 1: Deposit operation from SpotAccount to Validator(handling dusts)
        RebalanceDeposit, // 2: Rebalancing deposit operation; from StakingAccount to Validator
        UserWithdrawal, // 3: User withdrawal; From Validator to EVM
        RebalanceWithdrawal // 4: Rebalancing withdrawal; From Validator to StakingAccount

    }

    // Update the L1Operation struct to use the enum
    struct L1Operation {
        address validator;
        uint256 amount;
        OperationType operationType;
    }

    /* ========== EVENTS ========== */

    event StakeReceived(address indexed staking, address indexed staker, uint256 amount);
    event WithdrawalQueued(
        address indexed staking,
        address indexed user,
        uint256 indexed withdrawalId,
        uint256 kHYPEAmount,
        uint256 hypeAmount,
        uint256 feeAmount
    );
    event WithdrawalConfirmed(address indexed user, uint256 indexed withdrawalId, uint256 amount);
    event WithdrawalCancelled(
        address indexed user, uint256 indexed withdrawalId, uint256 amount, uint256 totalCancelled
    );
    event StakingLimitUpdated(uint256 newStakingLimit);
    event MinStakeAmountUpdated(uint256 newMinStakeAmount);
    event MaxStakeAmountUpdated(uint256 newMaxStakeAmount);
    event MinWithdrawalAmountUpdated(uint256 newMinWithdrawalAmount);
    event WithdrawalDelayUpdated(uint256 newDelay);
    event Delegate(address indexed staking, address indexed validator, uint256 amount);
    event TargetBufferUpdated(uint256 newTargetBuffer);
    event BufferIncreased(uint256 amountAdded, uint256 newTotal);
    event BufferDecreased(uint256 amountRemoved, uint256 newTotal);
    event ValidatorWithdrawal(address indexed staking, address indexed validator, uint256 amount);
    event WhitelistEnabled();
    event WhitelistDisabled();
    event AddressWhitelisted(address indexed account);
    event AddressRemovedFromWhitelist(address indexed account);
    // Add events for pause state changes
    event StakingPaused(address indexed by);
    event StakingUnpaused(address indexed by);
    event WithdrawalPaused(address indexed by);
    event WithdrawalUnpaused(address indexed by);
    event WithdrawalRedelegated(uint256 amount);
    event UnstakeFeeRateUpdated(uint256 newRate);
    // Add event for treasury updates
    event TreasuryUpdated(address indexed oldTreasury, address indexed newTreasury);
    // Add event for stake & unstake queued L1 operations, amount is decimal 8 here
    event L1DelegationQueued(
        address indexed staking, address indexed validator, uint256 amount, OperationType operationType
    );
    event L1DelegationProcessed(
        address indexed staking, address indexed validator, uint256 amount, OperationType operationType
    );
    event SpotWithdrawn(uint256 amount);
    // Add events for airdrops
    /**
     * @notice Emitted when a token is withdrawn from spot balance
     * @param tokenId The ID of the token withdrawn
     * @param amount The amount withdrawn
     * @param recipient The address receiving the tokens
     */
    event TokenWithdrawnFromSpot(uint64 indexed tokenId, uint64 amount, address indexed recipient);
    /**
     * @notice Emitted when a token is rescued from the contract
     * @param token The address of the token rescued (address(0) for native tokens)
     * @param amount The amount rescued
     * @param recipient The address receiving the tokens
     */
    event TokenRescued(address indexed token, uint256 amount, address indexed recipient);
    /**
     * @notice Emitted when L1 operations are queued for retry
     * @param validators Array of validator addresses
     * @param amounts Array of amounts
     * @param operationTypes Array of operation types
     */
    event L1OperationsQueued(address[] validators, uint256[] amounts, OperationType[] operationTypes);
    /**
     * @notice Emitted when L1 operations are processed in batch
     * @param processedCount Number of operations processed
     * @param remainingCount Number of operations remaining
     */
    event L1OperationsBatchProcessed(uint256 processedCount, uint256 remainingCount);
    /**
     * @notice Emitted when the L1 operations queue is reset
     * @param queueLength Length of the queue before reset
     */
    event L1OperationsQueueReset(uint256 queueLength);
    /**
     * @notice Emitted when an emergency withdrawal is executed
     * @param validator Address of the validator
     * @param amount Amount withdrawn
     */
    event EmergencyWithdrawalExecuted(address indexed validator, uint256 amount);

    /* ========== VIEW FUNCTIONS ========== */

    /// @notice Gets the total amount of HYPE staked
    function totalStaked() external view returns (uint256);

    /// @notice Gets the total amount of HYPE claimed
    function totalClaimed() external view returns (uint256);

    /// @notice Gets the total amount of queued withdrawals
    function totalQueuedWithdrawals() external view returns (uint256);

    /// @notice Gets the current HYPE buffer amount
    function hypeBuffer() external view returns (uint256);

    /// @notice Gets the target buffer size
    function targetBuffer() external view returns (uint256);

    /// @notice Gets the maximum total staking limit
    function stakingLimit() external view returns (uint256);

    /// @notice Gets the minimum stake amount per transaction
    function minStakeAmount() external view returns (uint256);

    /// @notice Gets the maximum stake amount per transaction
    function maxStakeAmount() external view returns (uint256);

    /// @notice Gets the withdrawal delay period
    function withdrawalDelay() external view returns (uint256);

    /// @notice Gets withdrawal request details for a user
    function withdrawalRequests(address user, uint256 id) external view returns (WithdrawalRequest memory);

    /// @notice Gets the next withdrawal ID for a user
    function nextWithdrawalId(address user) external view returns (uint256);

    /// @notice Gets the current unstake fee rate
    function unstakeFeeRate() external view returns (uint256);

    /* ========== MUTATIVE FUNCTIONS ========== */

    /// @notice Stakes HYPE tokens
    function stake() external payable;

    /// @notice Queues a withdrawal request
    function queueWithdrawal(uint256 amount) external;

    /// @notice Confirms a withdrawal request
    function confirmWithdrawal(uint256 withdrawalId) external;

    /**
     * @notice Process validator withdrawals requested by ValidatorManager
     * @param validators Array of validator addresses
     * @param amounts Array of amounts to withdraw
     */
    function processValidatorWithdrawals(address[] calldata validators, uint256[] calldata amounts) external;

    /**
     * @notice Delegate available balance to current validator
     * @param amount Amount to delegate
     */
    function processValidatorRedelegation(uint256 amount) external;

    /**
     * @notice Queue L1 operations directly for retrying failed operations
     * @param validators Array of validator addresses
     * @param amounts Array of amounts to process
     * @param operationTypes Array of operation types
     */
    function queueL1Operations(
        address[] calldata validators,
        uint256[] calldata amounts,
        OperationType[] calldata operationTypes
    ) external;

    /* ========== WHITELIST FUNCTIONS ========== */

    function enableWhitelist() external;
    function disableWhitelist() external;
    function addToWhitelist(address[] calldata accounts) external;
    function removeFromWhitelist(address[] calldata accounts) external;
    function isWhitelisted(address account) external view returns (bool);
    function whitelistLength() external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/extensions/IAccessControlEnumerable.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "../IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC-165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../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, IAccessControl, ERC165Upgradeable {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;


    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
    struct AccessControlStorage {
        mapping(bytes32 role => RoleData) _roles;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;

    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
        assembly {
            $.slot := AccessControlStorageLocation
        }
    }

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    function __AccessControl_init() internal onlyInitializing {
    }

    function __AccessControl_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        return $._roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @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 returns (bytes32) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        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 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 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 `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        AccessControlStorage storage $ = _getAccessControlStorage();
        bytes32 previousAdminRole = getRoleAdmin(role);
        $._roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (!hasRole(role, account)) {
            $._roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        AccessControlStorage storage $ = _getAccessControlStorage();
        if (hasRole(role, account)) {
            $._roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @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.
     */
    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. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    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 `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 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);
 * }
 * ```
 */
abstract contract ERC165Upgradeable is Initializable, IERC165 {
    function __ERC165_init() internal onlyInitializing {
    }

    function __ERC165_init_unchained() internal onlyInitializing {
    }
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @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);
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"EnumerableMapNonexistentKey","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AllRebalanceRequestsClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakingManager","type":"address"},{"indexed":true,"internalType":"address","name":"oldDelegation","type":"address"},{"indexed":true,"internalType":"address","name":"newDelegation","type":"address"}],"name":"DelegationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cooldown","type":"uint256"}],"name":"EmergencyCooldownUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"EmergencyWithdrawalLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawalProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawalRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"PerformanceReportGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RebalanceBatchProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"cooldown","type":"uint256"}],"name":"RebalanceCooldownUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RebalanceRequestAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RebalanceRequestClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardEventReported","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":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SlashingEventReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxLimit","type":"uint256"}],"name":"StakeLimitsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"}],"name":"StakeRebalanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"ValidatorPerformanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorReactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"uint256","name":"performanceScore","type":"uint256"}],"name":"ValidatorScoreUpdated","type":"event"},{"inputs":[],"name":"BASIS_POINTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"activateValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activeValidatorsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stakingManager","type":"address"},{"internalType":"address[]","name":"validators","type":"address[]"}],"name":"closeRebalanceRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"deactivateValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegations","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stakingManager","type":"address"}],"name":"getDelegation","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMembers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"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":"address","name":"validator","type":"address"}],"name":"hasPendingRebalance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"admin","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_pauserRegistry","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauserRegistry","outputs":[{"internalType":"contract IPauserRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"reactivateValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stakingManager","type":"address"},{"internalType":"address[]","name":"validators","type":"address[]"},{"internalType":"uint256[]","name":"withdrawalAmounts","type":"uint256[]"}],"name":"rebalanceWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reportRewardEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reportSlashingEvent","outputs":[],"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":"stakingManager","type":"address"},{"internalType":"address","name":"validator","type":"address"}],"name":"setDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSlashing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"performanceScore","type":"uint256"}],"name":"updateValidatorPerformance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"validatorActiveState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"validatorAt","outputs":[{"internalType":"address","name":"validator","type":"address"},{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"performanceScore","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct IValidatorManager.Validator","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"validatorBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"validatorInfo","outputs":[{"components":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"performanceScore","type":"uint256"},{"internalType":"uint256","name":"lastUpdateTime","type":"uint256"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct IValidatorManager.Validator","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"validatorLastUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorPerformance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"performanceScore","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorRebalanceRequests","outputs":[{"internalType":"address","name":"staking","type":"address"},{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"validatorScores","outputs":[{"internalType":"uint256","name":"performanceScore","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"validatorSlashing","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6080806040523460d0577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b604051612aea90816100d58239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80604d565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a714611e15575080630d2bd90914611da95780630e15561a14611d8c5780630eb9acea14611a805780630f43a67714611a6257806319363ad3146118f0578063248a9ca3146118c95780632b293768146117f45780632f2ff15d146117c257806332e0aa1f146116e057806336568abe1461169b57806337ce96ac146115d55780634db69d261461159e5780634f1811dd1461151f57806357afa91c146114be578063631f15a91461149a5780637623a74e1461134a578063825b747714611277578063886f1195146112505780638ac7834b146111ff5780638e87ce2d146111cb5780638f50bd13146111885780639010d07c1461113657806391d14854146110e0578063a217fddf146110c4578063a3246ad314611008578063aaa54e0d14610ec7578063b1845c5614610e8e578063b46e552014610cbd578063ba50b87914610b14578063bfc69e1c14610aec578063bffe348614610aab578063ca15c87314610a75578063d547741f14610a3a578063da13ffbf14610a01578063e1f1c4a7146109e4578063e47c355b1461062d578063ec87621c14610605578063f30720d6146105e7578063f5a9f94a146105815763f8c8765e146101e1575f80fd5b3461057e57608036600319011261057e576101fa611e82565b610202611e98565b90604435906001600160a01b0382169081830361057a576064356001600160a01b0381169390849003610576575f80516020612a95833981519152549460ff8660401c16159567ffffffffffffffff81168015908161056e575b6001149081610564575b15908161055b575b5061054c5767ffffffffffffffff1981166001175f80516020612a958339815191525586610520575b506001600160a01b0383169283156104e3576001600160a01b03821691821561049e57851561046057861561041b57610315946102ff61030a936102d96128bc565b6102e16128bc565b6102e96128bc565b60015f80516020612a558339815191525561257c565b6103f3575b50612618565b6103be575b506126be565b610389575b5082546001600160a01b0319161782556103315780f35b68ff0000000000000000195f80516020612a9583398151915254165f80516020612a95833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6103b7905f80516020612a7583398151915285525f805160206129f583398151915260205260408520612987565b505f61031a565b6103ec905f80516020612a1583398151915288525f805160206129f583398151915260205260408820612987565b505f61030f565b610414908a80525f805160206129f583398151915260205260408b20612987565b505f610304565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207061757365722072656769737472790000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7261636c65206164647265737360501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964206d616e6167657220616464726573730000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274496e76616c69642061646d696e206164647265737360581b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f80516020612a95833981519152555f610297565b63f92ee8a960e01b8852600488fd5b9050155f61026e565b303b159150610266565b88915061025c565b8580fd5b8480fd5b80fd5b503461057e57602036600319011261057e576020806105dd6105d76105d26001600160a01b036105af611e82565b166105cd6105c8825f52600a60205260405f2054151590565b6120c3565b612538565b611edf565b5061208c565b0151604051908152f35b503461057e578060031936011261057e576020600154604051908152f35b503461057e578060031936011261057e5760206040515f80516020612a158339815191528152f35b503461057e57606036600319011261057e57610647611e82565b9060243567ffffffffffffffff81116109e057610668903690600401611eae565b9260443567ffffffffffffffff81116109dc57610689903690600401611eae565b8454604051635b14f18360e01b8152306004820152919492939190602090829060249082906001600160a01b03165afa9081156109d157906106d39187916109a2575b5015611f95565b6106db6121d9565b6106e3612211565b83860361096b578515610937576001600160a01b0316845b8681106107e05750803b1561057a576040519363c2ef1d9360e01b855286604486016040600488015252606485019286975b8089106107b157505084830360031901602486015280835294955085946001600160fb1b038111610576578560208682968196829560051b809285830137010301925af180156107a657610791575b5060015f80516020612a558339815191525580f35b8161079b91611f5b565b61057e57805f61077c565b6040513d84823e3d90fd5b909384356001600160a01b038116908190036107dc576020828192600194520195019801979061072d565b8880fd5b6108066001600160a01b036107fe6107f9848b88611fd6565b611fe6565b16151561218d565b6108146107f9828986611fd6565b90610820818787611fd6565b359160018060a01b0316808852600d602052610840604089205415612141565b82156108f2577f6154de7bd286a60f27d1045c5314775291c7eaae5a4b57a2a792ec28d68eac35602060019461087e6108788561288b565b506120c3565b60405161088a81611f0f565b8781528281018581526040808301848152878f5260048652908e20925183546001600160a01b031990811660a08c901b8c900392831617855592518a8501805490941691161790915551600291909101556108e484612937565b50604051908152a2016106fb565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207769746864726177616c20616d6f756e74000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b456d7074792061727261797360a01b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606490fd5b6109c4915060203d6020116109ca575b6109bc8183611f5b565b810190611f7d565b5f6106cc565b503d6109b2565b6040513d88823e3d90fd5b8380fd5b5080fd5b503461057e578060031936011261057e5760206040516127108152f35b503461057e57602036600319011261057e576020906040906001600160a01b03610a29611e82565b168152600683522054604051908152f35b503461057e57604036600319011261057e57610a71600435610a5a611e98565b90610a6c610a678261204a565b6122c9565b612355565b5080f35b503461057e57602036600319011261057e57604060209160043581525f805160206129f583398151915283522054604051908152f35b503461057e57602036600319011261057e576020906001600160a01b03610ad0611e82565b16815260038252604060018060a01b0391205416604051908152f35b503461057e578060031936011261057e5760206040515f80516020612a758339815191528152f35b503461057e57602036600319011261057e57610b2e611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb257610b709184916109a2575015611f95565b610b786121d9565b6001600160a01b03165f818152600a6020526040902054610b9a9015156120c3565b5f80516020612a1583398151915282525f80516020612a3583398151915260209081526040808420335f908152925290205460ff1615610c7c576003610bec6105d2610be58461288b565b91906120c3565b5001805460ff811615610c375760ff191690557f23d934bfe7f1275bc6fd70432159c9cc1c0075d069f89da6a40f43bfe7a94ed38280a260015f80516020612a558339815191525580f35b60405162461bcd60e51b815260206004820152601a60248201527f56616c696461746f7220616c726561647920696e6163746976650000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606490fd5b6040513d85823e3d90fd5b503461057e57602036600319011261057e57610cd7611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb257610d199184916109a2575015611f95565b610d21612211565b6001600160a01b0316610d3581151561218d565b610d4a815f52600a60205260405f2054151590565b610e4957604051610d5a81611f3f565b828152602081019083825260408101428152606082019260018452600854600160401b811015610e3557806001610d949201600855611edf565b939093610e2157906003939291518355516001830155516002820155019051151560ff801983541691161790556008545f198101908111610e0d57818352600b6020526040832055610de5816128e7565b507fb2b8c5f713f27009f7a78ec2167999c472e5ee8bc591102da17bc4a6551236c88280a280f35b634e487b7160e01b83526011600452602483fd5b634e487b7160e01b87526004879052602487fd5b634e487b7160e01b87526041600452602487fd5b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220616c72656164792065786973747300000000000000006044820152606490fd5b503461057e57602036600319011261057e576020906040906001600160a01b03610eb6611e82565b168152600783522054604051908152f35b503461057e57604036600319011261057e57610ee1611e82565b610ee9611e98565b8254604051635b14f18360e01b815230600482015291929190602090829060249082906001600160a01b03165afa8015610ffd57610f2e9185916109a2575015611f95565b610f36612211565b610f47610f428361210f565b612007565b6001600160a01b0316908115610fb8578183526003602081815260408086205485875292909152842080546001600160a01b0319166001600160a01b03938416908117909155929116907f5cbf8b4dd601c76e8851d991825e8d0d29d914f78f40fcc8ebddd97d913f149c8480a480f35b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207374616b696e67206d616e616765720000000000000000006044820152606490fd5b6040513d86823e3d90fd5b503461057e57602036600319011261057e5760043581525f805160206129f583398151915260205260408120604051908160208254918281520190819285526020852090855b8181106110ae5750505082611064910383611f5b565b604051928392602084019060208552518091526040840192915b81811061108c575050500390f35b82516001600160a01b031684528594506020938401939092019160010161107e565b825484526020909301926001928301920161104e565b503461057e578060031936011261057e57602090604051908152f35b503461057e57604036600319011261057e5760406110fc611e98565b9160043581525f80516020612a35833981519152602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461057e57604036600319011261057e5761116f60209160043581525f805160206129f5833981519152835260406024359120612397565b905460405160039290921b1c6001600160a01b03168152f35b503461057e57602036600319011261057e5760206111c16001600160a01b036111af611e82565b165f52600d60205260405f2054151590565b6040519015158152f35b503461057e57602036600319011261057e5760206111f56105d26001600160a01b036105af611e82565b5054604051908152f35b503461057e57602036600319011261057e576060906040906001600160a01b03611227611e82565b168152600560205220805490600260018201549101549060405192835260208301526040820152f35b503461057e578060031936011261057e57546040516001600160a01b039091168152602090f35b503461057e57604036600319011261057e57611291611e82565b6024359061129d61226d565b6112a9610f428261210f565b811561130d5760207fd36143b3ca1520d3b9e429976a829d6bc40c6b097d16399efae03a37f310ae49916112df84600254611ffa565b60025560018060a01b0316928385526007825260408520611301828254611ffa565b9055604051908152a280f35b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081c995dd85c9908185b5bdd5b9d605a1b6044820152606490fd5b503461057e57602036600319011261057e57611364611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb2576113a69184916109a2575015611f95565b6113ae6121d9565b6113b6612211565b6001600160a01b03165f818152600a60205260409020546113d89015156120c3565b60036113e96105d2610be58461288b565b5001805460ff811661145557600190611416611410855f52600d60205260405f2054151590565b15612141565b60ff19161790557f65cf6d2b9cf96b1ffffa32041ec7c360f76b05f5f4f5e13c7f19495246d6f4f48280a260015f80516020612a558339815191525580f35b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220616c72656164792061637469766500000000000000006044820152606490fd5b503461057e57602036600319011261057e5760206111c16114b9611e82565b61210f565b503461057e57602036600319011261057e576060906040906001600160a01b036114e6611e82565b16815260046020522060018060a01b0381541690600260018060a01b036001830154169101549060405192835260208301526040820152f35b503461057e57602036600319011261057e57608061156f6105d76105d2611544611e82565b61154c612068565b506001600160a01b03165f818152600a60205260409020546105cd9015156120c3565b61159c60405180926060809180518452602081015160208501526040810151604085015201511515910152565bf35b503461057e57602036600319011261057e57602060026115ca6105d26001600160a01b036105af611e82565b500154604051908152f35b503461057e57604036600319011261057e576115ef611e82565b602435906115fb61226d565b611607610f428261210f565b811561165f5760207f63ce9927e6e9c82f626f47fe72a77d38f6d8c9bf9d49e4584acf3e90b1946a1a9161163d84600154611ffa565b60015560018060a01b0316928385526006825260408520611301828254611ffa565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081cdb185cda08185b5bdd5b9d60621b6044820152606490fd5b503461057e57604036600319011261057e576116b5611e98565b336001600160a01b038216036116d157610a7190600435612355565b63334bd91960e11b8252600482fd5b503461057e57602036600319011261057e57600435906116fe612068565b50600854821015611787576009548210156117735761159c61173c6105d760a09460098552806020862001548560031b1c809552600b602052611edf565b60405192600180861b0316835260208301906060809180518452602081015160208501526040810151604085015201511515910152565b634e487b7160e01b81526032600452602490fd5b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b503461057e57604036600319011261057e57610a716004356117e2611e98565b906117ef610a678261204a565b61230f565b503461057e57602036600319011261057e576001600160a01b03611816611e82565b168152600360205260409020546001600160a01b031680156118905761183b8161210f565b1561184b57602090604051908152f35b60405162461bcd60e51b815260206004820152601e60248201527f44656c6567617465642076616c696461746f72206e6f742061637469766500006044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270139bc819195b1959d85d1a5bdb881cd95d607a1b6044820152606490fd5b503461057e57602036600319011261057e5760206118e860043561204a565b604051908152f35b503461057e57606036600319011261057e5761190a611e82565b8154604051635b14f18360e01b8152306004820152604435926024803593919291602091839182906001600160a01b03165afa8015611a57576119549186916109a2575015611f95565b61195c61226d565b611968610f428261210f565b6127108311611a1a576001600160a01b0316916002906119aa61198a85612538565b8461199482611edf565b50558260016119a283611edf565b500155611edf565b508242910155604051926119bd84611f0f565b835260208301908152604083019042825284865260056020526040862093518455516001840155519101557f5fccbb07a0dab375247a9d144c14a3db4061295b18e45d352478c9f6edb6a3c860408051428152436020820152a280f35b60405162461bcd60e51b815260206004820152601560248201527453636f72652065786365656473206d6178696d756d60581b6044820152606490fd5b6040513d87823e3d90fd5b503461057e578060031936011261057e576020600854604051908152f35b5034611ba7576040366003190112611ba757611a9a611e82565b60243567ffffffffffffffff8111611ba757611aba903690600401611eae565b5f54604051635b14f18360e01b815230600482015291939190602090829060249082906001600160a01b03165afa8015611b9c57611aff915f916109a2575015611f95565b611b076121d9565b611b0f612211565b600c5415611d51578215611d1e576001600160a01b0316915f918291905b818310611bab5750505080611b52575b8260015f80516020612a558339815191525580f35b813b15611ba7575f9160248392604051948593849263296e882960e21b845260048401525af18015611b9c57611b89575b80611b3d565b611b9591505f90611f5b565b5f80611b83565b6040513d5f823e3d90fd5b5f80fd5b91929091906001600160a01b03611bc66107f9868686611fd6565b1693611bdd855f52600d60205260405f2054151590565b15611ce457845f52600460205260405f20948660405196611bfd88611f0f565b80546001600160a01b03908116808a52600183015490911660208a0152600290910154604090980197885203611c91577f3fb733198c279e91bafa2fdf515f5ef58924785e1326715671cc7b4c92d743906020611c5e600195895190611ffa565b97835f52600482525f60026040822082815582898201550155611c80846123ac565b5051604051908152a2019190611b2d565b60405162461bcd60e51b815260206004820152602560248201527f496e76616c6964207374616b696e67206d616e6167657220666f7220726562616044820152646c616e636560d81b6064820152608490fd5b60405162461bcd60e51b8152602060048201526012602482015271139bc81c195b991a5b99c81c995c5d595cdd60721b6044820152606490fd5b60405162461bcd60e51b815260206004820152600b60248201526a456d70747920617272617960a81b6044820152606490fd5b60405162461bcd60e51b81526020600482015260136024820152724e6f2070656e64696e6720726571756573747360681b6044820152606490fd5b34611ba7575f366003190112611ba7576020600254604051908152f35b34611ba7575f366003190112611ba7575f6008545f5b818110611dd157602083604051908152f35b60ff6003611dde83611edf565b50015416611def575b600101611dbf565b915f198114611e015760010191611de7565b634e487b7160e01b5f52601160045260245ffd5b34611ba7576020366003190112611ba7576004359063ffffffff60e01b8216809203611ba757602091635a05180f60e01b8114908115611e57575b5015158152f35b637965db0b60e01b811491508115611e71575b5083611e50565b6301ffc9a760e01b14905083611e6a565b600435906001600160a01b0382168203611ba757565b602435906001600160a01b0382168203611ba757565b9181601f84011215611ba75782359167ffffffffffffffff8311611ba7576020808501948460051b010111611ba757565b600854811015611efb5760085f5260205f209060021b01905f90565b634e487b7160e01b5f52603260045260245ffd5b6060810190811067ffffffffffffffff821117611f2b57604052565b634e487b7160e01b5f52604160045260245ffd5b6080810190811067ffffffffffffffff821117611f2b57604052565b90601f8019910116810190811067ffffffffffffffff821117611f2b57604052565b90816020910312611ba757518015158103611ba75790565b15611f9c57565b60405162461bcd60e51b815260206004820152601260248201527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b6044820152606490fd5b9190811015611efb5760051b0190565b356001600160a01b0381168103611ba75790565b91908201809211611e0157565b1561200e57565b60405162461bcd60e51b815260206004820152601460248201527356616c696461746f72206e6f742061637469766560601b6044820152606490fd5b5f525f80516020612a35833981519152602052600160405f20015490565b6040519061207582611f3f565b5f6060838281528260208201528260408201520152565b9060405161209981611f3f565b606060ff600383958054855260018101546020860152600281015460408601520154161515910152565b156120ca57565b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220646f6573206e6f7420657869737400000000000000006044820152606490fd5b600361213a6105d260ff9360018060a01b03166105cd6105c8825f52600a60205260405f2054151590565b5001541690565b1561214857565b60405162461bcd60e51b815260206004820152601f60248201527f56616c696461746f72206861732070656e64696e6720726562616c616e6365006044820152606490fd5b1561219457565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c69642076616c696461746f722061646472657373000000000000006044820152606490fd5b60025f80516020612a5583398151915254146122025760025f80516020612a5583398151915255565b633ee5aeb560e01b5f5260045ffd5b335f9081527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a602052604090205460ff161561224957565b63e2517d3f60e01b5f52336004525f80516020612a1583398151915260245260445ffd5b335f9081527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec602052604090205460ff16156122a557565b63e2517d3f60e01b5f52336004525f80516020612a7583398151915260245260445ffd5b5f8181525f80516020612a358339815191526020908152604080832033845290915290205460ff16156122f95750565b63e2517d3f60e01b5f523360045260245260445ffd5b6123198282612764565b918261232457505090565b5f9182525f805160206129f58339815191526020526040909120612351916001600160a01b031690612987565b5090565b61235f82826127ef565b918261236a57505090565b5f9182525f805160206129f58339815191526020526040909120612351916001600160a01b031690612487565b8054821015611efb575f5260205f2001905f90565b5f818152600d60205260409020548015612481575f198101818111611e0157600c545f19810191908211611e0157818103612433575b505050600c54801561241f575f19016123fc81600c612397565b8154905f199060031b1b19169055600c555f52600d6020525f6040812055600190565b634e487b7160e01b5f52603160045260245ffd5b61246b61244461245593600c612397565b90549060031b1c928392600c612397565b819391549060031b91821b915f19901b19161790565b90555f52600d60205260405f20555f80806123e2565b50505f90565b906001820191815f528260205260405f20548015155f14612530575f198101818111611e015782545f19810191908211611e01578181036124fb575b5050508054801561241f575f1901906124dc8282612397565b8154905f199060031b1b19169055555f526020525f6040812055600190565b61251b61250b6124559386612397565b90549060031b1c92839286612397565b90555f528360205260405f20555f80806124c3565b505050505f90565b805f52600b60205260405f205490811580612568575b612556575090565b63015ab34360e11b5f5260045260245ffd5b50805f52600a60205260405f20541561254e565b6001600160a01b0381165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16612613576001600160a01b03165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391905f805160206129d58339815191528180a4600190565b505f90565b6001600160a01b0381165f9081527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a602052604090205460ff16612613576001600160a01b03165f8181527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a60205260408120805460ff191660011790553391905f80516020612a15833981519152905f805160206129d58339815191529080a4600190565b6001600160a01b0381165f9081527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec602052604090205460ff16612613576001600160a01b03165f8181527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec60205260408120805460ff191660011790553391905f80516020612a75833981519152905f805160206129d58339815191529080a4600190565b5f8181525f80516020612a35833981519152602090815260408083206001600160a01b038616845290915290205460ff16612481575f8181525f80516020612a35833981519152602090815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291905f805160206129d58339815191529080a4600190565b5f8181525f80516020612a35833981519152602090815260408083206001600160a01b038616845290915290205460ff1615612481575f8181525f80516020612a35833981519152602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b805f52600b60205260405f205480155f146128b457505f52600a60205260405f20541515905f90565b600192909150565b60ff5f80516020612a958339815191525460401c16156128d857565b631afcd79f60e31b5f5260045ffd5b805f52600a60205260405f2054155f1461261357600954600160401b811015611f2b576129206124558260018594016009556009612397565b9055600954905f52600a60205260405f2055600190565b805f52600d60205260405f2054155f1461261357600c54600160401b811015611f2b57612970612455826001859401600c55600c612397565b9055600c54905f52600d60205260405f2055600190565b5f82815260018201602052604090205461248157805490600160401b821015611f2b57826129bf612455846001809601855584612397565b90558054925f520160205260405f205560019056fe2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0dc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0802dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00ced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a26469706673582212201fa37769918cc943d916ff9602c6797854517220ef2c16ad9fa7a3883db04d1664736f6c634300081a0033

Deployed Bytecode

0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a714611e15575080630d2bd90914611da95780630e15561a14611d8c5780630eb9acea14611a805780630f43a67714611a6257806319363ad3146118f0578063248a9ca3146118c95780632b293768146117f45780632f2ff15d146117c257806332e0aa1f146116e057806336568abe1461169b57806337ce96ac146115d55780634db69d261461159e5780634f1811dd1461151f57806357afa91c146114be578063631f15a91461149a5780637623a74e1461134a578063825b747714611277578063886f1195146112505780638ac7834b146111ff5780638e87ce2d146111cb5780638f50bd13146111885780639010d07c1461113657806391d14854146110e0578063a217fddf146110c4578063a3246ad314611008578063aaa54e0d14610ec7578063b1845c5614610e8e578063b46e552014610cbd578063ba50b87914610b14578063bfc69e1c14610aec578063bffe348614610aab578063ca15c87314610a75578063d547741f14610a3a578063da13ffbf14610a01578063e1f1c4a7146109e4578063e47c355b1461062d578063ec87621c14610605578063f30720d6146105e7578063f5a9f94a146105815763f8c8765e146101e1575f80fd5b3461057e57608036600319011261057e576101fa611e82565b610202611e98565b90604435906001600160a01b0382169081830361057a576064356001600160a01b0381169390849003610576575f80516020612a95833981519152549460ff8660401c16159567ffffffffffffffff81168015908161056e575b6001149081610564575b15908161055b575b5061054c5767ffffffffffffffff1981166001175f80516020612a958339815191525586610520575b506001600160a01b0383169283156104e3576001600160a01b03821691821561049e57851561046057861561041b57610315946102ff61030a936102d96128bc565b6102e16128bc565b6102e96128bc565b60015f80516020612a558339815191525561257c565b6103f3575b50612618565b6103be575b506126be565b610389575b5082546001600160a01b0319161782556103315780f35b68ff0000000000000000195f80516020612a9583398151915254165f80516020612a95833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b6103b7905f80516020612a7583398151915285525f805160206129f583398151915260205260408520612987565b505f61031a565b6103ec905f80516020612a1583398151915288525f805160206129f583398151915260205260408820612987565b505f61030f565b610414908a80525f805160206129f583398151915260205260408b20612987565b505f610304565b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207061757365722072656769737472790000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7261636c65206164647265737360501b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964206d616e6167657220616464726573730000000000000000006044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274496e76616c69642061646d696e206164647265737360581b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f80516020612a95833981519152555f610297565b63f92ee8a960e01b8852600488fd5b9050155f61026e565b303b159150610266565b88915061025c565b8580fd5b8480fd5b80fd5b503461057e57602036600319011261057e576020806105dd6105d76105d26001600160a01b036105af611e82565b166105cd6105c8825f52600a60205260405f2054151590565b6120c3565b612538565b611edf565b5061208c565b0151604051908152f35b503461057e578060031936011261057e576020600154604051908152f35b503461057e578060031936011261057e5760206040515f80516020612a158339815191528152f35b503461057e57606036600319011261057e57610647611e82565b9060243567ffffffffffffffff81116109e057610668903690600401611eae565b9260443567ffffffffffffffff81116109dc57610689903690600401611eae565b8454604051635b14f18360e01b8152306004820152919492939190602090829060249082906001600160a01b03165afa9081156109d157906106d39187916109a2575b5015611f95565b6106db6121d9565b6106e3612211565b83860361096b578515610937576001600160a01b0316845b8681106107e05750803b1561057a576040519363c2ef1d9360e01b855286604486016040600488015252606485019286975b8089106107b157505084830360031901602486015280835294955085946001600160fb1b038111610576578560208682968196829560051b809285830137010301925af180156107a657610791575b5060015f80516020612a558339815191525580f35b8161079b91611f5b565b61057e57805f61077c565b6040513d84823e3d90fd5b909384356001600160a01b038116908190036107dc576020828192600194520195019801979061072d565b8880fd5b6108066001600160a01b036107fe6107f9848b88611fd6565b611fe6565b16151561218d565b6108146107f9828986611fd6565b90610820818787611fd6565b359160018060a01b0316808852600d602052610840604089205415612141565b82156108f2577f6154de7bd286a60f27d1045c5314775291c7eaae5a4b57a2a792ec28d68eac35602060019461087e6108788561288b565b506120c3565b60405161088a81611f0f565b8781528281018581526040808301848152878f5260048652908e20925183546001600160a01b031990811660a08c901b8c900392831617855592518a8501805490941691161790915551600291909101556108e484612937565b50604051908152a2016106fb565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c6964207769746864726177616c20616d6f756e74000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b456d7074792061727261797360a01b6044820152606490fd5b60405162461bcd60e51b815260206004820152600f60248201526e098cadccee8d040dad2e6dac2e8c6d608b1b6044820152606490fd5b6109c4915060203d6020116109ca575b6109bc8183611f5b565b810190611f7d565b5f6106cc565b503d6109b2565b6040513d88823e3d90fd5b8380fd5b5080fd5b503461057e578060031936011261057e5760206040516127108152f35b503461057e57602036600319011261057e576020906040906001600160a01b03610a29611e82565b168152600683522054604051908152f35b503461057e57604036600319011261057e57610a71600435610a5a611e98565b90610a6c610a678261204a565b6122c9565b612355565b5080f35b503461057e57602036600319011261057e57604060209160043581525f805160206129f583398151915283522054604051908152f35b503461057e57602036600319011261057e576020906001600160a01b03610ad0611e82565b16815260038252604060018060a01b0391205416604051908152f35b503461057e578060031936011261057e5760206040515f80516020612a758339815191528152f35b503461057e57602036600319011261057e57610b2e611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb257610b709184916109a2575015611f95565b610b786121d9565b6001600160a01b03165f818152600a6020526040902054610b9a9015156120c3565b5f80516020612a1583398151915282525f80516020612a3583398151915260209081526040808420335f908152925290205460ff1615610c7c576003610bec6105d2610be58461288b565b91906120c3565b5001805460ff811615610c375760ff191690557f23d934bfe7f1275bc6fd70432159c9cc1c0075d069f89da6a40f43bfe7a94ed38280a260015f80516020612a558339815191525580f35b60405162461bcd60e51b815260206004820152601a60248201527f56616c696461746f7220616c726561647920696e6163746976650000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d139bdd08185d5d1a1bdc9a5e995960921b6044820152606490fd5b6040513d85823e3d90fd5b503461057e57602036600319011261057e57610cd7611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb257610d199184916109a2575015611f95565b610d21612211565b6001600160a01b0316610d3581151561218d565b610d4a815f52600a60205260405f2054151590565b610e4957604051610d5a81611f3f565b828152602081019083825260408101428152606082019260018452600854600160401b811015610e3557806001610d949201600855611edf565b939093610e2157906003939291518355516001830155516002820155019051151560ff801983541691161790556008545f198101908111610e0d57818352600b6020526040832055610de5816128e7565b507fb2b8c5f713f27009f7a78ec2167999c472e5ee8bc591102da17bc4a6551236c88280a280f35b634e487b7160e01b83526011600452602483fd5b634e487b7160e01b87526004879052602487fd5b634e487b7160e01b87526041600452602487fd5b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220616c72656164792065786973747300000000000000006044820152606490fd5b503461057e57602036600319011261057e576020906040906001600160a01b03610eb6611e82565b168152600783522054604051908152f35b503461057e57604036600319011261057e57610ee1611e82565b610ee9611e98565b8254604051635b14f18360e01b815230600482015291929190602090829060249082906001600160a01b03165afa8015610ffd57610f2e9185916109a2575015611f95565b610f36612211565b610f47610f428361210f565b612007565b6001600160a01b0316908115610fb8578183526003602081815260408086205485875292909152842080546001600160a01b0319166001600160a01b03938416908117909155929116907f5cbf8b4dd601c76e8851d991825e8d0d29d914f78f40fcc8ebddd97d913f149c8480a480f35b60405162461bcd60e51b815260206004820152601760248201527f496e76616c6964207374616b696e67206d616e616765720000000000000000006044820152606490fd5b6040513d86823e3d90fd5b503461057e57602036600319011261057e5760043581525f805160206129f583398151915260205260408120604051908160208254918281520190819285526020852090855b8181106110ae5750505082611064910383611f5b565b604051928392602084019060208552518091526040840192915b81811061108c575050500390f35b82516001600160a01b031684528594506020938401939092019160010161107e565b825484526020909301926001928301920161104e565b503461057e578060031936011261057e57602090604051908152f35b503461057e57604036600319011261057e5760406110fc611e98565b9160043581525f80516020612a35833981519152602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b503461057e57604036600319011261057e5761116f60209160043581525f805160206129f5833981519152835260406024359120612397565b905460405160039290921b1c6001600160a01b03168152f35b503461057e57602036600319011261057e5760206111c16001600160a01b036111af611e82565b165f52600d60205260405f2054151590565b6040519015158152f35b503461057e57602036600319011261057e5760206111f56105d26001600160a01b036105af611e82565b5054604051908152f35b503461057e57602036600319011261057e576060906040906001600160a01b03611227611e82565b168152600560205220805490600260018201549101549060405192835260208301526040820152f35b503461057e578060031936011261057e57546040516001600160a01b039091168152602090f35b503461057e57604036600319011261057e57611291611e82565b6024359061129d61226d565b6112a9610f428261210f565b811561130d5760207fd36143b3ca1520d3b9e429976a829d6bc40c6b097d16399efae03a37f310ae49916112df84600254611ffa565b60025560018060a01b0316928385526007825260408520611301828254611ffa565b9055604051908152a280f35b60405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081c995dd85c9908185b5bdd5b9d605a1b6044820152606490fd5b503461057e57602036600319011261057e57611364611e82565b8154604051635b14f18360e01b815230600482015290602090829060249082906001600160a01b03165afa8015610cb2576113a69184916109a2575015611f95565b6113ae6121d9565b6113b6612211565b6001600160a01b03165f818152600a60205260409020546113d89015156120c3565b60036113e96105d2610be58461288b565b5001805460ff811661145557600190611416611410855f52600d60205260405f2054151590565b15612141565b60ff19161790557f65cf6d2b9cf96b1ffffa32041ec7c360f76b05f5f4f5e13c7f19495246d6f4f48280a260015f80516020612a558339815191525580f35b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220616c72656164792061637469766500000000000000006044820152606490fd5b503461057e57602036600319011261057e5760206111c16114b9611e82565b61210f565b503461057e57602036600319011261057e576060906040906001600160a01b036114e6611e82565b16815260046020522060018060a01b0381541690600260018060a01b036001830154169101549060405192835260208301526040820152f35b503461057e57602036600319011261057e57608061156f6105d76105d2611544611e82565b61154c612068565b506001600160a01b03165f818152600a60205260409020546105cd9015156120c3565b61159c60405180926060809180518452602081015160208501526040810151604085015201511515910152565bf35b503461057e57602036600319011261057e57602060026115ca6105d26001600160a01b036105af611e82565b500154604051908152f35b503461057e57604036600319011261057e576115ef611e82565b602435906115fb61226d565b611607610f428261210f565b811561165f5760207f63ce9927e6e9c82f626f47fe72a77d38f6d8c9bf9d49e4584acf3e90b1946a1a9161163d84600154611ffa565b60015560018060a01b0316928385526006825260408520611301828254611ffa565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081cdb185cda08185b5bdd5b9d60621b6044820152606490fd5b503461057e57604036600319011261057e576116b5611e98565b336001600160a01b038216036116d157610a7190600435612355565b63334bd91960e11b8252600482fd5b503461057e57602036600319011261057e57600435906116fe612068565b50600854821015611787576009548210156117735761159c61173c6105d760a09460098552806020862001548560031b1c809552600b602052611edf565b60405192600180861b0316835260208301906060809180518452602081015160208501526040810151604085015201511515910152565b634e487b7160e01b81526032600452602490fd5b60405162461bcd60e51b8152602060048201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152606490fd5b503461057e57604036600319011261057e57610a716004356117e2611e98565b906117ef610a678261204a565b61230f565b503461057e57602036600319011261057e576001600160a01b03611816611e82565b168152600360205260409020546001600160a01b031680156118905761183b8161210f565b1561184b57602090604051908152f35b60405162461bcd60e51b815260206004820152601e60248201527f44656c6567617465642076616c696461746f72206e6f742061637469766500006044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270139bc819195b1959d85d1a5bdb881cd95d607a1b6044820152606490fd5b503461057e57602036600319011261057e5760206118e860043561204a565b604051908152f35b503461057e57606036600319011261057e5761190a611e82565b8154604051635b14f18360e01b8152306004820152604435926024803593919291602091839182906001600160a01b03165afa8015611a57576119549186916109a2575015611f95565b61195c61226d565b611968610f428261210f565b6127108311611a1a576001600160a01b0316916002906119aa61198a85612538565b8461199482611edf565b50558260016119a283611edf565b500155611edf565b508242910155604051926119bd84611f0f565b835260208301908152604083019042825284865260056020526040862093518455516001840155519101557f5fccbb07a0dab375247a9d144c14a3db4061295b18e45d352478c9f6edb6a3c860408051428152436020820152a280f35b60405162461bcd60e51b815260206004820152601560248201527453636f72652065786365656473206d6178696d756d60581b6044820152606490fd5b6040513d87823e3d90fd5b503461057e578060031936011261057e576020600854604051908152f35b5034611ba7576040366003190112611ba757611a9a611e82565b60243567ffffffffffffffff8111611ba757611aba903690600401611eae565b5f54604051635b14f18360e01b815230600482015291939190602090829060249082906001600160a01b03165afa8015611b9c57611aff915f916109a2575015611f95565b611b076121d9565b611b0f612211565b600c5415611d51578215611d1e576001600160a01b0316915f918291905b818310611bab5750505080611b52575b8260015f80516020612a558339815191525580f35b813b15611ba7575f9160248392604051948593849263296e882960e21b845260048401525af18015611b9c57611b89575b80611b3d565b611b9591505f90611f5b565b5f80611b83565b6040513d5f823e3d90fd5b5f80fd5b91929091906001600160a01b03611bc66107f9868686611fd6565b1693611bdd855f52600d60205260405f2054151590565b15611ce457845f52600460205260405f20948660405196611bfd88611f0f565b80546001600160a01b03908116808a52600183015490911660208a0152600290910154604090980197885203611c91577f3fb733198c279e91bafa2fdf515f5ef58924785e1326715671cc7b4c92d743906020611c5e600195895190611ffa565b97835f52600482525f60026040822082815582898201550155611c80846123ac565b5051604051908152a2019190611b2d565b60405162461bcd60e51b815260206004820152602560248201527f496e76616c6964207374616b696e67206d616e6167657220666f7220726562616044820152646c616e636560d81b6064820152608490fd5b60405162461bcd60e51b8152602060048201526012602482015271139bc81c195b991a5b99c81c995c5d595cdd60721b6044820152606490fd5b60405162461bcd60e51b815260206004820152600b60248201526a456d70747920617272617960a81b6044820152606490fd5b60405162461bcd60e51b81526020600482015260136024820152724e6f2070656e64696e6720726571756573747360681b6044820152606490fd5b34611ba7575f366003190112611ba7576020600254604051908152f35b34611ba7575f366003190112611ba7575f6008545f5b818110611dd157602083604051908152f35b60ff6003611dde83611edf565b50015416611def575b600101611dbf565b915f198114611e015760010191611de7565b634e487b7160e01b5f52601160045260245ffd5b34611ba7576020366003190112611ba7576004359063ffffffff60e01b8216809203611ba757602091635a05180f60e01b8114908115611e57575b5015158152f35b637965db0b60e01b811491508115611e71575b5083611e50565b6301ffc9a760e01b14905083611e6a565b600435906001600160a01b0382168203611ba757565b602435906001600160a01b0382168203611ba757565b9181601f84011215611ba75782359167ffffffffffffffff8311611ba7576020808501948460051b010111611ba757565b600854811015611efb5760085f5260205f209060021b01905f90565b634e487b7160e01b5f52603260045260245ffd5b6060810190811067ffffffffffffffff821117611f2b57604052565b634e487b7160e01b5f52604160045260245ffd5b6080810190811067ffffffffffffffff821117611f2b57604052565b90601f8019910116810190811067ffffffffffffffff821117611f2b57604052565b90816020910312611ba757518015158103611ba75790565b15611f9c57565b60405162461bcd60e51b815260206004820152601260248201527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b6044820152606490fd5b9190811015611efb5760051b0190565b356001600160a01b0381168103611ba75790565b91908201809211611e0157565b1561200e57565b60405162461bcd60e51b815260206004820152601460248201527356616c696461746f72206e6f742061637469766560601b6044820152606490fd5b5f525f80516020612a35833981519152602052600160405f20015490565b6040519061207582611f3f565b5f6060838281528260208201528260408201520152565b9060405161209981611f3f565b606060ff600383958054855260018101546020860152600281015460408601520154161515910152565b156120ca57565b60405162461bcd60e51b815260206004820152601860248201527f56616c696461746f7220646f6573206e6f7420657869737400000000000000006044820152606490fd5b600361213a6105d260ff9360018060a01b03166105cd6105c8825f52600a60205260405f2054151590565b5001541690565b1561214857565b60405162461bcd60e51b815260206004820152601f60248201527f56616c696461746f72206861732070656e64696e6720726562616c616e6365006044820152606490fd5b1561219457565b60405162461bcd60e51b815260206004820152601960248201527f496e76616c69642076616c696461746f722061646472657373000000000000006044820152606490fd5b60025f80516020612a5583398151915254146122025760025f80516020612a5583398151915255565b633ee5aeb560e01b5f5260045ffd5b335f9081527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a602052604090205460ff161561224957565b63e2517d3f60e01b5f52336004525f80516020612a1583398151915260245260445ffd5b335f9081527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec602052604090205460ff16156122a557565b63e2517d3f60e01b5f52336004525f80516020612a7583398151915260245260445ffd5b5f8181525f80516020612a358339815191526020908152604080832033845290915290205460ff16156122f95750565b63e2517d3f60e01b5f523360045260245260445ffd5b6123198282612764565b918261232457505090565b5f9182525f805160206129f58339815191526020526040909120612351916001600160a01b031690612987565b5090565b61235f82826127ef565b918261236a57505090565b5f9182525f805160206129f58339815191526020526040909120612351916001600160a01b031690612487565b8054821015611efb575f5260205f2001905f90565b5f818152600d60205260409020548015612481575f198101818111611e0157600c545f19810191908211611e0157818103612433575b505050600c54801561241f575f19016123fc81600c612397565b8154905f199060031b1b19169055600c555f52600d6020525f6040812055600190565b634e487b7160e01b5f52603160045260245ffd5b61246b61244461245593600c612397565b90549060031b1c928392600c612397565b819391549060031b91821b915f19901b19161790565b90555f52600d60205260405f20555f80806123e2565b50505f90565b906001820191815f528260205260405f20548015155f14612530575f198101818111611e015782545f19810191908211611e01578181036124fb575b5050508054801561241f575f1901906124dc8282612397565b8154905f199060031b1b19169055555f526020525f6040812055600190565b61251b61250b6124559386612397565b90549060031b1c92839286612397565b90555f528360205260405f20555f80806124c3565b505050505f90565b805f52600b60205260405f205490811580612568575b612556575090565b63015ab34360e11b5f5260045260245ffd5b50805f52600a60205260405f20541561254e565b6001600160a01b0381165f9081527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d602052604090205460ff16612613576001600160a01b03165f8181527fb7db2dd08fcb62d0c9e08c51941cae53c267786a0b75803fb7960902fc8ef97d60205260408120805460ff191660011790553391905f805160206129d58339815191528180a4600190565b505f90565b6001600160a01b0381165f9081527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a602052604090205460ff16612613576001600160a01b03165f8181527f06484cc59dc38e4f67c31122333a17ca81b3ca18cdf02bfc298072fa52b0316a60205260408120805460ff191660011790553391905f80516020612a15833981519152905f805160206129d58339815191529080a4600190565b6001600160a01b0381165f9081527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec602052604090205460ff16612613576001600160a01b03165f8181527f6a07288dad4cb198070ae9ab0d91c908f3652738923841b35a5b72d3571a1cec60205260408120805460ff191660011790553391905f80516020612a75833981519152905f805160206129d58339815191529080a4600190565b5f8181525f80516020612a35833981519152602090815260408083206001600160a01b038616845290915290205460ff16612481575f8181525f80516020612a35833981519152602090815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291905f805160206129d58339815191529080a4600190565b5f8181525f80516020612a35833981519152602090815260408083206001600160a01b038616845290915290205460ff1615612481575f8181525f80516020612a35833981519152602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b805f52600b60205260405f205480155f146128b457505f52600a60205260405f20541515905f90565b600192909150565b60ff5f80516020612a958339815191525460401c16156128d857565b631afcd79f60e31b5f5260045ffd5b805f52600a60205260405f2054155f1461261357600954600160401b811015611f2b576129206124558260018594016009556009612397565b9055600954905f52600a60205260405f2055600190565b805f52600d60205260405f2054155f1461261357600c54600160401b811015611f2b57612970612455826001859401600c55600c612397565b9055600c54905f52600d60205260405f2055600190565b5f82815260018201602052604090205461248157805490600160401b821015611f2b57826129bf612455846001809601855584612397565b90558054925f520160205260405f205560019056fe2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0dc1f6fe24621ce81ec5827caf0253cadb74709b061630e6b55e82371705932000241ecf16d79d0f8dbfb92cbc07fe17840425976cf0667f022fe9877caa831b0802dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00ced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a26469706673582212201fa37769918cc943d916ff9602c6797854517220ef2c16ad9fa7a3883db04d1664736f6c634300081a0033

Block Transaction Gas Used Reward
view all blocks ##produced##

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.