ETH Price: $3,454.86 (+1.65%)

Contract

0x86a9f3e908b4658A1327952Eb1eC297a4212E1bb
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Create Fee Distr...214133982024-12-16 6:50:358 days ago1734331835IN
MEV Bot: 0x86a...1bb
0 ETH0.001545168.25533916
Create Fee Distr...214133972024-12-16 6:50:238 days ago1734331823IN
MEV Bot: 0x86a...1bb
0 ETH0.001534248.19699833
Create Fee Distr...214133922024-12-16 6:49:238 days ago1734331763IN
MEV Bot: 0x86a...1bb
0 ETH0.001563148.07822937
Create Fee Distr...213057042024-12-01 5:55:2323 days ago1733032523IN
MEV Bot: 0x86a...1bb
0 ETH0.001317287.03783144
Create Fee Distr...213057032024-12-01 5:55:1123 days ago1733032511IN
MEV Bot: 0x86a...1bb
0 ETH0.001201666.42013173
Create Fee Distr...213057032024-12-01 5:55:1123 days ago1733032511IN
MEV Bot: 0x86a...1bb
0 ETH0.001201666.42013173
Create Fee Distr...213057012024-12-01 5:54:4723 days ago1733032487IN
MEV Bot: 0x86a...1bb
0 ETH0.001377617.36015209
Create Fee Distr...213056992024-12-01 5:54:2323 days ago1733032463IN
MEV Bot: 0x86a...1bb
0 ETH0.001263966.53210105
Create Fee Distr...211956072024-11-15 20:54:3539 days ago1731704075IN
MEV Bot: 0x86a...1bb
0 ETH0.0045029524.05786759
Create Fee Distr...211956052024-11-15 20:54:1139 days ago1731704051IN
MEV Bot: 0x86a...1bb
0 ETH0.0045329324.21803319
Create Fee Distr...211956052024-11-15 20:54:1139 days ago1731704051IN
MEV Bot: 0x86a...1bb
0 ETH0.0045329324.21803319
Create Fee Distr...210852682024-10-31 11:18:1154 days ago1730373491IN
MEV Bot: 0x86a...1bb
0 ETH0.001463757.56456833
Create Fee Distr...210852672024-10-31 11:17:5954 days ago1730373479IN
MEV Bot: 0x86a...1bb
0 ETH0.001442517.70687192
Create Fee Distr...210852662024-10-31 11:17:4754 days ago1730373467IN
MEV Bot: 0x86a...1bb
0 ETH0.001461187.80662923
Create Fee Distr...210852642024-10-31 11:17:2354 days ago1730373443IN
MEV Bot: 0x86a...1bb
0 ETH0.001306056.97783466
Create Fee Distr...210852632024-10-31 11:17:1154 days ago1730373431IN
MEV Bot: 0x86a...1bb
0 ETH0.001363677.18067985
Create Fee Distr...209702332024-10-15 10:00:5970 days ago1728986459IN
MEV Bot: 0x86a...1bb
0 ETH0.0026672513.78420242
Create Fee Distr...209702322024-10-15 10:00:4770 days ago1728986447IN
MEV Bot: 0x86a...1bb
0 ETH0.0025571813.66220384
Create Fee Distr...209702302024-10-15 10:00:2370 days ago1728986423IN
MEV Bot: 0x86a...1bb
0 ETH0.0026772713.83595036
Create Fee Distr...209702292024-10-15 10:00:1170 days ago1728986411IN
MEV Bot: 0x86a...1bb
0 ETH0.0026180313.52983003
Create Fee Distr...208641932024-09-30 14:53:3585 days ago1727708015IN
MEV Bot: 0x86a...1bb
0 ETH0.0027973614.94540159
Create Fee Distr...208639232024-09-30 13:59:3585 days ago1727704775IN
MEV Bot: 0x86a...1bb
0 ETH0.0025792613.78020289
Create Fee Distr...208638992024-09-30 13:54:4785 days ago1727704487IN
MEV Bot: 0x86a...1bb
0 ETH0.0028004614.96199074
Create Fee Distr...207621302024-09-16 8:55:3599 days ago1726476935IN
MEV Bot: 0x86a...1bb
0 ETH0.0025443314.9603136
Create Fee Distr...207621272024-09-16 8:54:5999 days ago1726476899IN
MEV Bot: 0x86a...1bb
0 ETH0.0029025115
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
214133982024-12-16 6:50:358 days ago1734331835
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
214133972024-12-16 6:50:238 days ago1734331823
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
214133922024-12-16 6:49:238 days ago1734331763
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
213057042024-12-01 5:55:2323 days ago1733032523
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
213057032024-12-01 5:55:1123 days ago1733032511
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
213057032024-12-01 5:55:1123 days ago1733032511
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
213057012024-12-01 5:54:4723 days ago1733032487
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
213056992024-12-01 5:54:2323 days ago1733032463
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
211956072024-11-15 20:54:3539 days ago1731704075
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
211956052024-11-15 20:54:1139 days ago1731704051
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
211956052024-11-15 20:54:1139 days ago1731704051
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
210852682024-10-31 11:18:1154 days ago1730373491
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
210852672024-10-31 11:17:5954 days ago1730373479
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
210852662024-10-31 11:17:4754 days ago1730373467
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
210852642024-10-31 11:17:2354 days ago1730373443
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
210852632024-10-31 11:17:1154 days ago1730373431
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
209702332024-10-15 10:00:5970 days ago1728986459
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
209702322024-10-15 10:00:4770 days ago1728986447
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
209702302024-10-15 10:00:2370 days ago1728986423
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
209702292024-10-15 10:00:1170 days ago1728986411
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
208641932024-09-30 14:53:3585 days ago1727708015
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
208639232024-09-30 13:59:3585 days ago1727704775
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
208638992024-09-30 13:54:4785 days ago1727704487
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
207621302024-09-16 8:55:3599 days ago1726476935
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
207621272024-09-16 8:54:5999 days ago1726476899
MEV Bot: 0x86a...1bb
 Contract Creation0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FeeDistributorFactory

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 26 : FeeDistributorFactory.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../@openzeppelin/contracts/proxy/Clones.sol";
import "../@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "../assetRecovering/OwnableAssetRecoverer.sol";
import "./IFeeDistributorFactory.sol";
import "../feeDistributor/IFeeDistributor.sol";
import "../access/Ownable.sol";
import "../access/OwnableWithOperator.sol";
import "../p2pEth2Depositor/IP2pOrgUnlimitedEthDepositor.sol";
import "../structs/P2pStructs.sol";

/// @notice Should be a FeeDistributor contract
/// @param _passedAddress passed address that does not support IFeeDistributor interface
error FeeDistributorFactory__NotFeeDistributor(address _passedAddress);

/// @notice Should be a P2pEth2Depositor contract
/// @param _passedAddress passed address that does not support IP2pEth2Depositor interface
error FeeDistributorFactory__NotP2pEth2Depositor(address _passedAddress);

/// @notice Reference FeeDistributor should be set before calling `createFeeDistributor`
error FeeDistributorFactory__ReferenceFeeDistributorNotSet();

/// @notice caller should be owner, operator, or P2pEth2Depositor contract
/// @param _caller calling address
error FeeDistributorFactory__CallerNotAuthorized(address _caller);

/// @notice Default client basis points should be >= 0 and <= 10000
/// @param _defaultClientBasisPoints passed incorrect default client basis points
error FeeDistributorFactory__InvalidDefaultClientBasisPoints(uint96 _defaultClientBasisPoints);

/// @title Factory for cloning (EIP-1167) FeeDistributor instances pre client
contract FeeDistributorFactory is OwnableAssetRecoverer, OwnableWithOperator, ERC165, IFeeDistributorFactory {

    /// @notice Default Client Basis Points
    /// @dev Used when no client config provided.
    /// Default Referrer Basis Points is zero.
    uint96 private s_defaultClientBasisPoints;

    /// @notice The address of P2pEth2Depositor
    address private s_p2pEth2Depositor;

    /// @notice client address -> array of client FeeDistributors mapping
    mapping(address => address[]) private s_allClientFeeDistributors;

    /// @notice array of all FeeDistributors for all clients
    address[] private s_allFeeDistributors;

    /// @dev Set values known at the initial deploy time.
    /// @param _defaultClientBasisPoints Default Client Basis Points
    constructor(uint96 _defaultClientBasisPoints) {
        if (_defaultClientBasisPoints >= 10000) {
            revert FeeDistributorFactory__InvalidDefaultClientBasisPoints(_defaultClientBasisPoints);
        }

        s_defaultClientBasisPoints = _defaultClientBasisPoints;

        emit FeeDistributorFactory__DefaultClientBasisPointsSet(_defaultClientBasisPoints);
    }

    /// @notice Set a new version of P2pEth2Depositor contract
    /// @param _p2pEth2Depositor the address of the new P2pEth2Depositor contract
    function setP2pEth2Depositor(address _p2pEth2Depositor) external onlyOwner {
        if (!ERC165Checker.supportsInterface(_p2pEth2Depositor, type(IP2pOrgUnlimitedEthDepositor).interfaceId)) {
            revert FeeDistributorFactory__NotP2pEth2Depositor(_p2pEth2Depositor);
        }

        s_p2pEth2Depositor = _p2pEth2Depositor;
        emit FeeDistributorFactory__P2pEth2DepositorSet(_p2pEth2Depositor);
    }

    /// @notice Set a new Default Client Basis Points
    /// @param _defaultClientBasisPoints Default Client Basis Points
    function setDefaultClientBasisPoints(uint96 _defaultClientBasisPoints) external onlyOwner {
        if (_defaultClientBasisPoints >= 10000) {
            revert FeeDistributorFactory__InvalidDefaultClientBasisPoints(_defaultClientBasisPoints);
        }

        s_defaultClientBasisPoints = _defaultClientBasisPoints;

        emit FeeDistributorFactory__DefaultClientBasisPointsSet(_defaultClientBasisPoints);
    }

    /// @inheritdoc IFeeDistributorFactory
    function createFeeDistributor(
        address _referenceFeeDistributor,
        FeeRecipient memory _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) external returns (address newFeeDistributorAddress) {
        check_Operator_Owner_P2pEth2Depositor(msg.sender);

        if (_referenceFeeDistributor == address(0)) {
            revert FeeDistributorFactory__ReferenceFeeDistributorNotSet();
        }

        if (!ERC165Checker.supportsInterface(_referenceFeeDistributor, type(IFeeDistributor).interfaceId)) {
            revert FeeDistributorFactory__NotFeeDistributor(_referenceFeeDistributor);
        }

        if (_clientConfig.basisPoints == 0) {
            _clientConfig.basisPoints = s_defaultClientBasisPoints;
        }

        // clone the reference implementation of FeeDistributor
        newFeeDistributorAddress = Clones.cloneDeterministic(
            _referenceFeeDistributor,
            _getSalt(_clientConfig, _referrerConfig)
        );

        // cast address to FeeDistributor
        IFeeDistributor newFeeDistributor = IFeeDistributor(newFeeDistributorAddress);

        // set the client address to the cloned FeeDistributor instance
        newFeeDistributor.initialize(_clientConfig, _referrerConfig);

        // append new FeeDistributor address to all client feeDistributors array
        s_allClientFeeDistributors[_clientConfig.recipient].push(newFeeDistributorAddress);

        // append new FeeDistributor address to all feeDistributors array
        s_allFeeDistributors.push(newFeeDistributorAddress);

        // emit event with the address of the newly created instance for the external listener
        emit FeeDistributorFactory__FeeDistributorCreated(
            newFeeDistributorAddress,
            _clientConfig.recipient,
            _referenceFeeDistributor,
            _clientConfig.basisPoints
        );

        return newFeeDistributorAddress;
    }

    /// @inheritdoc IFeeDistributorFactory
    function predictFeeDistributorAddress(
        address _referenceFeeDistributor,
        FeeRecipient memory _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) public view returns (address) {
        if (_clientConfig.basisPoints == 0) {
            _clientConfig.basisPoints = s_defaultClientBasisPoints;
        }

        return Clones.predictDeterministicAddress(
            _referenceFeeDistributor,
            _getSalt(_clientConfig, _referrerConfig)
        );
    }

    /// @inheritdoc IFeeDistributorFactory
    function allClientFeeDistributors(address _client) external view returns (address[] memory) {
        return s_allClientFeeDistributors[_client];
    }

    /// @inheritdoc IFeeDistributorFactory
    function allFeeDistributors() external view returns (address[] memory) {
        return s_allFeeDistributors;
    }

    /// @inheritdoc IFeeDistributorFactory
    function p2pEth2Depositor() external view returns (address) {
        return s_p2pEth2Depositor;
    }

    /// @inheritdoc IFeeDistributorFactory
    function defaultClientBasisPoints() external view returns (uint96) {
        return s_defaultClientBasisPoints;
    }

    /// @inheritdoc ERC165
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IFeeDistributorFactory).interfaceId || super.supportsInterface(interfaceId);
    }

    /// @inheritdoc IOwnable
    function owner() public view override(Ownable, OwnableBase, IOwnable) returns (address) {
        return super.owner();
    }

    /// @inheritdoc IFeeDistributorFactory
    function operator() public view override(OwnableWithOperator, IFeeDistributorFactory) returns (address) {
        return super.operator();
    }

    /// @inheritdoc IFeeDistributorFactory
    function checkOperatorOrOwner(address _address) public view override(OwnableWithOperator, IFeeDistributorFactory) {
        return super.checkOperatorOrOwner(_address);
    }

    /// @inheritdoc IFeeDistributorFactory
    function checkP2pEth2Depositor(address _address) external view {
        if (s_p2pEth2Depositor != _address) {
            revert FeeDistributorFactory__NotP2pEth2Depositor(_address);
        }
    }

    /// @inheritdoc IFeeDistributorFactory
    function check_Operator_Owner_P2pEth2Depositor(address _address) public view {
        address currentOwner = owner();
        address currentOperator = operator();

        if (currentOperator != _address
            && currentOwner != _address
            && s_p2pEth2Depositor != _address
        ) {
            revert FeeDistributorFactory__CallerNotAuthorized(_address);
        }
    }

    /// @notice Calculates the salt required for deterministic clone creation
    /// depending on clientConfig and referrerConfig
    /// @param _clientConfig address and basis points (percent * 100) of the client
    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.
    /// @return bytes32 salt
    function _getSalt(
        FeeRecipient memory _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) private pure returns (bytes32)
    {
        return keccak256(abi.encode(_clientConfig, _referrerConfig));
    }
}

File 2 of 26 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)

pragma solidity 0.8.10;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

File 3 of 26 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity 0.8.10;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 4 of 26 : ERC165Checker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.2) (utils/introspection/ERC165Checker.sol)

pragma solidity 0.8.10;

import "./IERC165.sol";

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface,
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            _supportsERC165Interface(account, type(IERC165).interfaceId) &&
            !_supportsERC165Interface(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && _supportsERC165Interface(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     *
     * _Available since v3.4._
     */
    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
        internal
        view
        returns (bool[] memory)
    {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in _interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!_supportsERC165Interface(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     * Interface identification is specified in ERC-165.
     */
    function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

File 5 of 26 : OwnableAssetRecoverer.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]>
// SPDX-License-Identifier: MIT

// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol
pragma solidity 0.8.10;

import "./OwnableTokenRecoverer.sol";
import "./AssetRecoverer.sol";

/// @title Public Asset Recoverer with public functions callable by assetAccessingAddress
/// @notice Recover ether, ERC20, ERC721 and ERC1155 from a derived contract
abstract contract OwnableAssetRecoverer is OwnableTokenRecoverer, AssetRecoverer {

    // Functions

    /**
     * @notice transfers ether from this contract
     * @dev using `address.call` is safer to transfer to other contracts
     * @param _recipient address to transfer ether to
     * @param _amount amount of ether to transfer
     */
    function transferEther(address _recipient, uint256 _amount) external onlyOwner {
        _transferEther(_recipient, _amount);
    }
}

File 6 of 26 : IFeeDistributorFactory.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../access/IOwnable.sol";
import "../feeDistributor/IFeeDistributor.sol";
import "../structs/P2pStructs.sol";

/// @dev External interface of FeeDistributorFactory declared to support ERC165 detection.
interface IFeeDistributorFactory is IOwnable, IERC165 {

    /// @notice Emits when a new FeeDistributor instance has been created for a client
    /// @param _newFeeDistributorAddress address of the newly created FeeDistributor contract instance
    /// @param _clientAddress address of the client for whom the new instance was created
    /// @param _referenceFeeDistributor The address of the reference implementation of FeeDistributor used as the basis for clones
    /// @param _clientBasisPoints client basis points (percent * 100)
    event FeeDistributorFactory__FeeDistributorCreated(
        address indexed _newFeeDistributorAddress,
        address indexed _clientAddress,
        address indexed _referenceFeeDistributor,
        uint96 _clientBasisPoints
    );

    /// @notice Emits when a new P2pEth2Depositor contract address has been set.
    /// @param _p2pEth2Depositor the address of the new P2pEth2Depositor contract
    event FeeDistributorFactory__P2pEth2DepositorSet(
        address indexed _p2pEth2Depositor
    );

    /// @notice Emits when a new value of defaultClientBasisPoints has been set.
    /// @param _defaultClientBasisPoints new value of defaultClientBasisPoints
    event FeeDistributorFactory__DefaultClientBasisPointsSet(
        uint96 _defaultClientBasisPoints
    );

    /// @notice Creates a FeeDistributor instance for a client
    /// @dev _referrerConfig can be zero if there is no referrer.
    ///
    /// @param _referenceFeeDistributor The address of the reference implementation of FeeDistributor used as the basis for clones
    /// @param _clientConfig address and basis points (percent * 100) of the client
    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.
    /// @return newFeeDistributorAddress user FeeDistributor instance that has just been deployed
    function createFeeDistributor(
        address _referenceFeeDistributor,
        FeeRecipient calldata _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) external returns (address newFeeDistributorAddress);

    /// @notice Computes the address of a FeeDistributor created by `createFeeDistributor` function
    /// @dev FeeDistributor instances are guaranteed to have the same address if all of
    /// 1) referenceFeeDistributor 2) clientConfig 3) referrerConfig
    /// are the same
    /// @param _referenceFeeDistributor The address of the reference implementation of FeeDistributor used as the basis for clones
    /// @param _clientConfig address and basis points (percent * 100) of the client
    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.
    /// @return address user FeeDistributor instance that will be or has been deployed
    function predictFeeDistributorAddress(
        address _referenceFeeDistributor,
        FeeRecipient calldata _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) external view returns (address);

    /// @notice Returns an array of client FeeDistributors
    /// @param _client client address
    /// @return address[] array of client FeeDistributors
    function allClientFeeDistributors(
        address _client
    ) external view returns (address[] memory);

    /// @notice Returns an array of all FeeDistributors for all clients
    /// @return address[] array of all FeeDistributors
    function allFeeDistributors() external view returns (address[] memory);

    /// @notice The address of P2pEth2Depositor
    /// @return address of P2pEth2Depositor
    function p2pEth2Depositor() external view returns (address);

    /// @notice Returns default client basis points
    /// @return default client basis points
    function defaultClientBasisPoints() external view returns (uint96);

    /// @notice Returns the current operator
    /// @return address of the current operator
    function operator() external view returns (address);

    /// @notice Reverts if the passed address is neither operator nor owner
    /// @param _address passed address
    function checkOperatorOrOwner(address _address) external view;

    /// @notice Reverts if the passed address is not P2pEth2Depositor
    /// @param _address passed address
    function checkP2pEth2Depositor(address _address) external view;

    /// @notice Reverts if the passed address is neither of: 1) operator 2) owner 3) P2pEth2Depositor
    /// @param _address passed address
    function check_Operator_Owner_P2pEth2Depositor(address _address) external view;
}

File 7 of 26 : IFeeDistributor.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../structs/P2pStructs.sol";

/// @dev External interface of FeeDistributor declared to support ERC165 detection.
interface IFeeDistributor is IERC165 {

    /// @notice Emits once the client and the optional referrer have been set.
    /// @param _client address of the client.
    /// @param _clientBasisPoints basis points (percent * 100) of EL rewards that should go to the client
    /// @param _referrer address of the referrer.
    /// @param _referrerBasisPoints basis points (percent * 100) of EL rewards that should go to the referrer
    event FeeDistributor__Initialized(
        address indexed _client,
        uint96 _clientBasisPoints,
        address indexed _referrer,
        uint96 _referrerBasisPoints
    );

    /// @notice Emits on successful withdrawal
    /// @param _serviceAmount how much wei service received
    /// @param _clientAmount how much wei client received
    /// @param _referrerAmount how much wei referrer received
    event FeeDistributor__Withdrawn(
        uint256 _serviceAmount,
        uint256 _clientAmount,
        uint256 _referrerAmount
    );

    /// @notice Emits on request for a voluntary exit of validators
    /// @param _pubkeys pubkeys of validators
    event FeeDistributor__VoluntaryExit(
        bytes[] _pubkeys
    );

    /// @notice Emits if case there was some ether left after `withdraw` and it has been sent successfully.
    /// @param _to destination address for ether.
    /// @param _amount how much wei the destination address received.
    event FeeDistributor__EtherRecovered(
        address indexed _to,
        uint256 _amount
    );

    /// @notice Set client address.
    /// @dev Could not be in the constructor since it is different for different clients.
    /// _referrerConfig can be zero if there is no referrer.
    /// @param _clientConfig address and basis points (percent * 100) of the client
    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.
    function initialize(
        FeeRecipient calldata _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) external;

    /// @notice Increase the number of deposited validators.
    /// @dev Should be called when a new ETH2 deposit has been made
    /// @param _validatorCountToAdd number of newly deposited validators
    function increaseDepositedCount(
        uint32 _validatorCountToAdd
    ) external;

    /// @notice Request a voluntary exit of validators
    /// @dev Should be called by the client when they want to signal P2P that certain validators need to be exited
    /// @param _pubkeys pubkeys of validators
    function voluntaryExit(
        bytes[] calldata _pubkeys
    ) external;

    /// @notice Returns the factory address
    /// @return address factory address
    function factory() external view returns (address);

    /// @notice Returns the service address
    /// @return address service address
    function service() external view returns (address);

    /// @notice Returns the client address
    /// @return address client address
    function client() external view returns (address);

    /// @notice Returns the client basis points
    /// @return uint256 client basis points
    function clientBasisPoints() external view returns (uint256);

    /// @notice Returns the referrer address
    /// @return address referrer address
    function referrer() external view returns (address);

    /// @notice Returns the referrer basis points
    /// @return uint256 referrer basis points
    function referrerBasisPoints() external view returns (uint256);

    /// @notice Returns the address for ETH2 0x01 withdrawal credentials associated with this FeeDistributor
    /// @dev Return FeeDistributor's own address if FeeDistributor should be CL rewards recipient
    /// Otherwise, return the client address
    /// @return address address for ETH2 0x01 withdrawal credentials
    function eth2WithdrawalCredentialsAddress() external view returns (address);
}

File 8 of 26 : Ownable.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./OwnableBase.sol";

/**
* @notice _newOwner cannot be a zero address
*/
error Ownable__NewOwnerIsZeroAddress();

/**
 * @dev OpenZeppelin's Ownable with modifier onlyOwner extracted to OwnableBase
 * and removed `renounceOwnership`
 */
abstract contract Ownable is OwnableBase {

    /**
     * @dev Emits when the owner has been changed.
     * @param _previousOwner address of the previous owner
     * @param _newOwner address of the new owner
     */
    event OwnershipTransferred(address indexed _previousOwner, address indexed _newOwner);

    address private s_owner;

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual override returns (address) {
        return s_owner;
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     * @param _newOwner address of the new owner
     */
    function transferOwnership(address _newOwner) external virtual onlyOwner {
        if (_newOwner == address(0)) {
            revert Ownable__NewOwnerIsZeroAddress();
        }
        _transferOwnership(_newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     * @param _newOwner address of the new owner
     */
    function _transferOwnership(address _newOwner) internal virtual {
        address oldOwner = s_owner;
        s_owner = _newOwner;
        emit OwnershipTransferred(oldOwner, _newOwner);
    }
}

File 9 of 26 : OwnableWithOperator.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./Ownable2Step.sol";
import "./IOwnableWithOperator.sol";

/**
* @notice newOperator is the zero address
*/
error Access__ZeroNewOperator();

/**
* @notice newOperator is the same as the old one
*/
error Access__SameOperator(address _operator);

/**
* @notice caller is neither the operator nor owner
*/
error Access__CallerNeitherOperatorNorOwner(address _caller, address _operator, address _owner);

/**
* @notice address is neither the operator nor owner
*/
error Access__AddressNeitherOperatorNorOwner(address _address, address _operator, address _owner);

/**
 * @dev Ownable with an additional role of operator
 */
abstract contract OwnableWithOperator is Ownable2Step, IOwnableWithOperator {
    address private s_operator;

    /**
     * @dev Emits when the operator has been changed
     * @param _previousOperator address of the previous operator
     * @param _newOperator address of the new operator
     */
    event OperatorChanged(
        address indexed _previousOperator,
        address indexed _newOperator
    );

    /**
     * @dev Throws if called by any account other than the operator or the owner.
     */
    modifier onlyOperatorOrOwner() {
        address currentOwner = owner();
        address currentOperator = s_operator;

        if (currentOperator != _msgSender() && currentOwner != _msgSender()) {
            revert Access__CallerNeitherOperatorNorOwner(_msgSender(), currentOperator, currentOwner);
        }

        _;
    }

    function checkOperatorOrOwner(address _address) public view virtual {
        address currentOwner = owner();
        address currentOperator = s_operator;

        if (_address == address(0) || (currentOperator != _address && currentOwner != _address)) {
            revert Access__AddressNeitherOperatorNorOwner(_address, currentOperator, currentOwner);
        }
    }

    /**
     * @dev Returns the current operator.
     */
    function operator() public view virtual returns (address) {
        return s_operator;
    }

    /**
     * @dev Transfers operator to a new account (`newOperator`).
     * Can only be called by the current owner.
     */
    function changeOperator(address _newOperator) external virtual onlyOwner {
        if (_newOperator == address(0)) {
            revert Access__ZeroNewOperator();
        }
        if (_newOperator == s_operator) {
            revert Access__SameOperator(_newOperator);
        }

        _changeOperator(_newOperator);
    }

    /**
     * @dev Transfers operator to a new account (`newOperator`).
     * Internal function without access restriction.
     */
    function _changeOperator(address _newOperator) internal virtual {
        address oldOperator = s_operator;
        s_operator = _newOperator;
        emit OperatorChanged(oldOperator, _newOperator);
    }

    /**
     * @dev Dismisses the old operator without setting a new one.
     * Can only be called by the current owner.
     */
    function dismissOperator() external virtual onlyOwner {
        _changeOperator(address(0));
    }
}

File 10 of 26 : IP2pOrgUnlimitedEthDepositor.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../feeDistributor/IFeeDistributor.sol";
import "../structs/P2pStructs.sol";

/// @dev External interface of P2pOrgUnlimitedEthDepositor declared to support ERC165 detection.
interface IP2pOrgUnlimitedEthDepositor is IERC165 {

    /// @notice Emits when a client adds ETH for staking
    /// @param _sender address who sent ETH
    /// @param _feeDistributorInstance address of FeeDistributor instance that determines the terms of staking service
    /// @param _amount sent amount of ETH in wei
    /// @param _expiration block timestamp after which the client will be able to get a refund
    event P2pOrgUnlimitedEthDepositor__ClientEthAdded(
        address indexed _sender,
        address indexed _feeDistributorInstance,
        uint256 _amount,
        uint40 _expiration
    );

    /// @notice Emits when a refund has been sent to the client
    /// @param _feeDistributorInstance address of FeeDistributor instance that was associated with the client deposit
    /// @param _client address who received the refunded ETH
    /// @param _amount refunded amount of ETH in wei
    event P2pOrgUnlimitedEthDepositor__Refund(
        address indexed _feeDistributorInstance,
        address indexed _client,
        uint256 _amount
    );

    /// @notice Emits when P2P has made ETH2 deposits with client funds and withdrawal credentials
    /// @param _feeDistributorAddress address of FeeDistributor instance that was associated with the client deposit
    /// @param _validatorCount number of validators that has been created
    event P2pOrgUnlimitedEthDepositor__Eth2Deposit(
        address indexed _feeDistributorAddress,
        uint256 _validatorCount
    );

    /// @notice Emits when all the available ETH has been forwarded to Beacon DepositContract
    /// @param _feeDistributorAddress address of FeeDistributor instance that was associated with the client deposit
    event P2pOrgUnlimitedEthDepositor__Eth2DepositCompleted(
        address indexed _feeDistributorAddress
    );

    /// @notice Emits when some (but not all) of the available ETH has been forwarded to Beacon DepositContract
    /// @param _feeDistributorAddress address of FeeDistributor instance that was associated with the client deposit
    event P2pOrgUnlimitedEthDepositor__Eth2DepositInProgress(
        address indexed _feeDistributorAddress
    );

    /// @notice Emits when P2P rejects the service for a given FeeDistributor client instance.
    /// The client can get a full refund immediately in this case.
    /// @param _feeDistributorAddress address of FeeDistributor instance that was associated with the client deposit
    /// @param _reason optional reason why P2P decided not to provide service
    event P2pOrgUnlimitedEthDepositor__ServiceRejected(
        address indexed _feeDistributorAddress,
        string _reason
    );

    /// @notice Send unlimited amount of ETH along with the fixed terms of staking service
    /// Callable by clients
    /// @param _referenceFeeDistributor address of FeeDistributor template that determines the terms of staking service
    /// @param _clientConfig address and basis points (percent * 100) of the client
    /// @param _referrerConfig address and basis points (percent * 100) of the referrer.
    /// @return feeDistributorInstance client FeeDistributor instance corresponding to the passed template
    function addEth(
        address _referenceFeeDistributor,
        FeeRecipient calldata _clientConfig,
        FeeRecipient calldata _referrerConfig
    ) external payable returns(address feeDistributorInstance);

    /// @notice Reject the service for a given FeeDistributor client instance.
    /// @dev Allows the client to avoid waiting for expiration to get a refund.
    /// @dev Can be helpful if the client made a mistake while adding ETH.
    /// @dev Callable by P2P
    /// @param _feeDistributorInstance client FeeDistributor instance corresponding to the passed template
    /// @param _reason optional reason why P2P decided not to provide service
    function rejectService(
        address _feeDistributorInstance,
        string calldata _reason
    ) external;

    /// @notice refund the unused for staking ETH after the expiration timestamp.
    /// If not called, all multiples of 32 ETH will be used for staking eventually.
    /// @param _feeDistributorInstance client FeeDistributor instance that has non-zero ETH amount (can be checked by `depositAmount`)
    function refund(address _feeDistributorInstance) external;

    /// @notice Send ETH to ETH2 DepositContract on behalf of the client. Callable by P2P
    /// @param _feeDistributorInstance user FeeDistributor instance that determines the terms of staking service
    /// @param _pubkeys BLS12-381 public keys
    /// @param _signatures BLS12-381 signatures
    /// @param _depositDataRoots SHA-256 hashes of the SSZ-encoded DepositData objects
    function makeBeaconDeposit(
        address _feeDistributorInstance,
        bytes[] calldata _pubkeys,
        bytes[] calldata _signatures,
        bytes32[] calldata _depositDataRoots
    ) external;

    /// @notice Returns the total contract ETH balance in wei
    /// @return uint256 total contract ETH balance in wei
    function totalBalance() external view returns (uint256);

    /// @notice Returns the amount of ETH in wei that is associated with a client FeeDistributor instance
    /// @param _feeDistributorInstance address of client FeeDistributor instance
    /// @return uint112 amount of ETH in wei
    function depositAmount(address _feeDistributorInstance) external view returns (uint112);

    /// @notice Returns the block timestamp after which the client will be able to get a refund
    /// @param _feeDistributorInstance address of client FeeDistributor instance
    /// @return uint40 block timestamp
    function depositExpiration(address _feeDistributorInstance) external view returns (uint40);

    /// @notice Returns the status of the deposit
    /// @param _feeDistributorInstance address of client FeeDistributor instance
    /// @return ClientDepositStatus status
    function depositStatus(address _feeDistributorInstance) external view returns (ClientDepositStatus);
}

File 11 of 26 : P2pStructs.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../feeDistributor/IFeeDistributor.sol";

/// @dev 256 bit struct
/// @member basisPoints basis points (percent * 100) of EL rewards that should go to the recipient
/// @member recipient address of the recipient
struct FeeRecipient {
    uint96 basisPoints;
    address payable recipient;
}

/// @dev 256 bit struct
/// @member depositedCount the number of deposited validators
/// @member exitedCount the number of validators requested to exit
/// @member collateralReturnedValue amount of ETH returned to the client to cover the collaterals
/// @member cooldownUntil timestamp after which it will be possible to withdraw ignoring the client's revert on ETH receive
struct ValidatorData {
    uint32 depositedCount;
    uint32 exitedCount;
    uint112 collateralReturnedValue;
    uint80 cooldownUntil;
}

/// @dev status of the client deposit
/// @member None default status indicating that no ETH is waiting to be forwarded to Beacon DepositContract
/// @member EthAdded client added ETH
/// @member BeaconDepositInProgress P2P has forwarded some (but not all) ETH to Beacon DepositContract
/// If all ETH has been forwarded, the status will be None.
/// @member ServiceRejected P2P has rejected the service for a given FeeDistributor instance
// The client can get a refund immediately.
enum ClientDepositStatus {
    None,
    EthAdded,
    BeaconDepositInProgress,
    ServiceRejected
}

/// @dev 256 bit struct
/// @member amount amount of ETH in wei to be used for an ETH2 deposit corresponding to a particular FeeDistributor instance
/// @member expiration block timestamp after which the client will be able to get a refund
/// @member status deposit status
/// @member reservedForFutureUse unused space making up to 256 bit
struct ClientDeposit {
    uint112 amount;
    uint40 expiration;
    ClientDepositStatus status;
    uint96 reservedForFutureUse;
}

File 12 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity 0.8.10;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 13 of 26 : OwnableTokenRecoverer.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]>
// SPDX-License-Identifier: MIT

// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol
pragma solidity 0.8.10;

import "./TokenRecoverer.sol";
import "../access/OwnableBase.sol";

/// @title Token Recoverer with public functions callable by assetAccessingAddress
/// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract
abstract contract OwnableTokenRecoverer is TokenRecoverer, OwnableBase {
    // Functions

    /**
     * @notice transfer an ERC20 token from this contract
     * @dev `SafeERC20.safeTransfer` doesn't always return a bool
     * as it performs an internal `require` check
     * @param _token address of the ERC20 token
     * @param _recipient address to transfer the tokens to
     * @param _amount amount of tokens to transfer
     */
    function transferERC20(
        address _token,
        address _recipient,
        uint256 _amount
    ) external onlyOwner {
        _transferERC20(_token, _recipient, _amount);
    }

    /**
     * @notice transfer an ERC721 token from this contract
     * @dev `IERC721.safeTransferFrom` doesn't always return a bool
     * as it performs an internal `require` check
     * @param _token address of the ERC721 token
     * @param _recipient address to transfer the token to
     * @param _tokenId id of the individual token
     */
    function transferERC721(
        address _token,
        address _recipient,
        uint256 _tokenId
    ) external onlyOwner {
        _transferERC721(_token, _recipient, _tokenId);
    }

    /**
     * @notice transfer an ERC1155 token from this contract
     * @dev see `AssetRecoverer`
     * @param _token address of the ERC1155 token that is being recovered
     * @param _recipient address to transfer the token to
     * @param _tokenId id of the individual token to transfer
     * @param _amount amount of tokens to transfer
     * @param _data data to transfer along
     */
    function transferERC1155(
        address _token,
        address _recipient,
        uint256 _tokenId,
        uint256 _amount,
        bytes calldata _data
    ) external onlyOwner {
        _transferERC1155(_token, _recipient, _tokenId, _amount, _data);
    }
}

File 14 of 26 : AssetRecoverer.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]>
// SPDX-License-Identifier: MIT

// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol
pragma solidity 0.8.10;

import "./TokenRecoverer.sol";

/**
* @notice could not transfer ether
* @param _recipient address to transfer ether to
* @param _amount amount of ether to transfer
*/
error AssetRecoverer__TransferFailed(address _recipient, uint256 _amount);


/// @title Asset Recoverer
/// @notice Recover ether, ERC20, ERC721 and ERC1155 from a derived contract
abstract contract AssetRecoverer is TokenRecoverer {
    event EtherTransferred(address indexed _recipient, uint256 _amount);

    /**
     * @notice transfers ether from this contract
     * @dev using `address.call` is safer to transfer to other contracts
     * @param _recipient address to transfer ether to
     * @param _amount amount of ether to transfer
     */
    function _transferEther(address _recipient, uint256 _amount) internal virtual burnDisallowed(_recipient) {
        (bool success, ) = _recipient.call{value: _amount}("");
        if (!success) {
            revert AssetRecoverer__TransferFailed(_recipient, _amount);
        }
        emit EtherTransferred(_recipient, _amount);
    }
}

File 15 of 26 : TokenRecoverer.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, Lido <[email protected]>
// SPDX-License-Identifier: MIT

// https://github.com/lidofinance/lido-otc-seller/blob/master/contracts/lib/AssetRecoverer.sol
pragma solidity 0.8.10;

import {IERC20} from "../@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "../@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC1155} from "../@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {SafeERC20} from "../@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
* @notice prevents burn for transfer functions
* @dev _recipient should not be a zero address
*/
error TokenRecoverer__NoBurn();


/// @title Token Recoverer
/// @notice Recover ERC20, ERC721 and ERC1155 from a derived contract
abstract contract TokenRecoverer {
    using SafeERC20 for IERC20;

    event ERC20Transferred(address indexed _token, address indexed _recipient, uint256 _amount);
    event ERC721Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId);
    event ERC1155Transferred(address indexed _token, address indexed _recipient, uint256 _tokenId, uint256 _amount, bytes _data);

    /**
     * @notice prevents burn for transfer functions
     * @dev checks for zero address and reverts if true
     * @param _recipient address of the transfer recipient
     */
    modifier burnDisallowed(address _recipient) {
        if (_recipient == address(0)) {
            revert TokenRecoverer__NoBurn();
        }
        _;
    }

    /**
     * @notice transfer an ERC20 token from this contract
     * @dev `SafeERC20.safeTransfer` doesn't always return a bool
     * as it performs an internal `require` check
     * @param _token address of the ERC20 token
     * @param _recipient address to transfer the tokens to
     * @param _amount amount of tokens to transfer
     */
    function _transferERC20(
        address _token,
        address _recipient,
        uint256 _amount
    ) internal virtual burnDisallowed(_recipient) {
        IERC20(_token).safeTransfer(_recipient, _amount);
        emit ERC20Transferred(_token, _recipient, _amount);
    }

    /**
     * @notice transfer an ERC721 token from this contract
     * @dev `IERC721.safeTransferFrom` doesn't always return a bool
     * as it performs an internal `require` check
     * @param _token address of the ERC721 token
     * @param _recipient address to transfer the token to
     * @param _tokenId id of the individual token
     */
    function _transferERC721(
        address _token,
        address _recipient,
        uint256 _tokenId
    ) internal virtual burnDisallowed(_recipient) {
        IERC721(_token).transferFrom(address(this), _recipient, _tokenId);
        emit ERC721Transferred(_token, _recipient, _tokenId);
    }

    /**
     * @notice transfer an ERC1155 token from this contract
     * @dev `IERC1155.safeTransferFrom` doesn't always return a bool
     * as it performs an internal `require` check
     * @param _token address of the ERC1155 token that is being recovered
     * @param _recipient address to transfer the token to
     * @param _tokenId id of the individual token to transfer
     * @param _amount amount of tokens to transfer
     * @param _data data to transfer along
     */
    function _transferERC1155(
        address _token,
        address _recipient,
        uint256 _tokenId,
        uint256 _amount,
        bytes calldata _data
    ) internal virtual burnDisallowed(_recipient) {
        IERC1155(_token).safeTransferFrom(address(this), _recipient, _tokenId, _amount, _data);
        emit ERC1155Transferred(_token, _recipient, _tokenId, _amount, _data);
    }
}

File 16 of 26 : OwnableBase.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "../@openzeppelin/contracts/utils/Context.sol";
import "./IOwnable.sol";

/**
* @notice Throws if called by any account other than the owner.
* @param _caller address of the caller
* @param _owner address of the owner
*/
error OwnableBase__CallerNotOwner(address _caller, address _owner);

/**
 * @dev minimalistic version of OpenZeppelin's Ownable.
 * The owner is abstract and is not persisted in storage.
 * Needs to be overridden in a child contract.
 */
abstract contract OwnableBase is Context, IOwnable {

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        address caller = _msgSender();
        address currentOwner = owner();

        if (currentOwner != caller) {
            revert OwnableBase__CallerNotOwner(caller, currentOwner);
        }
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     * Needs to be overridden in a child contract.
     */
    function owner() public view virtual override returns (address);
}

File 17 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity 0.8.10;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 18 of 26 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity 0.8.10;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 19 of 26 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity 0.8.10;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 20 of 26 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity 0.8.10;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 21 of 26 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity 0.8.10;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 22 of 26 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity 0.8.10;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 23 of 26 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity 0.8.10;

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

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

File 24 of 26 : IOwnable.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

/**
 * @dev External interface of Ownable.
 */
interface IOwnable {
    /**
     * @dev Returns the address of the current owner.
     */
    function owner() external view returns (address);
}

File 25 of 26 : Ownable2Step.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>, OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./Ownable.sol";

/**
* @notice caller must be pendingOwner
*/
error Ownable2Step__CallerNotNewOwner();

/**
* @notice new owner address should be different from the current owner
*/
error Ownable2Step__NewOwnerShouldNotBeCurrentOwner();

/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private s_pendingOwner;

    /**
     * @dev Emits in transferOwnership (start of the transfer)
     * @param _previousOwner address of the previous owner
     * @param _newOwner address of the new owner
     */
    event OwnershipTransferStarted(address indexed _previousOwner, address indexed _newOwner);

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return s_pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        address currentOwner = owner();
        if (newOwner == currentOwner) {
            revert Ownable2Step__NewOwnerShouldNotBeCurrentOwner();
        }

        s_pendingOwner = newOwner;
        emit OwnershipTransferStarted(currentOwner, newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete s_pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() external {
        address sender = _msgSender();
        if (pendingOwner() != sender) {
            revert Ownable2Step__CallerNotNewOwner();
        }
        _transferOwnership(sender);
    }
}

File 26 of 26 : IOwnableWithOperator.sol
// SPDX-FileCopyrightText: 2023 P2P Validator <[email protected]>
// SPDX-License-Identifier: MIT

pragma solidity 0.8.10;

import "./IOwnable.sol";

/**
 * @dev Ownable with an additional role of operator
 */
interface IOwnableWithOperator is IOwnable {
    /**
     * @dev Returns the current operator.
     */
    function operator() external view returns (address);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint96","name":"_defaultClientBasisPoints","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"Access__AddressNeitherOperatorNorOwner","type":"error"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"}],"name":"Access__SameOperator","type":"error"},{"inputs":[],"name":"Access__ZeroNewOperator","type":"error"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"AssetRecoverer__TransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"}],"name":"FeeDistributorFactory__CallerNotAuthorized","type":"error"},{"inputs":[{"internalType":"uint96","name":"_defaultClientBasisPoints","type":"uint96"}],"name":"FeeDistributorFactory__InvalidDefaultClientBasisPoints","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributorFactory__NotFeeDistributor","type":"error"},{"inputs":[{"internalType":"address","name":"_passedAddress","type":"address"}],"name":"FeeDistributorFactory__NotP2pEth2Depositor","type":"error"},{"inputs":[],"name":"FeeDistributorFactory__ReferenceFeeDistributorNotSet","type":"error"},{"inputs":[],"name":"Ownable2Step__CallerNotNewOwner","type":"error"},{"inputs":[],"name":"Ownable2Step__NewOwnerShouldNotBeCurrentOwner","type":"error"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"OwnableBase__CallerNotOwner","type":"error"},{"inputs":[],"name":"TokenRecoverer__NoBurn","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ERC1155Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"ERC20Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ERC721Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"EtherTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"_defaultClientBasisPoints","type":"uint96"}],"name":"FeeDistributorFactory__DefaultClientBasisPointsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_newFeeDistributorAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_clientAddress","type":"address"},{"indexed":true,"internalType":"address","name":"_referenceFeeDistributor","type":"address"},{"indexed":false,"internalType":"uint96","name":"_clientBasisPoints","type":"uint96"}],"name":"FeeDistributorFactory__FeeDistributorCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_p2pEth2Depositor","type":"address"}],"name":"FeeDistributorFactory__P2pEth2DepositorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOperator","type":"address"},{"indexed":true,"internalType":"address","name":"_newOperator","type":"address"}],"name":"OperatorChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"_newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_client","type":"address"}],"name":"allClientFeeDistributors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allFeeDistributors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOperator","type":"address"}],"name":"changeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"checkOperatorOrOwner","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"checkP2pEth2Depositor","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"check_Operator_Owner_P2pEth2Depositor","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referenceFeeDistributor","type":"address"},{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct FeeRecipient","name":"_clientConfig","type":"tuple"},{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct FeeRecipient","name":"_referrerConfig","type":"tuple"}],"name":"createFeeDistributor","outputs":[{"internalType":"address","name":"newFeeDistributorAddress","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultClientBasisPoints","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dismissOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"p2pEth2Depositor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_referenceFeeDistributor","type":"address"},{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct FeeRecipient","name":"_clientConfig","type":"tuple"},{"components":[{"internalType":"uint96","name":"basisPoints","type":"uint96"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct FeeRecipient","name":"_referrerConfig","type":"tuple"}],"name":"predictFeeDistributorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"_defaultClientBasisPoints","type":"uint96"}],"name":"setDefaultClientBasisPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_p2pEth2Depositor","type":"address"}],"name":"setP2pEth2Depositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"transferERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620033f0380380620033f0833981810160405281019062000037919062000277565b620000576200004b6200011f60201b60201c565b6200012760201b60201c565b612710816bffffffffffffffffffffffff1610620000ae57806040517f67207ebd000000000000000000000000000000000000000000000000000000008152600401620000a59190620002ba565b60405180910390fd5b80600260146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f16ca7427ef4cff132e9bd0645f341aeb72504918fa8de41275d7687062580ac081604051620001109190620002ba565b60405180910390a150620002d7565b600033905090565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905562000162816200016560201b620015911760201c565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b60006bffffffffffffffffffffffff82169050919050565b62000251816200022e565b81146200025d57600080fd5b50565b600081519050620002718162000246565b92915050565b60006020828403121562000290576200028f62000229565b5b6000620002a08482850162000260565b91505092915050565b620002b4816200022e565b82525050565b6000602082019050620002d16000830184620002a9565b92915050565b61310980620002e76000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c8063759858bd116100c3578063dbecc6161161007c578063dbecc6161461034c578063e05f977414610368578063e30c397814610386578063ea7a8b51146103a4578063f25aaa31146103d4578063f2fde38b146103f25761014d565b8063759858bd146102c457806379ba5097146102e05780638da5cb5b146102ea5780639db5dbe414610308578063b83802f514610324578063d27011bc1461032e5761014d565b80631b54769e116101155780631b54769e146101f2578063262bf3761461020e578063570ca7351461022a5780636b439fa6146102485780636cc856ae146102645780637143ead0146102945761014d565b806301ffc9a71461015257806305b1137b1461018257806306394c9b1461019e57806310de2dff146101ba5780631aca6376146101d6575b600080fd5b61016c6004803603810190610167919061246a565b61040e565b60405161017991906124b2565b60405180910390f35b61019c60048036038101906101979190612561565b610488565b005b6101b860048036038101906101b391906125a1565b610522565b005b6101d460048036038101906101cf91906125a1565b6106b4565b005b6101f060048036038101906101eb91906125ce565b610749565b005b61020c600480360381019061020791906125a1565b6107e5565b005b610228600480360381019061022391906125a1565b6107f1565b005b61023261096f565b60405161023f9190612630565b60405180910390f35b610262600480360381019061025d919061268f565b61097e565b005b61027e600480360381019061027991906127ff565b610ac9565b60405161028b9190612630565b60405180910390f35b6102ae60048036038101906102a991906125a1565b610b44565b6040516102bb9190612910565b60405180910390f35b6102de60048036038101906102d991906125a1565b610c11565b005b6102e8610d32565b005b6102f2610db6565b6040516102ff9190612630565b60405180910390f35b610322600480360381019061031d91906125ce565b610dc5565b005b61032c610e61565b005b610336610ef9565b6040516103439190612630565b60405180910390f35b61036660048036038101906103619190612997565b610f23565b005b610370610fc5565b60405161037d9190612a40565b60405180910390f35b61038e610fe7565b60405161039b9190612630565b60405180910390f35b6103be60048036038101906103b991906127ff565b611011565b6040516103cb9190612630565b60405180910390f35b6103dc611366565b6040516103e99190612910565b60405180910390f35b61040c600480360381019061040791906125a1565b6113f4565b005b60007f1e9abf3f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610481575061048082611655565b5b9050919050565b60006104926116bf565b9050600061049e610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105125781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610509929190612a5b565b60405180910390fd5b61051c84846116c7565b50505050565b600061052c6116bf565b90506000610538610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105ac5781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016105a3929190612a5b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610613576040517f6cca850000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156106a657826040517fb16f970500000000000000000000000000000000000000000000000000000000815260040161069d9190612630565b60405180910390fd5b6106af83611833565b505050565b8073ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461074657806040517f6a9cd8d300000000000000000000000000000000000000000000000000000000815260040161073d9190612630565b60405180910390fd5b50565b60006107536116bf565b9050600061075f610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146107d35781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016107ca929190612a5b565b60405180910390fd5b6107de8585856118f9565b5050505050565b6107ee81611a3b565b50565b60006107fb6116bf565b90506000610807610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461087b5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610872929190612a5b565b60405180910390fd5b6108a5837fa14db5c700000000000000000000000000000000000000000000000000000000611b58565b6108e657826040517f6a9cd8d30000000000000000000000000000000000000000000000000000000081526004016108dd9190612630565b60405180910390fd5b82600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167f3b3a306a1063967a354a4bdf142b2687bd66b44fa554a7fdb72c860b0a4979e560405160405180910390a2505050565b6000610979611b7d565b905090565b60006109886116bf565b90506000610994610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a085781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016109ff929190612a5b565b60405180910390fd5b612710836bffffffffffffffffffffffff1610610a5c57826040517f67207ebd000000000000000000000000000000000000000000000000000000008152600401610a539190612a40565b60405180910390fd5b82600260146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f16ca7427ef4cff132e9bd0645f341aeb72504918fa8de41275d7687062580ac083604051610abc9190612a40565b60405180910390a1505050565b60008083600001516bffffffffffffffffffffffff161415610b2857600260149054906101000a90046bffffffffffffffffffffffff1683600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250505b610b3b84610b368585611ba7565b611bda565b90509392505050565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015610c0557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610bbb575b50505050509050919050565b6000610c1b610db6565b90506000610c2761096f565b90508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610c9157508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610ceb57508273ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15610d2d57826040517f0fc9a8f5000000000000000000000000000000000000000000000000000000008152600401610d249190612630565b60405180910390fd5b505050565b6000610d3c6116bf565b90508073ffffffffffffffffffffffffffffffffffffffff16610d5d610fe7565b73ffffffffffffffffffffffffffffffffffffffff1614610daa576040517f4b5dfa7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610db381611bef565b50565b6000610dc0611c20565b905090565b6000610dcf6116bf565b90506000610ddb610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610e4f5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610e46929190612a5b565b60405180910390fd5b610e5a858585611c49565b5050505050565b6000610e6b6116bf565b90506000610e77610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610eeb5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610ee2929190612a5b565b60405180910390fd5b610ef56000611833565b5050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000610f2d6116bf565b90506000610f39610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610fad5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610fa4929190612a5b565b60405180910390fd5b610fbb888888888888611d47565b5050505050505050565b6000600260149054906101000a90046bffffffffffffffffffffffff16905090565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061101c33610c11565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415611083576040517f3a19005f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad847f9967e99b00000000000000000000000000000000000000000000000000000000611b58565b6110ee57836040517fff92625f0000000000000000000000000000000000000000000000000000000081526004016110e59190612630565b60405180910390fd5b600083600001516bffffffffffffffffffffffff16141561114c57600260149054906101000a90046bffffffffffffffffffffffff1683600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250505b61115f8461115a8585611ba7565b611e98565b905060008190508073ffffffffffffffffffffffffffffffffffffffff1663f818e09385856040518363ffffffff1660e01b81526004016111a1929190612b3e565b600060405180830381600087803b1580156111bb57600080fd5b505af11580156111cf573d6000803e3d6000fd5b5050505060046000856020015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506005829080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff16846020015173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f823fa26ee04d357b943057dc9a7d14011cdfccc7942d1c3583f21142b338e90987600001516040516113569190612a40565b60405180910390a4509392505050565b606060058054806020026020016040519081016040528092919081815260200182805480156113ea57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116113a0575b5050505050905090565b60006113fe6116bf565b9050600061140a610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461147e5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401611475929190612a5b565b60405180910390fd5b6000611488610db6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114f0576040517f4310d9f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b600033905090565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561172f576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff168360405161175590612b98565b60006040518083038185875af1925050503d8060008114611792576040519150601f19603f3d011682016040523d82523d6000602084013e611797565b606091505b50509050806117df5783836040517f7304e9270000000000000000000000000000000000000000000000000000000081526004016117d6929190612bbc565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f2bd8874aee0f667380057c67e3a812157e4b7649b244d6fcbc9094a9a1f7ee1d846040516118259190612be5565b60405180910390a250505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167fd58299b712891143e76310d5e664c4203c940a67db37cf856bdaa3c5c76a802c60405160405180910390a35050565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611961576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166323b872dd3085856040518463ffffffff1660e01b815260040161199e93929190612c00565b600060405180830381600087803b1580156119b857600080fd5b505af11580156119cc573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fcd68d836931d28b26c81fd06a68b603542d9b3a2fd1ba1c1bd30c9e2e5f4e6eb84604051611a2d9190612be5565b60405180910390a350505050565b6000611a45610db6565b90506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611b0d57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015611b0c57508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b5b15611b53578281836040517ff8864219000000000000000000000000000000000000000000000000000000008152600401611b4a93929190612c37565b60405180910390fd5b505050565b6000611b6383611f6f565b8015611b755750611b748383611fbc565b5b905092915050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008282604051602001611bbc929190612b3e565b60405160208183030381529060405280519060200120905092915050565b6000611be783833061207b565b905092915050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055611c1d81611591565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611cb1576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cdc83838673ffffffffffffffffffffffffffffffffffffffff166120fb9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fe8de91d538b06154a2c48315768c5046f47e127d7fd3f726fd85cc723f29b05284604051611d399190612be5565b60405180910390a350505050565b84600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611daf576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff1663f242432a3088888888886040518763ffffffff1660e01b8152600401611df296959493929190612cbb565b600060405180830381600087803b158015611e0c57600080fd5b505af1158015611e20573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f1c84289b4389ba8251b26974eaec89409eb21a1198ca5eb281c86388da2e778b87878787604051611e879493929190612d17565b60405180910390a350505050505050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528360601b60148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f5915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f69576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6090612db4565b60405180910390fd5b92915050565b6000611f9b827f01ffc9a700000000000000000000000000000000000000000000000000000000611fbc565b8015611fb55750611fb38263ffffffff60e01b611fbc565b155b9050919050565b6000806301ffc9a760e01b83604051602401611fd89190612de3565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d91506000519050828015612063575060208210155b801561206f5750600081115b94505050505092915050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528460601b60148201527f5af43d82803e903d91602b57fd5bf3ff0000000000000000000000000000000060288201528260601b603882015283604c82015260378120606c820152605560378201209150509392505050565b61217c8363a9059cbb60e01b848460405160240161211a929190612bbc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612181565b505050565b60006121e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122489092919063ffffffff16565b905060008151111561224357808060200190518101906122039190612e2a565b612242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223990612ec9565b60405180910390fd5b5b505050565b60606122578484600085612260565b90509392505050565b6060824710156122a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229c90612f5b565b60405180910390fd5b6122ae85612374565b6122ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e490612fc7565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516123169190613056565b60006040518083038185875af1925050503d8060008114612353576040519150601f19603f3d011682016040523d82523d6000602084013e612358565b606091505b5091509150612368828286612397565b92505050949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156123a7578290506123f7565b6000835111156123ba5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123ee91906130b1565b60405180910390fd5b9392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61244781612412565b811461245257600080fd5b50565b6000813590506124648161243e565b92915050565b6000602082840312156124805761247f612408565b5b600061248e84828501612455565b91505092915050565b60008115159050919050565b6124ac81612497565b82525050565b60006020820190506124c760008301846124a3565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006124f8826124cd565b9050919050565b612508816124ed565b811461251357600080fd5b50565b600081359050612525816124ff565b92915050565b6000819050919050565b61253e8161252b565b811461254957600080fd5b50565b60008135905061255b81612535565b92915050565b6000806040838503121561257857612577612408565b5b600061258685828601612516565b92505060206125978582860161254c565b9150509250929050565b6000602082840312156125b7576125b6612408565b5b60006125c584828501612516565b91505092915050565b6000806000606084860312156125e7576125e6612408565b5b60006125f586828701612516565b935050602061260686828701612516565b92505060406126178682870161254c565b9150509250925092565b61262a816124ed565b82525050565b60006020820190506126456000830184612621565b92915050565b60006bffffffffffffffffffffffff82169050919050565b61266c8161264b565b811461267757600080fd5b50565b60008135905061268981612663565b92915050565b6000602082840312156126a5576126a4612408565b5b60006126b38482850161267a565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61270a826126c1565b810181811067ffffffffffffffff82111715612729576127286126d2565b5b80604052505050565b600061273c6123fe565b90506127488282612701565b919050565b6000612758826124cd565b9050919050565b6127688161274d565b811461277357600080fd5b50565b6000813590506127858161275f565b92915050565b6000604082840312156127a1576127a06126bc565b5b6127ab6040612732565b905060006127bb8482850161267a565b60008301525060206127cf84828501612776565b60208301525092915050565b600080fd5b6000604082840312156127f6576127f56127db565b5b81905092915050565b600080600060a0848603121561281857612817612408565b5b600061282686828701612516565b93505060206128378682870161278b565b9250506060612848868287016127e0565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612887816124ed565b82525050565b6000612899838361287e565b60208301905092915050565b6000602082019050919050565b60006128bd82612852565b6128c7818561285d565b93506128d28361286e565b8060005b838110156129035781516128ea888261288d565b97506128f5836128a5565b9250506001810190506128d6565b5085935050505092915050565b6000602082019050818103600083015261292a81846128b2565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261295757612956612932565b5b8235905067ffffffffffffffff81111561297457612973612937565b5b6020830191508360018202830111156129905761298f61293c565b5b9250929050565b60008060008060008060a087890312156129b4576129b3612408565b5b60006129c289828a01612516565b96505060206129d389828a01612516565b95505060406129e489828a0161254c565b94505060606129f589828a0161254c565b935050608087013567ffffffffffffffff811115612a1657612a1561240d565b5b612a2289828a01612941565b92509250509295509295509295565b612a3a8161264b565b82525050565b6000602082019050612a556000830184612a31565b92915050565b6000604082019050612a706000830185612621565b612a7d6020830184612621565b9392505050565b612a8d8161264b565b82525050565b612a9c8161274d565b82525050565b604082016000820151612ab86000850182612a84565b506020820151612acb6020850182612a93565b50505050565b6000612ae0602084018461267a565b905092915050565b6000612af76020840184612776565b905092915050565b60408201612b106000830183612ad1565b612b1d6000850182612a84565b50612b2b6020830183612ae8565b612b386020850182612a93565b50505050565b6000608082019050612b536000830185612aa2565b612b606040830184612aff565b9392505050565b600081905092915050565b50565b6000612b82600083612b67565b9150612b8d82612b72565b600082019050919050565b6000612ba382612b75565b9150819050919050565b612bb68161252b565b82525050565b6000604082019050612bd16000830185612621565b612bde6020830184612bad565b9392505050565b6000602082019050612bfa6000830184612bad565b92915050565b6000606082019050612c156000830186612621565b612c226020830185612621565b612c2f6040830184612bad565b949350505050565b6000606082019050612c4c6000830186612621565b612c596020830185612621565b612c666040830184612621565b949350505050565b600082825260208201905092915050565b82818337600083830152505050565b6000612c9a8385612c6e565b9350612ca7838584612c7f565b612cb0836126c1565b840190509392505050565b600060a082019050612cd06000830189612621565b612cdd6020830188612621565b612cea6040830187612bad565b612cf76060830186612bad565b8181036080830152612d0a818486612c8e565b9050979650505050505050565b6000606082019050612d2c6000830187612bad565b612d396020830186612bad565b8181036040830152612d4c818486612c8e565b905095945050505050565b600082825260208201905092915050565b7f455243313136373a2063726561746532206661696c6564000000000000000000600082015250565b6000612d9e601783612d57565b9150612da982612d68565b602082019050919050565b60006020820190508181036000830152612dcd81612d91565b9050919050565b612ddd81612412565b82525050565b6000602082019050612df86000830184612dd4565b92915050565b612e0781612497565b8114612e1257600080fd5b50565b600081519050612e2481612dfe565b92915050565b600060208284031215612e4057612e3f612408565b5b6000612e4e84828501612e15565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000612eb3602a83612d57565b9150612ebe82612e57565b604082019050919050565b60006020820190508181036000830152612ee281612ea6565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000612f45602683612d57565b9150612f5082612ee9565b604082019050919050565b60006020820190508181036000830152612f7481612f38565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000612fb1601d83612d57565b9150612fbc82612f7b565b602082019050919050565b60006020820190508181036000830152612fe081612fa4565b9050919050565b600081519050919050565b60005b83811015613010578082015181840152602081019050612ff5565b8381111561301f576000848401525b50505050565b600061303082612fe7565b61303a8185612b67565b935061304a818560208601612ff2565b80840191505092915050565b60006130628284613025565b915081905092915050565b600081519050919050565b60006130838261306d565b61308d8185612d57565b935061309d818560208601612ff2565b6130a6816126c1565b840191505092915050565b600060208201905081810360008301526130cb8184613078565b90509291505056fea264697066735822122062a4f3ac8dbe71b43c0e0d734053768751ca8d6c907adfb428a184b51c6b42e264736f6c634300080a00330000000000000000000000000000000000000000000000000000000000002328

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061014d5760003560e01c8063759858bd116100c3578063dbecc6161161007c578063dbecc6161461034c578063e05f977414610368578063e30c397814610386578063ea7a8b51146103a4578063f25aaa31146103d4578063f2fde38b146103f25761014d565b8063759858bd146102c457806379ba5097146102e05780638da5cb5b146102ea5780639db5dbe414610308578063b83802f514610324578063d27011bc1461032e5761014d565b80631b54769e116101155780631b54769e146101f2578063262bf3761461020e578063570ca7351461022a5780636b439fa6146102485780636cc856ae146102645780637143ead0146102945761014d565b806301ffc9a71461015257806305b1137b1461018257806306394c9b1461019e57806310de2dff146101ba5780631aca6376146101d6575b600080fd5b61016c6004803603810190610167919061246a565b61040e565b60405161017991906124b2565b60405180910390f35b61019c60048036038101906101979190612561565b610488565b005b6101b860048036038101906101b391906125a1565b610522565b005b6101d460048036038101906101cf91906125a1565b6106b4565b005b6101f060048036038101906101eb91906125ce565b610749565b005b61020c600480360381019061020791906125a1565b6107e5565b005b610228600480360381019061022391906125a1565b6107f1565b005b61023261096f565b60405161023f9190612630565b60405180910390f35b610262600480360381019061025d919061268f565b61097e565b005b61027e600480360381019061027991906127ff565b610ac9565b60405161028b9190612630565b60405180910390f35b6102ae60048036038101906102a991906125a1565b610b44565b6040516102bb9190612910565b60405180910390f35b6102de60048036038101906102d991906125a1565b610c11565b005b6102e8610d32565b005b6102f2610db6565b6040516102ff9190612630565b60405180910390f35b610322600480360381019061031d91906125ce565b610dc5565b005b61032c610e61565b005b610336610ef9565b6040516103439190612630565b60405180910390f35b61036660048036038101906103619190612997565b610f23565b005b610370610fc5565b60405161037d9190612a40565b60405180910390f35b61038e610fe7565b60405161039b9190612630565b60405180910390f35b6103be60048036038101906103b991906127ff565b611011565b6040516103cb9190612630565b60405180910390f35b6103dc611366565b6040516103e99190612910565b60405180910390f35b61040c600480360381019061040791906125a1565b6113f4565b005b60007f1e9abf3f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610481575061048082611655565b5b9050919050565b60006104926116bf565b9050600061049e610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105125781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610509929190612a5b565b60405180910390fd5b61051c84846116c7565b50505050565b600061052c6116bf565b90506000610538610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146105ac5781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016105a3929190612a5b565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610613576040517f6cca850000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156106a657826040517fb16f970500000000000000000000000000000000000000000000000000000000815260040161069d9190612630565b60405180910390fd5b6106af83611833565b505050565b8073ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461074657806040517f6a9cd8d300000000000000000000000000000000000000000000000000000000815260040161073d9190612630565b60405180910390fd5b50565b60006107536116bf565b9050600061075f610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146107d35781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016107ca929190612a5b565b60405180910390fd5b6107de8585856118f9565b5050505050565b6107ee81611a3b565b50565b60006107fb6116bf565b90506000610807610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461087b5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610872929190612a5b565b60405180910390fd5b6108a5837fa14db5c700000000000000000000000000000000000000000000000000000000611b58565b6108e657826040517f6a9cd8d30000000000000000000000000000000000000000000000000000000081526004016108dd9190612630565b60405180910390fd5b82600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff167f3b3a306a1063967a354a4bdf142b2687bd66b44fa554a7fdb72c860b0a4979e560405160405180910390a2505050565b6000610979611b7d565b905090565b60006109886116bf565b90506000610994610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a085781816040517f078c72590000000000000000000000000000000000000000000000000000000081526004016109ff929190612a5b565b60405180910390fd5b612710836bffffffffffffffffffffffff1610610a5c57826040517f67207ebd000000000000000000000000000000000000000000000000000000008152600401610a539190612a40565b60405180910390fd5b82600260146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f16ca7427ef4cff132e9bd0645f341aeb72504918fa8de41275d7687062580ac083604051610abc9190612a40565b60405180910390a1505050565b60008083600001516bffffffffffffffffffffffff161415610b2857600260149054906101000a90046bffffffffffffffffffffffff1683600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250505b610b3b84610b368585611ba7565b611bda565b90509392505050565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015610c0557602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610bbb575b50505050509050919050565b6000610c1b610db6565b90506000610c2761096f565b90508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610c9157508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b8015610ceb57508273ffffffffffffffffffffffffffffffffffffffff16600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614155b15610d2d57826040517f0fc9a8f5000000000000000000000000000000000000000000000000000000008152600401610d249190612630565b60405180910390fd5b505050565b6000610d3c6116bf565b90508073ffffffffffffffffffffffffffffffffffffffff16610d5d610fe7565b73ffffffffffffffffffffffffffffffffffffffff1614610daa576040517f4b5dfa7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610db381611bef565b50565b6000610dc0611c20565b905090565b6000610dcf6116bf565b90506000610ddb610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610e4f5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610e46929190612a5b565b60405180910390fd5b610e5a858585611c49565b5050505050565b6000610e6b6116bf565b90506000610e77610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610eeb5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610ee2929190612a5b565b60405180910390fd5b610ef56000611833565b5050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000610f2d6116bf565b90506000610f39610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610fad5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401610fa4929190612a5b565b60405180910390fd5b610fbb888888888888611d47565b5050505050505050565b6000600260149054906101000a90046bffffffffffffffffffffffff16905090565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600061101c33610c11565b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415611083576040517f3a19005f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad847f9967e99b00000000000000000000000000000000000000000000000000000000611b58565b6110ee57836040517fff92625f0000000000000000000000000000000000000000000000000000000081526004016110e59190612630565b60405180910390fd5b600083600001516bffffffffffffffffffffffff16141561114c57600260149054906101000a90046bffffffffffffffffffffffff1683600001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff16815250505b61115f8461115a8585611ba7565b611e98565b905060008190508073ffffffffffffffffffffffffffffffffffffffff1663f818e09385856040518363ffffffff1660e01b81526004016111a1929190612b3e565b600060405180830381600087803b1580156111bb57600080fd5b505af11580156111cf573d6000803e3d6000fd5b5050505060046000856020015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506005829080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508473ffffffffffffffffffffffffffffffffffffffff16846020015173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f823fa26ee04d357b943057dc9a7d14011cdfccc7942d1c3583f21142b338e90987600001516040516113569190612a40565b60405180910390a4509392505050565b606060058054806020026020016040519081016040528092919081815260200182805480156113ea57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116113a0575b5050505050905090565b60006113fe6116bf565b9050600061140a610db6565b90508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461147e5781816040517f078c7259000000000000000000000000000000000000000000000000000000008152600401611475929190612a5b565b60405180910390fd5b6000611488610db6565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614156114f0576040517f4310d9f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b600033905090565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561172f576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008373ffffffffffffffffffffffffffffffffffffffff168360405161175590612b98565b60006040518083038185875af1925050503d8060008114611792576040519150601f19603f3d011682016040523d82523d6000602084013e611797565b606091505b50509050806117df5783836040517f7304e9270000000000000000000000000000000000000000000000000000000081526004016117d6929190612bbc565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f2bd8874aee0f667380057c67e3a812157e4b7649b244d6fcbc9094a9a1f7ee1d846040516118259190612be5565b60405180910390a250505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167fd58299b712891143e76310d5e664c4203c940a67db37cf856bdaa3c5c76a802c60405160405180910390a35050565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611961576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166323b872dd3085856040518463ffffffff1660e01b815260040161199e93929190612c00565b600060405180830381600087803b1580156119b857600080fd5b505af11580156119cc573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fcd68d836931d28b26c81fd06a68b603542d9b3a2fd1ba1c1bd30c9e2e5f4e6eb84604051611a2d9190612be5565b60405180910390a350505050565b6000611a45610db6565b90506000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161480611b0d57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015611b0c57508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b5b15611b53578281836040517ff8864219000000000000000000000000000000000000000000000000000000008152600401611b4a93929190612c37565b60405180910390fd5b505050565b6000611b6383611f6f565b8015611b755750611b748383611fbc565b5b905092915050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008282604051602001611bbc929190612b3e565b60405160208183030381529060405280519060200120905092915050565b6000611be783833061207b565b905092915050565b600160006101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055611c1d81611591565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b81600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611cb1576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611cdc83838673ffffffffffffffffffffffffffffffffffffffff166120fb9092919063ffffffff16565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fe8de91d538b06154a2c48315768c5046f47e127d7fd3f726fd85cc723f29b05284604051611d399190612be5565b60405180910390a350505050565b84600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611daf576040517fa8cefabd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff1663f242432a3088888888886040518763ffffffff1660e01b8152600401611df296959493929190612cbb565b600060405180830381600087803b158015611e0c57600080fd5b505af1158015611e20573d6000803e3d6000fd5b505050508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f1c84289b4389ba8251b26974eaec89409eb21a1198ca5eb281c86388da2e778b87878787604051611e879493929190612d17565b60405180910390a350505050505050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528360601b60148201527f5af43d82803e903d91602b57fd5bf300000000000000000000000000000000006028820152826037826000f5915050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611f69576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f6090612db4565b60405180910390fd5b92915050565b6000611f9b827f01ffc9a700000000000000000000000000000000000000000000000000000000611fbc565b8015611fb55750611fb38263ffffffff60e01b611fbc565b155b9050919050565b6000806301ffc9a760e01b83604051602401611fd89190612de3565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000806000602060008551602087018a617530fa92503d91506000519050828015612063575060208210155b801561206f5750600081115b94505050505092915050565b60006040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081528460601b60148201527f5af43d82803e903d91602b57fd5bf3ff0000000000000000000000000000000060288201528260601b603882015283604c82015260378120606c820152605560378201209150509392505050565b61217c8363a9059cbb60e01b848460405160240161211a929190612bbc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050612181565b505050565b60006121e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122489092919063ffffffff16565b905060008151111561224357808060200190518101906122039190612e2a565b612242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161223990612ec9565b60405180910390fd5b5b505050565b60606122578484600085612260565b90509392505050565b6060824710156122a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229c90612f5b565b60405180910390fd5b6122ae85612374565b6122ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e490612fc7565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516123169190613056565b60006040518083038185875af1925050503d8060008114612353576040519150601f19603f3d011682016040523d82523d6000602084013e612358565b606091505b5091509150612368828286612397565b92505050949350505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b606083156123a7578290506123f7565b6000835111156123ba5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123ee91906130b1565b60405180910390fd5b9392505050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61244781612412565b811461245257600080fd5b50565b6000813590506124648161243e565b92915050565b6000602082840312156124805761247f612408565b5b600061248e84828501612455565b91505092915050565b60008115159050919050565b6124ac81612497565b82525050565b60006020820190506124c760008301846124a3565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006124f8826124cd565b9050919050565b612508816124ed565b811461251357600080fd5b50565b600081359050612525816124ff565b92915050565b6000819050919050565b61253e8161252b565b811461254957600080fd5b50565b60008135905061255b81612535565b92915050565b6000806040838503121561257857612577612408565b5b600061258685828601612516565b92505060206125978582860161254c565b9150509250929050565b6000602082840312156125b7576125b6612408565b5b60006125c584828501612516565b91505092915050565b6000806000606084860312156125e7576125e6612408565b5b60006125f586828701612516565b935050602061260686828701612516565b92505060406126178682870161254c565b9150509250925092565b61262a816124ed565b82525050565b60006020820190506126456000830184612621565b92915050565b60006bffffffffffffffffffffffff82169050919050565b61266c8161264b565b811461267757600080fd5b50565b60008135905061268981612663565b92915050565b6000602082840312156126a5576126a4612408565b5b60006126b38482850161267a565b91505092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61270a826126c1565b810181811067ffffffffffffffff82111715612729576127286126d2565b5b80604052505050565b600061273c6123fe565b90506127488282612701565b919050565b6000612758826124cd565b9050919050565b6127688161274d565b811461277357600080fd5b50565b6000813590506127858161275f565b92915050565b6000604082840312156127a1576127a06126bc565b5b6127ab6040612732565b905060006127bb8482850161267a565b60008301525060206127cf84828501612776565b60208301525092915050565b600080fd5b6000604082840312156127f6576127f56127db565b5b81905092915050565b600080600060a0848603121561281857612817612408565b5b600061282686828701612516565b93505060206128378682870161278b565b9250506060612848868287016127e0565b9150509250925092565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b612887816124ed565b82525050565b6000612899838361287e565b60208301905092915050565b6000602082019050919050565b60006128bd82612852565b6128c7818561285d565b93506128d28361286e565b8060005b838110156129035781516128ea888261288d565b97506128f5836128a5565b9250506001810190506128d6565b5085935050505092915050565b6000602082019050818103600083015261292a81846128b2565b905092915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261295757612956612932565b5b8235905067ffffffffffffffff81111561297457612973612937565b5b6020830191508360018202830111156129905761298f61293c565b5b9250929050565b60008060008060008060a087890312156129b4576129b3612408565b5b60006129c289828a01612516565b96505060206129d389828a01612516565b95505060406129e489828a0161254c565b94505060606129f589828a0161254c565b935050608087013567ffffffffffffffff811115612a1657612a1561240d565b5b612a2289828a01612941565b92509250509295509295509295565b612a3a8161264b565b82525050565b6000602082019050612a556000830184612a31565b92915050565b6000604082019050612a706000830185612621565b612a7d6020830184612621565b9392505050565b612a8d8161264b565b82525050565b612a9c8161274d565b82525050565b604082016000820151612ab86000850182612a84565b506020820151612acb6020850182612a93565b50505050565b6000612ae0602084018461267a565b905092915050565b6000612af76020840184612776565b905092915050565b60408201612b106000830183612ad1565b612b1d6000850182612a84565b50612b2b6020830183612ae8565b612b386020850182612a93565b50505050565b6000608082019050612b536000830185612aa2565b612b606040830184612aff565b9392505050565b600081905092915050565b50565b6000612b82600083612b67565b9150612b8d82612b72565b600082019050919050565b6000612ba382612b75565b9150819050919050565b612bb68161252b565b82525050565b6000604082019050612bd16000830185612621565b612bde6020830184612bad565b9392505050565b6000602082019050612bfa6000830184612bad565b92915050565b6000606082019050612c156000830186612621565b612c226020830185612621565b612c2f6040830184612bad565b949350505050565b6000606082019050612c4c6000830186612621565b612c596020830185612621565b612c666040830184612621565b949350505050565b600082825260208201905092915050565b82818337600083830152505050565b6000612c9a8385612c6e565b9350612ca7838584612c7f565b612cb0836126c1565b840190509392505050565b600060a082019050612cd06000830189612621565b612cdd6020830188612621565b612cea6040830187612bad565b612cf76060830186612bad565b8181036080830152612d0a818486612c8e565b9050979650505050505050565b6000606082019050612d2c6000830187612bad565b612d396020830186612bad565b8181036040830152612d4c818486612c8e565b905095945050505050565b600082825260208201905092915050565b7f455243313136373a2063726561746532206661696c6564000000000000000000600082015250565b6000612d9e601783612d57565b9150612da982612d68565b602082019050919050565b60006020820190508181036000830152612dcd81612d91565b9050919050565b612ddd81612412565b82525050565b6000602082019050612df86000830184612dd4565b92915050565b612e0781612497565b8114612e1257600080fd5b50565b600081519050612e2481612dfe565b92915050565b600060208284031215612e4057612e3f612408565b5b6000612e4e84828501612e15565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b6000612eb3602a83612d57565b9150612ebe82612e57565b604082019050919050565b60006020820190508181036000830152612ee281612ea6565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000612f45602683612d57565b9150612f5082612ee9565b604082019050919050565b60006020820190508181036000830152612f7481612f38565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000612fb1601d83612d57565b9150612fbc82612f7b565b602082019050919050565b60006020820190508181036000830152612fe081612fa4565b9050919050565b600081519050919050565b60005b83811015613010578082015181840152602081019050612ff5565b8381111561301f576000848401525b50505050565b600061303082612fe7565b61303a8185612b67565b935061304a818560208601612ff2565b80840191505092915050565b60006130628284613025565b915081905092915050565b600081519050919050565b60006130838261306d565b61308d8185612d57565b935061309d818560208601612ff2565b6130a6816126c1565b840191505092915050565b600060208201905081810360008301526130cb8184613078565b90509291505056fea264697066735822122062a4f3ac8dbe71b43c0e0d734053768751ca8d6c907adfb428a184b51c6b42e264736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000000000000000000000000000000000000002328

-----Decoded View---------------
Arg [0] : _defaultClientBasisPoints (uint96): 9000

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000002328


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.