ETH Price: $2,420.41 (-0.50%)

Transaction Decoder

Block:
15871317 at Oct-31-2022 11:27:23 PM +UTC
Transaction Fee:
0.00071033524002447 ETH $1.72
Gas Used:
51,195 Gas / 13.875090146 Gwei

Emitted Events:

110 Diamond.0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31( 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31, 0x0000000000000000000000003df03cd0fcffdc255c25a9905656065bff5f01aa, 0x000000000000000000000000f849de01b080adc3a814fabe1e2087475cf2e354, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
0x3dF03cd0...BFF5f01aA
0.033656154349322263 Eth
Nonce: 15
0.032945819109297793 Eth
Nonce: 16
0.00071033524002447
(Fee Recipient: 0x535...0A3)
7.109992967377910995 Eth7.110069759877910995 Eth0.0000767925
0x9f0F6E4e...bEdCC7C1D

Execution Trace

Diamond.a22cb465( )
  • NftCommonFacet.setApprovalForAll( _operator=0xF849de01B080aDC3A814FaBE1E2087475cF2E354, _approved=True )
    File 1 of 2: Diamond
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Authors: Nick Mudge (https://twitter.com/mudgen)
    *
    * Implementation of a diamond.
    /******************************************************************************/
    import {LibDiamond} from "./libraries/LibDiamond.sol";
    import {DiamondCutFacet} from "./facets/DiamondCutFacet.sol";
    import {DiamondLoupeFacet} from "./facets/DiamondLoupeFacet.sol";
    import {OwnershipFacet} from "./facets/OwnershipFacet.sol";
    contract Diamond {
        constructor(address _contractOwner) {
            LibDiamond.setContractOwner(_contractOwner);
            LibDiamond.addDiamondFunctions(
                address(new DiamondCutFacet()),
                address(new DiamondLoupeFacet()),
                address(new OwnershipFacet())
            );
        }
        // Find facet for function that is called and execute the
        // function if a facet is found and return any value.
        fallback() external payable {
            LibDiamond.DiamondStorage storage ds;
            bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
            assembly {
                ds.slot := position
            }
            address facet = ds.selectorToFacetAndPosition[msg.sig].facetAddress;
            require(facet != address(0), "Diamond: Function does not exist");
            assembly {
                calldatacopy(0, 0, calldatasize())
                let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
                returndatacopy(0, 0, returndatasize())
                switch result
                    case 0 {
                        revert(0, returndatasize())
                    }
                    default {
                        return(0, returndatasize())
                    }
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
    /******************************************************************************/
    import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
    import {LibDiamond} from "../libraries/LibDiamond.sol";
    contract DiamondCutFacet is IDiamondCut {
        /// @notice Add/replace/remove any number of functions and optionally execute
        ///         a function with delegatecall
        /// @param _diamondCut Contains the facet addresses and function selectors
        /// @param _init The address of the contract or facet to execute _calldata
        /// @param _calldata A function call, including function selector and arguments
        ///                  _calldata is executed with delegatecall on _init
        function diamondCut(
            FacetCut[] calldata _diamondCut,
            address _init,
            bytes calldata _calldata
        ) external override {
            LibDiamond.enforceIsContractOwner();
            LibDiamond.diamondCut(_diamondCut, _init, _calldata);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
    /******************************************************************************/
    import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
    import {IDiamondLoupe} from "../interfaces/IDiamondLoupe.sol";
    import {IERC165} from "../interfaces/IERC165.sol";
    import {IOwnable} from "../interfaces/IOwnable.sol";
    import {LibMeta} from "./LibMeta.sol";
    library LibDiamond {
        bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
        struct FacetAddressAndPosition {
            address facetAddress;
            uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
        }
        struct FacetFunctionSelectors {
            bytes4[] functionSelectors;
            uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
        }
        struct DiamondStorage {
            // maps function selector to the facet address and
            // the position of the selector in the facetFunctionSelectors.selectors array
            mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
            // maps facet addresses to function selectors
            mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
            // facet addresses
            address[] facetAddresses;
            // Used to query if a contract implements an interface.
            // Used to implement ERC-165.
            mapping(bytes4 => bool) supportedInterfaces;
            // owner of the contract
            address contractOwner;
        }
        function diamondStorage() internal pure returns (DiamondStorage storage ds) {
            bytes32 position = DIAMOND_STORAGE_POSITION;
            assembly {
                ds.slot := position
            }
        }
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        function setContractOwner(address _newOwner) internal {
            DiamondStorage storage ds = diamondStorage();
            address previousOwner = ds.contractOwner;
            ds.contractOwner = _newOwner;
            emit OwnershipTransferred(previousOwner, _newOwner);
        }
        function contractOwner() internal view returns (address contractOwner_) {
            contractOwner_ = diamondStorage().contractOwner;
        }
        function enforceIsContractOwner() internal view {
            require(LibMeta.msgSender() == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
        }
        event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
        function addDiamondFunctions(
            address _diamondCutFacet,
            address _diamondLoupeFacet,
            address _ownershipFacet
        ) internal {
            IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](3);
            bytes4[] memory functionSelectors = new bytes4[](1);
            functionSelectors[0] = IDiamondCut.diamondCut.selector;
            cut[0] = IDiamondCut.FacetCut({facetAddress: _diamondCutFacet, action: IDiamondCut.FacetCutAction.Add, functionSelectors: functionSelectors});
            functionSelectors = new bytes4[](5);
            functionSelectors[0] = IDiamondLoupe.facets.selector;
            functionSelectors[1] = IDiamondLoupe.facetFunctionSelectors.selector;
            functionSelectors[2] = IDiamondLoupe.facetAddresses.selector;
            functionSelectors[3] = IDiamondLoupe.facetAddress.selector;
            functionSelectors[4] = IERC165.supportsInterface.selector;
            cut[1] = IDiamondCut.FacetCut({
                facetAddress: _diamondLoupeFacet,
                action: IDiamondCut.FacetCutAction.Add,
                functionSelectors: functionSelectors
            });
            functionSelectors = new bytes4[](2);
            functionSelectors[0] = IOwnable.transferOwnership.selector;
            functionSelectors[1] = IOwnable.owner.selector;
            cut[2] = IDiamondCut.FacetCut({facetAddress: _ownershipFacet, action: IDiamondCut.FacetCutAction.Add, functionSelectors: functionSelectors});
            diamondCut(cut, address(0), "");
        }
        // Internal function version of diamondCut
        function diamondCut(
            IDiamondCut.FacetCut[] memory _diamondCut,
            address _init,
            bytes memory _calldata
        ) internal {
            for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
                IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
                if (action == IDiamondCut.FacetCutAction.Add) {
                    addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else if (action == IDiamondCut.FacetCutAction.Replace) {
                    replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else if (action == IDiamondCut.FacetCutAction.Remove) {
                    removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else {
                    revert("LibDiamondCut: Incorrect FacetCutAction");
                }
            }
            emit DiamondCut(_diamondCut, _init, _calldata);
            initializeDiamondCut(_init, _calldata);
        }
        function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            // uint16 selectorCount = uint16(diamondStorage().selectors.length);
            require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
            uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
            // add new facet address if it does not exist
            if (selectorPosition == 0) {
                enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
                ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
                ds.facetAddresses.push(_facetAddress);
            }
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
                ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
                ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
                ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
                selectorPosition++;
            }
        }
        function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
            uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
            // add new facet address if it does not exist
            if (selectorPosition == 0) {
                enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
                ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
                ds.facetAddresses.push(_facetAddress);
            }
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
                removeFunction(oldFacetAddress, selector);
                // add function
                ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
                ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
                ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
                selectorPosition++;
            }
        }
        function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            // if function does not exist then do nothing and return
            require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                removeFunction(oldFacetAddress, selector);
            }
        }
        function removeFunction(address _facetAddress, bytes4 _selector) internal {
            DiamondStorage storage ds = diamondStorage();
            require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
            // an immutable function is a function defined directly in a diamond
            require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
            // replace selector with last selector, then delete last selector
            uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
            uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
            // if not the same then replace _selector with lastSelector
            if (selectorPosition != lastSelectorPosition) {
                bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
                ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
                ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint16(selectorPosition);
            }
            // delete the last selector
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
            delete ds.selectorToFacetAndPosition[_selector];
            // if no more selectors for facet address then delete the facet address
            if (lastSelectorPosition == 0) {
                // replace facet address with last facet address and delete last facet address
                uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
                uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
                if (facetAddressPosition != lastFacetAddressPosition) {
                    address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                    ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                    ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = uint16(facetAddressPosition);
                }
                ds.facetAddresses.pop();
                delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
            }
        }
        function initializeDiamondCut(address _init, bytes memory _calldata) internal {
            if (_init == address(0)) {
                require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
            } else {
                require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
                if (_init != address(this)) {
                    enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
                }
                (bool success, bytes memory error) = _init.delegatecall(_calldata);
                if (success == false) {
                    if (error.length > 0) {
                        // bubble up the error
                        revert(string(error));
                    } else {
                        revert("LibDiamondCut: _init function reverted");
                    }
                }
            }
        }
        function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
            uint256 contractSize;
            assembly {
                contractSize := extcodesize(_contract)
            }
            require(contractSize != 0, _errorMessage);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import {LibDiamond} from "../libraries/LibDiamond.sol";
    import {IOwnable} from "../interfaces/IOwnable.sol";
    contract OwnershipFacet is IOwnable {
        function transferOwnership(address _newOwner) external override {
            LibDiamond.enforceIsContractOwner();
            LibDiamond.setContractOwner(_newOwner);
        }
        function owner() external view override returns (address owner_) {
            owner_ = LibDiamond.contractOwner();
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
    /******************************************************************************/
    import {LibDiamond} from "../libraries/LibDiamond.sol";
    import {IDiamondLoupe} from "../interfaces/IDiamondLoupe.sol";
    import {IERC165} from "../interfaces/IERC165.sol";
    contract DiamondLoupeFacet is IDiamondLoupe, IERC165 {
        // Diamond Loupe Functions
        ////////////////////////////////////////////////////////////////////
        /// These functions are expected to be called frequently by tools.
        //
        // struct Facet {
        //     address facetAddress;
        //     bytes4[] functionSelectors;
        // }
        /// @notice Gets all facets and their selectors.
        /// @return facets_ Facet
        function facets() external view override returns (Facet[] memory facets_) {
            LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
            uint256 numFacets = ds.facetAddresses.length;
            facets_ = new Facet[](numFacets);
            for (uint256 i; i < numFacets; i++) {
                address facetAddress_ = ds.facetAddresses[i];
                facets_[i].facetAddress = facetAddress_;
                facets_[i].functionSelectors = ds.facetFunctionSelectors[facetAddress_].functionSelectors;
            }
        }
        /// @notice Gets all the function selectors provided by a facet.
        /// @param _facet The facet address.
        /// @return facetFunctionSelectors_
        function facetFunctionSelectors(address _facet) external view override returns (bytes4[] memory facetFunctionSelectors_) {
            LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
            facetFunctionSelectors_ = ds.facetFunctionSelectors[_facet].functionSelectors;
        }
        /// @notice Get all the facet addresses used by a diamond.
        /// @return facetAddresses_
        function facetAddresses() external view override returns (address[] memory facetAddresses_) {
            LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
            facetAddresses_ = ds.facetAddresses;
        }
        /// @notice Gets the facet that supports the given selector.
        /// @dev If facet is not found return address(0).
        /// @param _functionSelector The function selector.
        /// @return facetAddress_ The facet address.
        function facetAddress(bytes4 _functionSelector) external view override returns (address facetAddress_) {
            LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
            facetAddress_ = ds.selectorToFacetAndPosition[_functionSelector].facetAddress;
        }
        // This implements ERC-165.
        function supportsInterface(bytes4 _interfaceId) external view override returns (bool) {
            LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
            return ds.supportedInterfaces[_interfaceId];
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    /******************************************************************************/
    interface IDiamondCut {
        enum FacetCutAction {Add, Replace, Remove}
        struct FacetCut {
            address facetAddress;
            FacetCutAction action;
            bytes4[] functionSelectors;
        }
        /// @notice Add/replace/remove any number of functions and optionally execute
        ///         a function with delegatecall
        /// @param _diamondCut Contains the facet addresses and function selectors
        /// @param _init The address of the contract or facet to execute _calldata
        /// @param _calldata A function call, including function selector and arguments
        ///                  _calldata is executed with delegatecall on _init
        function diamondCut(
            FacetCut[] calldata _diamondCut,
            address _init,
            bytes calldata _calldata
        ) external;
        event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    // A loupe is a small magnifying glass used to look at diamonds.
    // These functions look at diamonds
    interface IDiamondLoupe {
        /// These functions are expected to be called frequently
        /// by tools.
        struct Facet {
            address facetAddress;
            bytes4[] functionSelectors;
        }
        /// @notice Gets all facet addresses and their four byte function selectors.
        /// @return facets_ Facet
        function facets() external view returns (Facet[] memory facets_);
        /// @notice Gets all the function selectors supported by a specific facet.
        /// @param _facet The facet address.
        /// @return facetFunctionSelectors_
        function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);
        /// @notice Get all the facet addresses used by a diamond.
        /// @return facetAddresses_
        function facetAddresses() external view returns (address[] memory facetAddresses_);
        /// @notice Gets the facet that supports the given selector.
        /// @dev If facet is not found return address(0).
        /// @param _functionSelector The function selector.
        /// @return facetAddress_ The facet address.
        function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.3.2 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.0;
    /**
     * @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);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    library LibMeta {
        bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
            keccak256(bytes("EIP712Domain(string name,string version,uint256 salt,address verifyingContract)"));
        function domainSeparator(string memory name, string memory version) internal view returns (bytes32 domainSeparator_) {
            domainSeparator_ = keccak256(
                abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes(version)), getChainID(), address(this))
            );
        }
        function getChainID() internal view returns (uint256 id) {
            assembly {
                id := chainid()
            }
        }
        function msgSender() internal view returns (address sender_) {
            if (msg.sender == address(this)) {
                bytes memory array = msg.data;
                uint256 index = msg.data.length;
                assembly {
                    // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                    sender_ := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
                }
            } else {
                sender_ = msg.sender;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /// @title ERC-173 Contract Ownership Standard
    ///  Note: the ERC-165 identifier for this interface is 0x7f5828d0
    /* is ERC165 */
    interface IOwnable {
        /// @notice Get the address of the owner
        /// @return owner_ The address of the owner.
        function owner() external view returns (address owner_);
        /// @notice Set the address of the new owner of the contract
        /// @dev Set _newOwner to address(0) to renounce any ownership.
        /// @param _newOwner The address of the new owner of the contract
        function transferOwnership(address _newOwner) external;
    }
    

    File 2 of 2: NftCommonFacet
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    pragma experimental ABIEncoderV2;
    import {NftCommon, Modifiers} from "../libraries/LibAppStorage.sol";
    import {LibNftCommon} from "../libraries/LibNftCommon.sol";
    import {LibMeta} from "../../shared/libraries/LibMeta.sol";
    import {LibERC721} from "../../shared/libraries/LibERC721.sol";
    import "@openzeppelin/contracts/utils/Strings.sol";
    contract NftCommonFacet is Modifiers {
        /// @notice Query the universal totalSupply of all NFTs ever minted
        /// @return totalSupply_ the number of all NFTs that have been minted
        function totalSupply() external view returns (uint256 totalSupply_) {
            totalSupply_ = s.tokenIdsCount;
        }
        /// @notice Count all NFTs assigned to an owner
        /// @dev NFTs assigned to the zero address are considered invalid, and this.
        ///  function throws for queries about the zero address.
        /// @param _owner An address for whom to query the balance
        /// @return balance_ The number of NFTs owned by `_owner`, possibly zero
        function balanceOf(address _owner) external view returns (uint256 balance_) {
            require(_owner != address(0), "NftCommonFacet: _owner can't be address(0)");
            balance_ = s.ownerTokenIds[_owner].length;
        }
        /// @notice Enumerate valid NFTs
        /// @dev Throws if `_index` >= `totalSupply()`.
        /// @param _index A counter less than `totalSupply()`
        /// @return tokenId_ The token identifier for the `_index`th NFT,
        ///  (sort order not specified)
        function tokenByIndex(uint256 _index) external view returns (uint256 tokenId_) {
            require(s.nfts[_index].owner != address(0), "NftCommonFacet: Rebel owner can't be address(0)");
            tokenId_ = _index;
        }
        /// @notice Enumerate NFTs assigned to an owner
        /// @dev Throws if `_index` >= `balanceOf(_owner)` or if
        ///  `_owner` is the zero address, representing invalid NFTs.
        /// @param _owner An address where we are interested in NFTs owned by them
        /// @param _index A counter less than `balanceOf(_owner)`
        /// @return tokenId_ The token identifier for the `_index`th NFT assigned to `_owner`,
        ///   (sort order not specified)
        function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 tokenId_) {
            require(_index < s.ownerTokenIds[_owner].length, "NftCommonFacet: index beyond owner balance");
            tokenId_ = s.ownerTokenIds[_owner][_index];
        }
        /// @notice Get all the Ids of NFTs owned by an address
        /// @param _owner The address to check for the NFTs
        /// @return tokenIds_ an array of unsigned integers,each representing the tokenId of each NFT
        function tokenIdsOfOwner(address _owner) external view returns (uint256[] memory tokenIds_) {
            tokenIds_ = s.ownerTokenIds[_owner];
        }
        /// @notice Get all details about all the NFTs owned by an address
        /// @param _owner The address to check for the NFTs
        /// @return nftCommons_ an array of structs, where each struct contains all the details of each NFT
        function allNftsOfOwner(address _owner) external view returns (NftCommon[] memory nftCommons_) {
            uint256 length = s.ownerTokenIds[_owner].length;
            nftCommons_ = new NftCommon[](length);
            for (uint256 i; i < length; i++) {
                nftCommons_[i] = LibNftCommon.getNftCommon(s.ownerTokenIds[_owner][i]);
            }
        }
        /// @notice Get all details about NFT by id
        /// @param _tokenId The identifier for an NFT
        /// @return nftCommon_ an struct, which contains all the details about NFT
        function getNftCommon(uint256 _tokenId) external view returns (NftCommon memory nftCommon_) {
            return LibNftCommon.getNftCommon(_tokenId);
        }
        /// @notice Find the owner of an NFT
        /// @dev NFTs assigned to zero address are considered invalid, and queries
        ///  about them do throw.
        /// @param _tokenId The identifier for an NFT
        /// @return owner_ The address of the owner of the NFT
        function ownerOf(uint256 _tokenId) external view returns (address owner_) {
            owner_ = s.nfts[_tokenId].owner;
            require(owner_ != address(0), "NftCommonFacet: invalid _tokenId");
        }
        /// @notice Get the approved address for a single NFT
        /// @dev Throws if `_tokenId` is not a valid NFT.
        /// @param _tokenId The NFT to find the approved address for
        /// @return approved_ The approved address for this NFT, or the zero address if there is none
        function getApproved(uint256 _tokenId) external view returns (address approved_) {
            require(s.nfts[_tokenId].owner != address(0), "ERC721: tokenId is invalid");
            approved_ = s.approved[_tokenId];
        }
        /// @notice Query if an address is an authorized operator for another address
        /// @param _owner The address that owns the NFTs
        /// @param _operator The address that acts on behalf of the owner
        /// @return approved_ True if `_operator` is an approved operator for `_owner`, false otherwise
        function isApprovedForAll(address _owner, address _operator) external view returns (bool approved_) {
            approved_ = s.operators[_owner][_operator];
        }
        /// @notice Transfers the ownership of an NFT from one address to another address
        /// @dev Throws unless `LibMeta.msgSender()` is the current owner, an authorized
        ///  operator, or the approved address for this NFT. Throws if `_from` is
        ///  not the current owner. Throws if `_to` is the zero address. Throws if
        ///  `_tokenId` is not a valid NFT. When transfer is complete, this function
        ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
        ///  `onERC721Received` on `_to` and throws if the return value is not
        ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
        /// @param _from The current owner of the NFT
        /// @param _to The new owner
        /// @param _tokenId The NFT to transfer
        /// @param _data Additional data with no specified format, sent in call to `_to`
        function safeTransferFrom(
            address _from,
            address _to,
            uint256 _tokenId,
            bytes calldata _data
        ) external {
            address sender = LibMeta.msgSender();
            internalTransferFrom(sender, _from, _to, _tokenId);
            LibERC721.checkOnERC721Received(sender, _from, _to, _tokenId, _data);
        }
        /// @notice Transfers the ownership of an NFT from one address to another address
        /// @dev This works identically to the other function with an extra data parameter,
        ///  except this function just sets data to "".
        /// @param _from The current owner of the NFT
        /// @param _to The new owner
        /// @param _tokenId The NFT to transfer
        function safeTransferFrom(
            address _from,
            address _to,
            uint256 _tokenId
        ) external {
            address sender = LibMeta.msgSender();
            internalTransferFrom(sender, _from, _to, _tokenId);
            LibERC721.checkOnERC721Received(sender, _from, _to, _tokenId, "");
        }
        /// @notice Transfers the ownership of multiple  NFTs from one address to another at once
        /// @dev Throws unless `LibMeta.msgSender()` is the current owner, an authorized
        ///  operator, or the approved address of each of the NFTs in `_tokenIds`. Throws if `_from` is
        ///  not the current owner. Throws if `_to` is the zero address. Throws if one of the NFTs in
        ///  `_tokenIds` is not a valid NFT. When transfer is complete, this function
        ///  checks if `_to` is a smart contract (code size > 0). If so, it calls
        ///  `onERC721Received` on `_to` and throws if the return value is not
        ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
        /// @param _from The current owner of the NFTs
        /// @param _to The new owner
        /// @param _tokenIds An array containing the identifiers of the NFTs to transfer
        /// @param _data Additional data with no specified format, sent in call to `_to`
        function safeBatchTransferFrom(
            address _from,
            address _to,
            uint256[] calldata _tokenIds,
            bytes calldata _data
        ) external {
            address sender = LibMeta.msgSender();
            for (uint256 index = 0; index < _tokenIds.length; index++) {
                uint256 _tokenId = _tokenIds[index];
                internalTransferFrom(sender, _from, _to, _tokenId);
                LibERC721.checkOnERC721Received(sender, _from, _to, _tokenId, _data);
            }
        }
        /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
        ///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
        ///  THEY MAY BE PERMANENTLY LOST
        /// @dev Throws unless `LibMeta.msgSender()` is the current owner, an authorized
        ///  operator, or the approved address for this NFT. Throws if `_from` is
        ///  not the current owner. Throws if `_to` is the zero address. Throws if
        ///  `_tokenId` is not a valid NFT.
        /// @param _from The current owner of the NFT
        /// @param _to The new owner
        /// @param _tokenId The NFT to transfer
        function transferFrom(
            address _from,
            address _to,
            uint256 _tokenId
        ) external {
            internalTransferFrom(LibMeta.msgSender(), _from, _to, _tokenId);
        }
        // This function is used by transfer functions
        function internalTransferFrom(
            address _sender,
            address _from,
            address _to,
            uint256 _tokenId
        ) internal {
            require(_to != address(0), "NftCommonFacet: Can't transfer to 0 address");
            require(_from != address(0), "NftCommonFacet: _from can't be 0 address");
            require(_from == s.nfts[_tokenId].owner, "NftCommonFacet: _from is not owner, transfer failed");
            require(
                _sender == _from || s.operators[_from][_sender] || _sender == s.approved[_tokenId],
                "NftCommonFacet: Not owner or approved to transfer"
            );
            LibNftCommon.transfer(_from, _to, _tokenId);
        }
        /// @notice Change or reaffirm the approved address for an NFT
        /// @dev The zero address indicates there is no approved address.
        ///  Throws unless `LibMeta.msgSender()` is the current NFT owner, or an authorized
        ///  operator of the current owner.
        /// @param _approved The new approved NFT controller
        /// @param _tokenId The NFT to approve
        function approve(address _approved, uint256 _tokenId) external {
            address owner = s.nfts[_tokenId].owner;
            require(owner == LibMeta.msgSender() || s.operators[owner][LibMeta.msgSender()], "ERC721: Not owner or operator of token.");
            s.approved[_tokenId] = _approved;
            emit LibERC721.Approval(owner, _approved, _tokenId);
        }
        /// @notice Enable or disable approval for a third party ("operator") to manage
        ///  all of `LibMeta.msgSender()`'s assets
        /// @dev Emits the ApprovalForAll event. The contract MUST allow
        ///  multiple operators per owner.
        /// @param _operator Address to add to the set of authorized operators
        /// @param _approved True if the operator is approved, false to revoke approval
        function setApprovalForAll(address _operator, bool _approved) external {
            s.operators[LibMeta.msgSender()][_operator] = _approved;
            emit LibERC721.ApprovalForAll(LibMeta.msgSender(), _operator, _approved);
        }
        ///@notice Return the universal name of the NFT
        function name() external view returns (string memory) {
            return s.name;
        }
        /// @notice An abbreviated name for NFTs in this contract
        function symbol() external view returns (string memory) {
            return s.symbol;
        }
        /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
        /// @dev URIs are defined in RFC 3986. The URI may point to a JSON file
        ///  that conforms to the "ERC721 Metadata JSON Schema".
        function tokenURI(uint256 _tokenId) external view returns (string memory) {
            return LibNftCommon.tokenBaseURI(_tokenId);
        }
        /// @notice Change base URI of the NFT assets metadata
        /// @param _uri Base URI of the NFT assets metadata
        function setBaseURI(string memory _uri) external onlyOwner {
            s.baseURI = _uri;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import {LibAppStorage, AppStorage, NftCommon} from "./LibAppStorage.sol";
    import {LibERC721} from "../../shared/libraries/LibERC721.sol";
    import {IERC20} from "../../shared/interfaces/IERC20.sol";
    import "@openzeppelin/contracts/utils/Strings.sol";
    library LibNftCommon {
        function getNftCommon(uint256 _tokenId) internal view returns(NftCommon memory) {
            AppStorage storage s = LibAppStorage.diamondStorage();
            return s.nfts[_tokenId];
        }
        function transfer(
            address _from,
            address _to,
            uint256 _tokenId
        ) internal {
            AppStorage storage s = LibAppStorage.diamondStorage();
            //remove
            uint256 index = s.ownerTokenIdIndexes[_from][_tokenId];
            uint256 lastIndex = s.ownerTokenIds[_from].length - 1;
            if (index != lastIndex) {
                uint256 lastTokenId = s.ownerTokenIds[_from][lastIndex];
                s.ownerTokenIds[_from][index] = lastTokenId;
                s.ownerTokenIdIndexes[_from][lastTokenId] = index;
            }
            s.ownerTokenIds[_from].pop();
            delete s.ownerTokenIdIndexes[_from][_tokenId];
            if (s.approved[_tokenId] != address(0)) {
                delete s.approved[_tokenId];
                emit LibERC721.Approval(_from, address(0), _tokenId);
            }
            // add
            setOwner(_tokenId, _to);
        }
        function validateAndLowerName(string memory _name) internal pure returns(string memory) {
            bytes memory name = abi.encodePacked(_name);
            uint256 len = name.length;
            
            require(len != 0, "LibNftCommon: Name can't be 0 chars");
            require(len < 26, "LibNftCommon: Name can't be greater than 25 characters");
            uint256 char = uint256(uint8(name[0]));
            require(char != 32, "LibNftCommon: First char of name can't be a space");
            char = uint256(uint8(name[len-1]));
            require(char != 32, "LibNftCommon: Last char of name can't be a space");
            for (uint256 i; i < len; i++) {
                char = uint256(uint8(name[i]));
                require(char > 31 && char < 127, "LibNftCommon: Invalid character in nft name");
                
                if (char < 91 && char > 64) {
                    name[i] = bytes1(uint8(char+32));
                }
            }
            return string(name);
        }
        function tokenBaseURI(uint256 _tokenId) internal view returns (string memory) {
            AppStorage storage s = LibAppStorage.diamondStorage();
            return bytes(s.baseURI).length > 0 ? string(abi.encodePacked(s.baseURI, Strings.toString(_tokenId))) : s.cloneBoxURI;
        }
        function setOwner(uint256 id, address newOwner) internal {
            AppStorage storage s = LibAppStorage.diamondStorage();
            address oldOwner = s.nfts[id].owner;
            s.nfts[id].owner = newOwner;
            s.ownerTokenIdIndexes[newOwner][id] = s.ownerTokenIds[newOwner].length;
            s.ownerTokenIds[newOwner].push(id);
            emit LibERC721.Transfer(oldOwner, newOwner, id);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import {LibDiamond} from "../../shared/libraries/LibDiamond.sol";
    import {LibMeta} from "../../shared/libraries/LibMeta.sol";
    struct NftCommon {
        uint256 tokenId;
        string name;
        address owner;
    }
    struct AppStorage {
        uint256 maxNftCount;
        uint256 maxNftSalePerUser;
        uint256 nftSalePrice;
        string name;
        string symbol;
        bytes32 whitelistMerkleRoot;
        uint256 whitelistSalePrice;
        mapping(address => bool) whitelistClaimed;
        bool whitelistIsActive;
        bool saleIsActive;
        bool freeMintEnabled;
        mapping(uint256 => NftCommon) nfts;
        mapping(address => uint256[]) ownerTokenIds;
        mapping(address => mapping(uint256 => uint256)) ownerTokenIdIndexes;
        mapping(uint256 => address) approved;
        mapping(address => mapping(address => bool)) operators;
        mapping(string => bool) nftNamesUsed;
        mapping(address => bool) gameManagers;
        uint256 tokenIdsCount;
        string baseURI;
        string cloneBoxURI;
    }
    library LibAppStorage {
        function diamondStorage() internal pure returns(AppStorage storage ds) {
            assembly {
                ds.slot := 0
            }
        }
    }
    contract Modifiers {
        AppStorage internal s;
        modifier onlyNftOwner(uint256 _tokenId) {
            require(LibMeta.msgSender() == s.nfts[_tokenId].owner, "LibAppStorage: Only nft owner can call this function");
            _;
        }
        modifier onlyOwner() {
            LibDiamond.enforceIsContractOwner();
            _;
        }
        modifier onlyGameManager() {
            require(s.gameManagers[LibMeta.msgSender()], "LibAppStorage: Only game manager can call this function");
            _;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    import "../interfaces/IERC721TokenReceiver.sol";
    library LibERC721 {
        /// @dev This emits when ownership of any NFT changes by any mechanism.
        ///  This event emits when NFTs are created (`from` == 0) and destroyed
        ///  (`to` == 0). Exception: during contract creation, any number of NFTs
        ///  may be created and assigned without emitting Transfer. At the time of
        ///  any transfer, the approved address for that NFT (if any) is reset to none.
        event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
        /// @dev This emits when the approved address for an NFT is changed or
        ///  reaffirmed. The zero address indicates there is no approved address.
        ///  When a Transfer event emits, this also indicates that the approved
        ///  address for that NFT (if any) is reset to none.
        event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
        /// @dev This emits when an operator is enabled or disabled for an owner.
        ///  The operator can manage all NFTs of the owner.
        event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
        bytes4 internal constant ERC721_RECEIVED = 0x150b7a02;
        function checkOnERC721Received(
            address _operator,
            address _from,
            address _to,
            uint256 _tokenId,
            bytes memory _data
        ) internal {
            uint256 size;
            assembly {
                size := extcodesize(_to)
            }
            if (size > 0) {
                require(
                    ERC721_RECEIVED == IERC721TokenReceiver(_to).onERC721Received(_operator, _from, _tokenId, _data),
                    "DemRebelFacet: Transfer rejected/failed by _to"
                );
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    library LibMeta {
        bytes32 internal constant EIP712_DOMAIN_TYPEHASH =
            keccak256(bytes("EIP712Domain(string name,string version,uint256 salt,address verifyingContract)"));
        function domainSeparator(string memory name, string memory version) internal view returns (bytes32 domainSeparator_) {
            domainSeparator_ = keccak256(
                abi.encode(EIP712_DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes(version)), getChainID(), address(this))
            );
        }
        function getChainID() internal view returns (uint256 id) {
            assembly {
                id := chainid()
            }
        }
        function msgSender() internal view returns (address sender_) {
            if (msg.sender == address(this)) {
                bytes memory array = msg.data;
                uint256 index = msg.data.length;
                assembly {
                    // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
                    sender_ := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
                }
            } else {
                sender_ = msg.sender;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev String operations.
     */
    library Strings {
        bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
        uint8 private constant _ADDRESS_LENGTH = 20;
        /**
         * @dev Converts a `uint256` to its ASCII `string` decimal representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
                digits -= 1;
                buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                value /= 10;
            }
            return string(buffer);
        }
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
         */
        function toHexString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
                return "0x00";
            }
            uint256 temp = value;
            uint256 length = 0;
            while (temp != 0) {
                length++;
                temp >>= 8;
            }
            return toHexString(value, length);
        }
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
         */
        function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = "0";
            buffer[1] = "x";
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = _HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
            require(value == 0, "Strings: hex length insufficient");
            return string(buffer);
        }
        /**
         * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
         */
        function toHexString(address addr) internal pure returns (string memory) {
            return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    interface IERC20 {
        function name() external view returns (string memory);
        function symbol() external view returns (string memory);
        function decimals() external view returns (uint8);
        function totalSupply() external view returns (uint256);
        function balanceOf(address _owner) external view returns (uint256 balance);
        function transferFrom(
            address _from,
            address _to,
            uint256 _value
        ) external returns (bool success);
        function transfer(address _to, uint256 _value) external returns (bool success);
        function approve(address _spender, uint256 _value) external returns (bool success);
        function allowance(address _owner, address _spender) external view returns (uint256 remaining);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535
    /******************************************************************************/
    import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
    import {IDiamondLoupe} from "../interfaces/IDiamondLoupe.sol";
    import {IERC165} from "../interfaces/IERC165.sol";
    import {IOwnable} from "../interfaces/IOwnable.sol";
    import {LibMeta} from "./LibMeta.sol";
    library LibDiamond {
        bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
        struct FacetAddressAndPosition {
            address facetAddress;
            uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array
        }
        struct FacetFunctionSelectors {
            bytes4[] functionSelectors;
            uint16 facetAddressPosition; // position of facetAddress in facetAddresses array
        }
        struct DiamondStorage {
            // maps function selector to the facet address and
            // the position of the selector in the facetFunctionSelectors.selectors array
            mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition;
            // maps facet addresses to function selectors
            mapping(address => FacetFunctionSelectors) facetFunctionSelectors;
            // facet addresses
            address[] facetAddresses;
            // Used to query if a contract implements an interface.
            // Used to implement ERC-165.
            mapping(bytes4 => bool) supportedInterfaces;
            // owner of the contract
            address contractOwner;
        }
        function diamondStorage() internal pure returns (DiamondStorage storage ds) {
            bytes32 position = DIAMOND_STORAGE_POSITION;
            assembly {
                ds.slot := position
            }
        }
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        function setContractOwner(address _newOwner) internal {
            DiamondStorage storage ds = diamondStorage();
            address previousOwner = ds.contractOwner;
            ds.contractOwner = _newOwner;
            emit OwnershipTransferred(previousOwner, _newOwner);
        }
        function contractOwner() internal view returns (address contractOwner_) {
            contractOwner_ = diamondStorage().contractOwner;
        }
        function enforceIsContractOwner() internal view {
            require(LibMeta.msgSender() == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
        }
        event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
        function addDiamondFunctions(
            address _diamondCutFacet,
            address _diamondLoupeFacet,
            address _ownershipFacet
        ) internal {
            IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](3);
            bytes4[] memory functionSelectors = new bytes4[](1);
            functionSelectors[0] = IDiamondCut.diamondCut.selector;
            cut[0] = IDiamondCut.FacetCut({facetAddress: _diamondCutFacet, action: IDiamondCut.FacetCutAction.Add, functionSelectors: functionSelectors});
            functionSelectors = new bytes4[](5);
            functionSelectors[0] = IDiamondLoupe.facets.selector;
            functionSelectors[1] = IDiamondLoupe.facetFunctionSelectors.selector;
            functionSelectors[2] = IDiamondLoupe.facetAddresses.selector;
            functionSelectors[3] = IDiamondLoupe.facetAddress.selector;
            functionSelectors[4] = IERC165.supportsInterface.selector;
            cut[1] = IDiamondCut.FacetCut({
                facetAddress: _diamondLoupeFacet,
                action: IDiamondCut.FacetCutAction.Add,
                functionSelectors: functionSelectors
            });
            functionSelectors = new bytes4[](2);
            functionSelectors[0] = IOwnable.transferOwnership.selector;
            functionSelectors[1] = IOwnable.owner.selector;
            cut[2] = IDiamondCut.FacetCut({facetAddress: _ownershipFacet, action: IDiamondCut.FacetCutAction.Add, functionSelectors: functionSelectors});
            diamondCut(cut, address(0), "");
        }
        // Internal function version of diamondCut
        function diamondCut(
            IDiamondCut.FacetCut[] memory _diamondCut,
            address _init,
            bytes memory _calldata
        ) internal {
            for (uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++) {
                IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action;
                if (action == IDiamondCut.FacetCutAction.Add) {
                    addFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else if (action == IDiamondCut.FacetCutAction.Replace) {
                    replaceFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else if (action == IDiamondCut.FacetCutAction.Remove) {
                    removeFunctions(_diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors);
                } else {
                    revert("LibDiamondCut: Incorrect FacetCutAction");
                }
            }
            emit DiamondCut(_diamondCut, _init, _calldata);
            initializeDiamondCut(_init, _calldata);
        }
        function addFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            // uint16 selectorCount = uint16(diamondStorage().selectors.length);
            require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
            uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
            // add new facet address if it does not exist
            if (selectorPosition == 0) {
                enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
                ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
                ds.facetAddresses.push(_facetAddress);
            }
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                require(oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists");
                ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
                ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
                ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
                selectorPosition++;
            }
        }
        function replaceFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            require(_facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)");
            uint16 selectorPosition = uint16(ds.facetFunctionSelectors[_facetAddress].functionSelectors.length);
            // add new facet address if it does not exist
            if (selectorPosition == 0) {
                enforceHasContractCode(_facetAddress, "LibDiamondCut: New facet has no code");
                ds.facetFunctionSelectors[_facetAddress].facetAddressPosition = uint16(ds.facetAddresses.length);
                ds.facetAddresses.push(_facetAddress);
            }
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                require(oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function");
                removeFunction(oldFacetAddress, selector);
                // add function
                ds.selectorToFacetAndPosition[selector].functionSelectorPosition = selectorPosition;
                ds.facetFunctionSelectors[_facetAddress].functionSelectors.push(selector);
                ds.selectorToFacetAndPosition[selector].facetAddress = _facetAddress;
                selectorPosition++;
            }
        }
        function removeFunctions(address _facetAddress, bytes4[] memory _functionSelectors) internal {
            require(_functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
            DiamondStorage storage ds = diamondStorage();
            // if function does not exist then do nothing and return
            require(_facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
            for (uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++) {
                bytes4 selector = _functionSelectors[selectorIndex];
                address oldFacetAddress = ds.selectorToFacetAndPosition[selector].facetAddress;
                removeFunction(oldFacetAddress, selector);
            }
        }
        function removeFunction(address _facetAddress, bytes4 _selector) internal {
            DiamondStorage storage ds = diamondStorage();
            require(_facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
            // an immutable function is a function defined directly in a diamond
            require(_facetAddress != address(this), "LibDiamondCut: Can't remove immutable function");
            // replace selector with last selector, then delete last selector
            uint256 selectorPosition = ds.selectorToFacetAndPosition[_selector].functionSelectorPosition;
            uint256 lastSelectorPosition = ds.facetFunctionSelectors[_facetAddress].functionSelectors.length - 1;
            // if not the same then replace _selector with lastSelector
            if (selectorPosition != lastSelectorPosition) {
                bytes4 lastSelector = ds.facetFunctionSelectors[_facetAddress].functionSelectors[lastSelectorPosition];
                ds.facetFunctionSelectors[_facetAddress].functionSelectors[selectorPosition] = lastSelector;
                ds.selectorToFacetAndPosition[lastSelector].functionSelectorPosition = uint16(selectorPosition);
            }
            // delete the last selector
            ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop();
            delete ds.selectorToFacetAndPosition[_selector];
            // if no more selectors for facet address then delete the facet address
            if (lastSelectorPosition == 0) {
                // replace facet address with last facet address and delete last facet address
                uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1;
                uint256 facetAddressPosition = ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
                if (facetAddressPosition != lastFacetAddressPosition) {
                    address lastFacetAddress = ds.facetAddresses[lastFacetAddressPosition];
                    ds.facetAddresses[facetAddressPosition] = lastFacetAddress;
                    ds.facetFunctionSelectors[lastFacetAddress].facetAddressPosition = uint16(facetAddressPosition);
                }
                ds.facetAddresses.pop();
                delete ds.facetFunctionSelectors[_facetAddress].facetAddressPosition;
            }
        }
        function initializeDiamondCut(address _init, bytes memory _calldata) internal {
            if (_init == address(0)) {
                require(_calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty");
            } else {
                require(_calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)");
                if (_init != address(this)) {
                    enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
                }
                (bool success, bytes memory error) = _init.delegatecall(_calldata);
                if (success == false) {
                    if (error.length > 0) {
                        // bubble up the error
                        revert(string(error));
                    } else {
                        revert("LibDiamondCut: _init function reverted");
                    }
                }
            }
        }
        function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
            uint256 contractSize;
            assembly {
                contractSize := extcodesize(_contract)
            }
            require(contractSize != 0, _errorMessage);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /******************************************************************************\\
    * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
    /******************************************************************************/
    interface IDiamondCut {
        enum FacetCutAction {Add, Replace, Remove}
        struct FacetCut {
            address facetAddress;
            FacetCutAction action;
            bytes4[] functionSelectors;
        }
        /// @notice Add/replace/remove any number of functions and optionally execute
        ///         a function with delegatecall
        /// @param _diamondCut Contains the facet addresses and function selectors
        /// @param _init The address of the contract or facet to execute _calldata
        /// @param _calldata A function call, including function selector and arguments
        ///                  _calldata is executed with delegatecall on _init
        function diamondCut(
            FacetCut[] calldata _diamondCut,
            address _init,
            bytes calldata _calldata
        ) external;
        event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
    }// SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.3.2 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.0;
    /**
     * @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);
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    // A loupe is a small magnifying glass used to look at diamonds.
    // These functions look at diamonds
    interface IDiamondLoupe {
        /// These functions are expected to be called frequently
        /// by tools.
        struct Facet {
            address facetAddress;
            bytes4[] functionSelectors;
        }
        /// @notice Gets all facet addresses and their four byte function selectors.
        /// @return facets_ Facet
        function facets() external view returns (Facet[] memory facets_);
        /// @notice Gets all the function selectors supported by a specific facet.
        /// @param _facet The facet address.
        /// @return facetFunctionSelectors_
        function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_);
        /// @notice Get all the facet addresses used by a diamond.
        /// @return facetAddresses_
        function facetAddresses() external view returns (address[] memory facetAddresses_);
        /// @notice Gets the facet that supports the given selector.
        /// @dev If facet is not found return address(0).
        /// @param _functionSelector The function selector.
        /// @return facetAddress_ The facet address.
        function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /// @title ERC-173 Contract Ownership Standard
    ///  Note: the ERC-165 identifier for this interface is 0x7f5828d0
    /* is ERC165 */
    interface IOwnable {
        /// @notice Get the address of the owner
        /// @return owner_ The address of the owner.
        function owner() external view returns (address owner_);
        /// @notice Set the address of the new owner of the contract
        /// @dev Set _newOwner to address(0) to renounce any ownership.
        /// @param _newOwner The address of the new owner of the contract
        function transferOwnership(address _newOwner) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.7;
    /// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
    interface IERC721TokenReceiver {
        /// @notice Handle the receipt of an NFT
        /// @dev The ERC721 smart contract calls this function on the recipient
        ///  after a `transfer`. This function MAY throw to revert and reject the
        ///  transfer. Return of other than the magic value MUST result in the
        ///  transaction being reverted.
        ///  Note: the contract address is always the message sender.
        /// @param _operator The address which called `safeTransferFrom` function
        /// @param _from The address which previously owned the token
        /// @param _tokenId The NFT identifier which is being transferred
        /// @param _data Additional data with no specified format
        /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
        ///  unless throwing
        function onERC721Received(
            address _operator,
            address _from,
            uint256 _tokenId,
            bytes calldata _data
        ) external returns (bytes4);
    }