creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/p2pSsvProxy/P2pSsvProxy.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"../@openzeppelin/contracts/utils/introspection/ERC165Checker.sol\";\n\nimport \"../constants/P2pConstants.sol\";\nimport \"../interfaces/ssv/ISSVNetwork.sol\";\nimport \"../interfaces/IDepositContract.sol\";\nimport \"../interfaces/p2p/IFeeDistributorFactory.sol\";\nimport \"../access/OwnableWithOperator.sol\";\nimport \"../assetRecovering/OwnableAssetRecoverer.sol\";\nimport \"../structs/P2pStructs.sol\";\nimport \"../p2pSsvProxyFactory/IP2pSsvProxyFactory.sol\";\nimport \"./IP2pSsvProxy.sol\";\n\n\n/// @notice _referenceFeeDistributor should implement IFeeDistributor interface\n/// @param _passedAddress passed address for _referenceFeeDistributor\nerror P2pSsvProxy__NotFeeDistributor(address _passedAddress);\n\n/// @notice Should be a P2pSsvProxyFactory contract\n/// @param _passedAddress passed address that does not support IP2pSsvProxyFactory interface\nerror P2pSsvProxy__NotP2pSsvProxyFactory(address _passedAddress);\n\n/// @notice Throws if called by any account other than the client.\n/// @param _caller address of the caller\n/// @param _client address of the client\nerror P2pSsvProxy__CallerNotClient(address _caller, address _client);\n\n/// @notice The caller was neither operator nor owner\n/// @param _caller address of the caller\n/// @param _operator address of the operator\n/// @param _owner address of the owner\nerror P2pSsvProxy__CallerNeitherOperatorNorOwner(address _caller, address _operator, address _owner);\n\n/// @notice The caller was neither operator nor owner nor client\n/// @param _caller address of the caller\nerror P2pSsvProxy__CallerNeitherOperatorNorOwnerNorClient(address _caller);\n\n/// @notice Only factory can call `initialize`.\n/// @param _msgSender sender address.\n/// @param _actualFactory the actual factory address that can call `initialize`.\nerror P2pSsvProxy__NotP2pSsvProxyFactoryCalled(address _msgSender, IP2pSsvProxyFactory _actualFactory);\n\n/// @notice _pubkeys and _operatorIds arrays should have the same lengths\nerror P2pSsvProxy__AmountOfParametersError();\n\n/// @notice Selector is not allowed for the caller.\n/// @param _caller caller address\n/// @param _selector function selector to be called on SSVNetwork\nerror P2pSsvProxy__SelectorNotAllowed(address _caller, bytes4 _selector);\n\n/// @title Proxy for SSVNetwork calls.\n/// @dev Each instance of P2pSsvProxy corresponds to 1 FeeDistributor instance.\n/// Thus, client to P2pSsvProxy instances is a 1-to-many relation.\n/// SSV tokens are managed by P2P.\n/// Clients cover the costs of SSV tokens by EL rewards via FeeDistributor instance.\ncontract P2pSsvProxy is OwnableAssetRecoverer, ERC165, IP2pSsvProxy {\n\n    /// @notice P2pSsvProxyFactory address\n    IP2pSsvProxyFactory private immutable i_p2pSsvProxyFactory;\n\n    /// @notice SSVNetwork address\n    ISSVNetwork private immutable i_ssvNetwork;\n\n    /// @notice SSV token (ERC-20) address\n    IERC20 private immutable i_ssvToken;\n\n    /// @notice FeeDistributor instance address\n    IFeeDistributor private s_feeDistributor;\n\n    /// @notice If caller is not client, revert\n    modifier onlyClient() {\n        address clientAddress = getClient();\n\n        if (clientAddress != msg.sender) {\n            revert P2pSsvProxy__CallerNotClient(msg.sender, clientAddress);\n        }\n        _;\n    }\n\n    /// @notice If caller is neither operator nor owner, revert\n    modifier onlyOperatorOrOwner() {\n        address currentOwner = owner();\n        address currentOperator = operator();\n\n        if (currentOperator != msg.sender && currentOwner != msg.sender) {\n            revert P2pSsvProxy__CallerNeitherOperatorNorOwner(msg.sender, currentOperator, currentOwner);\n        }\n\n        _;\n    }\n\n    /// @notice If caller is neither operator nor owner nor client, revert\n    modifier onlyOperatorOrOwnerOrClient() {\n        address operator_ = operator();\n        address owner_ = owner();\n        address client_ = getClient();\n\n        if (operator_ != msg.sender && owner_ != msg.sender && client_ != msg.sender) {\n            revert P2pSsvProxy__CallerNeitherOperatorNorOwnerNorClient(msg.sender);\n        }\n        _;\n    }\n\n    /// @notice If caller is not factory, revert\n    modifier onlyP2pSsvProxyFactory() {\n        if (msg.sender != address(i_p2pSsvProxyFactory)) {\n            revert P2pSsvProxy__NotP2pSsvProxyFactoryCalled(msg.sender, i_p2pSsvProxyFactory);\n        }\n        _;\n    }\n\n    /// @dev Set values that are constant, common for all clients, known at the initial deploy time.\n    /// @param _p2pSsvProxyFactory address of P2pSsvProxyFactory\n    constructor(\n        address _p2pSsvProxyFactory\n    ) {\n        if (!ERC165Checker.supportsInterface(_p2pSsvProxyFactory, type(IP2pSsvProxyFactory).interfaceId)) {\n            revert P2pSsvProxy__NotP2pSsvProxyFactory(_p2pSsvProxyFactory);\n        }\n        i_p2pSsvProxyFactory = IP2pSsvProxyFactory(_p2pSsvProxyFactory);\n\n        i_ssvNetwork = (block.chainid == 1)\n            ? ISSVNetwork(0xDD9BC35aE942eF0cFa76930954a156B3fF30a4E1)\n            : (block.chainid == 5)\n                    ? ISSVNetwork(0xC3CD9A0aE89Fff83b71b58b6512D43F8a41f363D)\n                    : ISSVNetwork(0x38A4794cCEd47d3baf7370CcC43B560D3a1beEFA);\n\n        i_ssvToken = (block.chainid == 1)\n            ? IERC20(0x9D65fF81a3c488d585bBfb0Bfe3c7707c7917f54)\n            : (block.chainid == 5)\n                    ? IERC20(0x3a9f01091C446bdE031E39ea8354647AFef091E7)\n                    : IERC20(0xad45A78180961079BFaeEe349704F411dfF947C6);\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function initialize(\n        address _feeDistributor\n    ) external onlyP2pSsvProxyFactory {\n        s_feeDistributor = IFeeDistributor(_feeDistributor);\n\n        i_ssvToken.approve(address(i_ssvNetwork), type(uint256).max);\n\n        emit P2pSsvProxy__Initialized(_feeDistributor);\n    }\n\n    /// @dev Access any SSVNetwork function as cluster owner (this P2pSsvProxy instance)\n    /// Each selector access is managed by P2pSsvProxyFactory roles (owner, operator, client)\n    fallback() external {\n        address caller = msg.sender;\n        bytes4 selector = msg.sig;\n\n        bool isAllowed = msg.sender == owner() ||\n            (msg.sender == operator() && i_p2pSsvProxyFactory.isOperatorSelectorAllowed(selector)) ||\n            (msg.sender == getClient() && i_p2pSsvProxyFactory.isClientSelectorAllowed(selector));\n\n        if (!isAllowed) {\n            revert P2pSsvProxy__SelectorNotAllowed(caller, selector);\n        }\n\n        (bool success, bytes memory data) = address(i_ssvNetwork).call(msg.data);\n        if (success) {\n            emit P2pSsvProxy__SuccessfullyCalledViaFallback(caller, selector);\n\n            assembly {\n                return(add(data, 0x20), mload(data))\n            }\n        } else {\n            // Decode the reason from the error data returned from the call and revert with it.\n            revert(string(data));\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function registerValidators(\n        SsvPayload calldata _ssvPayload\n    ) external onlyP2pSsvProxyFactory {\n        (\n            uint64[] memory operatorIds,\n            uint64 clusterIndex\n        ) = _getOperatorIdsAndClusterIndex(_ssvPayload.ssvOperators);\n\n        uint256 ssvSlot0 = uint256(_ssvPayload.ssvSlot0);\n\n        // see https://github.com/bloxapp/ssv-network/blob/1e61c35736578d4b03bacbff9da2128ad12a5620/contracts/libraries/ProtocolLib.sol#L15\n        uint64 currentNetworkFeeIndex = uint64(ssvSlot0 >> 192) + uint64(block.number - uint32(ssvSlot0)) * uint64(ssvSlot0 >> 128);\n\n        uint256 balance = _getBalance(_ssvPayload.cluster, clusterIndex, currentNetworkFeeIndex, _ssvPayload.tokenAmount);\n\n        i_ssvNetwork.registerValidator(\n            _ssvPayload.ssvValidators[0].pubkey,\n            operatorIds,\n            _ssvPayload.ssvValidators[0].sharesData,\n            _ssvPayload.tokenAmount,\n            _ssvPayload.cluster\n        );\n\n        for (uint256 i = 1; i < _ssvPayload.ssvValidators.length;) {\n            _registerValidator(\n                i,\n                operatorIds,\n                _ssvPayload.cluster,\n                clusterIndex,\n                _ssvPayload.ssvValidators[i].pubkey,\n                _ssvPayload.ssvValidators[i].sharesData,\n                currentNetworkFeeIndex,\n                balance\n            );\n\n            unchecked {++i;}\n        }\n\n        i_ssvNetwork.setFeeRecipientAddress(address(s_feeDistributor));\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function removeValidators(\n        bytes[] calldata _pubkeys,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external onlyOperatorOrOwnerOrClient {\n        uint256 validatorCount = _pubkeys.length;\n\n        if (!(\n            _clusters.length == validatorCount\n        )) {\n            revert P2pSsvProxy__AmountOfParametersError();\n        }\n\n        for (uint256 i = 0; i < validatorCount;) {\n            i_ssvNetwork.removeValidator(_pubkeys[i], _operatorIds, _clusters[i]);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function liquidate(\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external onlyOperatorOrOwner {\n        address clusterOwner = address(this);\n        uint256 validatorCount = _clusters.length;\n\n        for (uint256 i = 0; i < validatorCount;) {\n            i_ssvNetwork.liquidate(clusterOwner, _operatorIds, _clusters[i]);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function reactivate(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external onlyOperatorOrOwner {\n        uint256 tokenPerValidator = _tokenAmount / _clusters.length;\n        uint256 validatorCount = _clusters.length;\n\n        for (uint256 i = 0; i < validatorCount;) {\n            i_ssvNetwork.reactivate(_operatorIds, tokenPerValidator, _clusters[i]);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function depositToSSV(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external {\n        address clusterOwner = address(this);\n        uint256 validatorCount = _clusters.length;\n        uint256 tokenPerValidator = _tokenAmount / validatorCount;\n\n        for (uint256 i = 0; i < validatorCount;) {\n            i_ssvNetwork.deposit(clusterOwner, _operatorIds, tokenPerValidator, _clusters[i]);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function withdrawFromSSV(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external onlyOperatorOrOwner {\n        uint256 tokenPerValidator = _tokenAmount / _clusters.length;\n        uint256 validatorCount = _clusters.length;\n\n        for (uint256 i = 0; i < validatorCount;) {\n            i_ssvNetwork.withdraw(_operatorIds, tokenPerValidator, _clusters[i]);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function withdrawSSVTokens(\n        address _to,\n        uint256 _amount\n    ) external onlyOwner {\n        i_ssvToken.transfer(_to, _amount);\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function setFeeRecipientAddress(\n        address _feeRecipientAddress\n    ) external onlyOperatorOrOwner {\n        i_ssvNetwork.setFeeRecipientAddress(_feeRecipientAddress);\n    }\n\n    /// @notice Extract operatorIds and clusterIndex out of SsvOperator list\n    /// @param _ssvOperators list of SSV operator data\n    /// @return operatorIds list of SSV operator IDs, clusterIndex updated cluster index\n    function _getOperatorIdsAndClusterIndex(\n        SsvOperator[] calldata _ssvOperators\n    ) private view returns(\n        uint64[] memory operatorIds,\n        uint64 clusterIndex\n    ) {\n        // clusterIndex updating logic reflects\n        // https://github.com/bloxapp/ssv-network/blob/fe3b9b178344dd723b19792d01ab5010dfd2dcf9/contracts/modules/SSVClusters.sol#L77\n\n        clusterIndex = 0;\n        uint256 operatorCount = _ssvOperators.length;\n        operatorIds = new uint64[](operatorCount);\n        for (uint256 i = 0; i < operatorCount;) {\n            operatorIds[i] = _ssvOperators[i].id;\n\n            uint256 snapshot = uint256(_ssvOperators[i].snapshot);\n\n            // see https://github.com/bloxapp/ssv-network/blob/6ae5903a5c99c8d75b59fc0d35574d87f82e5861/contracts/libraries/OperatorLib.sol#L13\n            clusterIndex += uint64(snapshot >> 32) + (uint32(block.number) - uint32(snapshot)) * uint64(_ssvOperators[i].fee / 10_000_000);\n\n            unchecked {++i;}\n        }\n    }\n\n    /// @notice Calculate the balance for the subsequent cluster values in a batch\n    /// @param _cluster cluster value before the 1st validator registration\n    /// @param _newIndex clusterIndex value after the 1st validator registration\n    /// @param _currentNetworkFeeIndex currentNetworkFeeIndex from ssvSlot0\n    /// @param _tokenAmount amount of SSV tokens deposited along with the 1st validator registration\n    /// @return balance updated balance after the 1st validator registration\n    function _getBalance(\n        ISSVNetwork.Cluster calldata _cluster,\n        uint64 _newIndex,\n        uint64 _currentNetworkFeeIndex,\n        uint256 _tokenAmount\n    ) private pure returns(uint256 balance) {\n        uint256 balanceBefore = _cluster.balance + _tokenAmount;\n\n        // see https://github.com/bloxapp/ssv-network/blob/1e61c35736578d4b03bacbff9da2128ad12a5620/contracts/libraries/ClusterLib.sol#L16\n        uint64 networkFee = uint64(_currentNetworkFeeIndex - _cluster.networkFeeIndex) * _cluster.validatorCount;\n        uint64 usage = (_newIndex - _cluster.index) * _cluster.validatorCount + networkFee;\n        uint256 expandedUsage = uint256(usage) * 10_000_000;\n        balance = expandedUsage > balanceBefore? 0 : balanceBefore - expandedUsage;\n    }\n\n    /// @notice Register subsequent validators after the 1st one\n    /// @param i validator index in calldata\n    /// @param _operatorIds list of SSV operator IDs\n    /// @param _cluster cluster value before the 1st registration\n    /// @param _clusterIndex calculated clusterIndex after the 1st registration\n    /// @param _pubkey validator pubkey\n    /// @param _sharesData validator SSV sharesData\n    /// @param _currentNetworkFeeIndex currentNetworkFeeIndex from ssvSlot0\n    /// @param _balance cluster balance after the 1st validator registration\n    function _registerValidator(\n        uint256 i,\n        uint64[] memory _operatorIds,\n        ISSVNetwork.Cluster calldata _cluster,\n        uint64 _clusterIndex,\n        bytes calldata _pubkey,\n        bytes calldata _sharesData,\n        uint64 _currentNetworkFeeIndex,\n        uint256 _balance\n    ) private {\n        ISSVClusters.Cluster memory cluster = ISSVClusters.Cluster({\n            validatorCount: uint32(_cluster.validatorCount + i),\n            networkFeeIndex: _currentNetworkFeeIndex,\n            index: _clusterIndex,\n            active: true,\n            balance: _balance\n        });\n\n        i_ssvNetwork.registerValidator(\n            _pubkey,\n            _operatorIds,\n            _sharesData,\n            0,\n            cluster\n        );\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function getClient() public view returns (address) {\n        return s_feeDistributor.client();\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function getFactory() external view returns (address) {\n        return address(i_p2pSsvProxyFactory);\n    }\n\n    /// @inheritdoc IOwnable\n    function owner() public view override(OwnableBase, IOwnable) returns (address) {\n        return i_p2pSsvProxyFactory.owner();\n    }\n\n    /// @inheritdoc IOwnableWithOperator\n    function operator() public view returns (address) {\n        return i_p2pSsvProxyFactory.operator();\n    }\n\n    /// @inheritdoc IP2pSsvProxy\n    function getFeeDistributor() external view returns (address) {\n        return address(s_feeDistributor);\n    }\n\n    /// @inheritdoc ERC165\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n        return interfaceId == type(IP2pSsvProxy).interfaceId || super.supportsInterface(interfaceId);\n    }\n}\n"
      },
      "src/@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity 0.8.18;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "src/@openzeppelin/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity 0.8.18;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      },
      "src/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol)\n\npragma solidity 0.8.18;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Library used to query support of an interface declared via {IERC165}.\n *\n * Note that these functions return the actual result of the query: they do not\n * `revert` if an interface is not supported. It is up to the caller to decide\n * what to do in these cases.\n */\nlibrary ERC165Checker {\n    // As per the EIP-165 spec, no interface should ever match 0xffffffff\n    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;\n\n    /**\n     * @dev Returns true if `account` supports the {IERC165} interface,\n     */\n    function supportsERC165(address account) internal view returns (bool) {\n        // Any contract that implements ERC165 must explicitly indicate support of\n        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid\n        return\n            _supportsERC165Interface(account, type(IERC165).interfaceId) &&\n            !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);\n    }\n\n    /**\n     * @dev Returns true if `account` supports the interface defined by\n     * `interfaceId`. Support for {IERC165} itself is queried automatically.\n     *\n     * See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {\n        // query support of both ERC165 as per the spec and support of _interfaceId\n        return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);\n    }\n\n    /**\n     * @dev Returns a boolean array where each value corresponds to the\n     * interfaces passed in and whether they're supported or not. This allows\n     * you to batch check interfaces for a contract where your expectation\n     * is that some interfaces may not be supported.\n     *\n     * See {IERC165-supportsInterface}.\n     *\n     * _Available since v3.4._\n     */\n    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)\n        internal\n        view\n        returns (bool[] memory)\n    {\n        // an array of booleans corresponding to interfaceIds and whether they're supported or not\n        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);\n\n        // query support of ERC165 itself\n        if (supportsERC165(account)) {\n            // query support of each interface in interfaceIds\n            for (uint256 i = 0; i < interfaceIds.length; i++) {\n                interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);\n            }\n        }\n\n        return interfaceIdsSupported;\n    }\n\n    /**\n     * @dev Returns true if `account` supports all the interfaces defined in\n     * `interfaceIds`. Support for {IERC165} itself is queried automatically.\n     *\n     * Batch-querying can lead to gas savings by skipping repeated checks for\n     * {IERC165} support.\n     *\n     * See {IERC165-supportsInterface}.\n     */\n    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {\n        // query support of ERC165 itself\n        if (!supportsERC165(account)) {\n            return false;\n        }\n\n        // query support of each interface in _interfaceIds\n        for (uint256 i = 0; i < interfaceIds.length; i++) {\n            if (!_supportsERC165Interface(account, interfaceIds[i])) {\n                return false;\n            }\n        }\n\n        // all interfaces supported\n        return true;\n    }\n\n    /**\n     * @notice Query if a contract implements an interface, does not check ERC165 support\n     * @param account The address of the contract to query for support of an interface\n     * @param interfaceId The interface identifier, as specified in ERC-165\n     * @return true if the contract at account indicates support of the interface with\n     * identifier interfaceId, false otherwise\n     * @dev Assumes that account contains a contract that supports ERC165, otherwise\n     * the behavior of this method is undefined. This precondition can be checked\n     * with {supportsERC165}.\n     * Interface identification is specified in ERC-165.\n     */\n    function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {\n        // prepare call\n        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);\n\n        // perform static call\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly {\n            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0x00)\n        }\n\n        return success && returnSize >= 0x20 && returnValue > 0;\n    }\n}\n"
      },
      "src/constants/P2pConstants.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\n/// @dev Collateral size of 1 validator\nuint256 constant COLLATERAL = 32 ether;\n\n/// @dev Maximum number of SSV operator IDs per SSV operator owner address supported simultaniously by P2pSsvProxyFactory\nuint256 constant MAX_ALLOWED_SSV_OPERATOR_IDS = 8;\n"
      },
      "src/interfaces/ssv/ISSVNetwork.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.18;\nimport \"./ISSVClusters.sol\";\n\n/// @dev https://github.com/bloxapp/ssv-network/blob/8c945e82cc063eb8e40c467d314a470121821157/contracts/interfaces/ISSVNetwork.sol\ninterface ISSVNetwork is ISSVClusters {\n    function setFeeRecipientAddress(address feeRecipientAddress) external;\n}\n"
      },
      "src/interfaces/IDepositContract.sol": {
        "content": "// SPDX-License-Identifier: CC0-1.0\n\npragma solidity 0.8.18;\n\n// This interface is designed to be compatible with the Vyper version.\n/// @notice This is the Ethereum 2.0 deposit contract interface.\n/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs\ninterface IDepositContract {\n\n    /// @notice Submit a Phase 0 DepositData object.\n    /// @param pubkey A BLS12-381 public key.\n    /// @param withdrawal_credentials Commitment to a public key for withdrawals.\n    /// @param signature A BLS12-381 signature.\n    /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.\n    /// Used as a protection against malformed input.\n    function deposit(\n        bytes calldata pubkey,\n        bytes calldata withdrawal_credentials,\n        bytes calldata signature,\n        bytes32 deposit_data_root\n    ) external payable;\n}\n"
      },
      "src/interfaces/p2p/IFeeDistributorFactory.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../../@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../../access/IOwnable.sol\";\nimport \"./IFeeDistributor.sol\";\nimport \"../../structs/P2pStructs.sol\";\n\n/// @dev External interface of FeeDistributorFactory\ninterface IFeeDistributorFactory is IOwnable, IERC165 {\n\n    /// @notice Creates a FeeDistributor instance for a client\n    /// @dev _referrerConfig can be zero if there is no referrer.\n    ///\n    /// @param _referenceFeeDistributor The address of the reference implementation of FeeDistributor used as the basis for clones\n    /// @param _clientConfig address and basis points (percent * 100) of the client\n    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.\n    /// @return newFeeDistributorAddress user FeeDistributor instance that has just been deployed\n    function createFeeDistributor(\n        address _referenceFeeDistributor,\n        FeeRecipient calldata _clientConfig,\n        FeeRecipient calldata _referrerConfig\n    ) external returns (address newFeeDistributorAddress);\n\n    /// @notice Computes the address of a FeeDistributor created by `createFeeDistributor` function\n    /// @dev FeeDistributor instances are guaranteed to have the same address if all of\n    /// 1) referenceFeeDistributor 2) clientConfig 3) referrerConfig\n    /// are the same\n    /// @param _referenceFeeDistributor The address of the reference implementation of FeeDistributor used as the basis for clones\n    /// @param _clientConfig address and basis points (percent * 100) of the client\n    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.\n    /// @return address user FeeDistributor instance that will be or has been deployed\n    function predictFeeDistributorAddress(\n        address _referenceFeeDistributor,\n        FeeRecipient calldata _clientConfig,\n        FeeRecipient calldata _referrerConfig\n    ) external view returns (address);\n\n    /// @notice Returns an array of client FeeDistributors\n    /// @param _client client address\n    /// @return address[] array of client FeeDistributors\n    function allClientFeeDistributors(\n        address _client\n    ) external view returns (address[] memory);\n\n    /// @notice Returns an array of all FeeDistributors for all clients\n    /// @return address[] array of all FeeDistributors\n    function allFeeDistributors() external view returns (address[] memory);\n\n    /// @notice The address of P2pEth2Depositor\n    /// @return address of P2pEth2Depositor\n    function p2pEth2Depositor() external view returns (address);\n\n    /// @notice Returns default client basis points\n    /// @return default client basis points\n    function defaultClientBasisPoints() external view returns (uint96);\n\n    /// @notice Returns the current operator\n    /// @return address of the current operator\n    function operator() external view returns (address);\n\n    /// @notice Reverts if the passed address is neither operator nor owner\n    /// @param _address passed address\n    function checkOperatorOrOwner(address _address) external view;\n\n    /// @notice Reverts if the passed address is not P2pEth2Depositor\n    /// @param _address passed address\n    function checkP2pEth2Depositor(address _address) external view;\n\n    /// @notice Reverts if the passed address is neither of: 1) operator 2) owner 3) P2pEth2Depositor\n    /// @param _address passed address\n    function check_Operator_Owner_P2pEth2Depositor(address _address) external view;\n}\n"
      },
      "src/access/OwnableWithOperator.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"./Ownable2Step.sol\";\nimport \"./IOwnableWithOperator.sol\";\n\n/**\n* @notice newOperator is the zero address\n*/\nerror Access__ZeroNewOperator();\n\n/**\n* @notice newOperator is the same as the old one\n*/\nerror Access__SameOperator(address _operator);\n\n/**\n* @notice caller is neither the operator nor owner\n*/\nerror Access__CallerNeitherOperatorNorOwner(address _caller, address _operator, address _owner);\n\n/**\n* @notice address is neither the operator nor owner\n*/\nerror Access__AddressNeitherOperatorNorOwner(address _address, address _operator, address _owner);\n\n/**\n * @dev Ownable with an additional role of operator\n */\nabstract contract OwnableWithOperator is Ownable2Step, IOwnableWithOperator {\n    address private s_operator;\n\n    /**\n     * @dev Emits when the operator has been changed\n     * @param _previousOperator address of the previous operator\n     * @param _newOperator address of the new operator\n     */\n    event OperatorChanged(\n        address indexed _previousOperator,\n        address indexed _newOperator\n    );\n\n    /**\n     * @dev Throws if called by any account other than the operator or the owner.\n     */\n    modifier onlyOperatorOrOwner() {\n        address currentOwner = owner();\n        address currentOperator = s_operator;\n\n        if (currentOperator != _msgSender() && currentOwner != _msgSender()) {\n            revert Access__CallerNeitherOperatorNorOwner(_msgSender(), currentOperator, currentOwner);\n        }\n\n        _;\n    }\n\n    function checkOperatorOrOwner(address _address) public view virtual {\n        address currentOwner = owner();\n        address currentOperator = s_operator;\n\n        if (_address == address(0) || (currentOperator != _address && currentOwner != _address)) {\n            revert Access__AddressNeitherOperatorNorOwner(_address, currentOperator, currentOwner);\n        }\n    }\n\n    /**\n     * @dev Returns the current operator.\n     */\n    function operator() public view virtual returns (address) {\n        return s_operator;\n    }\n\n    /**\n     * @dev Transfers operator to a new account (`newOperator`).\n     * Can only be called by the current owner.\n     */\n    function changeOperator(address _newOperator) external virtual onlyOwner {\n        if (_newOperator == address(0)) {\n            revert Access__ZeroNewOperator();\n        }\n        if (_newOperator == s_operator) {\n            revert Access__SameOperator(_newOperator);\n        }\n\n        _changeOperator(_newOperator);\n    }\n\n    /**\n     * @dev Transfers operator to a new account (`newOperator`).\n     * Internal function without access restriction.\n     */\n    function _changeOperator(address _newOperator) internal virtual {\n        address oldOperator = s_operator;\n        s_operator = _newOperator;\n        emit OperatorChanged(oldOperator, _newOperator);\n    }\n\n    /**\n     * @dev Dismisses the old operator without setting a new one.\n     * Can only be called by the current owner.\n     */\n    function dismissOperator() external virtual onlyOwner {\n        _changeOperator(address(0));\n    }\n}\n"
      },
      "src/assetRecovering/OwnableAssetRecoverer.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, Lido <info@lido.fi>\n// SPDX-License-Identifier: MIT\n\n// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol\npragma solidity 0.8.18;\n\nimport \"./OwnableTokenRecoverer.sol\";\nimport \"./AssetRecoverer.sol\";\n\n/// @title Public Asset Recoverer with public functions callable by assetAccessingAddress\n/// @notice Recover ether, ERC20, ERC721 and ERC1155 from a derived contract\nabstract contract OwnableAssetRecoverer is OwnableTokenRecoverer, AssetRecoverer {\n\n    // Functions\n\n    /**\n     * @notice transfers ether from this contract\n     * @dev using `address.call` is safer to transfer to other contracts\n     * @param _recipient address to transfer ether to\n     * @param _amount amount of ether to transfer\n     */\n    function transferEther(address _recipient, uint256 _amount) external onlyOwner {\n        _transferEther(_recipient, _amount);\n    }\n}\n"
      },
      "src/structs/P2pStructs.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../interfaces/ssv/ISSVClusters.sol\";\n\n/// @dev 256 bit struct\n/// @member basisPoints basis points (percent * 100) of EL rewards that should go to the recipient\n/// @member recipient address of the recipient\nstruct FeeRecipient {\n    uint96 basisPoints;\n    address payable recipient;\n}\n\n/// @member pubkey The public key of the new validator\n/// @member sharesData Encrypted shares related to the new validator\nstruct SsvValidator {\n    bytes pubkey;\n    bytes sharesData;\n}\n\n/// @member signatures BLS12-381 signatures\n/// @member depositDataRoots SHA-256 hashes of the SSZ-encoded DepositData objects\nstruct DepositData {\n    bytes[] signatures;\n    bytes32[] depositDataRoots;\n}\n\n/// @dev Data from https://github.com/bloxapp/ssv-network/blob/8c945e82cc063eb8e40c467d314a470121821157/contracts/interfaces/ISSVNetworkCore.sol#L20\n/// @member owner SSV operator owner\n/// @member id SSV operator ID\n/// @member snapshot SSV operator snapshot (should be retrieved from SSVNetwork storage)\n/// @member fee SSV operator fee\nstruct SsvOperator {\n    address owner;\n    uint64 id;\n    bytes32 snapshot;\n    uint256 fee;\n}\n\n/// @member ssvOperators SSV operators for the cluster\n/// @member ssvValidators new SSV validators to be registered in the cluster\n/// @member cluster SSV cluster\n/// @member tokenAmount amount of ERC-20 SSV tokens for validator registration\n/// @member ssvSlot0 Slot # (uint256(keccak256(\"ssv.network.storage.protocol\")) - 1) from SSVNetwork\nstruct SsvPayload {\n    SsvOperator[] ssvOperators;\n    SsvValidator[] ssvValidators;\n    ISSVClusters.Cluster cluster;\n    uint256 tokenAmount;\n    bytes32 ssvSlot0;\n}\n"
      },
      "src/p2pSsvProxyFactory/IP2pSsvProxyFactory.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../structs/P2pStructs.sol\";\nimport \"../constants/P2pConstants.sol\";\nimport \"../interfaces/ssv/ISSVNetwork.sol\";\nimport \"../access/IOwnableWithOperator.sol\";\n\n/// @dev External interface of P2pSsvProxyFactory\ninterface IP2pSsvProxyFactory is IOwnableWithOperator, IERC165 {\n\n    /// @notice Emits when batch registration of validator with SSV is completed\n    /// @param _proxy address of P2pSsvProxy that was used for registration and became the cluster owner\n    event P2pSsvProxyFactory__RegistrationCompleted(\n        address indexed _proxy\n    );\n\n    /// @notice Emits when a new P2pSsvProxy instance was deployed and initialized\n    /// @param _p2pSsvProxy newly deployed P2pSsvProxy instance address\n    /// @param _client client address\n    /// @param _feeDistributor FeeDistributor instance address\n    event P2pSsvProxyFactory__P2pSsvProxyCreated(\n        address indexed _p2pSsvProxy,\n        address indexed _client,\n        address indexed _feeDistributor\n    );\n\n    /// @notice Emits when a new reference FeeDistributor has been set\n    /// @param _referenceFeeDistributor new reference FeeDistributor address\n    event P2pSsvProxyFactory__ReferenceFeeDistributorSet(\n        address indexed _referenceFeeDistributor\n    );\n\n    /// @notice Emits when a new value for ssvPerEthExchangeRateDividedByWei has been set\n    /// @param _ssvPerEthExchangeRateDividedByWei new value for ssvPerEthExchangeRateDividedByWei\n    event P2pSsvProxyFactory__SsvPerEthExchangeRateDividedByWeiSet(\n        uint112 _ssvPerEthExchangeRateDividedByWei\n    );\n\n    /// @notice Emits when a new value for maximum amount of SSV tokens per validator has been set\n    /// @param _maxSsvTokenAmountPerValidator new value for maximum amount of SSV tokens per validator\n    event P2pSsvProxyFactory__MaxSsvTokenAmountPerValidatorSet(\n        uint112 _maxSsvTokenAmountPerValidator\n    );\n\n    /// @notice Emits when a new reference P2pSsvProxy has been set\n    /// @param _referenceP2pSsvProxy new reference P2pSsvProxy address\n    event P2pSsvProxyFactory__ReferenceP2pSsvProxySet(\n        address indexed _referenceP2pSsvProxy\n    );\n\n    /// @notice Emits when new selectors were allowed for clients\n    /// @param _selectors newly allowed selectors\n    event P2pSsvProxyFactory__AllowedSelectorsForClientSet(\n        bytes4[] _selectors\n    );\n\n    /// @notice Emits when selectors were disallowed for clients\n    /// @param _selectors disallowed selectors\n    event P2pSsvProxyFactory__AllowedSelectorsForClientRemoved(\n        bytes4[] _selectors\n    );\n\n    /// @notice Emits when new selectors were allowed for operator\n    /// @param _selectors newly allowed selectors\n    event P2pSsvProxyFactory__AllowedSelectorsForOperatorSet(\n        bytes4[] _selectors\n    );\n\n    /// @notice Emits when selectors were disallowed for operator\n    /// @param _selectors disallowed selectors\n    event P2pSsvProxyFactory__AllowedSelectorsForOperatorRemoved(\n        bytes4[] _selectors\n    );\n\n    /// @notice Emits when new SSV operator owner addresses have been allowed\n    /// @param _allowedSsvOperatorOwners newly allowed SSV operator owner addresses\n    event P2pSsvProxyFactory__AllowedSsvOperatorOwnersSet(\n        address[] _allowedSsvOperatorOwners\n    );\n\n    /// @notice Emits when some SSV operator owner addresses have been removed from the allowlist\n    /// @param _allowedSsvOperatorOwners disallowed SSV operator owner addresses\n    event P2pSsvProxyFactory__AllowedSsvOperatorOwnersRemoved(\n        address[] _allowedSsvOperatorOwners\n    );\n\n    /// @notice Emits when new SSV operator IDs have been set to the given SSV operator owner\n    /// @param _ssvOperatorOwner SSV operator owner\n    event P2pSsvProxyFactory__SsvOperatorIdsSet(\n        address indexed _ssvOperatorOwner,\n        uint64[MAX_ALLOWED_SSV_OPERATOR_IDS] _operatorIds\n    );\n\n    /// @notice Emits when operator IDs list has been cleared for the given SSV operator owner\n    /// @param _ssvOperatorOwner SSV operator owner\n    event P2pSsvProxyFactory__SsvOperatorIdsCleared(\n        address indexed _ssvOperatorOwner\n    );\n\n    /// @notice Set Exchange rate between SSV and ETH set by P2P.\n    /// @dev (If 1 SSV = 0.007539 ETH, it should be 0.007539 * 10^18 = 7539000000000000).\n    /// @param _ssvPerEthExchangeRateDividedByWei Exchange rate\n    function setSsvPerEthExchangeRateDividedByWei(uint112 _ssvPerEthExchangeRateDividedByWei) external;\n\n    /// @notice Set Maximum amount of SSV tokens per validator that is allowed for client to deposit during `depositEthAndRegisterValidators`\n    /// @param _maxSsvTokenAmountPerValidator Maximum amount of SSV tokens per validator\n    function setMaxSsvTokenAmountPerValidator(uint112 _maxSsvTokenAmountPerValidator) external;\n\n    /// @notice Set template to be used for new P2pSsvProxy instances\n    /// @param _referenceP2pSsvProxy template to be used for new P2pSsvProxy instances\n    function setReferenceP2pSsvProxy(address _referenceP2pSsvProxy) external;\n\n    /// @notice Allow selectors (function signatures) for clients to call on SSVNetwork via P2pSsvProxy\n    /// @param _selectors selectors (function signatures) to allow for clients\n    function setAllowedSelectorsForClient(bytes4[] calldata _selectors) external;\n\n    /// @notice Disallow selectors (function signatures) for clients to call on SSVNetwork via P2pSsvProxy\n    /// @param _selectors selectors (function signatures) to disallow for clients\n    function removeAllowedSelectorsForClient(bytes4[] calldata _selectors) external;\n\n    /// @notice Allow selectors (function signatures) for P2P operator to call on SSVNetwork via P2pSsvProxy\n    /// @param _selectors selectors (function signatures) to allow for P2P operator\n    function setAllowedSelectorsForOperator(bytes4[] calldata _selectors) external;\n\n    /// @notice Disallow selectors (function signatures) for P2P operator to call on SSVNetwork via P2pSsvProxy\n    /// @param _selectors selectors (function signatures) to disallow for P2P operator\n    function removeAllowedSelectorsForOperator(bytes4[] calldata _selectors) external;\n\n    /// @notice Set template to be used for new FeeDistributor instances\n    /// @param _referenceFeeDistributor template to be used for new FeeDistributor instances\n    function setReferenceFeeDistributor(\n        address _referenceFeeDistributor\n    ) external;\n\n    /// @notice Allow addresses of SSV operator owners (both P2P and partners)\n    /// @param _allowedSsvOperatorOwners addresses of SSV operator owners to allow\n    function setAllowedSsvOperatorOwners(\n        address[] calldata _allowedSsvOperatorOwners\n    ) external;\n\n    /// @notice Disallow addresses of SSV operator owners (both P2P and partners)\n    /// @param _allowedSsvOperatorOwnersToRemove addresses of SSV operator owners to disallow\n    function removeAllowedSsvOperatorOwners(\n        address[] calldata _allowedSsvOperatorOwnersToRemove\n    ) external;\n\n    /// @notice Set own SSV operator IDs list\n    /// @dev To be called by SSV operator owner\n    /// @param _operatorIds SSV operator IDs list\n    function setSsvOperatorIds(\n        uint64[MAX_ALLOWED_SSV_OPERATOR_IDS] calldata _operatorIds\n    ) external;\n\n    /// @notice Set SSV operator IDs list for a SSV operator owner\n    /// @dev To be called by P2P\n    /// @param _operatorIds SSV operator IDs list\n    /// @param _ssvOperatorOwner SSV operator owner\n    function setSsvOperatorIds(\n        uint64[MAX_ALLOWED_SSV_OPERATOR_IDS] calldata _operatorIds,\n        address _ssvOperatorOwner\n    ) external;\n\n    /// @notice Clear own SSV operator IDs list\n    /// @dev To be called by SSV operator owner\n    function clearSsvOperatorIds() external;\n\n    /// @notice Clear SSV operator IDs list for a SSV operator owner\n    /// @dev To be called by P2P\n    /// @param _ssvOperatorOwner SSV operator owner\n    function clearSsvOperatorIds(\n        address _ssvOperatorOwner\n    ) external;\n\n    /// @notice Computes the address of a P2pSsvProxy created by `_createP2pSsvProxy` function\n    /// @dev P2pSsvProxy instances are guaranteed to have the same address if _feeDistributorInstance is the same\n    /// @param _feeDistributorInstance The address of FeeDistributor instance\n    /// @return address client P2pSsvProxy instance that will be or has been deployed\n    function predictP2pSsvProxyAddress(\n        address _feeDistributorInstance\n    ) external view returns (address);\n\n    /// @notice Deploy P2pSsvProxy instance if not deployed before\n    /// @param _feeDistributorInstance The address of FeeDistributor instance\n    /// @return p2pSsvProxyInstance client P2pSsvProxy instance that has been deployed\n    function createP2pSsvProxy(\n        address _feeDistributorInstance\n    ) external returns(address p2pSsvProxyInstance);\n\n    /// @notice Batch deposit ETH and register validators with SSV (up to 50, calldata size is the limit)\n    /// @param _depositData signatures and depositDataRoots from Beacon deposit data\n    /// @param _withdrawalCredentialsAddress address for 0x01 withdrawal credentials from Beacon deposit data (1 for the batch)\n    /// @param _ssvPayload a stuct with data necessary for SSV registration (see `SsvPayload` struct for details)\n    /// @param _clientConfig address and basis points (percent * 100) of the client (for FeeDistributor)\n    /// @param _referrerConfig address and basis points (percent * 100) of the referrer (for FeeDistributor)\n    /// @return p2pSsvProxy client P2pSsvProxy instance that became the SSV cluster owner\n    function depositEthAndRegisterValidators(\n        DepositData calldata _depositData,\n        address _withdrawalCredentialsAddress,\n\n        SsvPayload calldata _ssvPayload,\n\n        FeeRecipient calldata _clientConfig,\n        FeeRecipient calldata _referrerConfig\n    ) external payable returns (address p2pSsvProxy);\n\n    /// @notice Register validators with SSV (up to 60, calldata size is the limit) without ETH deposits\n    /// @param _ssvPayload a stuct with data necessary for SSV registration (see `SsvPayload` struct for details)\n    /// @param _clientConfig address and basis points (percent * 100) of the client (for FeeDistributor)\n    /// @param _referrerConfig address and basis points (percent * 100) of the referrer (for FeeDistributor)\n    /// @return p2pSsvProxy client P2pSsvProxy instance that became the SSV cluster owner\n    function registerValidators(\n        SsvPayload calldata _ssvPayload,\n        FeeRecipient calldata _clientConfig,\n        FeeRecipient calldata _referrerConfig\n    ) external payable returns (address p2pSsvProxy);\n\n    /// @notice Returns the FeeDistributorFactory address\n    /// @return FeeDistributorFactory address\n    function getFeeDistributorFactory() external view returns (address);\n\n    /// @notice A list of addresses of the deployed client P2pSsvProxy instances by client address\n    /// @param _client client address\n    /// @return A list of addresses of the deployed client P2pSsvProxy instances\n    function getAllClientP2pSsvProxies(\n        address _client\n    ) external view returns (address[] memory);\n\n    /// @notice Returns a list of all ever deployed client P2pSsvProxy instances\n    /// @return a list of all ever deployed client P2pSsvProxy instances\n    function getAllP2pSsvProxies() external view returns (address[] memory);\n\n    /// @notice Returns if a certain selector (function signature) is allowed for clients to call on SSVNetwork via P2pSsvProxy\n    /// @return True if allowed\n    function isClientSelectorAllowed(bytes4 _selector) external view returns (bool);\n\n    /// @notice Returns if a certain selector (function signature) is allowed for a P2P operator to call on SSVNetwork via P2pSsvProxy\n    /// @param _selector selector (function signature)\n    /// @return True if allowed\n    function isOperatorSelectorAllowed(bytes4 _selector) external view returns (bool);\n\n    /// @notice Returns SSV operator IDs list by operator owner address\n    /// @param _ssvOperatorOwner operator owner address\n    /// @return SSV operator IDs list\n    function getAllowedSsvOperatorIds(address _ssvOperatorOwner) external view returns (uint64[MAX_ALLOWED_SSV_OPERATOR_IDS] memory);\n\n    /// @notice Returns a set of addresses of SSV operator owners (both P2P and partners)\n    /// @return a set of addresses of SSV operator owners (both P2P and partners)\n    function getAllowedSsvOperatorOwners() external view returns (address[] memory);\n\n    /// @notice Returns a template set by P2P to be used for new FeeDistributor instances\n    /// @return a template set by P2P to be used for new FeeDistributor instances\n    function getReferenceFeeDistributor() external view returns (address);\n\n    /// @notice Returns a template set by P2P to be used for new P2pSsvProxy instances\n    /// @return a template set by P2P to be used for new P2pSsvProxy instances\n    function getReferenceP2pSsvProxy() external view returns (address);\n\n    /// @notice Returns exchange rate between SSV and ETH set by P2P\n    /// @dev (If 1 SSV = 0.007539 ETH, it should be 0.007539 * 10^18 = 7539000000000000).\n    /// Only used during validator registration without ETH deposits to cover SSV token costs with client ETH.\n    /// SSV tokens exchanged with this rate cannot be withdrawn by the client.\n    /// P2P is willing to tolarate potential discrepancies with the market exchange rate for the sake of simplicity.\n    /// The client agrees to this rate when calls `registerValidators` function.\n    /// @return exchange rate between SSV and ETH set by P2P\n    function getSsvPerEthExchangeRateDividedByWei() external view returns (uint112);\n\n    /// @notice Returns the maximum amount of SSV tokens per validator that is allowed for client to deposit during `depositEthAndRegisterValidators`\n    /// @return maximum amount of SSV tokens per validator\n    function getMaxSsvTokenAmountPerValidator() external view returns (uint112);\n\n    /// @notice Returns needed amount of ETH to cover SSV fees by SSV token amount\n    /// @param _tokenAmount SSV token amount\n    /// @return needed amount of ETH to cover SSV fees\n    function getNeededAmountOfEtherToCoverSsvFees(uint256 _tokenAmount) external view returns (uint256);\n}\n"
      },
      "src/p2pSsvProxy/IP2pSsvProxy.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../structs/P2pStructs.sol\";\nimport \"../access/IOwnableWithOperator.sol\";\nimport \"../interfaces/ssv/ISSVNetwork.sol\";\n\n/// @dev External interface of P2pSsvProxy declared to support ERC165 detection.\ninterface IP2pSsvProxy is IOwnableWithOperator, IERC165 {\n\n    /// @notice Emits when P2pSsvProxy instance is initialized\n    /// @param _feeDistributor FeeDistributor instance that determines the identity of this P2pSsvProxy instance\n    event P2pSsvProxy__Initialized(\n        address indexed _feeDistributor\n    );\n\n    /// @notice Emits when the function was called successfully on SSVNetwork via fallback\n    /// @param _caller caller of P2pSsvProxy\n    /// @param _selector selector of the function from SSVNetwork\n    event P2pSsvProxy__SuccessfullyCalledViaFallback(\n        address indexed _caller,\n        bytes4 indexed _selector\n    );\n\n    /// @notice Initialize the P2pSsvProxy instance\n    /// @dev Should only be called by P2pSsvProxyFactory\n    /// @param _feeDistributor FeeDistributor instance that determines the identity of this P2pSsvProxy instance\n    function initialize(\n        address _feeDistributor\n    ) external;\n\n    /// @notice Register a batch of validators with SSV\n    /// @dev Should be called by P2pSsvProxyFactory only\n    /// @param _ssvPayload struct with the SSV data required for registration\n    function registerValidators(\n        SsvPayload calldata _ssvPayload\n    ) external;\n\n    /// @notice Remove a batch of validators from SSV\n    /// @dev Can be called either by P2P or by the client\n    /// @param _pubkeys validator pubkeys\n    /// @param _operatorIds SSV operator IDs\n    /// @param _clusters SSV clusters, each of which should correspond to pubkey and operator IDs\n    function removeValidators(\n        bytes[] calldata _pubkeys,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external;\n\n    /// @notice Liquidate SSV clusters\n    /// @dev Should be called by P2P only.\n    /// This function is just batching calls for convenience. It's always possible to call the same function on SSVNetwork via fallback\n    /// @param _operatorIds SSV operator IDs\n    /// @param _clusters SSV clusters\n    function liquidate(\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external;\n\n    /// @notice Reactivate SSV clusters\n    /// @dev Should be called by P2P only\n    /// This function is just batching calls for convenience. It's always possible to call the same function on SSVNetwork via fallback\n    /// @param _tokenAmount SSV token amount to be deposited for reactivation\n    /// @param _operatorIds SSV operator IDs\n    /// @param _clusters SSV clusters\n    function reactivate(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external;\n\n    /// @notice Deposit SSV tokens to SSV clusters\n    /// @dev Can be called by anyone\n    /// This function is just batching calls for convenience. It's possible to call the same function on SSVNetwork directly\n    /// @param _tokenAmount SSV token amount to be deposited\n    /// @param _operatorIds SSV operator IDs\n    /// @param _clusters SSV clusters\n    function depositToSSV(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external;\n\n    /// @notice Withdraw SSV tokens from SSV clusters to this contract\n    /// @dev Should be called by P2P only\n    /// This function is just batching calls for convenience. It's always possible to call the same function on SSVNetwork via fallback\n    /// @param _tokenAmount SSV token amount to be withdrawn\n    /// @param _operatorIds SSV operator IDs\n    /// @param _clusters SSV clusters\n    function withdrawFromSSV(\n        uint256 _tokenAmount,\n        uint64[] calldata _operatorIds,\n        ISSVNetwork.Cluster[] calldata _clusters\n    ) external;\n\n    /// @notice Withdraw SSV tokens from this contract to the given address\n    /// @dev Should be called by P2P only\n    /// @param _to destination address\n    /// @param _amount SSV token amount to be withdrawn\n    function withdrawSSVTokens(\n        address _to,\n        uint256 _amount\n    ) external;\n\n    /// @notice Set a new fee recipient address for this contract (cluster owner)\n    /// @dev Should be called by P2P only.\n    /// Another FeeDistributor instance can become the fee recipient (e.g. if service percentages change).\n    /// Client address itself can become the fee recipient (e.g. if service percentage becomes zero due to some promo).\n    /// It's fine for P2P to determine the fee recipient since P2P is paying SSV tokens and EL rewards are a way to compansate for them.\n    /// Other operators are compansated via SSV tokens paid by P2P.\n    /// @param _feeRecipientAddress fee recipient address to set\n    function setFeeRecipientAddress(\n        address _feeRecipientAddress\n    ) external;\n\n    /// @notice Returns the client address\n    /// @return address client address\n    function getClient() external view returns (address);\n\n    /// @notice Returns the factory address\n    /// @return address factory address\n    function getFactory() external view returns (address);\n\n    /// @notice Returns the address of FeeDistributor instance accociated with this contract\n    /// @return FeeDistributor instance address\n    function getFeeDistributor() external view returns (address);\n}\n"
      },
      "src/@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity 0.8.18;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "src/interfaces/ssv/ISSVClusters.sol": {
        "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity 0.8.18;\n\n/// @dev https://github.com/bloxapp/ssv-network/blob/8c945e82cc063eb8e40c467d314a470121821157/contracts/interfaces/ISSVNetworkCore.sol\ninterface ISSVClusters {\n    /// @notice Represents a cluster of validators\n    struct Cluster {\n        /// @dev The number of validators in the cluster\n        uint32 validatorCount;\n        /// @dev The index of network fees related to this cluster\n        uint64 networkFeeIndex;\n        /// @dev The last index calculated for the cluster\n        uint64 index;\n        /// @dev Flag indicating whether the cluster is active\n        bool active;\n        /// @dev The balance of the cluster\n        uint256 balance;\n    }\n\n\n    /// @notice Registers a new validator on the SSV Network\n    /// @param publicKey The public key of the new validator\n    /// @param operatorIds Array of IDs of operators managing this validator\n    /// @param sharesData Encrypted shares related to the new validator\n    /// @param amount Amount of SSV tokens to be deposited\n    /// @param cluster Cluster to be used with the new validator\n    function registerValidator(\n        bytes calldata publicKey,\n        uint64[] memory operatorIds,\n        bytes calldata sharesData,\n        uint256 amount,\n        Cluster memory cluster\n    ) external;\n\n    /// @notice Removes an existing validator from the SSV Network\n    /// @param publicKey The public key of the validator to be removed\n    /// @param operatorIds Array of IDs of operators managing the validator\n    /// @param cluster Cluster associated with the validator\n    function removeValidator(bytes calldata publicKey, uint64[] memory operatorIds, Cluster memory cluster) external;\n\n    /**************************/\n    /* Cluster External Functions */\n    /**************************/\n\n    /// @notice Liquidates a cluster\n    /// @param owner The owner of the cluster\n    /// @param operatorIds Array of IDs of operators managing the cluster\n    /// @param cluster Cluster to be liquidated\n    function liquidate(address owner, uint64[] memory operatorIds, Cluster memory cluster) external;\n\n    /// @notice Reactivates a cluster\n    /// @param operatorIds Array of IDs of operators managing the cluster\n    /// @param amount Amount of SSV tokens to be deposited for reactivation\n    /// @param cluster Cluster to be reactivated\n    function reactivate(uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external;\n\n    /******************************/\n    /* Balance External Functions */\n    /******************************/\n\n    /// @notice Deposits tokens into a cluster\n    /// @param owner The owner of the cluster\n    /// @param operatorIds Array of IDs of operators managing the cluster\n    /// @param amount Amount of SSV tokens to be deposited\n    /// @param cluster Cluster where the deposit will be made\n    function deposit(address owner, uint64[] memory operatorIds, uint256 amount, Cluster memory cluster) external;\n\n    /// @notice Withdraws tokens from a cluster\n    /// @param operatorIds Array of IDs of operators managing the cluster\n    /// @param tokenAmount Amount of SSV tokens to be withdrawn\n    /// @param cluster Cluster where the withdrawal will be made\n    function withdraw(uint64[] memory operatorIds, uint256 tokenAmount, Cluster memory cluster) external;\n\n    /**\n     * @dev Emitted when the validator has been added.\n     * @param publicKey The public key of a validator.\n     * @param operatorIds The operator ids list.\n     * @param shares snappy compressed shares(a set of encrypted and public shares).\n     * @param cluster All the cluster data.\n     */\n    event ValidatorAdded(address indexed owner, uint64[] operatorIds, bytes publicKey, bytes shares, Cluster cluster);\n\n    /**\n     * @dev Emitted when the validator is removed.\n     * @param publicKey The public key of a validator.\n     * @param operatorIds The operator ids list.\n     * @param cluster All the cluster data.\n     */\n    event ValidatorRemoved(address indexed owner, uint64[] operatorIds, bytes publicKey, Cluster cluster);\n\n    event ClusterLiquidated(address indexed owner, uint64[] operatorIds, Cluster cluster);\n\n    event ClusterReactivated(address indexed owner, uint64[] operatorIds, Cluster cluster);\n\n    event ClusterWithdrawn(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster);\n\n    event ClusterDeposited(address indexed owner, uint64[] operatorIds, uint256 value, Cluster cluster);\n}\n"
      },
      "src/access/IOwnable.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\n/**\n * @dev External interface of Ownable.\n */\ninterface IOwnable {\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() external view returns (address);\n}\n"
      },
      "src/interfaces/p2p/IFeeDistributor.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../../@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../../structs/P2pStructs.sol\";\n\n/// @dev External interface of FeeDistributor declared to support ERC165 detection.\ninterface IFeeDistributor is IERC165 {\n\n    /// @notice Emits once the client and the optional referrer have been set.\n    /// @param _client address of the client.\n    /// @param _clientBasisPoints basis points (percent * 100) of EL rewards that should go to the client\n    /// @param _referrer address of the referrer.\n    /// @param _referrerBasisPoints basis points (percent * 100) of EL rewards that should go to the referrer\n    event FeeDistributor__Initialized(\n        address indexed _client,\n        uint96 _clientBasisPoints,\n        address indexed _referrer,\n        uint96 _referrerBasisPoints\n    );\n\n    /// @notice Emits on successful withdrawal\n    /// @param _serviceAmount how much wei service received\n    /// @param _clientAmount how much wei client received\n    /// @param _referrerAmount how much wei referrer received\n    event FeeDistributor__Withdrawn(\n        uint256 _serviceAmount,\n        uint256 _clientAmount,\n        uint256 _referrerAmount\n    );\n\n    /// @notice Emits on request for a voluntary exit of validators\n    /// @param _pubkeys pubkeys of validators\n    event FeeDistributor__VoluntaryExit(\n        bytes[] _pubkeys\n    );\n\n    /// @notice Emits if case there was some ether left after `withdraw` and it has been sent successfully.\n    /// @param _to destination address for ether.\n    /// @param _amount how much wei the destination address received.\n    event FeeDistributor__EtherRecovered(\n        address indexed _to,\n        uint256 _amount\n    );\n\n    /// @notice Set client address.\n    /// @dev Could not be in the constructor since it is different for different clients.\n    /// _referrerConfig can be zero if there is no referrer.\n    /// @param _clientConfig address and basis points (percent * 100) of the client\n    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.\n    function initialize(\n        FeeRecipient calldata _clientConfig,\n        FeeRecipient calldata _referrerConfig\n    ) external;\n\n    /// @notice Increase the number of deposited validators.\n    /// @dev Should be called when a new ETH2 deposit has been made\n    /// @param _validatorCountToAdd number of newly deposited validators\n    function increaseDepositedCount(\n        uint32 _validatorCountToAdd\n    ) external;\n\n    /// @notice Request a voluntary exit of validators\n    /// @dev Should be called by the client when they want to signal P2P that certain validators need to be exited\n    /// @param _pubkeys pubkeys of validators\n    function voluntaryExit(\n        bytes[] calldata _pubkeys\n    ) external;\n\n    /// @notice Returns the factory address\n    /// @return address factory address\n    function factory() external view returns (address);\n\n    /// @notice Returns the service address\n    /// @return address service address\n    function service() external view returns (address);\n\n    /// @notice Returns the client address\n    /// @return address client address\n    function client() external view returns (address);\n\n    /// @notice Returns the client basis points\n    /// @return uint256 client basis points\n    function clientBasisPoints() external view returns (uint256);\n\n    /// @notice Returns the referrer address\n    /// @return address referrer address\n    function referrer() external view returns (address);\n\n    /// @notice Returns the referrer basis points\n    /// @return uint256 referrer basis points\n    function referrerBasisPoints() external view returns (uint256);\n\n    /// @notice Returns the address for ETH2 0x01 withdrawal credentials associated with this FeeDistributor\n    /// @dev Return FeeDistributor's own address if FeeDistributor should be CL rewards recipient\n    /// Otherwise, return the client address\n    /// @return address address for ETH2 0x01 withdrawal credentials\n    function eth2WithdrawalCredentialsAddress() external view returns (address);\n}\n"
      },
      "src/access/Ownable2Step.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"./Ownable.sol\";\n\n/**\n* @notice caller must be pendingOwner\n*/\nerror Ownable2Step__CallerNotNewOwner();\n\n/**\n* @notice new owner address should be different from the current owner\n*/\nerror Ownable2Step__NewOwnerShouldNotBeCurrentOwner();\n\n/**\n * @dev Contract module which provides 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} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private s_pendingOwner;\n\n    /**\n     * @dev Emits in transferOwnership (start of the transfer)\n     * @param _previousOwner address of the previous owner\n     * @param _newOwner address of the new owner\n     */\n    event OwnershipTransferStarted(address indexed _previousOwner, address indexed _newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return s_pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        address currentOwner = owner();\n        if (newOwner == currentOwner) {\n            revert Ownable2Step__NewOwnerShouldNotBeCurrentOwner();\n        }\n\n        s_pendingOwner = newOwner;\n        emit OwnershipTransferStarted(currentOwner, newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete s_pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() external {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert Ownable2Step__CallerNotNewOwner();\n        }\n        _transferOwnership(sender);\n    }\n}\n"
      },
      "src/access/IOwnableWithOperator.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"./IOwnable.sol\";\n\n/**\n * @dev Ownable with an additional role of operator\n */\ninterface IOwnableWithOperator is IOwnable {\n    /**\n     * @dev Returns the current operator.\n     */\n    function operator() external view returns (address);\n}\n"
      },
      "src/assetRecovering/OwnableTokenRecoverer.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, Lido <info@lido.fi>\n// SPDX-License-Identifier: MIT\n\n// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol\npragma solidity 0.8.18;\n\nimport \"./TokenRecoverer.sol\";\nimport \"../access/OwnableBase.sol\";\n\n/// @title Token Recoverer with public functions callable by assetAccessingAddress\n/// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract\nabstract contract OwnableTokenRecoverer is TokenRecoverer, OwnableBase {\n    // Functions\n\n    /**\n     * @notice transfer an ERC20 token from this contract\n     * @dev `SafeERC20.safeTransfer` doesn't always return a bool\n     * as it performs an internal `require` check\n     * @param _token address of the ERC20 token\n     * @param _recipient address to transfer the tokens to\n     * @param _amount amount of tokens to transfer\n     */\n    function transferERC20(\n        address _token,\n        address _recipient,\n        uint256 _amount\n    ) external onlyOwner {\n        _transferERC20(_token, _recipient, _amount);\n    }\n\n    /**\n     * @notice transfer an ERC721 token from this contract\n     * @dev `IERC721.safeTransferFrom` doesn't always return a bool\n     * as it performs an internal `require` check\n     * @param _token address of the ERC721 token\n     * @param _recipient address to transfer the token to\n     * @param _tokenId id of the individual token\n     */\n    function transferERC721(\n        address _token,\n        address _recipient,\n        uint256 _tokenId\n    ) external onlyOwner {\n        _transferERC721(_token, _recipient, _tokenId);\n    }\n\n    /**\n     * @notice transfer an ERC1155 token from this contract\n     * @dev see `AssetRecoverer`\n     * @param _token address of the ERC1155 token that is being recovered\n     * @param _recipient address to transfer the token to\n     * @param _tokenId id of the individual token to transfer\n     * @param _amount amount of tokens to transfer\n     * @param _data data to transfer along\n     */\n    function transferERC1155(\n        address _token,\n        address _recipient,\n        uint256 _tokenId,\n        uint256 _amount,\n        bytes calldata _data\n    ) external onlyOwner {\n        _transferERC1155(_token, _recipient, _tokenId, _amount, _data);\n    }\n}\n"
      },
      "src/assetRecovering/AssetRecoverer.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, Lido <info@lido.fi>\n// SPDX-License-Identifier: MIT\n\n// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol\npragma solidity 0.8.18;\n\nimport \"./TokenRecoverer.sol\";\n\n/**\n* @notice could not transfer ether\n* @param _recipient address to transfer ether to\n* @param _amount amount of ether to transfer\n*/\nerror AssetRecoverer__TransferFailed(address _recipient, uint256 _amount);\n\n\n/// @title Asset Recoverer\n/// @notice Recover ether, ERC20, ERC721 and ERC1155 from a derived contract\nabstract contract AssetRecoverer is TokenRecoverer {\n    event EtherTransferred(address indexed _recipient, uint256 _amount);\n\n    /**\n     * @notice transfers ether from this contract\n     * @dev using `address.call` is safer to transfer to other contracts\n     * @param _recipient address to transfer ether to\n     * @param _amount amount of ether to transfer\n     */\n    function _transferEther(address _recipient, uint256 _amount) internal virtual burnDisallowed(_recipient) {\n        (bool success, ) = _recipient.call{value: _amount}(\"\");\n        if (!success) {\n            revert AssetRecoverer__TransferFailed(_recipient, _amount);\n        }\n        emit EtherTransferred(_recipient, _amount);\n    }\n}\n"
      },
      "src/access/Ownable.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"./OwnableBase.sol\";\n\n/**\n* @notice _newOwner cannot be a zero address\n*/\nerror Ownable__NewOwnerIsZeroAddress();\n\n/**\n * @dev OpenZeppelin's Ownable with modifier onlyOwner extracted to OwnableBase\n * and removed `renounceOwnership`\n */\nabstract contract Ownable is OwnableBase {\n\n    /**\n     * @dev Emits when the owner has been changed.\n     * @param _previousOwner address of the previous owner\n     * @param _newOwner address of the new owner\n     */\n    event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);\n\n    address private s_owner;\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual override returns (address) {\n        return s_owner;\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     * @param _newOwner address of the new owner\n     */\n    function transferOwnership(address _newOwner) external virtual onlyOwner {\n        if (_newOwner == address(0)) {\n            revert Ownable__NewOwnerIsZeroAddress();\n        }\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     * @param _newOwner address of the new owner\n     */\n    function _transferOwnership(address _newOwner) internal virtual {\n        address oldOwner = s_owner;\n        s_owner = _newOwner;\n        emit OwnershipTransferred(oldOwner, _newOwner);\n    }\n}\n"
      },
      "src/assetRecovering/TokenRecoverer.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>, Lido <info@lido.fi>\n// SPDX-License-Identifier: MIT\n\n// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol\npragma solidity 0.8.18;\n\nimport {IERC20} from \"../@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {IERC721} from \"../@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {IERC1155} from \"../@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\nimport {SafeERC20} from \"../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/**\n* @notice prevents burn for transfer functions\n* @dev _recipient should not be a zero address\n*/\nerror TokenRecoverer__NoBurn();\n\n\n/// @title Token Recoverer\n/// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract\nabstract contract TokenRecoverer {\n    using SafeERC20 for IERC20;\n\n    event ERC20Transferred(address indexed _token, address indexed _recipient, uint256 _amount);\n    event ERC721Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId);\n    event ERC1155Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId, uint256 _amount, bytes _data);\n\n    /**\n     * @notice prevents burn for transfer functions\n     * @dev checks for zero address and reverts if true\n     * @param _recipient address of the transfer recipient\n     */\n    modifier burnDisallowed(address _recipient) {\n        if (_recipient == address(0)) {\n            revert TokenRecoverer__NoBurn();\n        }\n        _;\n    }\n\n    /**\n     * @notice transfer an ERC20 token from this contract\n     * @dev `SafeERC20.safeTransfer` doesn't always return a bool\n     * as it performs an internal `require` check\n     * @param _token address of the ERC20 token\n     * @param _recipient address to transfer the tokens to\n     * @param _amount amount of tokens to transfer\n     */\n    function _transferERC20(\n        address _token,\n        address _recipient,\n        uint256 _amount\n    ) internal virtual burnDisallowed(_recipient) {\n        IERC20(_token).safeTransfer(_recipient, _amount);\n        emit ERC20Transferred(_token, _recipient, _amount);\n    }\n\n    /**\n     * @notice transfer an ERC721 token from this contract\n     * @dev `IERC721.safeTransferFrom` doesn't always return a bool\n     * as it performs an internal `require` check\n     * @param _token address of the ERC721 token\n     * @param _recipient address to transfer the token to\n     * @param _tokenId id of the individual token\n     */\n    function _transferERC721(\n        address _token,\n        address _recipient,\n        uint256 _tokenId\n    ) internal virtual burnDisallowed(_recipient) {\n        IERC721(_token).transferFrom(address(this), _recipient, _tokenId);\n        emit ERC721Transferred(_token, _recipient, _tokenId);\n    }\n\n    /**\n     * @notice transfer an ERC1155 token from this contract\n     * @dev `IERC1155.safeTransferFrom` doesn't always return a bool\n     * as it performs an internal `require` check\n     * @param _token address of the ERC1155 token that is being recovered\n     * @param _recipient address to transfer the token to\n     * @param _tokenId id of the individual token to transfer\n     * @param _amount amount of tokens to transfer\n     * @param _data data to transfer along\n     */\n    function _transferERC1155(\n        address _token,\n        address _recipient,\n        uint256 _tokenId,\n        uint256 _amount,\n        bytes calldata _data\n    ) internal virtual burnDisallowed(_recipient) {\n        IERC1155(_token).safeTransferFrom(address(this), _recipient, _tokenId, _amount, _data);\n        emit ERC1155Transferred(_token, _recipient, _tokenId, _amount, _data);\n    }\n}\n"
      },
      "src/access/OwnableBase.sol": {
        "content": "// SPDX-FileCopyrightText: 2023 P2P Validator <info@p2p.org>\n// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.18;\n\nimport \"../@openzeppelin/contracts/utils/Context.sol\";\nimport \"./IOwnable.sol\";\n\n/**\n* @notice Throws if called by any account other than the owner.\n* @param _caller address of the caller\n* @param _owner address of the owner\n*/\nerror OwnableBase__CallerNotOwner(address _caller, address _owner);\n\n/**\n * @dev minimalistic version of OpenZeppelin's Ownable.\n * The owner is abstract and is not persisted in storage.\n * Needs to be overridden in a child contract.\n */\nabstract contract OwnableBase is Context, IOwnable {\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        address caller = _msgSender();\n        address currentOwner = owner();\n\n        if (currentOwner != caller) {\n            revert OwnableBase__CallerNotOwner(caller, currentOwner);\n        }\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     * Needs to be overridden in a child contract.\n     */\n    function owner() public view virtual override returns (address);\n}\n"
      },
      "src/@openzeppelin/contracts/token/ERC721/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity 0.8.18;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
      },
      "src/@openzeppelin/contracts/token/ERC1155/IERC1155.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)\n\npragma solidity 0.8.18;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155 is IERC165 {\n    /**\n     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n     */\n    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n    /**\n     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n     * transfers.\n     */\n    event TransferBatch(\n        address indexed operator,\n        address indexed from,\n        address indexed to,\n        uint256[] ids,\n        uint256[] values\n    );\n\n    /**\n     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n     * `approved`.\n     */\n    event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n    /**\n     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n     *\n     * If an {URI} event was emitted for `id`, the standard\n     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n     * returned by {IERC1155MetadataURI-uri}.\n     */\n    event URI(string value, uint256 indexed id);\n\n    /**\n     * @dev Returns the amount of tokens of token type `id` owned by `account`.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function balanceOf(address account, uint256 id) external view returns (uint256);\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n     *\n     * Requirements:\n     *\n     * - `accounts` and `ids` must have the same length.\n     */\n    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\n        external\n        view\n        returns (uint256[] memory);\n\n    /**\n     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n     *\n     * Emits an {ApprovalForAll} event.\n     *\n     * Requirements:\n     *\n     * - `operator` cannot be the caller.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address account, address operator) external view returns (bool);\n\n    /**\n     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n     *\n     * Emits a {TransferSingle} event.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n     * - `from` must have a balance of tokens of type `id` of at least `amount`.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n     * acceptance magic value.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 id,\n        uint256 amount,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n     *\n     * Emits a {TransferBatch} event.\n     *\n     * Requirements:\n     *\n     * - `ids` and `amounts` must have the same length.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n     * acceptance magic value.\n     */\n    function safeBatchTransferFrom(\n        address from,\n        address to,\n        uint256[] calldata ids,\n        uint256[] calldata amounts,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "src/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity 0.8.18;\n\nimport \"../IERC20.sol\";\nimport \"../extensions/draft-IERC20Permit.sol\";\nimport \"../../../utils/Address.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 SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) 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(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) 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    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20Permit 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(IERC20 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        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "src/@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity 0.8.18;\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 Context {\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"
      },
      "src/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity 0.8.18;\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 */\ninterface IERC20Permit {\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    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"
      },
      "src/@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity 0.8.18;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\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     *\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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, \"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(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) 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        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(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        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(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        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason 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            // 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}\n"
      }
    },
    "settings": {
      "remappings": [
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "libraries": {}
    }
  }}