creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20PermitUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n *     doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n *     token.safeTransferFrom(msg.sender, address(this), value);\n *     ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     *\n     * CAUTION: See Security Considerations above.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     */\n    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.\n     * Revert on invalid signature.\n     */\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        require(returndata.length == 0 || abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\n        // and not revert is the subcall reverts.\n\n        (bool success, bytes memory returndata) = address(token).call(data);\n        return\n            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     *\n     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
      },
      "contracts/OperationalStaking.sol": {
        "content": "//SPDX-License-Identifier: MIT\npragma solidity 0.8.13;\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n\ncontract OperationalStaking is OwnableUpgradeable {\n    using SafeERC20Upgradeable for IERC20Upgradeable;\n\n    uint256 public constant DIVIDER = 10 ** 18; // 18 decimals used for scaling rates\n    uint128 public constant REWARD_REDEEM_THRESHOLD = 10 ** 8; // minimum number of tokens that can be redeemed\n    uint128 public constant DEFAULT_VALIDATOR_ENABLE_MIN_STAKE = 35000 * 10 ** 18; // minimum number of self-staked tokens for a validator to become / stay enabled\n    uint128 public constant DEFAULT_DELEGATOR_MIN_STAKE = 10 ** 18; // stake/unstake operations are invalid if they put you below this threshold (except unstaking to 0)\n\n    IERC20Upgradeable public CQT;\n    uint128 public rewardPool; // how many tokens are allocated for rewards\n    uint128 public validatorCoolDown; // how many blocks until validator unstaking is unlocked\n    uint128 public delegatorCoolDown; // how many blocks until delegator unstaking is unlocked\n    uint128 public recoverUnstakingCoolDown; //how many blocks until delegator recoverUnstaking or redelegateUnstaked is unlocked\n    uint128 public maxCapMultiplier; // *see readme\n    uint128 public validatorMaxStake; // how many tokens validators can stake at most\n    address public stakingManager;\n    uint128 public validatorsN; // number of validators, used to get validator ids\n    mapping(uint128 => Validator) internal _validators; // id -> validator instance\n\n    uint128 public validatorEnableMinStake; // minimum number of self-staked tokens for a validator to become / stay enabled\n    uint128 public delegatorMinStake; // stake/unstake operations are invalid if they put you below this threshold (except unstaking to 0)\n\n    bool private _unpaused;\n\n    struct Staking {\n        uint128 shares; // # of validator shares that the delegator owns\n        uint128 staked; // # of CQT that a delegator delegated originally through stake() transaction\n    }\n\n    struct Unstaking {\n        uint128 outCoolDownEnd; // epoch when unstaking can be redeemed (taken out)\n        uint128 recoverCoolDownEnd; // epoch when unstaking can be recovered (to the same validator) or redelegated\n        uint128 amount; // # of unstaked CQT\n    }\n\n    struct Validator {\n        uint128 commissionAvailableToRedeem;\n        uint128 exchangeRate; // validator exchange rate\n        address _address; // wallet address of the operator which is mapped to the validator instance\n        uint128 delegated; // track amount of tokens delegated\n        uint128 totalShares; // total number of validator shares\n        uint128 commissionRate;\n        uint256 disabledAtBlock;\n        mapping(address => Staking) stakings;\n        mapping(address => Unstaking[]) unstakings;\n        bool frozen;\n    }\n\n    event InitializedSemantics(\n        address cqt,\n        uint128 validatorCoolDown,\n        uint128 delegatorCoolDown,\n        uint128 recoverUnstakingCoolDown,\n        uint128 maxCapMultiplier,\n        uint128 validatorMaxStake,\n        uint128 validatorEnableMinStake,\n        uint128 delegatorMinStake\n    );\n\n    event RewardTokensDeposited(uint128 amount);\n\n    event ValidatorAdded(uint128 indexed id, uint128 commissionRate, address indexed validator);\n\n    event Staked(uint128 indexed validatorId, address delegator, uint128 amount);\n\n    event Unstaked(uint128 indexed validatorId, address indexed delegator, uint128 amount, uint128 unstakeId);\n\n    event RecoveredUnstake(uint128 indexed validatorId, address indexed delegator, uint128 amount, uint128 unstakingId);\n\n    event UnstakeRedeemed(uint128 indexed validatorId, address indexed delegator, uint128 indexed unstakeId, uint128 amount);\n\n    event AllocatedTokensTaken(uint128 amount);\n\n    event RewardFailedDueZeroStake(uint128 indexed validatorId, uint128 amount);\n\n    event RewardFailedDueValidatorDisabled(uint128 indexed validatorId, uint128 amount);\n\n    event RewardFailedDueValidatorFrozen(uint128 indexed validatorId, uint128 amount);\n\n    event RewardRedeemed(uint128 indexed validatorId, address indexed beneficiary, uint128 amount);\n\n    event CommissionRewardRedeemed(uint128 indexed validatorId, address indexed beneficiary, uint128 amount);\n\n    event StakingManagerChanged(address indexed operationalManager);\n\n    event ValidatorCommissionRateChanged(uint128 indexed validatorId, uint128 amount);\n\n    event ValidatorMaxCapChanged(uint128 amount);\n\n    event ValidatorEnableMinStakeChanged(uint128 amount);\n\n    event DelegatorMinStakeChanged(uint128 amount);\n\n    event ValidatorUnstakeCooldownChanged(uint128 amount);\n\n    event DelegatorUnstakeCooldownChanged(uint128 amount);\n\n    event RecoverUnstakeCooldownChanged(uint128 amount);\n\n    event ValidatorDisabled(uint128 indexed validatorId, uint256 blockNumber);\n\n    event Redelegated(uint128 indexed oldValidatorId, uint128 indexed newValidatorId, address indexed delegator, uint128 amount, uint128 unstakingId);\n\n    event MaxCapMultiplierChanged(uint128 newMaxCapMultiplier);\n\n    event ValidatorEnabled(uint128 indexed validatorId);\n\n    event ValidatorAddressChanged(uint128 indexed validatorId, address indexed newAddress);\n\n    event Paused(address account);\n\n    event Unpaused(address account);\n\n    event ValidatorFrozen(uint128 indexed validatorId, string reason);\n\n    event ValidatorUnfrozen(uint128 indexed validatorId);\n\n    event RewardsDisbursed(uint128 indexed rewardId);\n\n    modifier onlyStakingManager() {\n        require(stakingManager == msg.sender, \"Caller is not stakingManager\");\n        _;\n    }\n\n    modifier onlyStakingManagerOrOwner() {\n        require(msg.sender == stakingManager || msg.sender == owner(), \"Caller is not stakingManager or owner\");\n        _;\n    }\n\n    modifier whenNotPaused() {\n        require(_unpaused, \"paused\");\n        _;\n    }\n\n    function initialize(address cqt, uint128 dCoolDown, uint128 vCoolDown, uint128 rCoolDown, uint128 maxCapM, uint128 vMaxStake) external initializer {\n        require(cqt != address(0), \"Invalid cqt address\");\n        __Ownable_init();\n        validatorCoolDown = vCoolDown; // 180*6857 = ~ 6 months\n        delegatorCoolDown = dCoolDown; //  28*6857 = ~ 28 days\n        recoverUnstakingCoolDown = rCoolDown; // 3*6857 = ~ 3 days\n        maxCapMultiplier = maxCapM;\n        validatorMaxStake = vMaxStake;\n        require(validatorMaxStake >= DEFAULT_VALIDATOR_ENABLE_MIN_STAKE);\n\n        validatorEnableMinStake = DEFAULT_VALIDATOR_ENABLE_MIN_STAKE;\n        delegatorMinStake = DEFAULT_DELEGATOR_MIN_STAKE;\n\n        _unpaused = true;\n\n        CQT = IERC20Upgradeable(cqt);\n        emit InitializedSemantics(cqt, vCoolDown, dCoolDown, rCoolDown, maxCapM, vMaxStake, validatorEnableMinStake, delegatorMinStake);\n    }\n\n    function setStakingManagerAddress(address newAddress) external onlyOwner {\n        require(newAddress != address(0), \"Invalid address\");\n        stakingManager = newAddress;\n        emit StakingManagerChanged(newAddress);\n    }\n\n    /*\n     * Transfer CQT from the owner to the contract for reward allocation\n     */\n    function depositRewardTokens(uint128 amount) external onlyOwner {\n        require(amount > 0, \"Amount is 0\");\n        rewardPool += amount;\n        _transferToContract(msg.sender, amount);\n        emit RewardTokensDeposited(amount);\n    }\n\n    /*\n     * Transfer reward CQT from the contract to the owner\n     */\n    function takeOutRewardTokens(uint128 amount) external onlyOwner {\n        require(amount > 0, \"Amount is 0\");\n        require(amount <= rewardPool, \"Reward pool is too small\");\n        rewardPool -= amount;\n        emit AllocatedTokensTaken(amount);\n        _transferFromContract(msg.sender, amount);\n    }\n\n    /*\n     * Updates validator max cap multiplier that determines how many tokens can be delegated\n     */\n    function setMaxCapMultiplier(uint128 newMaxCapMultiplier) external onlyOwner {\n        require(newMaxCapMultiplier > 0, \"Must be greater than 0\");\n        maxCapMultiplier = newMaxCapMultiplier;\n        emit MaxCapMultiplierChanged(newMaxCapMultiplier);\n    }\n\n    /*\n     * Updates maximum number of tokens that a validator can stake\n     */\n    function setValidatorMaxStake(uint128 maxStake) external onlyOwner {\n        require(maxStake > 0, \"Provided max stake is 0\");\n        require(maxStake >= validatorEnableMinStake, \"maxStake should be greater than validatorEnableMinStake\");\n        validatorMaxStake = maxStake;\n        emit ValidatorMaxCapChanged(maxStake);\n    }\n\n    /*\n     * Updates minimum number of tokens that a validator must self-stake before enabling\n     */\n    function setValidatorEnableMinStake(uint128 minStake) public onlyOwner {\n        require(minStake <= validatorMaxStake, \"minStake cannot be greater than validatorMaxStake\");\n        validatorEnableMinStake = minStake;\n        emit ValidatorEnableMinStakeChanged(minStake);\n    }\n\n    /*\n     * Updates minimum valid position threshold for per-delegator stake\n     */\n    function setDelegatorMinStake(uint128 minStake) public onlyOwner {\n        require(minStake <= validatorMaxStake, \"minStake cannot be greater than validatorMaxStake\");\n        delegatorMinStake = minStake;\n        emit DelegatorMinStakeChanged(minStake);\n    }\n\n    /*\n     * Updates the validator cool down period (in blocks)\n     * Note: this doesn't effect the existing unstakes\n     */\n    function setValidatorCoolDown(uint128 coolDown) external onlyOwner {\n        validatorCoolDown = coolDown;\n        emit ValidatorUnstakeCooldownChanged(coolDown);\n    }\n\n    /*\n     * Updates the delegator cool down period (in blocks)\n     * Note: this doesn't effect the existing unstakes\n     */\n    function setDelegatorCoolDown(uint128 coolDown) external onlyOwner {\n        delegatorCoolDown = coolDown;\n        emit DelegatorUnstakeCooldownChanged(coolDown);\n    }\n\n    /*\n     * Updates the delegator recover Unstaking cool down period (in blocks)\n     * Note: this doesn't effect the existing unstakes\n     */\n    function setRecoverUnstakingCoolDown(uint128 coolDown) external onlyOwner {\n        recoverUnstakingCoolDown = coolDown;\n        emit RecoverUnstakeCooldownChanged(coolDown);\n    }\n\n    /*\n     * Adds new validator instance\n     */\n    function addValidator(address validator, uint128 commissionRate) external onlyOwner whenNotPaused returns (uint256 id) {\n        require(commissionRate < DIVIDER, \"Rate must be less than 100%\");\n        require(validator != address(0), \"Validator address is 0\");\n        require(validatorsN < 256, \"Too many validators\");\n        Validator storage v = _validators[validatorsN]; // use current number of validators for the id of a new validator instance\n        v._address = validator;\n        v.exchangeRate = uint128(DIVIDER); // make it 1:1 initially\n        v.commissionRate = commissionRate;\n        v.disabledAtBlock = 1; // set it to 1 to indicate that the validator is disabled\n\n        emit ValidatorAdded(validatorsN, commissionRate, validator);\n        validatorsN += 1;\n\n        return validatorsN - 1;\n    }\n\n    /*\n     * Reward emission\n     */\n    function rewardValidators(uint128 rewardId, uint128[] calldata ids, uint128[] calldata amounts) external onlyStakingManager whenNotPaused {\n        require(ids.length == amounts.length, \"Given ids and amounts arrays must be of the same length\");\n        uint128 newRewardPool = rewardPool;\n        uint128 amount;\n        uint128 validatorId;\n        uint128 commissionPaid;\n\n        for (uint256 j = 0; j < ids.length; j++) {\n            amount = amounts[j];\n            validatorId = ids[j];\n            // ensure each validator exists\n            require(validatorId < validatorsN, \"Invalid validatorId\");\n\n            // make sure there are enough tokens in the reward pool\n            require(newRewardPool >= amount, \"Reward pool is too small\");\n\n            Validator storage v = _validators[validatorId];\n\n            if (v.frozen) {\n                emit RewardFailedDueValidatorFrozen(validatorId, amount);\n                continue;\n            }\n\n            if (v.disabledAtBlock != 0) {\n                // validator became disabled (due to e.g. unstaking past base stake)\n                // between proof submission and finalization\n                emit RewardFailedDueValidatorDisabled(validatorId, amount);\n                continue;\n            }\n\n            if (v.totalShares == 0) {\n                // mathematically undefined -- no exchangeRate can turn zero into nonzero\n                // (this condition is only possible in testing with minValidatorEnableStake == 0;\n                //  in prod, validators with zero stake will always be disabled and so will trigger\n                //  the above check, not this one)\n                emit RewardFailedDueZeroStake(validatorId, amount);\n                continue;\n            }\n\n            commissionPaid = uint128((uint256(amount) * uint256(v.commissionRate)) / DIVIDER);\n\n            // distribute the tokens by increasing the exchange rate\n            // div by zero impossible due to check above\n            // (and in fact, presuming minValidatorEnableStake >= DIVIDER, v.totalShares will\n            //  always be >= DIVIDER while validator is enabled)\n            v.exchangeRate += uint128((uint256(amount - commissionPaid) * uint256(DIVIDER)) / v.totalShares);\n\n            // commission is not compounded\n            // commisison is distributed under the validator instance\n            v.commissionAvailableToRedeem += commissionPaid;\n\n            newRewardPool -= amount;\n        }\n\n        rewardPool = newRewardPool; // can never access these tokens anymore, reserved for validator rewards\n        emit RewardsDisbursed(rewardId);\n    }\n\n    /*\n     * Disables validator instance starting from the given block\n     */\n    function disableValidator(uint128 validatorId) external onlyStakingManagerOrOwner {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n\n        if (v.disabledAtBlock != 0) {\n            // silently succeed\n            return;\n        }\n\n        v.disabledAtBlock = block.number;\n        emit ValidatorDisabled(validatorId, block.number);\n    }\n\n    /*\n     * Enables validator instance by setting the disabledAtBlock to 0\n     */\n    function enableValidator(uint128 validatorId) external onlyStakingManagerOrOwner {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n\n        if (v.disabledAtBlock == 0) {\n            // silently succeed\n            return;\n        }\n\n        uint128 staked = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);\n        require(staked >= validatorEnableMinStake, \"Validator is insufficiently staked\");\n\n        v.disabledAtBlock = 0;\n        emit ValidatorEnabled(validatorId);\n    }\n\n    /*\n     * Determines whether a validator is currently able to be used by operators\n     */\n    function isValidatorEnabled(uint128 validatorId) external view returns (bool) {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        return _validators[validatorId].disabledAtBlock == 0;\n    }\n\n    /*\n     * Updates validator comission rate\n     * Commission rate is a number between 0 and 10^18 (0%-100%)\n     */\n    function setValidatorCommissionRate(uint128 validatorId, uint128 amount) external onlyOwner {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(amount < DIVIDER, \"Rate must be less than 100%\");\n        _validators[validatorId].commissionRate = amount;\n        emit ValidatorCommissionRateChanged(validatorId, amount);\n    }\n\n    /*\n     * Used to transfer CQT from delegators, validators, and the owner to the contract\n     */\n    function _transferToContract(address from, uint128 amount) internal {\n        CQT.safeTransferFrom(from, address(this), amount);\n    }\n\n    /*\n     * Used to transfer CQT from contract, for reward redemption or transferring out unstaked tokens\n     */\n    function _transferFromContract(address to, uint128 amount) internal {\n        CQT.safeTransfer(to, amount);\n    }\n\n    /*\n     * Used to convert validator shares to CQT\n     */\n    function _sharesToTokens(uint128 sharesN, uint128 rate) internal pure returns (uint128) {\n        return uint128((uint256(sharesN) * uint256(rate)) / DIVIDER);\n    }\n\n    /*\n     * Used to convert CQT to validator shares\n     */\n    function _tokensToShares(uint128 amount, uint128 rate) internal pure returns (uint128) {\n        return uint128((uint256(amount) * DIVIDER) / uint256(rate)); // Rounding down from uint256 to uint128 leading to loss of precision for which checks are implemented in _redeemRewards and _unstake\n    }\n\n    /*\n     * Delegates tokens under the provided validator\n     */\n    function stake(uint128 validatorId, uint128 amount) external whenNotPaused {\n        _stake(validatorId, amount, true);\n    }\n\n    /*\n     * withTransfer is set to false when delegators recover unstaked or redelegated tokens.\n     * These tokens are already in the contract.\n     */\n    function _stake(uint128 validatorId, uint128 amount, bool withTransfer) internal {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(amount >= DEFAULT_DELEGATOR_MIN_STAKE, \"Stake amount is too small\");\n        Validator storage v = _validators[validatorId];\n        bool isValidator = msg.sender == v._address;\n\n        require(!v.frozen, \"Validator is frozen\");\n\n        // validators should be able to stake if they are disabled.\n        if (!isValidator) require(v.disabledAtBlock == 0, \"Validator is disabled\");\n\n        Staking storage s = v.stakings[msg.sender];\n\n        uint128 newStaked = s.staked + amount;\n\n        require(newStaked >= delegatorMinStake, \"Cannot stake to a position less than delegatorMinStake\");\n\n        uint128 sharesAdd = _tokensToShares(amount, v.exchangeRate);\n\n        if (isValidator) {\n            // compares with newStaked to ignore compounded rewards\n            require(newStaked <= validatorMaxStake, \"Validator max stake exceeded\");\n        } else {\n            // cannot stake more than validator delegation max cap\n            uint128 delegationMaxCap = v.stakings[v._address].staked * maxCapMultiplier;\n            uint128 newDelegated = v.delegated + amount;\n            require(newDelegated <= delegationMaxCap, \"Validator max delegation exceeded\");\n            v.delegated = newDelegated;\n        }\n\n        // \"buy/mint\" shares\n        v.totalShares += sharesAdd;\n        s.shares += sharesAdd;\n\n        // keep track of staked tokens\n        s.staked = newStaked;\n        if (withTransfer) _transferToContract(msg.sender, amount);\n        emit Staked(validatorId, msg.sender, amount);\n    }\n\n    /*\n     * Undelegates all staked tokens from the provided validator\n     */\n    function unstakeAll(uint128 validatorId) external whenNotPaused {\n        _unstake(validatorId, 0); // pass 0 to request full amount\n    }\n\n    /*\n     * Undelegates some number of tokens from the provided validator\n     */\n    function unstake(uint128 validatorId, uint128 amount) external whenNotPaused {\n        require(amount > 0, \"Amount is 0\");\n        _unstake(validatorId, amount);\n    }\n\n    /*\n     * Undelegates tokens from the provided validator\n     */\n    function _unstake(uint128 validatorId, uint128 amount) internal {\n        require(validatorId < validatorsN, \"Invalid validator\");\n\n        Validator storage v = _validators[validatorId];\n        Staking storage s = v.stakings[msg.sender];\n        if (msg.sender == v._address) {\n            require(!v.frozen, \"Validator is frozen\");\n        }\n\n        require(amount <= s.staked, \"Cannot unstake amount greater than current stake\");\n\n        bool isUnstakingAll = amount == 0 || amount == s.staked;\n        uint128 effectiveAmount = isUnstakingAll ? s.staked : amount;\n        uint128 newStaked = s.staked - effectiveAmount;\n\n        if (isUnstakingAll) {\n            // enforce precondition for later math that effectiveAmount is always nonzero\n            require(effectiveAmount > 0, \"Already fully unstaked\");\n        } else {\n            // to prevent buildup of Unstaking[] elements, do not allow user to repeatedly unstake trivial amounts\n            // (but do allow removal of a trivial amount if it is the entire remaining stake)\n            require(effectiveAmount >= REWARD_REDEEM_THRESHOLD, \"Unstake amount is too small\");\n\n            // to prevent \"spam\" delegations, and runaway exchangeRate inflation from all-but-dust self-stake unstaking,\n            // disallow unstaking that would result in a new stake below delegatorMinStake\n            // (with the exception of an unstaking that takes the stake exactly to zero)\n            require(newStaked >= delegatorMinStake, \"Cannot unstake to a position below delegatorMinStake (except to zero)\");\n        }\n\n        bool isValidator = msg.sender == v._address;\n\n        // disable validator if they unstaked to below their required self-stake\n        if (isValidator && validatorEnableMinStake > 0 && v.disabledAtBlock == 0 && newStaked < validatorEnableMinStake) {\n            uint256 disabledAtBlock = block.number;\n            v.disabledAtBlock = disabledAtBlock;\n            emit ValidatorDisabled(validatorId, disabledAtBlock);\n        }\n\n        if (isValidator && v.disabledAtBlock == 0) {\n            // validators will have to disable themselves if they want to unstake tokens below delegation max cap\n            uint128 newValidatorMaxCap = newStaked * maxCapMultiplier;\n            require(v.delegated <= newValidatorMaxCap, \"Cannot decrease delegation max-cap below current delegation while validator is enabled\");\n        }\n        if (!isValidator) {\n            v.delegated -= effectiveAmount;\n        }\n\n        uint128 sharesToRemove = _tokensToShares(effectiveAmount, v.exchangeRate);\n\n        // sometimes, due to conversion inconsistencies, sharesToRemove might end up larger than s.shares;\n        // so we clamp sharesToRemove to s.shares (the redeemer unstakes trivially more tokens in this case)\n        if (sharesToRemove > s.shares) sharesToRemove = s.shares;\n\n        // sanity check: sharesToRemove should never be zero while amount is nonzero, as this would enable\n        // infinite draining of funds\n        require(sharesToRemove > 0, \"Underflow error\");\n\n        if (uint256(sharesToRemove) * uint256(v.exchangeRate) < uint256(effectiveAmount) * uint256(DIVIDER)) {\n            effectiveAmount = uint128((uint256(sharesToRemove) * uint256(v.exchangeRate)) / uint256(DIVIDER));\n        }\n        s.shares -= sharesToRemove;\n        v.totalShares -= sharesToRemove;\n        // remove staked tokens\n        s.staked = newStaked;\n\n        // create unstaking instance\n        uint128 outCoolDownEnd = uint128(v.disabledAtBlock != 0 ? v.disabledAtBlock : block.number);\n        uint128 recoverCoolDownEnd = outCoolDownEnd + recoverUnstakingCoolDown;\n        outCoolDownEnd += (isValidator ? validatorCoolDown : delegatorCoolDown);\n        uint128 unstakeId = uint128(v.unstakings[msg.sender].length);\n        v.unstakings[msg.sender].push(Unstaking(outCoolDownEnd, recoverCoolDownEnd, effectiveAmount));\n        emit Unstaked(validatorId, msg.sender, effectiveAmount, unstakeId);\n    }\n\n    /*\n     * Restakes unstaked tokens (with the same validator)\n     */\n    function recoverUnstaking(uint128 amount, uint128 validatorId, uint128 unstakingId) external whenNotPaused {\n        Validator storage v = _validators[validatorId];\n        require(amount > 0, \"Amount is 0\");\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(!v.frozen, \"Validator is frozen\");\n        require(_validators[validatorId].unstakings[msg.sender].length > unstakingId, \"Unstaking does not exist\");\n        Unstaking storage us = _validators[validatorId].unstakings[msg.sender][unstakingId];\n        require(us.amount >= amount, \"Unstaking has less tokens\");\n        require(block.number > us.recoverCoolDownEnd, \"recover cooldown not over\");\n\n        us.amount -= amount;\n        // set cool down end to 0 to release gas if new unstaking amount is 0\n        if (us.amount == 0) {\n            us.recoverCoolDownEnd = 0;\n            us.outCoolDownEnd = 0;\n        }\n        emit RecoveredUnstake(validatorId, msg.sender, amount, unstakingId);\n        _stake(validatorId, amount, false);\n    }\n\n    /*\n     * Transfers out unlocked unstaked tokens back to the delegator\n     */\n    function transferUnstakedOut(uint128 amount, uint128 validatorId, uint128 unstakingId) external whenNotPaused {\n        Validator storage v = _validators[validatorId];\n        require(amount > 0, \"Amount is 0\");\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(!v.frozen, \"Validator is frozen\");\n        require(_validators[validatorId].unstakings[msg.sender].length > unstakingId, \"Unstaking does not exist\");\n        Unstaking storage us = _validators[validatorId].unstakings[msg.sender][unstakingId];\n        require(block.number > us.outCoolDownEnd, \"Cooldown period has not ended\");\n        require(us.amount >= amount, \"Amount is too high\");\n        us.amount -= amount;\n        // set cool down end to 0 to release gas if new unstaking amount is 0\n        if (us.amount == 0) {\n            us.recoverCoolDownEnd = 0;\n            us.outCoolDownEnd = 0;\n        }\n        emit UnstakeRedeemed(validatorId, msg.sender, unstakingId, amount);\n        _transferFromContract(msg.sender, amount);\n    }\n\n    /*\n     * Redeems all available rewards\n     */\n    function redeemAllRewards(uint128 validatorId, address beneficiary) external whenNotPaused {\n        _redeemRewards(validatorId, beneficiary, 0); // pass 0 to request full amount\n    }\n\n    /*\n     * Redeems partial rewards\n     */\n    function redeemRewards(uint128 validatorId, address beneficiary, uint128 amount) external whenNotPaused {\n        require(amount > 0, \"Amount is 0\");\n        _redeemRewards(validatorId, beneficiary, amount);\n    }\n\n    function _redeemRewards(uint128 validatorId, address beneficiary, uint128 amount) internal {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(beneficiary != address(0x0), \"Invalid beneficiary\");\n        Validator storage v = _validators[validatorId];\n        Staking storage s = v.stakings[msg.sender];\n\n        require(!v.frozen, \"Validator is frozen\");\n\n        // how many tokens a delegator/validator has in total on the contract\n        // include earned commission if the delegator is the validator\n        uint128 totalValue = _sharesToTokens(s.shares, v.exchangeRate);\n\n        // how many tokens a delegator/validator has \"unlocked\", free to be redeemed\n        // (i.e. not staked or in unstaking cooldown)\n        uint128 totalUnlockedValue = (totalValue < s.staked) ? 0 : (totalValue - s.staked);\n\n        bool isRedeemingAll = (amount == 0 || amount == totalUnlockedValue); // amount is 0 when it's requested to redeem all rewards\n\n        // make sure rewards exist\n        // (note that this still works in the case where we're redeeming all! always doing this check saves a branch op)\n        require(amount <= totalUnlockedValue, \"Cannot redeem amount greater than held, unstaked rewards\");\n\n        uint128 effectiveAmount = isRedeemingAll ? totalUnlockedValue : amount;\n\n        // can only redeem above redeem threshold\n        require(effectiveAmount >= REWARD_REDEEM_THRESHOLD, \"Requested amount must be higher than redeem threshold\");\n        // make sure rewardPool has funds to cover effective amount before transfer\n        require(rewardPool >= effectiveAmount, \"Requested amount is not available in the staking contract reward pool\");\n\n        uint128 sharesToBurn = _tokensToShares(effectiveAmount, v.exchangeRate);\n\n        // sometimes, due to conversion inconsistencies, sharesToBurn might end up larger than s.shares;\n        // so we clamp sharesToBurn to s.shares (the redeemer gets trivially more value out in this case)\n        if (sharesToBurn > s.shares) sharesToBurn = s.shares;\n\n        // sanity check: sharesToBurn should never be zero while effectiveAmount is nonzero, as this\n        // would enable infinite draining of funds\n        require(sharesToBurn > 0, \"Underflow error\");\n        if (uint256(sharesToBurn) * uint256(v.exchangeRate) < uint256(effectiveAmount) * uint256(DIVIDER)) {\n            effectiveAmount = uint128((uint256(sharesToBurn) * uint256(v.exchangeRate)) / uint256(DIVIDER));\n        }\n        v.totalShares -= sharesToBurn;\n        s.shares -= sharesToBurn;\n\n        emit RewardRedeemed(validatorId, beneficiary, effectiveAmount);\n        _transferFromContract(beneficiary, effectiveAmount);\n    }\n\n    function redeemCommission(uint128 validatorId, address beneficiary, uint128 amount) public whenNotPaused {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        require(beneficiary != address(0x0), \"Invalid beneficiary\");\n        Validator storage v = _validators[validatorId];\n        require(v._address == msg.sender, \"The sender is not the validator\");\n\n        require(!v.frozen, \"Validator is frozen\");\n\n        require(v.commissionAvailableToRedeem > 0, \"No commission available to redeem\");\n        require(amount > 0, \"The requested amount is 0\");\n        require(amount <= v.commissionAvailableToRedeem, \"Requested amount is higher than commission available to redeem\");\n        // make sure rewardPool has funds to cover effective amount before transfer\n        require(rewardPool >= amount, \"Requested amount is not available in the staking contract reward pool\");\n        v.commissionAvailableToRedeem -= amount;\n\n        _transferFromContract(beneficiary, amount);\n        emit CommissionRewardRedeemed(validatorId, beneficiary, amount);\n    }\n\n    function redeemAllCommission(uint128 validatorId, address beneficiary) external whenNotPaused {\n        redeemCommission(validatorId, beneficiary, _validators[validatorId].commissionAvailableToRedeem);\n    }\n\n    /*\n     * Redelegates tokens to another validator if a validator got disabled.\n     * First the tokens need to be unstaked\n     */\n    function redelegateUnstaked(uint128 amount, uint128 oldValidatorId, uint128 newValidatorId, uint128 unstakingId) external whenNotPaused {\n        require(oldValidatorId < validatorsN, \"Invalid validator\");\n        require(oldValidatorId != newValidatorId, \"Old and new validators are the same\");\n        require(amount > 0, \"Amount is 0\");\n        Validator storage vOld = _validators[oldValidatorId];\n        Validator storage vNew = _validators[newValidatorId];\n        // new staking should not be from same an address to same (new) validator to bypass cooldown\n        require(vNew._address != msg.sender, \"New Validator cannot be same as sender\");\n        // assets of delegators cannot be moved to a frozen validator\n        require(!vNew.frozen, \"Target validator is frozen\");\n        // assets of delegators cannot be moved to a disabled validator\n        require(vNew.disabledAtBlock == 0, \"Target validator is disabled\");\n        // assets of delegators cannot be moved while validator is frozen\n        require(!vOld.frozen, \"Validator is frozen\");\n        require(vOld.disabledAtBlock != 0, \"Validator is not disabled\");\n        require(vOld._address != msg.sender, \"Validator cannot redelegate\");\n        require(vOld.unstakings[msg.sender].length > unstakingId, \"Unstaking does not exist\");\n        Unstaking storage us = vOld.unstakings[msg.sender][unstakingId];\n        require(us.amount >= amount, \"Unstaking has less tokens\");\n        require(block.number > us.recoverCoolDownEnd, \"recover cooldown not over\");\n\n        // stake tokens back to the contract using new validator, set withTransfer to false since the tokens are already in the contract\n        us.amount -= amount;\n\n        // set cool down end to 0 to release gas if new unstaking amount is 0\n        if (us.amount == 0) {\n            us.recoverCoolDownEnd = 0;\n            us.outCoolDownEnd = 0;\n        }\n        emit Redelegated(oldValidatorId, newValidatorId, msg.sender, amount, unstakingId);\n        _stake(newValidatorId, amount, false);\n    }\n\n    /*\n     * Changes the validator staking address, this will transfer validator staking data and optionally unstakings\n     */\n    function setValidatorAddress(uint128 validatorId, address newAddress) external whenNotPaused {\n        Validator storage v = _validators[validatorId];\n        // Check if the sender is the validator\n        require(msg.sender == v._address, \"Sender is not the validator\");\n        // Check if the new address is different from the current address\n        require(newAddress != v._address, \"The new address cannot be equal to the current validator address\");\n        require(newAddress != address(0), \"Invalid validator address\");\n        // Check if the validatorId exists and is not frozen\n        require(!v.frozen, \"Validator is already frozen\");\n\n        // Check if the newAddress is already present as validator or delegator in the system\n        require(!checkDelegatorExists(newAddress), \"newAddress must not already exist in the system\");\n\n        // Transfer shares and staked amount from sender to the new address\n        v.stakings[newAddress].shares += v.stakings[msg.sender].shares;\n        v.stakings[newAddress].staked += v.stakings[msg.sender].staked;\n        // New addresses total stake shold not exceed validatorMaxStake\n        require(v.stakings[newAddress].staked <= validatorMaxStake, \"Validator max stake exceeded\");\n        // Remove stakings of the sender\n        delete v.stakings[msg.sender];\n        // Transfer unstakings from sender to new address\n        Unstaking[] storage oldUnstakings = v.unstakings[msg.sender];\n        uint256 length = oldUnstakings.length;\n        require(length <= 300, \"Cannot transfer more than 300 unstakings\");\n        Unstaking[] storage newUnstakings = v.unstakings[newAddress];\n        for (uint128 i = 0; i < length; ++i) {\n            newUnstakings.push(oldUnstakings[i]);\n        }\n        // Remove unstakings of the sender\n        delete v.unstakings[msg.sender];\n\n        // Update validator address\n        v._address = newAddress;\n        emit ValidatorAddressChanged(validatorId, newAddress);\n    }\n\n    /*\n     * Gets metadata\n     */\n    function getMetadata()\n        external\n        view\n        returns (\n            address CQTaddress,\n            address _stakingManager,\n            uint128 _validatorsN,\n            uint128 _rewardPool,\n            uint128 _validatorCoolDown,\n            uint128 _delegatorCoolDown,\n            uint128 _recoverUnstakingCoolDown,\n            uint128 _maxCapMultiplier,\n            uint128 _validatorMaxStake,\n            uint128 _validatorEnableMinStake,\n            uint128 _delegatorMinStake\n        )\n    {\n        return (\n            address(CQT),\n            stakingManager,\n            validatorsN,\n            rewardPool,\n            validatorCoolDown,\n            delegatorCoolDown,\n            recoverUnstakingCoolDown,\n            maxCapMultiplier,\n            validatorMaxStake,\n            validatorEnableMinStake,\n            delegatorMinStake\n        );\n    }\n\n    /*\n     * Returns validator metadata with how many tokens were staked and delegated excluding compounded rewards\n     */\n    function getValidatorMetadata(uint128 validatorId) public view returns (address _address, uint128 staked, uint128 delegated, uint128 commissionRate, uint256 disabledAtBlock) {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n        return (v._address, v.stakings[v._address].staked, v.delegated, v.commissionRate, v.disabledAtBlock);\n    }\n\n    /*\n     * Returns metadata for each validator\n     */\n    function getAllValidatorsMetadata()\n        external\n        view\n        returns (address[] memory addresses, uint128[] memory staked, uint128[] memory delegated, uint128[] memory commissionRates, uint256[] memory disabledAtBlocks)\n    {\n        return getValidatorsMetadata(0, validatorsN);\n    }\n\n    /*\n     * Returns metadata for validators whose ids are between startId and endId exclusively\n     */\n    function getValidatorsMetadata(\n        uint128 startId,\n        uint128 endId\n    ) public view returns (address[] memory addresses, uint128[] memory staked, uint128[] memory delegated, uint128[] memory commissionRates, uint256[] memory disabledAtBlocks) {\n        require(endId <= validatorsN, \"Invalid end id\");\n        require(startId < endId, \"Start id must be less than end id\");\n\n        uint128 n = endId - startId;\n        addresses = new address[](n);\n        staked = new uint128[](n);\n        delegated = new uint128[](n);\n        commissionRates = new uint128[](n);\n        disabledAtBlocks = new uint256[](n);\n\n        uint128 i;\n        for (uint128 id = startId; id < endId; ++id) {\n            i = id - startId;\n            (addresses[i], staked[i], delegated[i], commissionRates[i], disabledAtBlocks[i]) = getValidatorMetadata(id);\n        }\n        return (addresses, staked, delegated, commissionRates, disabledAtBlocks);\n    }\n\n    /*\n     * Returns validator staked and delegated token amounts, excluding compounded rewards\n     */\n    function getValidatorStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated) {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n        return (v.stakings[v._address].staked, v.delegated);\n    }\n\n    /*\n     * Returns validator staked and delegated token amounts, including compounded rewards\n     */\n    function getValidatorsCompoundedStakes() external view returns (uint128[] memory validatorIds, bool[] memory isEnableds, uint128[] memory cstaked) {\n        validatorIds = new uint128[](validatorsN);\n        isEnableds = new bool[](validatorsN);\n        cstaked = new uint128[](validatorsN);\n        for (uint128 i = 0; i < validatorsN; i++) {\n            Validator storage v = _validators[i];\n            validatorIds[i] = i;\n            isEnableds[i] = v.disabledAtBlock == 0;\n            cstaked[i] = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);\n        }\n\n        return (validatorIds, isEnableds, cstaked);\n    }\n\n    /*\n     * Returns validator staked and delegated token amounts, including compounded rewards\n     */\n    function getValidatorCompoundedStakingData(uint128 validatorId) external view returns (uint128 staked, uint128 delegated) {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n        // this includes staked + compounded rewards\n        staked = _sharesToTokens(v.stakings[v._address].shares, v.exchangeRate);\n        // this includes delegated + compounded rewards\n        delegated = _sharesToTokens(v.totalShares, v.exchangeRate) - staked;\n        return (staked, delegated);\n    }\n\n    /*\n     * Returns the amount that's staked, earned by delegator plus unstaking information.\n     * CommissionEarned is for validators\n     */\n    function getDelegatorMetadata(\n        address delegator,\n        uint128 validatorId\n    ) external view returns (uint128 staked, uint128 rewards, uint128 commissionEarned, uint128[] memory unstakingAmounts, uint128[] memory unstakingsEndEpochs) {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n        Staking storage s = v.stakings[delegator];\n        staked = s.staked;\n        uint128 sharesValue = _sharesToTokens(s.shares, v.exchangeRate);\n        if (sharesValue <= s.staked) rewards = 0;\n        else rewards = sharesValue - s.staked;\n        // if requested delegator is the requested validator\n        if (v._address == delegator) commissionEarned = v.commissionAvailableToRedeem;\n        Unstaking[] memory unstakings = v.unstakings[delegator];\n        uint256 unstakingsN = unstakings.length;\n        unstakingAmounts = new uint128[](unstakingsN);\n        unstakingsEndEpochs = new uint128[](unstakingsN);\n        for (uint256 i = 0; i < unstakingsN; i++) {\n            unstakingAmounts[i] = unstakings[i].amount;\n            unstakingsEndEpochs[i] = unstakings[i].outCoolDownEnd;\n        }\n        return (staked, rewards, commissionEarned, unstakingAmounts, unstakingsEndEpochs);\n    }\n\n    // function getDelegatorMetadataPaginated(\n    //     address delegator,\n    //     uint128 validatorId,\n    //     uint128 start,\n    //     uint128 end\n    // )\n    //     external\n    //     view\n    //     returns (uint128[] memory staked, uint128[] memory rewards, uint128[] memory commissionEarned, uint128[] memory unstakingAmounts, uint128[] memory unstakingsEndEpochs)\n    // {\n    //     require(validatorId < validatorsN, \"Invalid validator\");\n    //     Validator storage v = _validators[validatorId];\n    //     Staking storage s = v.stakings[delegator];\n    //     staked = new uint128[](end - start + 1);\n    //     rewards = new uint128[](end - start + 1);\n    //     commissionEarned = new uint128[](end - start + 1);\n    //     unstakingAmounts = new uint128[](end - start + 1);\n    //     unstakingsEndEpochs = new uint128[](end - start + 1);\n\n    //     for (uint256 i = start; i <= end; i++) {\n    //         Unstaking memory u = v.unstakings[delegator][i];\n    //         staked[i - start] = s.shares[u.shareIndex];\n    //         if (s.shares[u.shareIndex] <= _sharesToTokens(s.shares[u.shareIndex], v.exchangeRate)) {\n    //             rewards[i - start] = 0;\n    //         } else {\n    //             rewards[i - start] = _sharesToTokens(s.shares[u.shareIndex], v.exchangeRate) - s.shares[u.shareIndex];\n    //         }\n    //         if (v._address == delegator) {\n    //             commissionEarned[i - start] = v.commissionAvailableToRedeem;\n    //         } else {\n    //             commissionEarned[i - start] = 0;\n    //         }\n    //         unstakingAmounts[i - start] = u.amount;\n    //         unstakingsEndEpochs[i - start] = u.coolDownEnd;\n    //     }\n\n    //     return (staked, rewards, commissionEarned, unstakingAmounts, unstakingsEndEpochs);\n    // }\n\n    /*\n     * Returns the total amount including compounded stake and unstaked tokens\n     * CommissionEarned is also included (if delegator is a validator)\n     */\n    function getDelegatorTotalLocked(address delegator) external view returns (uint128 totalValueLocked) {\n        for (uint128 i = 0; i < validatorsN; i++) {\n            Validator storage v = _validators[i];\n            Staking storage s = v.stakings[delegator];\n            totalValueLocked += _sharesToTokens(s.shares, v.exchangeRate);\n            if (v._address == delegator) totalValueLocked += v.commissionAvailableToRedeem;\n            Unstaking[] memory unstakings = v.unstakings[delegator];\n            uint256 unstakingsN = unstakings.length;\n            for (uint256 j = 0; j < unstakingsN; j++) {\n                totalValueLocked += unstakings[j].amount;\n            }\n        }\n\n        return totalValueLocked;\n    }\n\n    function checkDelegatorExists(address newAddress) public view returns (bool) {\n        for (uint128 i = 0; i < validatorsN; i++) {\n            Validator storage v = _validators[i];\n            if (v._address == newAddress) {\n                return true;\n            }\n\n            Staking storage s = v.stakings[newAddress];\n            if (s.staked > 0 || s.shares > 0) {\n                return true;\n            }\n\n            if (v.unstakings[newAddress].length > 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    function pause() external onlyOwner whenNotPaused {\n        _unpaused = false;\n        emit Paused(_msgSender());\n    }\n\n    function unpause() external onlyOwner {\n        require(!_unpaused, \"must be paused\");\n        _unpaused = true;\n        emit Unpaused(_msgSender());\n    }\n\n    function paused() external view returns (bool) {\n        return !_unpaused;\n    }\n\n    function freezeValidator(uint128 validatorId, string memory reason) public onlyOwner {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n\n        require(!v.frozen, \"Validator is already frozen\");\n\n        v.frozen = true;\n        emit ValidatorFrozen(validatorId, reason);\n    }\n\n    function unfreezeValidator(uint128 validatorId) external onlyOwner {\n        require(validatorId < validatorsN, \"Invalid validator\");\n        Validator storage v = _validators[validatorId];\n\n        require(v.frozen, \"Validator not frozen\");\n\n        v.frozen = false;\n        emit ValidatorUnfrozen(validatorId);\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 1
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}