// File: contracts/HumanboundToken.sol



// SPDX-License-Identifier: MIT
pragma solidity >=0.8.13;

import "@violetprotocol/erc721extendable/contracts/extensions/metadata/ERC721Metadata.sol";

contract HumanboundToken is ERC721Metadata {
    constructor(
        string memory name_,
        string memory symbol_,
        address extendLogic,
        address approveLogic,
        address getterLogic,
        address onReceiveLogic,
        address transferLogic,
        address hooksLogic
    )
        ERC721Metadata(
            name_,
            symbol_,
            extendLogic,
            approveLogic,
            getterLogic,
            onReceiveLogic,
            transferLogic,
            hooksLogic
        )
    {}
}

// File: @violetprotocol/erc721extendable/contracts/extensions/metadata/ERC721Metadata.sol



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

import "../base/ERC721.sol";

/**
 * @dev ERC721Metadata Extendable contract
 *
 * Constructor arguments take usual `name` and `symbol` arguments for the token
 * with additional extension addresses specifying where the functional logic
 * for each of the token features live which is passed to the Base ERC721 contract
 *
 * Metadata-specific extensions must be extended immediately after deployment by
 * calling the `finaliseERC721MetadataExtending` function.
 *
 */
bytes4 constant ERC721MetadataInterfaceId = 0x5b5e139f;

contract ERC721Metadata is ERC721 {
    constructor(
        string memory name_,
        string memory symbol_,
        address extendLogic,
        address approveLogic,
        address getterLogic,
        address onReceiveLogic,
        address transferLogic,
        address hooksLogic
    ) ERC721(name_, symbol_, extendLogic, approveLogic, getterLogic, onReceiveLogic, transferLogic, hooksLogic) {}

    /**
     * @dev Extends the contract with Metadata-specific functionalities
     *
     * Must be called immediately after contract deployment.
     *
     */
    function finaliseERC721MetadataExtending(
        address metadataGetterLogic,
        address setTokenURILogic,
        address mintLogic,
        address burnLogic
    ) public {
        IExtendLogic self = IExtendLogic(address(this));

        self.extend(metadataGetterLogic);
        self.extend(setTokenURILogic);
        self.extend(mintLogic);
        self.extend(burnLogic);

        IERC165Register(address(this)).registerInterface(ERC721MetadataInterfaceId);
    }
}

// File: @violetprotocol/erc721extendable/contracts/extensions/base/ERC721.sol



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

import "@violetprotocol/extendable/extendable/Extendable.sol";
import "@violetprotocol/extendable/extensions/extend/IExtendLogic.sol";
import { ERC721State, ERC721Storage } from "../../storage/ERC721Storage.sol";

/**
 * @dev Core ERC721 Extendable contract
 *
 * Constructor arguments take usual `name` and `symbol` arguments for the token
 * with additional extension addresses specifying where the functional logic
 * for each of the token features live.
 *
 */
bytes4 constant ERC721InterfaceId = 0x80ac58cd;

contract ERC721 is Extendable {
    constructor(
        string memory name_,
        string memory symbol_,
        address extendLogic,
        address approveLogic,
        address getterLogic,
        address onReceiveLogic,
        address transferLogic,
        address hooksLogic
    ) Extendable(extendLogic) {
        // Set the token name and symbol
        ERC721State storage erc721State = ERC721Storage._getState();
        erc721State._name = name_;
        erc721State._symbol = symbol_;

        // Attempt to extend the contract with core functionality
        // Must use low-level calls since contract has not yet been fully deployed
        (bool extendApproveSuccess, ) = extendLogic.delegatecall(
            abi.encodeWithSignature("extend(address)", approveLogic)
        );
        require(extendApproveSuccess, "failed to initialise approve");

        (bool extendGetterSuccess, ) = extendLogic.delegatecall(
            abi.encodeWithSignature("extend(address)", getterLogic)
        );
        require(extendGetterSuccess, "failed to initialise getter");

        (bool extendOnReceiveSuccess, ) = extendLogic.delegatecall(
            abi.encodeWithSignature("extend(address)", onReceiveLogic)
        );
        require(extendOnReceiveSuccess, "failed to initialise onReceive");

        (bool extendTransferSuccess, ) = extendLogic.delegatecall(
            abi.encodeWithSignature("extend(address)", transferLogic)
        );
        require(extendTransferSuccess, "failed to initialise transfer");

        (bool extendHooksSuccess, ) = extendLogic.delegatecall(abi.encodeWithSignature("extend(address)", hooksLogic));
        require(extendHooksSuccess, "failed to initialise hooks");

        (bool registerInterfaceSuccess, ) = extendLogic.delegatecall(
            abi.encodeWithSignature("registerInterface(bytes4)", ERC721InterfaceId)
        );
        require(registerInterfaceSuccess, "failed to register erc721 interface");
    }
}

// File: @violetprotocol/extendable/extendable/Extendable.sol



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

import "../errors/Errors.sol";
import {CallerState, CallerContextStorage} from "../storage/CallerContextStorage.sol";
import {ExtendableState, ExtendableStorage} from "../storage/ExtendableStorage.sol";

/**
 *  ______  __  __  ______  ______  __   __  _____   ______  ______  __      ______    
 * /\  ___\/\_\_\_\/\__  _\/\  ___\/\ "-.\ \/\  __-./\  __ \/\  == \/\ \    /\  ___\
 * \ \  __\\/_/\_\/\/_/\ \/\ \  __\\ \ \-.  \ \ \/\ \ \  __ \ \  __<\ \ \___\ \  __\
 *  \ \_____\/\_\/\_\ \ \_\ \ \_____\ \_\\"\_\ \____-\ \_\ \_\ \_____\ \_____\ \_____\
 *   \/_____/\/_/\/_/  \/_/  \/_____/\/_/ \/_/\/____/ \/_/\/_/\/_____/\/_____/\/_____/
 *
 *  Core module for the Extendable framework
 *  
 *  Inherit this contract to make your contracts Extendable!
 *
 *  Your contract can perform ad-hoc addition or removal of functions
 *  which allows modularity, re-use, upgrade, and extension of your
 *  deployed contracts. You can make your contract immutable by removing
 *  the ability for it to be extended.
 *
 *  Constructor initialises owner-based permissioning to manage
 *  extending, where only the `owner` can extend the contract.
 *  
 *  You may change this constructor or use extension replacement to
 *  use a different permissioning pattern for your contract.
 *
 *  Requirements:
 *      - ExtendLogic contract must already be deployed
 */
contract Extendable {
    /**
     * @dev Contract constructor initialising the first extension `ExtendLogic`
     *      to allow the contract to be extended.
     *
     * This implementation assumes that the `ExtendLogic` being used also uses
     * an ownership pattern that only allows `owner` to extend the contract.
     * 
     * This constructor sets the owner of the contract and extends itself
     * using the ExtendLogic extension.
     *
     * To change owner or ownership mode, your contract must be extended with the
     * PermissioningLogic extension, giving it access to permissioning management.
     */
    constructor(address extendLogic) {
        // wrap main constructor logic in pre/post fallback hooks for callstack registration
        _beforeFallback();

        // extend extendable contract with the first extension: extend, using itself in low-level call
        (bool extendSuccess, ) = extendLogic.delegatecall(abi.encodeWithSignature("extend(address)", extendLogic));

        // check that initialisation tasks were successful
        require(extendSuccess, "failed to initialise extension");

        _afterFallback();
    }
    
    /**
     * @dev Delegates function calls to the specified `delegatee`.
     *
     * Performs a delegatecall to the `delegatee` with the incoming transaction data
     * as the input and returns the result. The transaction data passed also includes 
     * the function signature which determines what function is attempted to be called.
     * 
     * If the `delegatee` returns a ExtensionNotImplemented error, the `delegatee` is
     * an extension that does not implement the function to be called.
     *
     * Otherwise, the function execution fails/succeeds as determined by the function 
     * logic and returns as such.
     */
    function _delegate(address delegatee) internal virtual returns(bool) {
        _beforeFallback();
        
        bytes memory out;
        (bool success, bytes memory result) = delegatee.delegatecall(msg.data);

        _afterFallback();

        // copy all returndata to `out` once instead of duplicating copy for each conditional branch
        assembly {
            returndatacopy(out, 0, returndatasize())
        }

        // if the delegatecall execution did not succeed
        if (!success) {
            // check if failure was due to an ExtensionNotImplemented error
            if (Errors.catchCustomError(result, ExtensionNotImplemented.selector)) {
                // cleanly return false if error is caught
                return false;
            } else {
                // otherwise revert, passing in copied full returndata
                assembly {
                    revert(out, returndatasize())
                }
            }
        } else {
            // otherwise end execution and return the copied full returndata
            assembly {
                return(out, returndatasize())
            }
        }
    }
    
    /**
     * @dev Internal fallback function logic that attempts to delegate execution
     *      to extension contracts
     *
     * Initially attempts to locate an interfaceId match with a function selector
     * which are extensions that house single functions (singleton extensions)
     *
     * If no implementations are found that match the requested function signature,
     * returns ExtensionNotImplemented error
     */
    function _fallback() internal virtual {
        ExtendableState storage state = ExtendableStorage._getState();

        // if an extension exists that matches in the functionsig
        if (state.extensionContracts[msg.sig] != address(0x0)) {
            // call it
            _delegate(state.extensionContracts[msg.sig]);
        } else {                                                 
            revert ExtensionNotImplemented();
        }
    }

    /**
     * @dev Default fallback function to catch unrecognised selectors.
     *
     * Used in order to perform extension lookups by _fallback().
     *
     * Core fallback logic sandwiched between caller context work.
     */
    fallback() external payable virtual {
        _fallback();
    }
    
    /**
     * @dev Payable fallback function to catch unrecognised selectors with ETH payments.
     *
     * Used in order to perform extension lookups by _fallback().
     */
    receive() external payable virtual {
        _fallback();
    }
    
    /**
     * @dev Virtual hook that is called before _fallback().
     */
    function _beforeFallback() internal virtual {
        CallerState storage state = CallerContextStorage._getState();
        state.callerStack.push(msg.sender);
    }
    
    /**
     * @dev Virtual hook that is called after _fallback().
     */
    function _afterFallback() internal virtual {
        CallerState storage state = CallerContextStorage._getState();
        state.callerStack.pop();
    }
}

// File: @violetprotocol/extendable/extensions/extend/IExtendLogic.sol



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

import "../Extension.sol";
import {ExtendableState, ExtendableStorage} from "../../storage/ExtendableStorage.sol";

/**
 * @dev Interface for ExtendLogic extension
*/
interface IExtendLogic {
    /**
     * @dev Emitted when `extension` is successfully extended
     */
    event Extended(address extension);
    
    /**
     * @dev Emitted when extend() is called and contract owner has not been set
     */
    event OwnerInitialised(address newOwner);

    /**
     * @dev Extend function to extend your extendable contract with new logic
     *
     * Integrate with ExtendableStorage to persist state
     *
     * Sets the known implementor of each function of `extension` as the current call context
     * contract.
     *
     * Emits `Extended` event upon successful extending.
     *
     * Requirements:
     *  - `extension` contract must implement EIP-165.
     *  - `extension` must inherit IExtension
     *  - Must record the `extension` by both its interfaceId and address
     *  - The functions of `extension` must not already be extended by another attached extension
    */
    function extend(address extension) external;

    /**
     * @dev Returns a string-formatted representation of the full interface of the current
     *      Extendable contract as an interface named IExtended
     *
     * Expects `extension.getSolidityInterface` to return interface-compatible syntax with line-separated
     * function declarations including visibility, mutability and returns.
    */
    function getFullInterface() external view returns(string memory fullInterface);

    /**
     * @dev Returns an array of interfaceIds that are currently implemented by the current
     *      Extendable contract
    */
    function getExtensionsInterfaceIds() external view returns(bytes4[] memory);
    /**
     * @dev Returns an array of function selectors that are currently implemented by the current
     *      Extendable contract
    */
    function getExtensionsFunctionSelectors() external view returns(bytes4[] memory);

    /**
     * @dev Returns an array of all extension addresses that are currently attached to the
     *      current Extendable contract
    */
    function getExtensionAddresses() external view returns(address[] memory);
}

/**
 * @dev Abstract Extension for ExtendLogic
*/
abstract contract ExtendExtension is IExtendLogic, Extension {
    /**
     * @dev see {IExtension-getSolidityInterface}
    */
    function getSolidityInterface() override virtual public pure returns(string memory) {
        return  "function extend(address extension) external;\n"
                "function getFullInterface() external view returns(string memory);\n"
                "function getExtensionsInterfaceIds() external view returns(bytes4[] memory);\n"
                "function getExtensionsFunctionSelectors() external view returns(bytes4[] memory);\n"
                "function getExtensionAddresses() external view returns(address[] memory);\n";
    }

    /**
     * @dev see {IExtension-getInterface}
    */
    function getInterface() override virtual public pure returns(Interface[] memory interfaces) {
        interfaces = new Interface[](1);

        bytes4[] memory functions = new bytes4[](5);
        functions[0] = IExtendLogic.extend.selector;
        functions[1] = IExtendLogic.getFullInterface.selector;
        functions[2] = IExtendLogic.getExtensionsInterfaceIds.selector;
        functions[3] = IExtendLogic.getExtensionsFunctionSelectors.selector;
        functions[4] = IExtendLogic.getExtensionAddresses.selector;

        interfaces[0] = Interface(
            type(IExtendLogic).interfaceId,
            functions
        );
    }
}
// File: @violetprotocol/erc721extendable/contracts/storage/ERC721Storage.sol



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

struct ERC721State {
    // Token name
    string _name;
    // Token symbol
    string _symbol;
    // Mapping from token ID to owner address
    mapping(uint256 => address) _owners;
    // Mapping owner address to token count
    mapping(address => uint256) _balances;
    // Mapping from token ID to approved address
    mapping(uint256 => address) _tokenApprovals;
    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) _operatorApprovals;
}

library ERC721Storage {
    bytes32 constant STORAGE_NAME = keccak256("extendable:erc721:base");

    function _getState() internal view returns (ERC721State storage erc721State) {
        bytes32 position = keccak256(abi.encodePacked(address(this), STORAGE_NAME));
        assembly {
            erc721State.slot := position
        }
    }
}

// File: @violetprotocol/extendable/errors/Errors.sol



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

/**
 * @dev  ExtensionNotImplemented error is emitted by Extendable and Extensions
 *       where no implementation for a specified function signature exists
 *       in the contract
*/
error ExtensionNotImplemented();


/**
 * @dev  Utility library for contracts to catch custom errors
 *       Pass in a return `result` from a call, and the selector for your error message
 *       and the `catchCustomError` function will return `true` if the error was found
 *       or `false` otherwise
*/
library Errors {
    function catchCustomError(bytes memory result, bytes4 errorSelector) internal pure returns(bool) {
        bytes4 caught;
        assembly {
            caught := mload(add(result, 0x20))
        }

        return caught == errorSelector;
    }
}
// File: @violetprotocol/extendable/storage/CallerContextStorage.sol



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

struct CallerState {
    // Stores a list of callers in the order they are received
    // The current caller context is always the last-most address
    address[] callerStack;
}

library CallerContextStorage {
    bytes32 constant private STORAGE_NAME = keccak256("extendable.framework.v1:caller-state");

    function _getState()
        internal 
        view
        returns (CallerState storage callerState) 
    {
        bytes32 position = keccak256(abi.encodePacked(address(this), STORAGE_NAME));
        assembly {
            callerState.slot := position
        }
    }
}
// File: @violetprotocol/extendable/storage/ExtendableStorage.sol



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

/**
 * @dev Storage struct used to hold state for Extendable contracts
 */
struct ExtendableState {
    // Array of full interfaceIds extended by the Extendable contract instance
    bytes4[] implementedInterfaceIds;

    // Array of function selectors extended by the Extendable contract instance
    mapping(bytes4 => bytes4[]) implementedFunctionsByInterfaceId;

    // Mapping of interfaceId/functionSelector to the extension address that implements it
    mapping(bytes4 => address) extensionContracts;
}

/**
 * @dev Storage library to access storage slot for the state struct
 */
library ExtendableStorage {
    bytes32 constant private STORAGE_NAME = keccak256("extendable.framework.v1:extendable-state");

    function _getState()
        internal 
        view
        returns (ExtendableState storage extendableState) 
    {
        bytes32 position = keccak256(abi.encodePacked(address(this), STORAGE_NAME));
        assembly {
            extendableState.slot := position
        }
    }
}
// File: @violetprotocol/extendable/extensions/Extension.sol



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

import "./IExtension.sol";
import "../errors/Errors.sol";
import "../utils/CallerContext.sol";
import "../erc165/IERC165Logic.sol";

/**
 *  ______  __  __  ______  ______  __   __  _____   ______  ______  __      ______    
 * /\  ___\/\_\_\_\/\__  _\/\  ___\/\ "-.\ \/\  __-./\  __ \/\  == \/\ \    /\  ___\
 * \ \  __\\/_/\_\/\/_/\ \/\ \  __\\ \ \-.  \ \ \/\ \ \  __ \ \  __<\ \ \___\ \  __\
 *  \ \_____\/\_\/\_\ \ \_\ \ \_____\ \_\\"\_\ \____-\ \_\ \_\ \_____\ \_____\ \_____\
 *   \/_____/\/_/\/_/  \/_/  \/_____/\/_/ \/_/\/____/ \/_/\/_/\/_____/\/_____/\/_____/
 *
 *  Base contract for Extensions in the Extendable Framework
 *  
 *  Inherit and implement this contract to create Extension contracts!
 *
 *  Implements the EIP-165 standard for interface detection of implementations during runtime.
 *  Uses the ERC165 singleton pattern where the actual implementation logic of the interface is
 *  deployed in a separate contract. See ERC165Logic. Deterministic deployment guarantees the
 *  ERC165Logic contract to always exist as static address 0x16C940672fA7820C36b2123E657029d982629070
 *
 *  Define your custom Extension interface and implement it whilst inheriting this contract:
 *      contract YourExtension is IYourExtension, Extension {...}
 *
 */
abstract contract Extension is CallerContext, IExtension, IERC165, IERC165Register {
    address constant ERC165LogicAddress = 0x16C940672fA7820C36b2123E657029d982629070;

    /**
     * @dev Constructor registers your custom Extension interface under EIP-165:
     *      https://eips.ethereum.org/EIPS/eip-165
    */
    constructor() {
        Interface[] memory interfaces = getInterface();
        for (uint256 i = 0; i < interfaces.length; i++) {
            Interface memory iface = interfaces[i];
            registerInterface(iface.interfaceId);

            for (uint256 j = 0; j < iface.functions.length; j++) {
                registerInterface(iface.functions[j]);
            }
        }

        registerInterface(type(IExtension).interfaceId);
    }

    function supportsInterface(bytes4 interfaceId) external override virtual returns(bool) {
        (bool success, bytes memory result) = ERC165LogicAddress.delegatecall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceId));

        if (!success) {
            assembly {
                revert(result, returndatasize())
            }
        }

        return abi.decode(result, (bool));
    }

    function registerInterface(bytes4 interfaceId) public override virtual {
        (bool success, ) = ERC165LogicAddress.delegatecall(abi.encodeWithSignature("registerInterface(bytes4)", interfaceId));

        if (!success) {
            assembly {
                returndatacopy(0, 0, returndatasize())
                revert(0, returndatasize())
            }
        }
    }

    /**
     * @dev Unidentified function signature calls to any Extension reverts with
     *      ExtensionNotImplemented error
    */
    function _fallback() internal virtual {
        revert ExtensionNotImplemented();
    }

    /**
     * @dev Fallback function passes to internal _fallback() logic
    */
    fallback() external payable virtual {
        _fallback();
    }
    
    /**
     * @dev Payable fallback function passes to internal _fallback() logic
    */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Virtual override declaration of getFunctionSelectors() function to silence compiler
     *
     * Must be implemented in inherited contract.
    */
    function getInterface() override public virtual returns(Interface[] memory);
}
// File: @violetprotocol/extendable/extensions/IExtension.sol



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

struct Interface {
    bytes4 interfaceId;
    bytes4[] functions;
}

/**
 * @dev Interface for Extension
*/
interface IExtension {
    /**
     * @dev Returns a full view of the functional interface of the extension
     *
     * Must return a list of the functions in the interface of your custom Extension
     * in the same format and syntax as in the interface itself as a string, 
     * escaped-newline separated.
     *
     * OPEN TO SUGGESTIONS FOR IMPROVEMENT ON THIS METHODOLOGY FOR 
     * DEEP DESCRIPTIVE RUNTIME INTROSPECTION
     *
     * Intent is to allow developers that want to integrate with an Extendable contract
     * that will have a constantly evolving interface, due to the nature of Extendables,
     * to be able to easily inspect and query for the current state of the interface and
     * integrate with it.
     *
     * See {ExtendLogic-getSolidityInterface} for an example.
    */
    function getSolidityInterface() external pure returns(string memory);

    /**
     * @dev Returns the interface IDs that are implemented by the Extension
     *
     * These are full interface IDs and ARE NOT function selectors. Full interface IDs are
     * XOR'd function selectors of an interface. For example the interface ID of the ERC721
     * interface is 0x80ac58cd determined by the XOR or all function selectors of the interface.
     * 
     * If an interface only consists of a single function, then the interface ID is identical
     * to that function selector.
     * 
     * Provides a simple abstraction from the developer for any custom Extension to 
     * be EIP-165 compliant out-of-the-box simply by implementing this function. 
     *
     * Excludes any functions either already described by other interface definitions
     * that are not developed on top of this backbone i.e. EIP-165, IExtension
    */
    function getInterface() external returns(Interface[] memory interfaces);
}
// File: @violetprotocol/extendable/utils/CallerContext.sol



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

import {CallerState, CallerContextStorage} from "../storage/CallerContextStorage.sol";

/**
 * @dev CallerContext contract provides Extensions with proper caller-scoped contexts.
 *      Inherit this contract with your Extension to make use of caller references.
 *
 * `msg.sender` may not behave as developer intends when using within Extensions as many
 * calls may be exchanged between intra-contract extensions which result in a `msg.sender` as self.
 * Instead of using `msg.sender`, replace it with 
 *      - `_lastExternalCaller()` for the most recent caller in the call chain that is external to this contract
 *      - `_lastCaller()` for the most recent caller
 *
 * CallerContext provides a deep callstack to track the caller of the Extension/Extendable contract
 * at any point in the execution cycle.
 *
*/
contract CallerContext {
    /**
     * @dev Returns the most recent caller of this contract that came from outside this contract.
     *
     * Used by extensions that require fetching msg.sender that aren't cross-extension calls.
     * Cross-extension calls resolve msg.sender as the current contract and so the actual
     * caller context is obfuscated.
     * 
     * This function should be used in place of `msg.sender` where external callers are read.
     */
    function _lastExternalCaller() internal view returns(address) {
        CallerState storage state = CallerContextStorage._getState();

        for (uint i = state.callerStack.length - 1; i >= 0; i--) {
            address lastSubsequentCaller = state.callerStack[i];
            if (lastSubsequentCaller != address(this)) {
                return lastSubsequentCaller;
            }
        }

        revert("_lastExternalCaller: end of stack");
    }

    /**
     * @dev Returns the most recent caller of this contract.
     *
     * Last caller may also be the current contract.
     *
     * If the call is directly to the contract, without passing an Extendable, return `msg.sender` instead
     */
    function _lastCaller() internal view returns(address) {
        CallerState storage state = CallerContextStorage._getState();
        if (state.callerStack.length > 0)
            return state.callerStack[state.callerStack.length - 1];
        else
            return msg.sender;
    }
}
// File: @violetprotocol/extendable/erc165/IERC165Logic.sol



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

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


/**
 * @dev Storage based implementation of the {IERC165} interface.
 *
 * Uses Extendable storage pattern to populate the registered interfaces storage variable.
 */
interface IERC165Register {
    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function registerInterface(bytes4 interfaceId) external;
}