creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/interfaces/IERC2981.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Interface for the NFT Royalty Standard.\n *\n * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal\n * support for royalty payments across all NFT marketplaces and ecosystem participants.\n */\ninterface IERC2981 is IERC165 {\n    /**\n     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of\n     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.\n     */\n    function royaltyInfo(\n        uint256 tokenId,\n        uint256 salePrice\n    ) external view returns (address receiver, uint256 royaltyAmount);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721} from \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the address zero.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n     * reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/implementations/abstract/RMRKAbstractEquippable.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IERC2981} from \"@openzeppelin/contracts/interfaces/IERC2981.sol\";\nimport {\n    IERC721Metadata\n} from \"@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol\";\nimport {\n    RMRKMinifiedEquippable\n} from \"../../RMRK/equippable/RMRKMinifiedEquippable.sol\";\nimport {RMRKImplementationBase} from \"../utils/RMRKImplementationBase.sol\";\n\n/**\n * @title RMRKAbstractEquippable\n * @author RMRK team\n * @notice Abstract implementation of RMRK equipable module.\n */\nabstract contract RMRKAbstractEquippable is\n    RMRKImplementationBase,\n    RMRKMinifiedEquippable\n{\n    /**\n     * @notice Used to add an asset to a token.\n     * @dev If the given asset is already added to the token, the execution will be reverted.\n     * @dev If the asset ID is invalid, the execution will be reverted.\n     * @dev If the token already has the maximum amount of pending assets (128), the execution will be\n     *  reverted.\n     * @param tokenId ID of the token to add the asset to\n     * @param assetId ID of the asset to add to the token\n     * @param replacesAssetWithId ID of the asset to replace from the token's list of active assets\n     */\n    function addAssetToToken(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 replacesAssetWithId\n    ) public virtual onlyOwnerOrContributor {\n        _addAssetToToken(tokenId, assetId, replacesAssetWithId);\n    }\n\n    /**\n     * @notice Used to add an equippable asset entry.\n     * @dev The ID of the asset is automatically assigned to be the next available asset ID.\n     * @param equippableGroupId ID of the equippable group\n     * @param catalogAddress Address of the `Catalog` smart contract this asset belongs to\n     * @param metadataURI Metadata URI of the asset\n     * @param partIds An array of IDs of fixed and slot parts to be included in the asset\n     * @return assetId The ID of the newly added asset\n     */\n    function addEquippableAssetEntry(\n        uint64 equippableGroupId,\n        address catalogAddress,\n        string memory metadataURI,\n        uint64[] memory partIds\n    ) public virtual onlyOwnerOrContributor returns (uint256 assetId) {\n        unchecked {\n            ++_totalAssets;\n        }\n        _addAssetEntry(\n            uint64(_totalAssets),\n            equippableGroupId,\n            catalogAddress,\n            metadataURI,\n            partIds\n        );\n        assetId = _totalAssets;\n    }\n\n    /**\n     * @notice Used to add a asset entry.\n     * @dev The ID of the asset is automatically assigned to be the next available asset ID.\n     * @param metadataURI Metadata URI of the asset\n     * @return assetId ID of the newly added asset\n     */\n    function addAssetEntry(\n        string memory metadataURI\n    ) public virtual onlyOwnerOrContributor returns (uint256 assetId) {\n        unchecked {\n            ++_totalAssets;\n        }\n        _addAssetEntry(uint64(_totalAssets), metadataURI);\n        assetId = _totalAssets;\n    }\n\n    /**\n     * @notice Used to declare that the assets belonging to a given `equippableGroupId` are equippable into the `Slot`\n     *  associated with the `partId` of the collection at the specified `parentAddress`\n     * @param equippableGroupId ID of the equippable group\n     * @param parentAddress Address of the parent into which the equippable group can be equipped into\n     * @param partId ID of the `Slot` that the items belonging to the equippable group can be equipped into\n     */\n    function setValidParentForEquippableGroup(\n        uint64 equippableGroupId,\n        address parentAddress,\n        uint64 partId\n    ) public virtual onlyOwnerOrContributor {\n        _setValidParentForEquippableGroup(\n            equippableGroupId,\n            parentAddress,\n            partId\n        );\n    }\n\n    /**\n     * @inheritdoc IERC165\n     */\n    function supportsInterface(\n        bytes4 interfaceId\n    ) public view virtual override returns (bool) {\n        return\n            super.supportsInterface(interfaceId) ||\n            interfaceId == type(IERC2981).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            interfaceId == RMRK_INTERFACE();\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual override {\n        super._beforeTokenTransfer(from, to, tokenId);\n        if (to == address(0)) {\n            unchecked {\n                _totalSupply -= 1;\n            }\n        }\n    }\n\n    function _afterAddAssetToToken(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 replacesAssetWithId\n    ) internal virtual override {\n        super._afterAddAssetToToken(tokenId, assetId, replacesAssetWithId);\n        // This relies on no other auto accept mechanism being in place.\n        // We auto accept the first ever asset or any asset added by the token owner.\n        // This is done to allow a meta factory to mint, add assets and accept them in one transaction.\n        if (\n            _activeAssets[tokenId].length == 0 ||\n            _msgSender() == ownerOf(tokenId)\n        ) {\n            _acceptAsset(tokenId, _pendingAssets[tokenId].length - 1, assetId);\n        }\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/implementations/premint/RMRKEquippablePreMint.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {RMRKAbstractEquippable} from \"../abstract/RMRKAbstractEquippable.sol\";\nimport {RMRKImplementationBase} from \"../utils/RMRKImplementationBase.sol\";\nimport {RMRKTokenURIPerToken} from \"../utils/RMRKTokenURIPerToken.sol\";\n\n/**\n * @title RMRKEquippablePreMint\n * @author RMRK team\n * @notice Implementation of RMRK equippable module with pre-minting.\n */\ncontract RMRKEquippablePreMint is RMRKTokenURIPerToken, RMRKAbstractEquippable {\n    /**\n     * @notice Used to initialize the smart contract.\n     * @param name Name of the token collection\n     * @param symbol Symbol of the token collection\n     * @param collectionMetadata CID of the collection metadata\n     * @param maxSupply The maximum supply of tokens\n     * @param royaltyRecipient Recipient of resale royalties\n     * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points\n     */\n    constructor(\n        string memory name,\n        string memory symbol,\n        string memory collectionMetadata,\n        uint256 maxSupply,\n        address royaltyRecipient,\n        uint16 royaltyPercentageBps\n    )\n        RMRKImplementationBase(\n            name,\n            symbol,\n            collectionMetadata,\n            maxSupply,\n            royaltyRecipient,\n            royaltyPercentageBps\n        )\n    {}\n\n    /**\n     * @notice Used to mint the desired number of tokens to the specified address.\n     * @dev The `data` value of the `_safeMint` method is set to an empty value.\n     * @dev Can only be called while the open sale is open.\n     * @param to Address to which to mint the token\n     * @param numToMint Number of tokens to mint\n     * @param tokenURI URI assigned to all the minted tokens\n     * @return firstTokenId The ID of the first token to be minted in the current minting cycle\n     */\n    function mint(\n        address to,\n        uint256 numToMint,\n        string memory tokenURI\n    ) public virtual onlyOwnerOrContributor returns (uint256 firstTokenId) {\n        (uint256 nextToken, uint256 totalSupplyOffset) = _prepareMint(\n            numToMint\n        );\n\n        for (uint256 i = nextToken; i < totalSupplyOffset; ) {\n            _setTokenURI(i, tokenURI);\n            _safeMint(to, i, \"\");\n            unchecked {\n                ++i;\n            }\n        }\n\n        firstTokenId = nextToken;\n    }\n\n    /**\n     * @notice Used to mint a desired number of child tokens to a given parent token.\n     * @dev The `data` value of the `_safeMint` method is set to an empty value.\n     * @dev Can only be called while the open sale is open.\n     * @param to Address of the collection smart contract of the token into which to mint the child token\n     * @param numToMint Number of tokens to mint\n     * @param destinationId ID of the token into which to mint the new child token\n     * @param tokenURI URI assigned to all the minted tokens\n     * @return firstTokenId The ID of the first token to be minted in the current minting cycle\n     */\n    function nestMint(\n        address to,\n        uint256 numToMint,\n        uint256 destinationId,\n        string memory tokenURI\n    ) public virtual onlyOwnerOrContributor returns (uint256 firstTokenId) {\n        (uint256 nextToken, uint256 totalSupplyOffset) = _prepareMint(\n            numToMint\n        );\n\n        for (uint256 i = nextToken; i < totalSupplyOffset; ) {\n            _setTokenURI(i, tokenURI);\n            _nestMint(to, i, destinationId, \"\");\n            unchecked {\n                ++i;\n            }\n        }\n\n        firstTokenId = nextToken;\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/implementations/premint/RMRKEquippablePreMintSoulbound.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {RMRKAbstractEquippable} from \"../abstract/RMRKAbstractEquippable.sol\";\nimport {RMRKEquippablePreMint} from \"./RMRKEquippablePreMint.sol\";\nimport {RMRKSoulbound} from \"../../RMRK/extension/soulbound/RMRKSoulbound.sol\";\n\n/**\n * @title RMRKEquippablePreMintSoulbound\n * @author RMRK team\n * @notice Implementation of non-transferable RMRK equippable module with pre-minting.\n */\ncontract RMRKEquippablePreMintSoulbound is\n    RMRKSoulbound,\n    RMRKEquippablePreMint\n{\n    /**\n     * @notice Used to initialize the smart contract.\n     * @param name Name of the token collection\n     * @param symbol Symbol of the token collection\n     * @param collectionMetadata CID of the collection metadata\n     * @param maxSupply The maximum supply of tokens\n     * @param royaltyRecipient Recipient of resale royalties\n     * @param royaltyPercentageBps The percentage to be paid from the sale of the token expressed in basis points\n     */\n    constructor(\n        string memory name,\n        string memory symbol,\n        string memory collectionMetadata,\n        uint256 maxSupply,\n        address royaltyRecipient,\n        uint16 royaltyPercentageBps\n    )\n        RMRKEquippablePreMint(\n            name,\n            symbol,\n            collectionMetadata,\n            maxSupply,\n            royaltyRecipient,\n            royaltyPercentageBps\n        )\n    {}\n\n    /**\n     * @inheritdoc IERC165\n     */\n    function supportsInterface(\n        bytes4 interfaceId\n    )\n        public\n        view\n        virtual\n        override(RMRKSoulbound, RMRKAbstractEquippable)\n        returns (bool)\n    {\n        return\n            RMRKAbstractEquippable.supportsInterface(interfaceId) ||\n            RMRKSoulbound.supportsInterface(interfaceId);\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual override(RMRKSoulbound, RMRKAbstractEquippable) {\n        RMRKSoulbound._beforeTokenTransfer(from, to, tokenId);\n        RMRKAbstractEquippable._beforeTokenTransfer(from, to, tokenId);\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/implementations/utils/RMRKImplementationBase.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.21;\n\nimport {Ownable} from \"../../RMRK/access/Ownable.sol\";\nimport \"../../RMRK/library/RMRKErrors.sol\";\nimport {RMRKRoyalties} from \"../../RMRK/extension/RMRKRoyalties.sol\";\n\n/**\n * @title RMRKImplementationBase\n * @author RMRK team\n * @notice Smart contract of the RMRK minting utils module.\n * @dev This smart contract includes the top-level utilities for managing minting and implements Ownable by default.\n */\nabstract contract RMRKImplementationBase is RMRKRoyalties, Ownable {\n    string internal _contractURI;\n    string private _name;\n    string private _symbol;\n\n    uint256 private _nextId;\n    uint256 internal _totalSupply;\n    uint256 internal _maxSupply;\n    uint256 internal _totalAssets;\n\n    /**\n     * @notice Initializes the smart contract with a given maximum supply and minting price.\n     * @param name_ Name of the token collection\n     * @param symbol_ Symbol of the token collection\n     * @param contractURI_ The collection metadata URI\n     * @param maxSupply_ The maximum supply of tokens\n     * @param royaltyRecipient Address to which royalties should be sent\n     * @param royaltyPercentageBps The royalty percentage expressed in basis points\n     */\n    constructor(\n        string memory name_,\n        string memory symbol_,\n        string memory contractURI_,\n        uint256 maxSupply_,\n        address royaltyRecipient,\n        uint256 royaltyPercentageBps\n    ) RMRKRoyalties(royaltyRecipient, royaltyPercentageBps) {\n        _name = name_;\n        _symbol = symbol_;\n        _contractURI = contractURI_;\n        _maxSupply = maxSupply_;\n    }\n\n    /**\n     * @notice Used to retrieve the total supply of the tokens in a collection.\n     * @return totalSupply_ The number of tokens in a collection\n     */\n    function totalSupply() public view virtual returns (uint256 totalSupply_) {\n        totalSupply_ = _totalSupply;\n    }\n\n    /**\n     * @notice Used to retrieve the maximum supply of the collection.\n     * @return maxSupply_ The maximum supply of tokens in the collection\n     */\n    function maxSupply() public view virtual returns (uint256 maxSupply_) {\n        maxSupply_ = _maxSupply;\n    }\n\n    /**\n     * @notice Used to retrieve the total number of assets.\n     * @return totalAssets_ The total number of assets\n     */\n    function totalAssets() public view virtual returns (uint256 totalAssets_) {\n        totalAssets_ = _totalAssets;\n    }\n\n    /**\n     * @notice Used to retrieve the metadata URI of the collection.\n     * @return contractURI_ string The metadata URI of the collection\n     */\n    function contractURI()\n        public\n        view\n        virtual\n        returns (string memory contractURI_)\n    {\n        contractURI_ = _contractURI;\n    }\n\n    /**\n     * @notice Used to retrieve the collection name.\n     * @return name_ Name of the collection\n     */\n    function name() public view virtual returns (string memory name_) {\n        name_ = _name;\n    }\n\n    /**\n     * @notice Used to retrieve the collection symbol.\n     * @return symbol_ Symbol of the collection\n     */\n    function symbol() public view virtual returns (string memory symbol_) {\n        symbol_ = _symbol;\n    }\n\n    /**\n     * @inheritdoc RMRKRoyalties\n     */\n    function updateRoyaltyRecipient(\n        address newRoyaltyRecipient\n    ) public virtual override onlyOwner {\n        _setRoyaltyRecipient(newRoyaltyRecipient);\n    }\n\n    /**\n     * @notice Used to calculate the token IDs of tokens to be minted.\n     * @param numToMint Amount of tokens to be minted\n     * @return nextToken The ID of the first token to be minted in the current minting cycle\n     * @return totalSupplyOffset The ID of the last token to be minted in the current minting cycle\n     */\n    function _prepareMint(\n        uint256 numToMint\n    ) internal virtual returns (uint256 nextToken, uint256 totalSupplyOffset) {\n        if (numToMint == uint256(0)) revert RMRKMintZero();\n        if (numToMint + _nextId > _maxSupply) revert RMRKMintOverMax();\n\n        unchecked {\n            nextToken = _nextId + 1;\n            _nextId += numToMint;\n            _totalSupply += numToMint;\n            totalSupplyOffset = _nextId + 1;\n        }\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/implementations/utils/RMRKTokenURIPerToken.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\n/**\n * @title RMRKTokenURIPerToken\n * @author RMRK team\n * @notice Implementation of token URI per token.\n */\ncontract RMRKTokenURIPerToken {\n    mapping(uint256 => string) private _tokenURIs;\n\n    /**\n     * @notice Used to retrieve the metadata URI of a token.\n     * @param tokenId ID of the token to retrieve the metadata URI for\n     * @return tokenURI_ Metadata URI of the specified token\n     */\n    function tokenURI(\n        uint256 tokenId\n    ) public view virtual returns (string memory tokenURI_) {\n        tokenURI_ = _tokenURIs[tokenId];\n    }\n\n    /**\n     * @notice Used to set the token URI configuration.\n     * @param tokenId ID of the token to set the metadata URI for\n     * @param tokenURI_ Metadata URI to apply to all tokens, either as base or as full URI for every token\n     */\n    function _setTokenURI(\n        uint256 tokenId,\n        string memory tokenURI_\n    ) internal virtual {\n        _tokenURIs[tokenId] = tokenURI_;\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {Context} from \"@openzeppelin/contracts/utils/Context.sol\";\nimport \"../library/RMRKErrors.sol\";\n\n/**\n * @title Ownable\n * @author RMRK team\n * @notice A minimal ownable smart contract or owner and contributors.\n * @dev This smart contract is based on \"openzeppelin's access/Ownable.sol\".\n */\ncontract Ownable is Context {\n    address private _owner;\n    mapping(address => uint256) private _contributors;\n\n    /**\n     * @notice Used to anounce the transfer of ownership.\n     * @param previousOwner Address of the account that transferred their ownership role\n     * @param newOwner Address of the account receiving the ownership role\n     */\n    event OwnershipTransferred(\n        address indexed previousOwner,\n        address indexed newOwner\n    );\n\n    /**\n     * @notice Event that signifies that an address was granted contributor role or that the permission has been\n     *  revoked.\n     * @dev This can only be triggered by a current owner, so there is no need to include that information in the event.\n     * @param contributor Address of the account that had contributor role status updated\n     * @param isContributor A boolean value signifying whether the role has been granted (`true`) or revoked (`false`)\n     */\n    event ContributorUpdate(address indexed contributor, bool isContributor);\n\n    /**\n     * @dev Reverts if called by any account other than the owner or an approved contributor.\n     */\n    modifier onlyOwnerOrContributor() {\n        _onlyOwnerOrContributor();\n        _;\n    }\n\n    /**\n     * @dev Reverts if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _onlyOwner();\n        _;\n    }\n\n    /**\n     * @dev Initializes the contract by setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @notice Returns the address of the current owner.\n     * @return owner_ Address of the current owner\n     */\n    function owner() public view virtual returns (address owner_) {\n        owner_ = _owner;\n    }\n\n    /**\n     * @notice Leaves the contract without owner. Functions using the `onlyOwner` modifier will be disabled.\n     * @dev Can only be called by the current owner.\n     * @dev Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is\n     *  only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @notice Transfers ownership of the contract to a new owner.\n     * @dev Can only be called by the current owner.\n     * @param newOwner Address of the new owner's account\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) revert RMRKNewOwnerIsZeroAddress();\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @notice Transfers ownership of the contract to a new owner.\n     * @dev Internal function without access restriction.\n     * @dev Emits ***OwnershipTransferred*** event.\n     * @param newOwner Address of the new owner's account\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @notice Adds or removes a contributor to the smart contract.\n     * @dev Can only be called by the owner.\n     * @dev Emits ***ContributorUpdate*** event.\n     * @param contributor Address of the contributor's account\n     * @param grantRole A boolean value signifying whether the contributor role is being granted (`true`) or revoked\n     *  (`false`)\n     */\n    function manageContributor(\n        address contributor,\n        bool grantRole\n    ) external onlyOwner {\n        if (contributor == address(0)) revert RMRKNewContributorIsZeroAddress();\n        grantRole\n            ? _contributors[contributor] = 1\n            : _contributors[contributor] = 0;\n        emit ContributorUpdate(contributor, grantRole);\n    }\n\n    /**\n     * @notice Used to check if the address is one of the contributors.\n     * @param contributor Address of the contributor whose status we are checking\n     * @return isContributor_ Boolean value indicating whether the address is a contributor or not\n     */\n    function isContributor(\n        address contributor\n    ) public view returns (bool isContributor_) {\n        isContributor_ = _contributors[contributor] == 1;\n    }\n\n    /**\n     * @notice Used to verify that the caller is either the owner or a contributor.\n     * @dev If the caller is not the owner or a contributor, the execution will be reverted.\n     */\n    function _onlyOwnerOrContributor() private view {\n        if (owner() != _msgSender() && !isContributor(_msgSender()))\n            revert RMRKNotOwnerOrContributor();\n    }\n\n    /**\n     * @notice Used to verify that the caller is the owner.\n     * @dev If the caller is not the owner, the execution will be reverted.\n     */\n    function _onlyOwner() private view {\n        if (owner() != _msgSender()) revert RMRKNotOwner();\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/catalog/IRMRKCatalog.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @title IRMRKCatalog\n * @author RMRK team\n * @notice An interface Catalog for RMRK equippable module.\n */\ninterface IRMRKCatalog is IERC165 {\n    /**\n     * @notice Event to announce addition of a new part.\n     * @dev It is emitted when a new part is added.\n     * @param partId ID of the part that was added\n     * @param itemType Enum value specifying whether the part is `None`, `Slot` and `Fixed`\n     * @param zIndex An uint specifying the z value of the part. It is used to specify the depth which the part should\n     *  be rendered at\n     * @param equippableAddresses An array of addresses that can equip this part\n     * @param metadataURI The metadata URI of the part\n     */\n    event AddedPart(\n        uint64 indexed partId,\n        ItemType indexed itemType,\n        uint8 zIndex,\n        address[] equippableAddresses,\n        string metadataURI\n    );\n\n    /**\n     * @notice Event to announce new equippables to the part.\n     * @dev It is emitted when new addresses are marked as equippable for `partId`.\n     * @param partId ID of the part that had new equippable addresses added\n     * @param equippableAddresses An array of the new addresses that can equip this part\n     */\n    event AddedEquippables(\n        uint64 indexed partId,\n        address[] equippableAddresses\n    );\n\n    /**\n     * @notice Event to announce the overriding of equippable addresses of the part.\n     * @dev It is emitted when the existing list of addresses marked as equippable for `partId` is overwritten by a new one.\n     * @param partId ID of the part whose list of equippable addresses was overwritten\n     * @param equippableAddresses The new, full, list of addresses that can equip this part\n     */\n    event SetEquippables(uint64 indexed partId, address[] equippableAddresses);\n\n    /**\n     * @notice Event to announce that a given part can be equipped by any address.\n     * @dev It is emitted when a given part is marked as equippable by any.\n     * @param partId ID of the part marked as equippable by any address\n     */\n    event SetEquippableToAll(uint64 indexed partId);\n\n    /**\n     * @notice Used to define a type of the item. Possible values are `None`, `Slot` or `Fixed`.\n     * @dev Used for fixed and slot parts.\n     */\n    enum ItemType {\n        None,\n        Slot,\n        Fixed\n    }\n\n    /**\n     * @notice The integral structure of a standard RMRK catalog item defining it.\n     * @dev Requires a minimum of 3 storage slots per catalog item, equivalent to roughly 60,000 gas as of Berlin hard\n     *  fork (April 14, 2021), though 5-7 storage slots is more realistic, given the standard length of an IPFS URI.\n     *  This will result in between 25,000,000 and 35,000,000 gas per 250 assets--the maximum block size of Ethereum\n     *  mainnet is 30M at peak usage.\n     * @return itemType The item type of the part\n     * @return z The z value of the part defining how it should be rendered when presenting the full NFT\n     * @return equippable The array of addresses allowed to be equipped in this part\n     * @return metadataURI The metadata URI of the part\n     */\n    struct Part {\n        ItemType itemType; //1 byte\n        uint8 z; //1 byte\n        address[] equippable; //n Collections that can be equipped into this slot\n        string metadataURI; //n bytes 32+\n    }\n\n    /**\n     * @notice The structure used to add a new `Part`.\n     * @dev The part is added with specified ID, so you have to make sure that you are using an unused `partId`,\n     *  otherwise the addition of the part vill be reverted.\n     * @dev The full `IntakeStruct` looks like this:\n     *  [\n     *          partID,\n     *      [\n     *          itemType,\n     *          z,\n     *          [\n     *               permittedCollectionAddress0,\n     *               permittedCollectionAddress1,\n     *               permittedCollectionAddress2\n     *           ],\n     *           metadataURI\n     *       ]\n     *   ]\n     * @return partId ID to be assigned to the `Part`\n     * @return part A `Part` to be added\n     */\n    struct IntakeStruct {\n        uint64 partId;\n        Part part;\n    }\n\n    /**\n     * @notice Used to return the metadata URI of the associated Catalog.\n     * @return Catalog metadata URI\n     */\n    function getMetadataURI() external view returns (string memory);\n\n    /**\n     * @notice Used to return the `itemType` of the associated Catalog\n     * @return `itemType` of the associated Catalog\n     */\n    function getType() external view returns (string memory);\n\n    /**\n     * @notice Used to check whether the given address is allowed to equip the desired `Part`.\n     * @dev Returns true if a collection may equip asset with `partId`.\n     * @param partId The ID of the part that we are checking\n     * @param targetAddress The address that we are checking for whether the part can be equipped into it or not\n     * @return isEquippable The status indicating whether the `targetAddress` can be equipped into `Part` with `partId` or not\n     */\n    function checkIsEquippable(\n        uint64 partId,\n        address targetAddress\n    ) external view returns (bool isEquippable);\n\n    /**\n     * @notice Used to check if the part is equippable by all addresses.\n     * @dev Returns true if part is equippable to all.\n     * @param partId ID of the part that we are checking\n     * @return isEquippableToAll The status indicating whether the part with `partId` can be equipped by any address or not\n     */\n    function checkIsEquippableToAll(\n        uint64 partId\n    ) external view returns (bool isEquippableToAll);\n\n    /**\n     * @notice Used to retrieve a `Part` with id `partId`\n     * @param partId ID of the part that we are retrieving\n     * @return part The `Part` struct associated with given `partId`\n     */\n    function getPart(uint64 partId) external view returns (Part memory part);\n\n    /**\n     * @notice Used to retrieve multiple parts at the same time.\n     * @param partIds An array of part IDs that we want to retrieve\n     * @return part An array of `Part` structs associated with given `partIds`\n     */\n    function getParts(\n        uint64[] memory partIds\n    ) external view returns (Part[] memory part);\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/core/RMRKCore.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\n/**\n * @title RMRKCore\n * @author RMRK team\n * @notice Smart contract of the RMRK core module.\n * @dev This is currently just a passthrough contract which allows for granular editing of base-level ERC721 functions.\n */\ncontract RMRKCore {\n    string private constant _VERSION = \"2.5.4\";\n    bytes4 private constant _RMRK_INTERFACE = 0x524D524B; // \"RMRK\" in ASCII hex\n\n    /**\n     * @notice Version of the @rmrk-team/evm-contracts package\n     * @return version Version identifier for implementations of the @rmrk-team/evm-contracts package\n     */\n    function VERSION() public pure returns (string memory version) {\n        version = _VERSION;\n    }\n\n    /**\n     * @notice Interface identifier of the @rmrk-team/evm-contracts package\n     * @return rmrkInterface Interface identifier for implementations of the @rmrk-team/evm-contracts package\n     */\n    function RMRK_INTERFACE() public pure returns (bytes4 rmrkInterface) {\n        rmrkInterface = _RMRK_INTERFACE;\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/equippable/IERC6220.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC5773} from \"../multiasset/IERC5773.sol\";\n\n/**\n * @title IERC6220\n * @author RMRK team\n * @notice Interface smart contract of the RMRK equippable module.\n */\ninterface IERC6220 is IERC5773 {\n    /**\n     * @notice Used to store the core structure of the `Equippable` RMRK lego.\n     * @return assetId The ID of the asset equipping a child\n     * @return childAssetId The ID of the asset used as equipment\n     * @return childId The ID of token that is equipped\n     * @return childEquippableAddress Address of the collection to which the child asset belongs to\n     */\n    struct Equipment {\n        uint64 assetId;\n        uint64 childAssetId;\n        uint256 childId;\n        address childEquippableAddress;\n    }\n\n    /**\n     * @notice Used to provide a struct for inputing equip data.\n     * @dev Only used for input and not storage of data.\n     * @return tokenId ID of the token we are managing\n     * @return childIndex Index of a child in the list of token's active children\n     * @return assetId ID of the asset that we are equipping into\n     * @return slotPartId ID of the slot part that we are using to equip\n     * @return childAssetId ID of the asset that we are equipping\n     */\n    struct IntakeEquip {\n        uint256 tokenId;\n        uint256 childIndex;\n        uint64 assetId;\n        uint64 slotPartId;\n        uint64 childAssetId;\n    }\n\n    /**\n     * @notice Used to notify listeners that a child's asset has been equipped into one of its parent assets.\n     * @param tokenId ID of the token that had an asset equipped\n     * @param assetId ID of the asset associated with the token we are equipping into\n     * @param slotPartId ID of the slot we are using to equip\n     * @param childId ID of the child token we are equipping into the slot\n     * @param childAddress Address of the child token's collection\n     * @param childAssetId ID of the asset associated with the token we are equipping\n     */\n    event ChildAssetEquipped(\n        uint256 indexed tokenId,\n        uint64 indexed assetId,\n        uint64 indexed slotPartId,\n        uint256 childId,\n        address childAddress,\n        uint64 childAssetId\n    );\n\n    /**\n     * @notice Used to notify listeners that a child's asset has been unequipped from one of its parent assets.\n     * @param tokenId ID of the token that had an asset unequipped\n     * @param assetId ID of the asset associated with the token we are unequipping out of\n     * @param slotPartId ID of the slot we are unequipping from\n     * @param childId ID of the token being unequipped\n     * @param childAddress Address of the collection that a token that is being unequipped belongs to\n     * @param childAssetId ID of the asset associated with the token we are unequipping\n     */\n    event ChildAssetUnequipped(\n        uint256 indexed tokenId,\n        uint64 indexed assetId,\n        uint64 indexed slotPartId,\n        uint256 childId,\n        address childAddress,\n        uint64 childAssetId\n    );\n\n    /**\n     * @notice Used to notify listeners that the assets belonging to a `equippableGroupId` have been marked as\n     *  equippable into a given slot and parent\n     * @param equippableGroupId ID of the equippable group being marked as equippable into the slot associated with\n     *  `slotPartId` of the `parentAddress` collection\n     * @param slotPartId ID of the slot part of the catalog into which the parts belonging to the equippable group\n     *  associated with `equippableGroupId` can be equipped\n     * @param parentAddress Address of the collection into which the parts belonging to `equippableGroupId` can be\n     *  equipped\n     */\n    event ValidParentEquippableGroupIdSet(\n        uint64 indexed equippableGroupId,\n        uint64 indexed slotPartId,\n        address parentAddress\n    );\n\n    /**\n     * @notice Used to equip a child into a token.\n     * @dev The `IntakeEquip` stuct contains the following data:\n     *  [\n     *      tokenId,\n     *      childIndex,\n     *      assetId,\n     *      slotPartId,\n     *      childAssetId\n     *  ]\n     * @param data An `IntakeEquip` struct specifying the equip data\n     */\n    function equip(IntakeEquip memory data) external;\n\n    /**\n     * @notice Used to unequip child from parent token.\n     * @dev This can only be called by the owner of the token or by an account that has been granted permission to\n     *  manage the given token by the current owner.\n     * @param tokenId ID of the parent from which the child is being unequipped\n     * @param assetId ID of the parent's asset that contains the `Slot` into which the child is equipped\n     * @param slotPartId ID of the `Slot` from which to unequip the child\n     */\n    function unequip(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotPartId\n    ) external;\n\n    /**\n     * @notice Used to check whether the token has a given child equipped.\n     * @dev This is used to prevent from transferring a child that is equipped.\n     * @param tokenId ID of the parent token for which we are querying for\n     * @param childAddress Address of the child token's smart contract\n     * @param childId ID of the child token\n     * @return isEquipped A boolean value indicating whether the child token is equipped into the given token or not\n     */\n    function isChildEquipped(\n        uint256 tokenId,\n        address childAddress,\n        uint256 childId\n    ) external view returns (bool isEquipped);\n\n    /**\n     * @notice Used to verify whether a token can be equipped into a given parent's slot.\n     * @param parent Address of the parent token's smart contract\n     * @param tokenId ID of the token we want to equip\n     * @param assetId ID of the asset associated with the token we want to equip\n     * @param slotId ID of the slot that we want to equip the token into\n     * @return canBeEquipped A boolean indicating whether the token with the given asset can be equipped into the desired slot\n     */\n    function canTokenBeEquippedWithAssetIntoSlot(\n        address parent,\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotId\n    ) external view returns (bool canBeEquipped);\n\n    /**\n     * @notice Used to get the Equipment object equipped into the specified slot of the desired token.\n     * @dev The `Equipment` struct consists of the following data:\n     *  [\n     *      assetId,\n     *      childAssetId,\n     *      childId,\n     *      childEquippableAddress\n     *  ]\n     * @param tokenId ID of the token for which we are retrieving the equipped object\n     * @param targetCatalogAddress Address of the `Catalog` associated with the `Slot` part of the token\n     * @param slotPartId ID of the `Slot` part that we are checking for equipped objects\n     * @return equipment The `Equipment` struct containing data about the equipped object\n     */\n    function getEquipment(\n        uint256 tokenId,\n        address targetCatalogAddress,\n        uint64 slotPartId\n    ) external view returns (Equipment memory equipment);\n\n    /**\n     * @notice Used to get the asset and equippable data associated with given `assetId`.\n     * @param tokenId ID of the token for which to retrieve the asset\n     * @param assetId ID of the asset of which we are retrieving\n     * @return metadataURI The metadata URI of the asset\n     * @return equippableGroupId ID of the equippable group this asset belongs to\n     * @return catalogAddress The address of the catalog the part belongs to\n     * @return partIds An array of IDs of parts included in the asset\n     */\n    function getAssetAndEquippableData(\n        uint256 tokenId,\n        uint64 assetId\n    )\n        external\n        view\n        returns (\n            string memory metadataURI,\n            uint64 equippableGroupId,\n            address catalogAddress,\n            uint64[] memory partIds\n        );\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/equippable/RMRKMinifiedEquippable.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {IERC5773} from \"../multiasset/IERC5773.sol\";\nimport {IERC6220} from \"../equippable/IERC6220.sol\";\nimport {IERC721} from \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport {\n    IERC721Receiver\n} from \"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol\";\nimport {IERC7401} from \"../nestable/IERC7401.sol\";\nimport {Context} from \"@openzeppelin/contracts/utils/Context.sol\";\nimport {IRMRKCatalog} from \"../catalog/IRMRKCatalog.sol\";\nimport {RMRKCore} from \"../core/RMRKCore.sol\";\nimport {RMRKLib} from \"../library/RMRKLib.sol\";\nimport {ReentrancyGuard} from \"../security/ReentrancyGuard.sol\";\nimport \"../library/RMRKErrors.sol\";\n\n/**\n * @title RMRKMinifiedEquippable\n * @author RMRK team\n * @notice Smart contract of the RMRK Equippable module, without utility internal functions.\n * @dev This includes all the code for MultiAsset, Nestable and Equippable.\n * @dev Most of the code is duplicated from the other legos, this version is created to save size.\n */\ncontract RMRKMinifiedEquippable is\n    ReentrancyGuard,\n    Context,\n    IERC165,\n    IERC721,\n    IERC7401,\n    IERC6220,\n    RMRKCore\n{\n    using RMRKLib for uint64[];\n\n    uint256 private constant _MAX_LEVELS_TO_CHECK_FOR_INHERITANCE_LOOP = 100;\n\n    // Mapping owner address to token count\n    mapping(address => uint256) private _balances;\n\n    // Mapping from token ID to approver address to approved address\n    // The approver is necessary so approvals are invalidated for nested children on transfer\n    // WARNING: If a child NFT returns to a previous root owner, old permissions would be active again\n    mapping(uint256 => mapping(address => address)) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    // ------------------- NESTABLE --------------\n\n    // Mapping from token ID to DirectOwner struct\n    mapping(uint256 => DirectOwner) private _RMRKOwners;\n\n    // Mapping of tokenId to array of active children structs\n    mapping(uint256 => Child[]) internal _activeChildren;\n\n    // Mapping of tokenId to array of pending children structs\n    mapping(uint256 => Child[]) internal _pendingChildren;\n\n    // Mapping of child token address to child token ID to whether they are pending or active on any token\n    // We might have a first extra mapping from token ID, but since the same child cannot be nested into multiple tokens\n    //  we can strip it for size/gas savings.\n    mapping(address => mapping(uint256 => uint256)) internal _childIsInActive;\n\n    // -------------------------- MODIFIERS ----------------------------\n\n    /**\n     * @notice Used to verify that the caller is either the owner of the token or approved to manage it by its owner.\n     * @dev If the caller is not the owner of the token or approved to manage it by its owner, the execution will be\n     *  reverted.\n     * @param tokenId ID of the token to check\n     */\n    function _onlyApprovedOrOwner(uint256 tokenId) internal view {\n        address owner = ownerOf(tokenId);\n        if (\n            !(_msgSender() == owner ||\n                isApprovedForAll(owner, _msgSender()) ||\n                getApproved(tokenId) == _msgSender())\n        ) revert ERC721NotApprovedOrOwner();\n    }\n\n    /**\n     * @notice Used to verify that the caller is either the owner of the token or approved to manage it by its owner.\n     * @param tokenId ID of the token to check\n     */\n    modifier onlyApprovedOrOwner(uint256 tokenId) {\n        _onlyApprovedOrOwner(tokenId);\n        _;\n    }\n\n    /**\n     * @notice Used to verify that the caller is approved to manage the given token or it its direct owner.\n     * @dev This does not delegate to ownerOf, which returns the root owner, but rater uses an owner from DirectOwner\n     *  struct.\n     * @dev The execution is reverted if the caller is not immediate owner or approved to manage the given token.\n     * @dev Used for parent-scoped transfers.\n     * @param tokenId ID of the token to check.\n     */\n    function _onlyApprovedOrDirectOwner(uint256 tokenId) internal view {\n        (address owner, uint256 parentId, ) = directOwnerOf(tokenId);\n        // When the parent is an NFT, only it can do operations. Otherwise, the owner or approved address can\n        if (\n            (parentId != 0 && _msgSender() != owner) ||\n            !(_msgSender() == owner ||\n                isApprovedForAll(owner, _msgSender()) ||\n                getApproved(tokenId) == _msgSender())\n        ) {\n            revert RMRKNotApprovedOrDirectOwner();\n        }\n    }\n\n    /**\n     * @notice Used to verify that the caller is approved to manage the given token or is its direct owner.\n     * @param tokenId ID of the token to check\n     */\n    modifier onlyApprovedOrDirectOwner(uint256 tokenId) {\n        _onlyApprovedOrDirectOwner(tokenId);\n        _;\n    }\n\n    // ------------------------------- ERC721 ---------------------------------\n\n    /**\n     * @notice Used to retrieve the number of tokens in `owner`'s account.\n     * @param owner Address of the account being checked\n     * @return balance The balance of the given account\n     */\n    function balanceOf(\n        address owner\n    ) public view virtual returns (uint256 balance) {\n        if (owner == address(0)) revert ERC721AddressZeroIsNotaValidOwner();\n        balance = _balances[owner];\n    }\n\n    ////////////////////////////////////////\n    //              TRANSFERS\n    ////////////////////////////////////////\n\n    /**\n     * @notice Transfers a given token from `from` to `to`.\n     * @dev Requirements:\n     *\n     *  - `from` cannot be the zero address.\n     *  - `to` cannot be the zero address.\n     *  - `tokenId` token must be owned by `from`.\n     *  - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * @dev Emits a {Transfer} event.\n     * @param from Address from which to transfer the token from\n     * @param to Address to which to transfer the token to\n     * @param tokenId ID of the token to transfer\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual onlyApprovedOrDirectOwner(tokenId) {\n        _transfer(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @notice Used to safely transfer a given token token from `from` to `to`.\n     * @dev Requirements:\n     *\n     *  - `from` cannot be the zero address.\n     *  - `to` cannot be the zero address.\n     *  - `tokenId` token must exist and be owned by `from`.\n     *  - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *  - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     * @dev Emits a {Transfer} event.\n     * @param from Address to transfer the tokens from\n     * @param to Address to transfer the tokens to\n     * @param tokenId ID of the token to transfer\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @notice Used to safely transfer a given token token from `from` to `to`.\n     * @dev Requirements:\n     *\n     *  - `from` cannot be the zero address.\n     *  - `to` cannot be the zero address.\n     *  - `tokenId` token must exist and be owned by `from`.\n     *  - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *  - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     * @dev Emits a {Transfer} event.\n     * @param from Address to transfer the tokens from\n     * @param to Address to transfer the tokens to\n     * @param tokenId ID of the token to transfer\n     * @param data Additional data without a specified format to be sent along with the token transaction\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) public virtual onlyApprovedOrDirectOwner(tokenId) {\n        _transfer(from, to, tokenId, data);\n        if (!_checkOnERC721Received(from, to, tokenId, data))\n            revert ERC721TransferToNonReceiverImplementer();\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function nestTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        uint256 destinationId,\n        bytes memory data\n    ) public virtual onlyApprovedOrDirectOwner(tokenId) {\n        (address immediateOwner, uint256 parentId, ) = directOwnerOf(tokenId);\n        if (immediateOwner != from) revert ERC721TransferFromIncorrectOwner();\n        if (to == address(this) && tokenId == destinationId)\n            revert RMRKNestableTransferToSelf();\n\n        _checkDestination(to);\n        _checkForInheritanceLoop(tokenId, to, destinationId);\n\n        _beforeTokenTransfer(from, to, tokenId);\n        _beforeNestedTokenTransfer(\n            immediateOwner,\n            to,\n            parentId,\n            destinationId,\n            tokenId,\n            data\n        );\n        _balances[from] -= 1;\n        _updateOwnerAndClearApprovals(tokenId, destinationId, to);\n        _balances[to] += 1;\n\n        // Sending to NFT:\n        _sendToNFT(immediateOwner, to, parentId, destinationId, tokenId, data);\n    }\n\n    /**\n     * @notice Used to transfer the token from `from` to `to`.\n     * @dev As opposed to {transferFrom}, this imposes no restrictions on msg.sender\n     * @dev Requirements:\n     *\n     *  - `to` cannot be the zero address.\n     *  - `tokenId` token must be owned by `from`.\n     * @dev Emits a {Transfer} event.\n     * @param from Address of the account currently owning the given token\n     * @param to Address to transfer the token to\n     * @param tokenId ID of the token to transfer\n     * @param data Additional data with no specified format, sent in call to `to`\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        (address immediateOwner, uint256 parentId, ) = directOwnerOf(tokenId);\n        if (immediateOwner != from) revert ERC721TransferFromIncorrectOwner();\n        if (to == address(0)) revert ERC721TransferToTheZeroAddress();\n\n        _beforeTokenTransfer(from, to, tokenId);\n        _beforeNestedTokenTransfer(from, to, parentId, 0, tokenId, data);\n\n        _balances[from] -= 1;\n        _updateOwnerAndClearApprovals(tokenId, 0, to);\n        _balances[to] += 1;\n\n        emit Transfer(from, to, tokenId);\n        emit NestTransfer(from, to, parentId, 0, tokenId);\n\n        _afterTokenTransfer(from, to, tokenId);\n        _afterNestedTokenTransfer(from, to, parentId, 0, tokenId, data);\n    }\n\n    /**\n     * @notice Used to send a token to another token.\n     * @dev If the token being sent is currently owned by an externally owned account, the `parentId` should equal `0`.\n     * @dev Emits {Transfer} event.\n     * @dev Emits {NestTransfer} event.\n     * @param from Address from which the token is being sent\n     * @param to Address of the collection smart contract of the token to receive the given token\n     * @param parentId ID of the current parent token of the token being sent\n     * @param destinationId ID of the tokento receive the token being sent\n     * @param tokenId ID of the token being sent\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _sendToNFT(\n        address from,\n        address to,\n        uint256 parentId,\n        uint256 destinationId,\n        uint256 tokenId,\n        bytes memory data\n    ) private {\n        IERC7401 destContract = IERC7401(to);\n        destContract.addChild(destinationId, tokenId, data);\n\n        emit Transfer(from, to, tokenId);\n        emit NestTransfer(from, to, parentId, destinationId, tokenId);\n\n        _afterTokenTransfer(from, to, tokenId);\n        _afterNestedTokenTransfer(\n            from,\n            to,\n            parentId,\n            destinationId,\n            tokenId,\n            data\n        );\n    }\n\n    /**\n     * @notice Used to check if nesting a given token into a specified token would create an inheritance loop.\n     * @dev If a loop would occur, the tokens would be unmanageable, so the execution is reverted if one is detected.\n     * @dev The check for inheritance loop is bounded to guard against too much gas being consumed.\n     * @param currentId ID of the token that would be nested\n     * @param targetContract Address of the collection smart contract of the token into which the given token would be\n     *  nested\n     * @param targetId ID of the token into which the given token would be nested\n     */\n    function _checkForInheritanceLoop(\n        uint256 currentId,\n        address targetContract,\n        uint256 targetId\n    ) private view {\n        for (uint256 i; i < _MAX_LEVELS_TO_CHECK_FOR_INHERITANCE_LOOP; ) {\n            (\n                address nextOwner,\n                uint256 nextOwnerTokenId,\n                bool isNft\n            ) = IERC7401(targetContract).directOwnerOf(targetId);\n            // If there's a final address, we're good. There's no loop.\n            if (!isNft) {\n                return;\n            }\n            // Ff the current nft is an ancestor at some point, there is an inheritance loop\n            if (nextOwner == address(this) && nextOwnerTokenId == currentId) {\n                revert RMRKNestableTransferToDescendant();\n            }\n            // We reuse the parameters to save some contract size\n            targetContract = nextOwner;\n            targetId = nextOwnerTokenId;\n            unchecked {\n                ++i;\n            }\n        }\n        revert RMRKNestableTooDeep();\n    }\n\n    ////////////////////////////////////////\n    //              MINTING\n    ////////////////////////////////////////\n\n    /**\n     * @notice Used to safely mint the token to the specified address while passing the additional data to contract\n     *  recipients.\n     * @param to Address to which to mint the token\n     * @param tokenId ID of the token to mint\n     * @param data Additional data to send with the tokens\n     */\n    function _safeMint(\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        _innerMint(to, tokenId, 0, data);\n\n        emit Transfer(address(0), to, tokenId);\n        emit NestTransfer(address(0), to, 0, 0, tokenId);\n\n        _afterTokenTransfer(address(0), to, tokenId);\n        _afterNestedTokenTransfer(address(0), to, 0, 0, tokenId, data);\n        if (!_checkOnERC721Received(address(0), to, tokenId, data))\n            revert ERC721TransferToNonReceiverImplementer();\n    }\n\n    /**\n     * @notice Used to mint a child token to a given parent token.\n     * @param to Address of the collection smart contract of the token into which to mint the child token\n     * @param tokenId ID of the token to mint\n     * @param destinationId ID of the token into which to mint the new child token\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _nestMint(\n        address to,\n        uint256 tokenId,\n        uint256 destinationId,\n        bytes memory data\n    ) internal virtual {\n        _checkDestination(to);\n        _innerMint(to, tokenId, destinationId, data);\n        _sendToNFT(address(0), to, 0, destinationId, tokenId, data);\n    }\n\n    /**\n     * @notice Used to mint a child token into a given parent token.\n     * @dev Requirements:\n     *\n     *  - `to` cannot be the zero address.\n     *  - `tokenId` must not exist.\n     *  - `tokenId` must not be `0`.\n     * @param to Address of the collection smart contract of the token into which to mint the child token\n     * @param tokenId ID of the token to mint\n     * @param destinationId ID of the token into which to mint the new token\n     * @param data Additional data with no specified format, sent in call to `to`\n     */\n    function _innerMint(\n        address to,\n        uint256 tokenId,\n        uint256 destinationId,\n        bytes memory data\n    ) private {\n        if (to == address(0)) revert ERC721MintToTheZeroAddress();\n        if (_exists(tokenId)) revert ERC721TokenAlreadyMinted();\n        if (tokenId == uint256(0)) revert RMRKIdZeroForbidden();\n\n        _beforeTokenTransfer(address(0), to, tokenId);\n        _beforeNestedTokenTransfer(\n            address(0),\n            to,\n            0,\n            destinationId,\n            tokenId,\n            data\n        );\n\n        _balances[to] += 1;\n        _RMRKOwners[tokenId] = DirectOwner({\n            ownerAddress: to,\n            tokenId: destinationId\n        });\n    }\n\n    ////////////////////////////////////////\n    //              Ownership\n    ////////////////////////////////////////\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function ownerOf(\n        uint256 tokenId\n    ) public view virtual override(IERC7401, IERC721) returns (address owner_) {\n        (address owner, uint256 ownerTokenId, bool isNft) = directOwnerOf(\n            tokenId\n        );\n        if (isNft) {\n            owner = IERC7401(owner).ownerOf(ownerTokenId);\n        }\n        owner_ = owner;\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function directOwnerOf(\n        uint256 tokenId\n    )\n        public\n        view\n        virtual\n        returns (address owner_, uint256 parentId, bool isNFT)\n    {\n        DirectOwner memory owner = _RMRKOwners[tokenId];\n        if (owner.ownerAddress == address(0)) revert ERC721InvalidTokenId();\n\n        owner_ = owner.ownerAddress;\n        parentId = owner.tokenId;\n        isNFT = owner.tokenId != 0;\n    }\n\n    ////////////////////////////////////////\n    //              BURNING\n    ////////////////////////////////////////\n\n    /**\n     * @notice Used to burn a given token.\n     * @dev In case the token has any child tokens, the execution will be reverted.\n     * @param tokenId ID of the token to burn\n     */\n    function burn(uint256 tokenId) public virtual {\n        burn(tokenId, 0);\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function burn(\n        uint256 tokenId,\n        uint256 maxChildrenBurns\n    )\n        public\n        virtual\n        onlyApprovedOrDirectOwner(tokenId)\n        returns (uint256 burnedChildren)\n    {\n        (address immediateOwner, uint256 parentId, ) = directOwnerOf(tokenId);\n        address rootOwner = ownerOf(tokenId);\n\n        _beforeTokenTransfer(immediateOwner, address(0), tokenId);\n        _beforeNestedTokenTransfer(\n            immediateOwner,\n            address(0),\n            parentId,\n            0,\n            tokenId,\n            \"\"\n        );\n\n        _balances[immediateOwner] -= 1;\n        _approve(address(0), tokenId);\n        _approveForAssets(address(0), tokenId);\n\n        Child[] memory children = childrenOf(tokenId);\n\n        delete _activeChildren[tokenId];\n        delete _pendingChildren[tokenId];\n        delete _tokenApprovals[tokenId][rootOwner];\n\n        uint256 pendingRecursiveBurns;\n\n        uint256 length = children.length; //gas savings\n        for (uint256 i; i < length; ) {\n            if (burnedChildren >= maxChildrenBurns)\n                revert RMRKMaxRecursiveBurnsReached(\n                    children[i].contractAddress,\n                    children[i].tokenId\n                );\n            delete _childIsInActive[children[i].contractAddress][\n                children[i].tokenId\n            ];\n            unchecked {\n                // At this point we know pendingRecursiveBurns must be at least 1\n                pendingRecursiveBurns = maxChildrenBurns - burnedChildren;\n            }\n            // We substract one to the next level to count for the token being burned, then add it again on returns\n            // This is to allow the behavior of 0 recursive burns meaning only the current token is deleted.\n            burnedChildren +=\n                IERC7401(children[i].contractAddress).burn(\n                    children[i].tokenId,\n                    pendingRecursiveBurns - 1\n                ) +\n                1;\n            unchecked {\n                ++i;\n            }\n        }\n        // Can't remove before burning child since child will call back to get root owner\n        delete _RMRKOwners[tokenId];\n\n        emit Transfer(immediateOwner, address(0), tokenId);\n        emit NestTransfer(immediateOwner, address(0), parentId, 0, tokenId);\n\n        _afterTokenTransfer(immediateOwner, address(0), tokenId);\n        _afterNestedTokenTransfer(\n            immediateOwner,\n            address(0),\n            parentId,\n            0,\n            tokenId,\n            \"\"\n        );\n    }\n\n    ////////////////////////////////////////\n    //              APPROVALS\n    ////////////////////////////////////////\n\n    /**\n     * @notice Used to grant a one-time approval to manage one's token.\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * @dev The approval is cleared when the token is transferred.\n     * @dev Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     * @dev Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     * @dev Emits an {Approval} event.\n     * @param to Address receiving the approval\n     * @param tokenId ID of the token for which the approval is being granted\n     */\n    function approve(address to, uint256 tokenId) public virtual {\n        address owner = ownerOf(tokenId);\n        if (to == owner) revert ERC721ApprovalToCurrentOwner();\n\n        if (_msgSender() != owner && !isApprovedForAll(owner, _msgSender()))\n            revert ERC721ApproveCallerIsNotOwnerNorApprovedForAll();\n\n        _approve(to, tokenId);\n    }\n\n    /**\n     * @notice Used to retrieve the account approved to manage given token.\n     * @dev Requirements:\n     *\n     *  - `tokenId` must exist.\n     * @param tokenId ID of the token to check for approval\n     * @return approved Address of the account approved to manage the token\n     */\n    function getApproved(\n        uint256 tokenId\n    ) public view virtual returns (address approved) {\n        _requireMinted(tokenId);\n\n        approved = _tokenApprovals[tokenId][ownerOf(tokenId)];\n    }\n\n    /**\n     * @notice Used to approve or remove `operator` as an operator for the caller.\n     * @dev Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     * @dev Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     * @dev Emits an {ApprovalForAll} event.\n     * @param operator Address of the operator being managed\n     * @param approved A boolean value signifying whether the approval is being granted (`true`) or (`revoked`)\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual {\n        if (_msgSender() == operator) revert ERC721ApproveToCaller();\n        _operatorApprovals[_msgSender()][operator] = approved;\n        emit ApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @notice Used to check if the given address is allowed to manage the tokens of the specified address.\n     * @param owner Address of the owner of the tokens\n     * @param operator Address being checked for approval\n     * @return isApproved A boolean value signifying whether the *operator* is allowed to manage the tokens of the *owner* (`true`)\n     *  or not (`false`)\n     */\n    function isApprovedForAll(\n        address owner,\n        address operator\n    ) public view virtual returns (bool isApproved) {\n        isApproved = _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @notice Used to grant an approval to manage a given token.\n     * @dev Emits an {Approval} event.\n     * @param to Address to which the approval is being granted\n     * @param tokenId ID of the token for which the approval is being granted\n     */\n    function _approve(address to, uint256 tokenId) internal virtual {\n        address owner = ownerOf(tokenId);\n        _tokenApprovals[tokenId][owner] = to;\n        emit Approval(owner, to, tokenId);\n    }\n\n    /**\n     * @notice Used to update the owner of the token and clear the approvals associated with the previous owner.\n     * @dev The `destinationId` should equal `0` if the new owner is an externally owned account.\n     * @param tokenId ID of the token being updated\n     * @param destinationId ID of the token to receive the given token\n     * @param to Address of account to receive the token\n     */\n    function _updateOwnerAndClearApprovals(\n        uint256 tokenId,\n        uint256 destinationId,\n        address to\n    ) internal {\n        _RMRKOwners[tokenId] = DirectOwner({\n            ownerAddress: to,\n            tokenId: destinationId\n        });\n\n        // Clear approvals from the previous owner\n        _approve(address(0), tokenId);\n        _approveForAssets(address(0), tokenId);\n    }\n\n    ////////////////////////////////////////\n    //              UTILS\n    ////////////////////////////////////////\n\n    /**\n     * @notice Used to enforce that the given token has been minted.\n     * @dev Reverts if the `tokenId` has not been minted yet.\n     * @dev The validation checks whether the owner of a given token is a `0x0` address and considers it not minted if\n     *  it is. This means that both tokens that haven't been minted yet as well as the ones that have already been\n     *  burned will cause the transaction to be reverted.\n     * @param tokenId ID of the token to check\n     */\n    function _requireMinted(uint256 tokenId) internal view virtual {\n        if (!_exists(tokenId)) revert ERC721InvalidTokenId();\n    }\n\n    /**\n     * @notice Used to check whether the given token exists.\n     * @dev Tokens start existing when they are minted (`_mint`) and stop existing when they are burned (`_burn`).\n     * @param tokenId ID of the token being checked\n     * @return exists A boolean value signifying whether the token exists\n     */\n    function _exists(\n        uint256 tokenId\n    ) internal view virtual returns (bool exists) {\n        exists = _RMRKOwners[tokenId].ownerAddress != address(0);\n    }\n\n    /**\n     * @notice Used to invoke {IERC721Receiver-onERC721Received} on a target address.\n     * @dev The call is not executed if the target address is not a contract.\n     * @param from Address representing the previous owner of the given token\n     * @param to Yarget address that will receive the tokens\n     * @param tokenId ID of the token to be transferred\n     * @param data Optional data to send along with the call\n     * @return valid Boolean value signifying whether the call correctly returned the expected magic value\n     */\n    function _checkOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) private returns (bool valid) {\n        if (to.code.length != 0) {\n            try\n                IERC721Receiver(to).onERC721Received(\n                    _msgSender(),\n                    from,\n                    tokenId,\n                    data\n                )\n            returns (bytes4 retval) {\n                valid = retval == IERC721Receiver.onERC721Received.selector;\n            } catch (bytes memory reason) {\n                if (reason.length == uint256(0)) {\n                    revert ERC721TransferToNonReceiverImplementer();\n                } else {\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        } else {\n            valid = true;\n        }\n    }\n\n    ////////////////////////////////////////\n    //      CHILD MANAGEMENT PUBLIC\n    ////////////////////////////////////////\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function addChild(\n        uint256 parentId,\n        uint256 childId,\n        bytes memory data\n    ) public virtual {\n        _requireMinted(parentId);\n\n        address childAddress = _msgSender();\n        if (childAddress.code.length == 0) revert RMRKIsNotContract();\n\n        Child memory child = Child({\n            contractAddress: childAddress,\n            tokenId: childId\n        });\n\n        _beforeAddChild(parentId, childAddress, childId, data);\n\n        uint256 length = pendingChildrenOf(parentId).length;\n\n        if (length < 128) {\n            _pendingChildren[parentId].push(child);\n        } else {\n            revert RMRKMaxPendingChildrenReached();\n        }\n\n        // Previous length matches the index for the new child\n        emit ChildProposed(parentId, length, childAddress, childId);\n\n        _afterAddChild(parentId, childAddress, childId, data);\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function acceptChild(\n        uint256 parentId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId\n    ) public virtual onlyApprovedOrOwner(parentId) {\n        _acceptChild(parentId, childIndex, childAddress, childId);\n    }\n\n    /**\n     * @notice Used to accept a pending child token for a given parent token.\n     * @dev This moves the child token from parent token's pending child tokens array into the active child tokens\n     *  array.\n     * @dev Requirements:\n     *\n     *  - `tokenId` must exist\n     *  - `index` must be in range of the pending children array\n     * @dev Emits ***ChildAccepted*** event.\n     * @param parentId ID of the parent token for which the child token is being accepted\n     * @param childIndex Index of a child tokem in the given parent's pending children array\n     * @param childAddress Address of the collection smart contract of the child token expected to be located at the\n     *  specified index of the given parent token's pending children array\n     * @param childId ID of the child token expected to be located at the specified index of the given parent token's\n     *  pending children array\n     */\n    function _acceptChild(\n        uint256 parentId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId\n    ) internal virtual {\n        Child memory child = pendingChildOf(parentId, childIndex);\n        _checkExpectedChild(child, childAddress, childId);\n        if (_childIsInActive[childAddress][childId] != 0)\n            revert RMRKChildAlreadyExists();\n\n        _beforeAcceptChild(parentId, childIndex, childAddress, childId);\n\n        // Remove from pending:\n        _removeChildByIndex(_pendingChildren[parentId], childIndex);\n\n        // Add to active:\n        _activeChildren[parentId].push(child);\n        _childIsInActive[childAddress][childId] = 1; // We use 1 as true\n\n        emit ChildAccepted(parentId, childIndex, childAddress, childId);\n\n        _afterAcceptChild(parentId, childIndex, childAddress, childId);\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function rejectAllChildren(\n        uint256 tokenId,\n        uint256 maxRejections\n    ) public virtual onlyApprovedOrOwner(tokenId) {\n        if (_pendingChildren[tokenId].length > maxRejections)\n            revert RMRKUnexpectedNumberOfChildren();\n\n        _beforeRejectAllChildren(tokenId);\n        delete _pendingChildren[tokenId];\n        emit AllChildrenRejected(tokenId);\n        _afterRejectAllChildren(tokenId);\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function transferChild(\n        uint256 tokenId,\n        address to,\n        uint256 destinationId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId,\n        bool isPending,\n        bytes memory data\n    ) public virtual onlyApprovedOrOwner(tokenId) {\n        Child memory child;\n        if (isPending) {\n            child = pendingChildOf(tokenId, childIndex);\n        } else {\n            if (isChildEquipped(tokenId, childAddress, childId))\n                revert RMRKMustUnequipFirst();\n            child = childOf(tokenId, childIndex);\n        }\n        _checkExpectedChild(child, childAddress, childId);\n\n        _beforeTransferChild(\n            tokenId,\n            childIndex,\n            childAddress,\n            childId,\n            isPending,\n            data\n        );\n\n        if (isPending) {\n            _removeChildByIndex(_pendingChildren[tokenId], childIndex);\n        } else {\n            delete _childIsInActive[childAddress][childId];\n            _removeChildByIndex(_activeChildren[tokenId], childIndex);\n        }\n\n        if (to != address(0)) {\n            if (destinationId == uint256(0)) {\n                IERC721(childAddress).safeTransferFrom(\n                    address(this),\n                    to,\n                    childId,\n                    data\n                );\n            } else {\n                // Destination is an NFT\n                IERC7401(child.contractAddress).nestTransferFrom(\n                    address(this),\n                    to,\n                    child.tokenId,\n                    destinationId,\n                    data\n                );\n            }\n        }\n\n        emit ChildTransferred(\n            tokenId,\n            childIndex,\n            childAddress,\n            childId,\n            isPending,\n            to == address(0)\n        );\n        _afterTransferChild(\n            tokenId,\n            childIndex,\n            childAddress,\n            childId,\n            isPending,\n            data\n        );\n    }\n\n    /**\n     * @notice Used to verify that the child being accessed is the intended child.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param child A Child struct of a child being accessed\n     * @param expectedAddress The address expected to be the one of the child\n     * @param expectedId The token ID expected to be the one of the child\n     */\n    function _checkExpectedChild(\n        Child memory child,\n        address expectedAddress,\n        uint256 expectedId\n    ) private pure {\n        if (\n            expectedAddress != child.contractAddress ||\n            expectedId != child.tokenId\n        ) revert RMRKUnexpectedChildId();\n    }\n\n    ////////////////////////////////////////\n    //      CHILD MANAGEMENT GETTERS\n    ////////////////////////////////////////\n\n    /**\n     * @inheritdoc IERC7401\n     */\n\n    function childrenOf(\n        uint256 parentId\n    ) public view virtual returns (Child[] memory children) {\n        children = _activeChildren[parentId];\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n\n    function pendingChildrenOf(\n        uint256 parentId\n    ) public view virtual returns (Child[] memory children) {\n        children = _pendingChildren[parentId];\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function childOf(\n        uint256 parentId,\n        uint256 index\n    ) public view virtual returns (Child memory child) {\n        if (childrenOf(parentId).length <= index)\n            revert RMRKChildIndexOutOfRange();\n        child = _activeChildren[parentId][index];\n    }\n\n    /**\n     * @inheritdoc IERC7401\n     */\n    function pendingChildOf(\n        uint256 parentId,\n        uint256 index\n    ) public view virtual returns (Child memory child) {\n        if (pendingChildrenOf(parentId).length <= index)\n            revert RMRKPendingChildIndexOutOfRange();\n        child = _pendingChildren[parentId][index];\n    }\n\n    // HOOKS\n\n    /**\n     * @notice Hook that is called before any token transfer. This includes minting and burning.\n     * @dev Calling conditions:\n     *\n     *  - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be transferred to `to`.\n     *  - When `from` is zero, `tokenId` will be minted to `to`.\n     *  - When `to` is zero, ``from``'s `tokenId` will be burned.\n     *  - `from` and `to` are never zero at the same time.\n     *\n     *  To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param from Address from which the token is being transferred\n     * @param to Address to which the token is being transferred\n     * @param tokenId ID of the token being transferred\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after any transfer of tokens. This includes minting and burning.\n     * @dev Calling conditions:\n     *\n     *  - When `from` and `to` are both non-zero.\n     *  - `from` and `to` are never zero at the same time.\n     *\n     *  To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param from Address from which the token has been transferred\n     * @param to Address to which the token has been transferred\n     * @param tokenId ID of the token that has been transferred\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before nested token transfer.\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param from Address from which the token is being transferred\n     * @param to Address to which the token is being transferred\n     * @param fromTokenId ID of the token from which the given token is being transferred\n     * @param toTokenId ID of the token to which the given token is being transferred\n     * @param tokenId ID of the token being transferred\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _beforeNestedTokenTransfer(\n        address from,\n        address to,\n        uint256 fromTokenId,\n        uint256 toTokenId,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after nested token transfer.\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param from Address from which the token was transferred\n     * @param to Address to which the token was transferred\n     * @param fromTokenId ID of the token from which the given token was transferred\n     * @param toTokenId ID of the token to which the given token was transferred\n     * @param tokenId ID of the token that was transferred\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _afterNestedTokenTransfer(\n        address from,\n        address to,\n        uint256 fromTokenId,\n        uint256 toTokenId,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before a child is added to the pending tokens array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that will receive a new pending child token\n     * @param childAddress Address of the collection smart contract of the child token expected to be located at the\n     *  specified index of the given parent token's pending children array\n     * @param childId ID of the child token expected to be located at the specified index of the given parent token's\n     *  pending children array\n     * @param data Additional data with no specified format\n     */\n    function _beforeAddChild(\n        uint256 tokenId,\n        address childAddress,\n        uint256 childId,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after a child is added to the pending tokens array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that has received a new pending child token\n     * @param childAddress Address of the collection smart contract of the child token expected to be located at the\n     *  specified index of the given parent token's pending children array\n     * @param childId ID of the child token expected to be located at the specified index of the given parent token's\n     *  pending children array\n     * @param data Additional data with no specified format\n     */\n    function _afterAddChild(\n        uint256 tokenId,\n        address childAddress,\n        uint256 childId,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before a child is accepted to the active tokens array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param parentId ID of the token that will accept a pending child token\n     * @param childIndex Index of the child token to accept in the given parent token's pending children array\n     * @param childAddress Address of the collection smart contract of the child token expected to be located at the\n     *  specified index of the given parent token's pending children array\n     * @param childId ID of the child token expected to be located at the specified index of the given parent token's\n     *  pending children array\n     */\n    function _beforeAcceptChild(\n        uint256 parentId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after a child is accepted to the active tokens array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param parentId ID of the token that has accepted a pending child token\n     * @param childIndex Index of the child token that was accpeted in the given parent token's pending children array\n     * @param childAddress Address of the collection smart contract of the child token that was expected to be located\n     *  at the specified index of the given parent token's pending children array\n     * @param childId ID of the child token that was expected to be located at the specified index of the given parent\n     *  token's pending children array\n     */\n    function _afterAcceptChild(\n        uint256 parentId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before a child is transferred from a given child token array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that will transfer a child token\n     * @param childIndex Index of the child token that will be transferred from the given parent token's children array\n     * @param childAddress Address of the collection smart contract of the child token that is expected to be located\n     *  at the specified index of the given parent token's children array\n     * @param childId ID of the child token that is expected to be located at the specified index of the given parent\n     *  token's children array\n     * @param isPending A boolean value signifying whether the child token is being transferred from the pending child\n     *  tokens array (`true`) or from the active child tokens array (`false`)\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _beforeTransferChild(\n        uint256 tokenId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId,\n        bool isPending,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after a child is transferred from a given child token array of a given token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that has transferred a child token\n     * @param childIndex Index of the child token that was transferred from the given parent token's children array\n     * @param childAddress Address of the collection smart contract of the child token that was expected to be located\n     *  at the specified index of the given parent token's children array\n     * @param childId ID of the child token that was expected to be located at the specified index of the given parent\n     *  token's children array\n     * @param isPending A boolean value signifying whether the child token was transferred from the pending child tokens\n     *  array (`true`) or from the active child tokens array (`false`)\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function _afterTransferChild(\n        uint256 tokenId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId,\n        bool isPending,\n        bytes memory data\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before a pending child tokens array of a given token is cleared.\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that will reject all of the pending child tokens\n     */\n    function _beforeRejectAllChildren(uint256 tokenId) internal virtual {}\n\n    /**\n     * @notice Hook that is called after a pending child tokens array of a given token is cleared.\n     * @dev To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     * @param tokenId ID of the token that has rejected all of the pending child tokens\n     */\n    function _afterRejectAllChildren(uint256 tokenId) internal virtual {}\n\n    // HELPERS\n\n    /**\n     * @notice Used to remove a specified child token form an array using its index within said array.\n     * @dev The caller must ensure that the length of the array is valid compared to the index passed.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param array An array od Child struct containing info about the child tokens in a given child tokens array\n     * @param index An index of the child token to remove in the accompanying array\n     */\n    function _removeChildByIndex(Child[] storage array, uint256 index) private {\n        array[index] = array[array.length - 1];\n        array.pop();\n    }\n\n    /// Mapping of uint64 Ids to asset metadata\n    mapping(uint64 => string) internal _assets;\n\n    /// Mapping of tokenId to new asset, to asset to be replaced\n    mapping(uint256 => mapping(uint64 => uint64)) internal _assetReplacements;\n\n    /// Mapping of tokenId to an array of active assets\n    /// @dev Active recurses is unbounded, getting all would reach gas limit at around 30k items\n    /// so we leave this as internal in case a custom implementation needs to implement pagination\n    mapping(uint256 => uint64[]) internal _activeAssets;\n\n    /// Mapping of tokenId to an array of pending assets\n    mapping(uint256 => uint64[]) internal _pendingAssets;\n\n    /// Mapping of tokenId to an array of priorities for active assets\n    mapping(uint256 => uint64[]) internal _activeAssetPriorities;\n\n    /// Mapping of tokenId to assetId to whether the token has this asset assigned\n    mapping(uint256 => mapping(uint64 => bool)) internal _tokenAssets;\n\n    /// Mapping from owner to operator approvals for assets\n    mapping(address => mapping(address => bool))\n        private _operatorApprovalsForAssets;\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function getAssetMetadata(\n        uint256 tokenId,\n        uint64 assetId\n    ) public view override returns (string memory metadata) {\n        // Allow to get the asset metadata without a token having it:\n        if (tokenId != 0 && !_tokenAssets[tokenId][assetId])\n            revert RMRKTokenDoesNotHaveAsset();\n        metadata = _assets[assetId];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function getActiveAssets(\n        uint256 tokenId\n    ) public view virtual returns (uint64[] memory assetIds) {\n        assetIds = _activeAssets[tokenId];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function getPendingAssets(\n        uint256 tokenId\n    ) public view virtual returns (uint64[] memory assetIds) {\n        assetIds = _pendingAssets[tokenId];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function getActiveAssetPriorities(\n        uint256 tokenId\n    ) public view virtual returns (uint64[] memory priorities) {\n        priorities = _activeAssetPriorities[tokenId];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function getAssetReplacements(\n        uint256 tokenId,\n        uint64 newAssetId\n    ) public view virtual returns (uint64 replacedAssetId) {\n        replacedAssetId = _assetReplacements[tokenId][newAssetId];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function isApprovedForAllForAssets(\n        address owner,\n        address operator\n    ) public view virtual returns (bool isApproved) {\n        isApproved = _operatorApprovalsForAssets[owner][operator];\n    }\n\n    /**\n     * @inheritdoc IERC5773\n     */\n    function setApprovalForAllForAssets(\n        address operator,\n        bool approved\n    ) public virtual {\n        if (_msgSender() == operator)\n            revert RMRKApprovalForAssetsToCurrentOwner();\n\n        _operatorApprovalsForAssets[_msgSender()][operator] = approved;\n        emit ApprovalForAllForAssets(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @notice Used to validate the index on the pending assets array\n     * @dev The call is reverted if the index is out of range or the asset Id is not present at the index.\n     * @param tokenId ID of the token that the asset is validated from\n     * @param index Index of the asset in the pending array\n     * @param assetId Id of the asset expected to be in the index\n     */\n    function _validatePendingAssetAtIndex(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) private view {\n        if (index >= _pendingAssets[tokenId].length)\n            revert RMRKIndexOutOfRange();\n        if (assetId != _pendingAssets[tokenId][index])\n            revert RMRKUnexpectedAssetId();\n    }\n\n    /**\n     * @notice Used to remove the asset at the index on the pending assets array\n     * @param tokenId ID of the token that the asset is being removed from\n     * @param index Index of the asset in the pending array\n     * @param assetId Id of the asset expected to be in the index\n     */\n    function _removePendingAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) private {\n        _pendingAssets[tokenId].removeItemByIndex(index);\n        delete _assetReplacements[tokenId][assetId];\n    }\n\n    /**\n     * @notice Used to add an asset entry.\n     * @dev If the specified ID is already used by another asset, the execution will be reverted.\n     * @dev This internal function warrants custom access control to be implemented when used.\n     * @dev Emits ***AssetSet*** event.\n     * @param id ID of the asset to assign to the new asset\n     * @param metadataURI Metadata URI of the asset\n     */\n    function _addAssetEntry(\n        uint64 id,\n        string memory metadataURI\n    ) internal virtual {\n        if (id == uint64(0)) revert RMRKIdZeroForbidden();\n        if (bytes(_assets[id]).length > 0) revert RMRKAssetAlreadyExists();\n\n        _beforeAddAsset(id, metadataURI);\n        _assets[id] = metadataURI;\n\n        emit AssetSet(id);\n        _afterAddAsset(id, metadataURI);\n    }\n\n    /**\n     * @notice Used to add an asset to a token.\n     * @dev If the given asset is already added to the token, the execution will be reverted.\n     * @dev If the asset ID is invalid, the execution will be reverted.\n     * @dev If the token already has the maximum amount of pending assets (128), the execution will be\n     *  reverted.\n     * @dev Emits ***AssetAddedToTokens*** event.\n     * @param tokenId ID of the token to add the asset to\n     * @param assetId ID of the asset to add to the token\n     * @param replacesAssetWithId ID of the asset to replace from the token's list of active assets\n     */\n    function _addAssetToToken(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 replacesAssetWithId\n    ) internal virtual {\n        if (_tokenAssets[tokenId][assetId]) revert RMRKAssetAlreadyExists();\n\n        if (bytes(_assets[assetId]).length == uint256(0))\n            revert RMRKNoAssetMatchingId();\n\n        if (_pendingAssets[tokenId].length >= 128)\n            revert RMRKMaxPendingAssetsReached();\n\n        _beforeAddAssetToToken(tokenId, assetId, replacesAssetWithId);\n        _tokenAssets[tokenId][assetId] = true;\n        _pendingAssets[tokenId].push(assetId);\n\n        if (replacesAssetWithId != uint64(0)) {\n            _assetReplacements[tokenId][assetId] = replacesAssetWithId;\n        }\n\n        uint256[] memory tokenIds = new uint256[](1);\n        tokenIds[0] = tokenId;\n        emit AssetAddedToTokens(tokenIds, assetId, replacesAssetWithId);\n        _afterAddAssetToToken(tokenId, assetId, replacesAssetWithId);\n    }\n\n    /**\n     * @notice Hook that is called before an asset is added.\n     * @param id ID of the asset\n     * @param metadataURI Metadata URI of the asset\n     */\n    function _beforeAddAsset(\n        uint64 id,\n        string memory metadataURI\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after an asset is added.\n     * @param id ID of the asset\n     * @param metadataURI Metadata URI of the asset\n     */\n    function _afterAddAsset(\n        uint64 id,\n        string memory metadataURI\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before adding an asset to a token's pending assets array.\n     * @dev If the asset doesn't intend to replace another asset, the `replacesAssetWithId` value should be `0`.\n     * @param tokenId ID of the token to which the asset is being added\n     * @param assetId ID of the asset that is being added\n     * @param replacesAssetWithId ID of the asset that this asset is attempting to replace\n     */\n    function _beforeAddAssetToToken(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 replacesAssetWithId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after an asset has been added to a token's pending assets array.\n     * @dev If the asset doesn't intend to replace another asset, the `replacesAssetWithId` value should be `0`.\n     * @param tokenId ID of the token to which the asset is has been added\n     * @param assetId ID of the asset that is has been added\n     * @param replacesAssetWithId ID of the asset that this asset is attempting to replace\n     */\n    function _afterAddAssetToToken(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 replacesAssetWithId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before an asset is accepted to a token's active assets array.\n     * @param tokenId ID of the token for which the asset is being accepted\n     * @param index Index of the asset in the token's pending assets array\n     * @param assetId ID of the asset expected to be located at the specified `index`\n     */\n    function _beforeAcceptAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after an asset is accepted to a token's active assets array.\n     * @param tokenId ID of the token for which the asset has been accepted\n     * @param index Index of the asset in the token's pending assets array\n     * @param assetId ID of the asset expected to have been located at the specified `index`\n     * @param replacedAssetId ID of the asset that has been replaced by the accepted asset\n     */\n    function _afterAcceptAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId,\n        uint64 replacedAssetId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before rejecting an asset.\n     * @param tokenId ID of the token from which the asset is being rejected\n     * @param index Index of the asset in the token's pending assets array\n     * @param assetId ID of the asset expected to be located at the specified `index`\n     */\n    function _beforeRejectAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after rejecting an asset.\n     * @param tokenId ID of the token from which the asset has been rejected\n     * @param index Index of the asset in the token's pending assets array\n     * @param assetId ID of the asset expected to have been located at the specified `index`\n     */\n    function _afterRejectAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called before rejecting all assets of a token.\n     * @param tokenId ID of the token from which all of the assets are being rejected\n     */\n    function _beforeRejectAllAssets(uint256 tokenId) internal virtual {}\n\n    /**\n     * @notice Hook that is called after rejecting all assets of a token.\n     * @param tokenId ID of the token from which all of the assets have been rejected\n     */\n    function _afterRejectAllAssets(uint256 tokenId) internal virtual {}\n\n    /**\n     * @notice Hook that is called before the priorities for token's assets is set.\n     * @param tokenId ID of the token for which the asset priorities are being set\n     * @param priorities[] An array of priorities for token's active resources\n     */\n    function _beforeSetPriority(\n        uint256 tokenId,\n        uint64[] memory priorities\n    ) internal virtual {}\n\n    /**\n     * @notice Hook that is called after the priorities for token's assets is set.\n     * @param tokenId ID of the token for which the asset priorities have been set\n     * @param priorities[] An array of priorities for token's active resources\n     */\n    function _afterSetPriority(\n        uint256 tokenId,\n        uint64[] memory priorities\n    ) internal virtual {}\n\n    // ------------------- ASSETS --------------\n\n    // ------------------- ASSET APPROVALS --------------\n\n    /**\n     * @notice Mapping from token ID to approver address to approved address for assets.\n     * @dev The approver is necessary so approvals are invalidated for nested children on transfer.\n     * @dev WARNING: If a child NFT returns the original root owner, old permissions would be active again.\n     */\n    mapping(uint256 => mapping(address => address))\n        private _tokenApprovalsForAssets;\n\n    // ------------------- EQUIPPABLE --------------\n    /// Mapping of uint64 asset ID to corresponding catalog address.\n    mapping(uint64 => address) internal _catalogAddresses;\n    /// Mapping of uint64 ID to asset object.\n    mapping(uint64 => uint64) internal _equippableGroupIds;\n    /// Mapping of assetId to catalog parts applicable to this asset, both fixed and slot\n    mapping(uint64 => uint64[]) internal _partIds;\n\n    /// Mapping of token ID to catalog address to slot part ID to equipment information. Used to compose an NFT.\n    mapping(uint256 => mapping(address => mapping(uint64 => Equipment)))\n        internal _equipments;\n\n    /// Mapping of token ID to child (nestable) address to child ID to count of equipped items. Used to check if equipped.\n    mapping(uint256 => mapping(address => mapping(uint256 => uint256)))\n        internal _equipCountPerChild;\n\n    /// Mapping of `equippableGroupId` to parent contract address and valid `slotId`.\n    mapping(uint64 => mapping(address => uint64)) internal _validParentSlots;\n\n    /**\n     * @notice Used to verify that the caller is either the owner of the given token or approved to manage the token's assets\n     *  of the owner.\n     * @param tokenId ID of the token that we are checking\n     */\n    function _onlyApprovedForAssetsOrOwner(uint256 tokenId) internal view {\n        address owner = ownerOf(tokenId);\n        if (\n            !(_msgSender() == owner ||\n                isApprovedForAllForAssets(owner, _msgSender()) ||\n                getApprovedForAssets(tokenId) == _msgSender())\n        ) revert RMRKNotApprovedForAssetsOrOwner();\n    }\n\n    /**\n     * @notice Used to ensure that the caller is either the owner of the given token or approved to manage the token's assets\n     *  of the owner.\n     * @dev If that is not the case, the execution of the function will be reverted.\n     * @param tokenId ID of the token that we are checking\n     */\n    modifier onlyApprovedForAssetsOrOwner(uint256 tokenId) {\n        _onlyApprovedForAssetsOrOwner(tokenId);\n        _;\n    }\n\n    /**\n     * @inheritdoc IERC165\n     */\n    function supportsInterface(\n        bytes4 interfaceId\n    ) public view virtual override returns (bool) {\n        return\n            interfaceId == type(IERC165).interfaceId ||\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC7401).interfaceId ||\n            interfaceId == type(IERC5773).interfaceId ||\n            interfaceId == type(IERC6220).interfaceId;\n    }\n\n    // ------------------------------- ASSETS ------------------------------\n\n    // --------------------------- ASSET HANDLERS -------------------------\n\n    /**\n     * @notice Accepts a asset at from the pending array of given token.\n     * @dev Migrates the asset from the token's pending asset array to the token's active asset array.\n     * @dev Active assets cannot be removed by anyone, but can be replaced by a new asset.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - `index` must be in range of the length of the pending asset array.\n     * @dev Emits an {AssetAccepted} event.\n     * @param tokenId ID of the token for which to accept the pending asset\n     * @param index Index of the asset in the pending array to accept\n     * @param assetId ID of the asset that is being accepted\n     */\n    function acceptAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) public virtual onlyApprovedForAssetsOrOwner(tokenId) {\n        _acceptAsset(tokenId, index, assetId);\n    }\n\n    /**\n     * @notice Used to accept a pending asset.\n     * @dev The call is reverted if there is no pending asset at a given index.\n     * @dev Emits ***AssetAccepted*** event.\n     * @param tokenId ID of the token for which to accept the pending asset\n     * @param index Index of the asset in the pending array to accept\n     * @param assetId ID of the asset to accept in token's pending array\n     */\n    function _acceptAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) internal virtual {\n        _validatePendingAssetAtIndex(tokenId, index, assetId);\n        _beforeAcceptAsset(tokenId, index, assetId);\n\n        uint64 replacesId = _assetReplacements[tokenId][assetId];\n        uint256 replaceIndex;\n        bool replacefound;\n        if (replacesId != uint64(0))\n            (replaceIndex, replacefound) = _activeAssets[tokenId].indexOf(\n                replacesId\n            );\n\n        if (replacefound) {\n            // We don't want to remove and then push a new asset.\n            // This way we also keep the priority of the original asset\n            _activeAssets[tokenId][replaceIndex] = assetId;\n            delete _tokenAssets[tokenId][replacesId];\n        } else {\n            // We use the current size as next priority, by default priorities would be [0,1,2...]\n            _activeAssetPriorities[tokenId].push(\n                uint64(_activeAssets[tokenId].length)\n            );\n            _activeAssets[tokenId].push(assetId);\n            replacesId = uint64(0);\n        }\n        _removePendingAsset(tokenId, index, assetId);\n\n        emit AssetAccepted(tokenId, assetId, replacesId);\n        _afterAcceptAsset(tokenId, index, assetId, replacesId);\n    }\n\n    /**\n     * @notice Rejects a asset from the pending array of given token.\n     * @dev Removes the asset from the token's pending asset array.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - `index` must be in range of the length of the pending asset array.\n     * @dev Emits a {AssetRejected} event.\n     * @param tokenId ID of the token that the asset is being rejected from\n     * @param index Index of the asset in the pending array to be rejected\n     * @param assetId ID of the asset that is being rejected\n     */\n    function rejectAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) public virtual onlyApprovedForAssetsOrOwner(tokenId) {\n        _validatePendingAssetAtIndex(tokenId, index, assetId);\n        _beforeRejectAsset(tokenId, index, assetId);\n\n        _removePendingAsset(tokenId, index, assetId);\n        delete _tokenAssets[tokenId][assetId];\n\n        emit AssetRejected(tokenId, assetId);\n        _afterRejectAsset(tokenId, index, assetId);\n    }\n\n    /**\n     * @notice Rejects all assets from the pending array of a given token.\n     * @dev Effecitvely deletes the pending array.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     * @dev Emits a {AssetRejected} event with assetId = 0.\n     * @param tokenId ID of the token of which to clear the pending array.\n     * @param maxRejections Maximum number of expected assets to reject, used to prevent from rejecting assets which\n     *  arrive just before this operation.\n     */\n    function rejectAllAssets(\n        uint256 tokenId,\n        uint256 maxRejections\n    ) public virtual onlyApprovedForAssetsOrOwner(tokenId) {\n        uint256 len = _pendingAssets[tokenId].length;\n        if (len > maxRejections) revert RMRKUnexpectedNumberOfAssets();\n\n        _beforeRejectAllAssets(tokenId);\n\n        for (uint256 i; i < len; ) {\n            uint64 assetId = _pendingAssets[tokenId][i];\n            delete _assetReplacements[tokenId][assetId];\n            unchecked {\n                ++i;\n            }\n        }\n        delete (_pendingAssets[tokenId]);\n\n        emit AssetRejected(tokenId, uint64(0));\n        _afterRejectAllAssets(tokenId);\n    }\n\n    /**\n     * @notice Sets a new priority array for a given token.\n     * @dev The priority array is a non-sequential list of `uint64`s, where the lowest value is considered highest\n     *  priority.\n     * @dev Value `0` of a priority is a special case equivalent to unitialized.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - The length of `priorities` must be equal the length of the active assets array.\n     * @dev Emits a {AssetPrioritySet} event.\n     * @param tokenId ID of the token to set the priorities for\n     * @param priorities An array of priority values\n     */\n    function setPriority(\n        uint256 tokenId,\n        uint64[] memory priorities\n    ) public virtual onlyApprovedForAssetsOrOwner(tokenId) {\n        uint256 length = priorities.length;\n        if (length != _activeAssets[tokenId].length)\n            revert RMRKBadPriorityListLength();\n\n        _beforeSetPriority(tokenId, priorities);\n        _activeAssetPriorities[tokenId] = priorities;\n\n        emit AssetPrioritySet(tokenId);\n        _afterSetPriority(tokenId, priorities);\n    }\n\n    // --------------------------- ASSET INTERNALS -------------------------\n\n    /**\n     * @notice Used to add a asset entry.\n     * @dev This internal function warrants custom access control to be implemented when used.\n     * @param id ID of the asset being added\n     * @param equippableGroupId ID of the equippable group being marked as equippable into the slot associated with\n     *  `Parts` of the `Slot` type\n     * @param catalogAddress Address of the `Catalog` associated with the asset\n     * @param metadataURI The metadata URI of the asset\n     * @param partIds An array of IDs of fixed and slot parts to be included in the asset\n     */\n    function _addAssetEntry(\n        uint64 id,\n        uint64 equippableGroupId,\n        address catalogAddress,\n        string memory metadataURI,\n        uint64[] memory partIds\n    ) internal virtual {\n        _addAssetEntry(id, metadataURI);\n\n        if (catalogAddress == address(0) && partIds.length != 0)\n            revert RMRKCatalogRequiredForParts();\n\n        _catalogAddresses[id] = catalogAddress;\n        _equippableGroupIds[id] = equippableGroupId;\n        _partIds[id] = partIds;\n    }\n\n    // ----------------------- ASSET APPROVALS ------------------------\n\n    /**\n     * @notice Used to grant approvals for specific tokens to a specified address.\n     * @dev This can only be called by the owner of the token or by an account that has been granted permission to\n     *  manage all of the owner's assets.\n     * @param to Address of the account to receive the approval to the specified token\n     * @param tokenId ID of the token for which we are granting the permission\n     */\n    function approveForAssets(address to, uint256 tokenId) public virtual {\n        address owner = ownerOf(tokenId);\n        if (to == owner) revert RMRKApprovalForAssetsToCurrentOwner();\n\n        if (\n            _msgSender() != owner &&\n            !isApprovedForAllForAssets(owner, _msgSender())\n        ) revert RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll();\n        _approveForAssets(to, tokenId);\n    }\n\n    /**\n     * @notice Used to get the address of the user that is approved to manage the specified token from the current\n     *  owner.\n     * @param tokenId ID of the token we are checking\n     * @return approved Address of the account that is approved to manage the token\n     */\n    function getApprovedForAssets(\n        uint256 tokenId\n    ) public view virtual returns (address approved) {\n        _requireMinted(tokenId);\n        approved = _tokenApprovalsForAssets[tokenId][ownerOf(tokenId)];\n    }\n\n    /**\n     * @notice Internal function for granting approvals for a specific token.\n     * @param to Address of the account we are granting an approval to\n     * @param tokenId ID of the token we are granting the approval for\n     */\n    function _approveForAssets(address to, uint256 tokenId) internal virtual {\n        address owner = ownerOf(tokenId);\n        _tokenApprovalsForAssets[tokenId][owner] = to;\n        emit ApprovalForAssets(owner, to, tokenId);\n    }\n\n    // ------------------------------- EQUIPPING ------------------------------\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function equip(\n        IntakeEquip memory data\n    ) public virtual onlyApprovedForAssetsOrOwner(data.tokenId) nonReentrant {\n        address catalogAddress = _catalogAddresses[data.assetId];\n        uint64 slotPartId = data.slotPartId;\n        if (\n            _equipments[data.tokenId][catalogAddress][slotPartId]\n                .childEquippableAddress != address(0)\n        ) revert RMRKSlotAlreadyUsed();\n\n        // Check from parent's asset perspective:\n        _checkAssetAcceptsSlot(data.assetId, slotPartId);\n\n        IERC7401.Child memory child = childOf(data.tokenId, data.childIndex);\n\n        // Check from child perspective intention to be used in part\n        // We add reentrancy guard because of this call, it happens before updating state\n        if (\n            !IERC6220(child.contractAddress)\n                .canTokenBeEquippedWithAssetIntoSlot(\n                    address(this),\n                    child.tokenId,\n                    data.childAssetId,\n                    slotPartId\n                )\n        ) revert RMRKTokenCannotBeEquippedWithAssetIntoSlot();\n\n        // Check from catalog perspective\n        if (\n            !IRMRKCatalog(catalogAddress).checkIsEquippable(\n                slotPartId,\n                child.contractAddress\n            )\n        ) revert RMRKEquippableEquipNotAllowedByCatalog();\n\n        _beforeEquip(data);\n        Equipment memory newEquip = Equipment({\n            assetId: data.assetId,\n            childAssetId: data.childAssetId,\n            childId: child.tokenId,\n            childEquippableAddress: child.contractAddress\n        });\n\n        _equipments[data.tokenId][catalogAddress][slotPartId] = newEquip;\n        _equipCountPerChild[data.tokenId][child.contractAddress][\n            child.tokenId\n        ] += 1;\n\n        emit ChildAssetEquipped(\n            data.tokenId,\n            data.assetId,\n            slotPartId,\n            child.tokenId,\n            child.contractAddress,\n            data.childAssetId\n        );\n        _afterEquip(data);\n    }\n\n    /**\n     * @notice Private function to check if a given asset accepts a given slot or not.\n     * @dev Execution will be reverted if the `Slot` does not apply for the asset.\n     * @param assetId ID of the asset\n     * @param slotPartId ID of the `Slot`\n     */\n    function _checkAssetAcceptsSlot(\n        uint64 assetId,\n        uint64 slotPartId\n    ) private view {\n        (, bool found) = _partIds[assetId].indexOf(slotPartId);\n        if (!found) revert RMRKTargetAssetCannotReceiveSlot();\n    }\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function unequip(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotPartId\n    ) public virtual onlyApprovedForAssetsOrOwner(tokenId) {\n        address targetCatalogAddress = _catalogAddresses[assetId];\n        Equipment memory equipment = _equipments[tokenId][targetCatalogAddress][\n            slotPartId\n        ];\n        if (equipment.childEquippableAddress == address(0))\n            revert RMRKNotEquipped();\n        _beforeUnequip(tokenId, assetId, slotPartId);\n\n        delete _equipments[tokenId][targetCatalogAddress][slotPartId];\n        _equipCountPerChild[tokenId][equipment.childEquippableAddress][\n            equipment.childId\n        ] -= 1;\n\n        emit ChildAssetUnequipped(\n            tokenId,\n            assetId,\n            slotPartId,\n            equipment.childId,\n            equipment.childEquippableAddress,\n            equipment.childAssetId\n        );\n        _afterUnequip(tokenId, assetId, slotPartId);\n    }\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function isChildEquipped(\n        uint256 tokenId,\n        address childAddress,\n        uint256 childId\n    ) public view virtual returns (bool isEquipped) {\n        isEquipped = _equipCountPerChild[tokenId][childAddress][childId] != 0;\n    }\n\n    // --------------------- ADMIN VALIDATION ---------------------\n\n    /**\n     * @notice Internal function used to declare that the assets belonging to a given `equippableGroupId` are\n     *  equippable into the `Slot` associated with the `partId` of the collection at the specified `parentAddress`.\n     * @dev Emits ***ValidParentEquippableGroupIdSet*** event.\n     * @param equippableGroupId ID of the equippable group\n     * @param parentAddress Address of the parent into which the equippable group can be equipped into\n     * @param slotPartId ID of the `Slot` that the items belonging to the equippable group can be equipped into\n     */\n    function _setValidParentForEquippableGroup(\n        uint64 equippableGroupId,\n        address parentAddress,\n        uint64 slotPartId\n    ) internal virtual {\n        if (equippableGroupId == uint64(0) || slotPartId == uint64(0))\n            revert RMRKIdZeroForbidden();\n        _validParentSlots[equippableGroupId][parentAddress] = slotPartId;\n        emit ValidParentEquippableGroupIdSet(\n            equippableGroupId,\n            slotPartId,\n            parentAddress\n        );\n    }\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function canTokenBeEquippedWithAssetIntoSlot(\n        address parent,\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotId\n    ) public view virtual returns (bool canBeEquipped) {\n        uint64 equippableGroupId = _equippableGroupIds[assetId];\n        uint64 equippableSlot = _validParentSlots[equippableGroupId][parent];\n        if (equippableSlot == slotId) {\n            (, bool found) = getActiveAssets(tokenId).indexOf(assetId);\n            canBeEquipped = found;\n        }\n    }\n\n    // --------------------- Getting Extended Assets ---------------------\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function getAssetAndEquippableData(\n        uint256 tokenId,\n        uint64 assetId\n    )\n        public\n        view\n        virtual\n        returns (\n            string memory metadataURI,\n            uint64 equippableGroupId,\n            address catalogAddress,\n            uint64[] memory partIds\n        )\n    {\n        metadataURI = getAssetMetadata(tokenId, assetId);\n        equippableGroupId = _equippableGroupIds[assetId];\n        catalogAddress = _catalogAddresses[assetId];\n        partIds = _partIds[assetId];\n    }\n\n    ////////////////////////////////////////\n    //              UTILS\n    ////////////////////////////////////////\n\n    /**\n     * @inheritdoc IERC6220\n     */\n    function getEquipment(\n        uint256 tokenId,\n        address targetCatalogAddress,\n        uint64 slotPartId\n    ) public view virtual returns (Equipment memory equipment) {\n        equipment = _equipments[tokenId][targetCatalogAddress][slotPartId];\n    }\n\n    /**\n     * @notice Checks the destination is valid for a Nest Transfer/Mint.\n     * @dev The destination must be a contract that implements the IERC7401 interface.\n     * @param to Address of the destination\n     */\n    function _checkDestination(address to) internal view {\n        // Checking if it is a contract before calling it seems redundant, but otherwise it would revert with no error\n        if (to.code.length == 0) revert RMRKIsNotContract();\n        if (!IERC165(to).supportsInterface(type(IERC7401).interfaceId))\n            revert RMRKNestableTransferToNonRMRKNestableImplementer();\n    }\n\n    // HOOKS\n\n    /**\n     * @notice A hook to be called before a equipping a asset to the token.\n     * @dev The `IntakeEquip` struct consist of the following data:\n     *  [\n     *      tokenId,\n     *      childIndex,\n     *      assetId,\n     *      slotPartId,\n     *      childAssetId\n     *  ]\n     * @param data The `IntakeEquip` struct containing data of the asset that is being equipped\n     */\n    function _beforeEquip(IntakeEquip memory data) internal virtual {}\n\n    /**\n     * @notice A hook to be called after equipping a asset to the token.\n     * @dev The `IntakeEquip` struct consist of the following data:\n     *  [\n     *      tokenId,\n     *      childIndex,\n     *      assetId,\n     *      slotPartId,\n     *      childAssetId\n     *  ]\n     * @param data The `IntakeEquip` struct containing data of the asset that was equipped\n     */\n    function _afterEquip(IntakeEquip memory data) internal virtual {}\n\n    /**\n     * @notice A hook to be called before unequipping a asset from the token.\n     * @param tokenId ID of the token from which the asset is being unequipped\n     * @param assetId ID of the asset being unequipped\n     * @param slotPartId ID of the slot from which the asset is being unequipped\n     */\n    function _beforeUnequip(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotPartId\n    ) internal virtual {}\n\n    /**\n     * @notice A hook to be called after unequipping a asset from the token.\n     * @param tokenId ID of the token from which the asset was unequipped\n     * @param assetId ID of the asset that was unequipped\n     * @param slotPartId ID of the slot from which the asset was unequipped\n     */\n    function _afterUnequip(\n        uint256 tokenId,\n        uint64 assetId,\n        uint64 slotPartId\n    ) internal virtual {}\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/extension/RMRKRoyalties.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC2981} from \"@openzeppelin/contracts/interfaces/IERC2981.sol\";\nimport \"../library/RMRKErrors.sol\";\n\n/**\n * @title RMRKRoyalties\n * @author RMRK team\n * @notice Smart contract of the RMRK Royalties module.\n */\nabstract contract RMRKRoyalties {\n    /** is IERC2981 **/ // Inheritance is commmnted to prevent linearization issues\n    address private _royaltyRecipient;\n    uint256 private _royaltyPercentageBps;\n\n    /**\n     * @notice Used to initiate the smart contract.\n     * @dev `royaltyPercentageBps` is expressed in basis points, so 1 basis point equals 0.01% and 500 basis points\n     *  equal 5%.\n     * @param royaltyRecipient Address to which royalties should be sent\n     * @param royaltyPercentageBps The royalty percentage expressed in basis points\n     */\n    constructor(address royaltyRecipient, uint256 royaltyPercentageBps) {\n        _setRoyaltyRecipient(royaltyRecipient);\n        if (royaltyPercentageBps >= 10000) revert RMRKRoyaltiesTooHigh();\n        _royaltyPercentageBps = royaltyPercentageBps;\n    }\n\n    /**\n     * @notice Used to update recipient of royalties.\n     * @dev Custom access control has to be implemented to ensure that only the intended actors can update the\n     *  beneficiary.\n     * @param newRoyaltyRecipient Address of the new recipient of royalties\n     */\n    function updateRoyaltyRecipient(\n        address newRoyaltyRecipient\n    ) external virtual;\n\n    /**\n     * @notice Used to update the royalty recipient.\n     * @param newRoyaltyRecipient Address of the new recipient of royalties\n     */\n    function _setRoyaltyRecipient(address newRoyaltyRecipient) internal {\n        _royaltyRecipient = newRoyaltyRecipient;\n    }\n\n    /**\n     * @notice Used to retrieve the recipient of royalties.\n     * @return recipient Address of the recipient of royalties\n     */\n    function getRoyaltyRecipient()\n        public\n        view\n        virtual\n        returns (address recipient)\n    {\n        recipient = _royaltyRecipient;\n    }\n\n    /**\n     * @notice Used to retrieve the specified royalty percentage.\n     * @return royaltyPercentageBps The royalty percentage expressed in the basis points\n     */\n    function getRoyaltyPercentage()\n        public\n        view\n        virtual\n        returns (uint256 royaltyPercentageBps)\n    {\n        royaltyPercentageBps = _royaltyPercentageBps;\n    }\n\n    /**\n     * @notice Used to retrieve the information about who shall receive royalties of a sale of the specified token and\n     *  how much they will be.\n     * @param tokenId ID of the token for which the royalty info is being retrieved\n     * @param salePrice Price of the token sale\n     * @return receiver The beneficiary receiving royalties of the sale\n     * @return royaltyAmount The value of the royalties recieved by the `receiver` from the sale\n     */\n    function royaltyInfo(\n        uint256 tokenId,\n        uint256 salePrice\n    ) external view virtual returns (address receiver, uint256 royaltyAmount) {\n        uint256(tokenId); // Silence the warning about unused variable, needed for docs generation\n        receiver = _royaltyRecipient;\n        royaltyAmount = (salePrice * _royaltyPercentageBps) / 10000;\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/extension/soulbound/IERC6454.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @title IERC6454\n * @author RMRK team\n * @notice A minimal extension to identify the transferability of Non-Fungible Tokens.\n */\ninterface IERC6454 is IERC165 {\n    /**\n     * @notice Used to check whether the given token is transferable or not.\n     * @dev If this function returns `false`, the transfer of the token MUST revert execution.\n     * @dev If the tokenId does not exist, this method MUST revert execution, unless the token is being checked for\n     *  minting.\n     * @param tokenId ID of the token being checked\n     * @param from Address from which the token is being transferred\n     * @param to Address to which the token is being transferred\n     * @return isTransferable_ Boolean value indicating whether the given token is transferable\n     */\n    function isTransferable(\n        uint256 tokenId,\n        address from,\n        address to\n    ) external view returns (bool isTransferable_);\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/extension/soulbound/RMRKSoulbound.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC6454} from \"./IERC6454.sol\";\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../../library/RMRKErrors.sol\";\n\n/**\n * @title RMRKSoulbound\n * @author RMRK team\n * @notice Smart contract of the RMRK Soulbound module.\n */\nabstract contract RMRKSoulbound is IERC6454 {\n    /**\n     * @notice Hook that is called before any token transfer. This includes minting and burning.\n     * @dev This is a hook ensuring that all transfers of tokens are reverted if the token is soulbound.\n     * @dev The only exception of transfers being allowed is when the tokens are minted or when they are being burned.\n     * @param from Address from which the token is originating (current owner of the token)\n     * @param to Address to which the token would be sent\n     * @param tokenId ID of the token that would be transferred\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {\n        if (!isTransferable(tokenId, from, to))\n            revert RMRKCannotTransferSoulbound();\n    }\n\n    /**\n     * @inheritdoc IERC6454\n     */\n    function isTransferable(\n        uint256,\n        address from,\n        address to\n    ) public view virtual returns (bool isTransferable_) {\n        isTransferable_ = ((from == address(0) || // Exclude minting\n            to == address(0)) && from != to); // Exclude Burning // Besides the obvious transfer to self, if both are address 0 (general transferability check), it returns false\n    }\n\n    /**\n     * @inheritdoc IERC165\n     */\n    function supportsInterface(\n        bytes4 interfaceId\n    ) public view virtual returns (bool) {\n        return interfaceId == type(IERC6454).interfaceId;\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKErrors.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\n/// @title RMRKErrors\n/// @author RMRK team\n/// @notice A collection of errors used in the RMRK suite\n/// @dev Errors are kept in a centralised file in order to provide a central point of reference and to avoid error\n///  naming collisions due to inheritance\n\n/// Attempting to grant the token to 0x0 address\nerror ERC721AddressZeroIsNotaValidOwner();\n/// Attempting to grant approval to the current owner of the token\nerror ERC721ApprovalToCurrentOwner();\n/// Attempting to grant approval when not being owner or approved for all should not be permitted\nerror ERC721ApproveCallerIsNotOwnerNorApprovedForAll();\n/// Attempting to grant approval to self\nerror ERC721ApproveToCaller();\n/// Attempting to use an invalid token ID\nerror ERC721InvalidTokenId();\n/// Attempting to mint to 0x0 address\nerror ERC721MintToTheZeroAddress();\n/// Attempting to manage a token without being its owner or approved by the owner\nerror ERC721NotApprovedOrOwner();\n/// Attempting to mint an already minted token\nerror ERC721TokenAlreadyMinted();\n/// Attempting to transfer the token from an address that is not the owner\nerror ERC721TransferFromIncorrectOwner();\n/// Attempting to safe transfer to an address that is unable to receive the token\nerror ERC721TransferToNonReceiverImplementer();\n/// Attempting to transfer the token to a 0x0 address\nerror ERC721TransferToTheZeroAddress();\n/// Attempting to grant approval of assets to their current owner\nerror RMRKApprovalForAssetsToCurrentOwner();\n/// Attempting to grant approval of assets without being the caller or approved for all\nerror RMRKApproveForAssetsCallerIsNotOwnerNorApprovedForAll();\n/// Attempting to incorrectly configue a Catalog item\nerror RMRKBadConfig();\n/// Attempting to set the priorities with an array of length that doesn't match the length of active assets array\nerror RMRKBadPriorityListLength();\n/// Attempting to add an asset entry with `Part`s, without setting the `Catalog` address\nerror RMRKCatalogRequiredForParts();\n/// Attempting to transfer a soulbound (non-transferrable) token\nerror RMRKCannotTransferSoulbound();\n/// Attempting to accept a child that has already been accepted\nerror RMRKChildAlreadyExists();\n/// Attempting to interact with a child, using index that is higher than the number of children\nerror RMRKChildIndexOutOfRange();\n/// Attempting to find the index of a child token on a parent which does not own it.\nerror RMRKChildNotFoundInParent();\n/// Attempting to equip a `Part` with a child not approved by the Catalog\nerror RMRKEquippableEquipNotAllowedByCatalog();\n/// Attempting to use ID 0, which is not supported\n/// @dev The ID 0 in RMRK suite is reserved for empty values. Guarding against its use ensures the expected operation\nerror RMRKIdZeroForbidden();\n/// Attempting to interact with an asset, using index greater than number of assets\nerror RMRKIndexOutOfRange();\n/// Attempting to reclaim a child that can't be reclaimed\nerror RMRKInvalidChildReclaim();\n/// Attempting to interact with an end-user account when the contract account is expected\nerror RMRKIsNotContract();\n/// Attempting to interact with a contract that had its operation locked\nerror RMRKLocked();\n/// Attempting to add a pending child after the number of pending children has reached the limit (default limit is 128)\nerror RMRKMaxPendingChildrenReached();\n/// Attempting to add a pending asset after the number of pending assets has reached the limit (default limit is\n///  128)\nerror RMRKMaxPendingAssetsReached();\n/// Attempting to burn a total number of recursive children higher than maximum set\n/// @param childContract Address of the collection smart contract in which the maximum number of recursive burns was reached\n/// @param childId ID of the child token at which the maximum number of recursive burns was reached\nerror RMRKMaxRecursiveBurnsReached(address childContract, uint256 childId);\n/// Attempting to mint a number of tokens that would cause the total supply to be greater than maximum supply\nerror RMRKMintOverMax();\n/// Attempting to mint zero tokens\nerror RMRKMintZero();\n/// Attempting to pass complementary arrays of different lengths\nerror RMRKMismachedArrayLength();\n/// Attempting to transfer a child before it is unequipped\nerror RMRKMustUnequipFirst();\n/// Attempting to nest a child over the nestable limit (current limit is 100 levels of nesting)\nerror RMRKNestableTooDeep();\n/// Attempting to nest the token to own descendant, which would create a loop and leave the looped tokens in limbo\nerror RMRKNestableTransferToDescendant();\n/// Attempting to nest the token to a smart contract that doesn't support nesting\nerror RMRKNestableTransferToNonRMRKNestableImplementer();\n/// Attempting to nest the token into itself\nerror RMRKNestableTransferToSelf();\n/// Attempting to interact with an asset that can not be found\nerror RMRKNoAssetMatchingId();\n/// Attempting to manage an asset without owning it or having been granted permission by the owner to do so\nerror RMRKNotApprovedForAssetsOrOwner();\n/// Attempting to interact with a token without being its owner or having been granted permission by the\n///  owner to do so\n/// @dev When a token is nested, only the direct owner (NFT parent) can mange it. In that case, approved addresses are\n///  not allowed to manage it, in order to ensure the expected behaviour\nerror RMRKNotApprovedOrDirectOwner();\n/// Attempting to compose an asset wihtout having an associated Catalog\nerror RMRKNotComposableAsset();\n/// Attempting to unequip an item that isn't equipped\nerror RMRKNotEquipped();\n/// Attempting to interact with a management function without being the smart contract's owner\nerror RMRKNotOwner();\n/// Attempting to interact with a function without being the owner or contributor of the collection\nerror RMRKNotOwnerOrContributor();\n/// Attempting to transfer the ownership to the 0x0 address\nerror RMRKNewOwnerIsZeroAddress();\n/// Attempting to assign a 0x0 address as a contributor\nerror RMRKNewContributorIsZeroAddress();\n/// Attempting an operation requiring the token being nested, while it is not\nerror RMRKParentIsNotNFT();\n/// Attempting to add a `Part` with an ID that is already used\nerror RMRKPartAlreadyExists();\n/// Attempting to use a `Part` that doesn't exist\nerror RMRKPartDoesNotExist();\n/// Attempting to use a `Part` that is `Fixed` when `Slot` kind of `Part` should be used\nerror RMRKPartIsNotSlot();\n/// Attempting to interact with a pending child using an index greater than the size of pending array\nerror RMRKPendingChildIndexOutOfRange();\n/// Attempting to add an asset using an ID that has already been used\nerror RMRKAssetAlreadyExists();\n/// Attempting to equip an item into a slot that already has an item equipped\nerror RMRKSlotAlreadyUsed();\n/// Attempting to equip an item into a `Slot` that the target asset does not implement\nerror RMRKTargetAssetCannotReceiveSlot();\n/// Attempting to equip a child into a `Slot` and parent that the child's collection doesn't support\nerror RMRKTokenCannotBeEquippedWithAssetIntoSlot();\n/// Attempting to compose a NFT of a token without active assets\nerror RMRKTokenDoesNotHaveAsset();\n/// Attempting to determine the asset with the top priority on a token without assets\nerror RMRKTokenHasNoAssets();\n/// Attempting to accept or transfer a child which does not match the one at the specified index\nerror RMRKUnexpectedChildId();\n/// Attempting to reject all pending assets but more assets than expected are pending\nerror RMRKUnexpectedNumberOfAssets();\n/// Attempting to reject all pending children but children assets than expected are pending\nerror RMRKUnexpectedNumberOfChildren();\n/// Attempting to accept or reject an asset which does not match the one at the specified index\nerror RMRKUnexpectedAssetId();\n/// Attempting an operation expecting a parent to the token which is not the actual one\nerror RMRKUnexpectedParent();\n/// Attempting not to pass an empty array of equippable addresses when adding or setting the equippable addresses\nerror RMRKZeroLengthIdsPassed();\n/// Attempting to set the royalties to a value higher than 100% (10000 in basis points)\nerror RMRKRoyaltiesTooHigh();\n/// Attempting to do a bulk operation on a token that is not owned by the caller\nerror RMRKCanOnlyDoBulkOperationsOnOwnedTokens();\n/// Attempting to do a bulk operation with multiple tokens at a time\nerror RMRKCanOnlyDoBulkOperationsWithOneTokenAtATime();\n/// Attempting to pay with native token with a value different than expected\nerror RMRKWrongValueSent();\n// Attempting to send native token to a recipient that is unable to receive it\nerror TransferFailed();\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/library/RMRKLib.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\n/**\n * @title RMRKLib\n * @author RMRK team\n * @notice RMRK library smart contract.\n */\nlibrary RMRKLib {\n    error IndexOutOfBounds();\n\n    /**\n     * @notice Used to remove an item from the array using the specified index.\n     * @dev The item is removed by replacing it with the last item and removing the last element.\n     * @param array An array of items containing the item to be removed\n     * @param index Index of the item to remove\n     */\n    function removeItemByIndex(uint64[] storage array, uint256 index) internal {\n        //Check to see if this is already gated by require in all calls\n        if (index >= array.length) revert IndexOutOfBounds();\n        array[index] = array[array.length - 1];\n        array.pop();\n    }\n\n    /**\n     * @notice Used to determine the index of the item in the array by spedifying its value.\n     * @dev This was adapted from Cryptofin-Solidity `arrayUtils`.\n     * @dev If the item is not found the index returned will equal `0`.\n     * @param A The array containing the item to be found\n     * @param a The value of the item to find the index of\n     * @return The index of the item in the array\n     * @return A boolean value specifying whether the item was found\n     */\n    function indexOf(\n        uint64[] memory A,\n        uint64 a\n    ) internal pure returns (uint256, bool) {\n        uint256 length = A.length;\n        for (uint256 i; i < length; ) {\n            if (A[i] == a) {\n                return (i, true);\n            }\n            unchecked {\n                ++i;\n            }\n        }\n        return (0, false);\n    }\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/multiasset/IERC5773.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @title IERC5773\n * @author RMRK team\n * @notice Interface smart contract of the RMRK multi asset module.\n */\ninterface IERC5773 is IERC165 {\n    /**\n     * @notice Used to notify listeners that an asset object is initialized at `assetId`.\n     * @param assetId ID of the asset that was initialized\n     */\n    event AssetSet(uint64 indexed assetId);\n\n    /**\n     * @notice Used to notify listeners that an asset object at `assetId` is added to token's pending asset\n     *  array.\n     * @param tokenIds An array of token IDs that received a new pending asset\n     * @param assetId ID of the asset that has been added to the token's pending assets array\n     * @param replacesId ID of the asset that would be replaced\n     */\n    event AssetAddedToTokens(\n        uint256[] tokenIds,\n        uint64 indexed assetId,\n        uint64 indexed replacesId\n    );\n\n    /**\n     * @notice Used to notify listeners that an asset object at `assetId` is accepted by the token and migrated\n     *  from token's pending assets array to active assets array of the token.\n     * @param tokenId ID of the token that had a new asset accepted\n     * @param assetId ID of the asset that was accepted\n     * @param replacesId ID of the asset that was replaced\n     */\n    event AssetAccepted(\n        uint256 indexed tokenId,\n        uint64 indexed assetId,\n        uint64 indexed replacesId\n    );\n\n    /**\n     * @notice Used to notify listeners that an asset object at `assetId` is rejected from token and is dropped\n     *  from the pending assets array of the token.\n     * @param tokenId ID of the token that had an asset rejected\n     * @param assetId ID of the asset that was rejected\n     */\n    event AssetRejected(uint256 indexed tokenId, uint64 indexed assetId);\n\n    /**\n     * @notice Used to notify listeners that token's prioritiy array is reordered.\n     * @param tokenId ID of the token that had the asset priority array updated\n     */\n    event AssetPrioritySet(uint256 indexed tokenId);\n\n    /**\n     * @notice Used to notify listeners that owner has granted an approval to the user to manage the assets of a\n     *  given token.\n     * @dev Approvals must be cleared on transfer\n     * @param owner Address of the account that has granted the approval for all token's assets\n     * @param approved Address of the account that has been granted approval to manage the token's assets\n     * @param tokenId ID of the token on which the approval was granted\n     */\n    event ApprovalForAssets(\n        address indexed owner,\n        address indexed approved,\n        uint256 indexed tokenId\n    );\n\n    /**\n     * @notice Used to notify listeners that owner has granted approval to the user to manage assets of all of their\n     *  tokens.\n     * @param owner Address of the account that has granted the approval for all assets on all of their tokens\n     * @param operator Address of the account that has been granted the approval to manage the token's assets on all of\n     *  the tokens\n     * @param approved Boolean value signifying whether the permission has been granted (`true`) or revoked (`false`)\n     */\n    event ApprovalForAllForAssets(\n        address indexed owner,\n        address indexed operator,\n        bool approved\n    );\n\n    /**\n     * @notice Accepts an asset at from the pending array of given token.\n     * @dev Migrates the asset from the token's pending asset array to the token's active asset array.\n     * @dev Active assets cannot be removed by anyone, but can be replaced by a new asset.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - `index` must be in range of the length of the pending asset array.\n     * @dev Emits an {AssetAccepted} event.\n     * @param tokenId ID of the token for which to accept the pending asset\n     * @param index Index of the asset in the pending array to accept\n     * @param assetId ID of the asset expected to be in the index\n     */\n    function acceptAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) external;\n\n    /**\n     * @notice Rejects an asset from the pending array of given token.\n     * @dev Removes the asset from the token's pending asset array.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - `index` must be in range of the length of the pending asset array.\n     * @dev Emits a {AssetRejected} event.\n     * @param tokenId ID of the token that the asset is being rejected from\n     * @param index Index of the asset in the pending array to be rejected\n     * @param assetId ID of the asset expected to be in the index\n     */\n    function rejectAsset(\n        uint256 tokenId,\n        uint256 index,\n        uint64 assetId\n    ) external;\n\n    /**\n     * @notice Rejects all assets from the pending array of a given token.\n     * @dev Effecitvely deletes the pending array.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     * @dev Emits a {AssetRejected} event with assetId = 0.\n     * @param tokenId ID of the token of which to clear the pending array.\n     * @param maxRejections Maximum number of expected assets to reject, used to prevent from rejecting assets which\n     *  arrive just before this operation.\n     */\n    function rejectAllAssets(uint256 tokenId, uint256 maxRejections) external;\n\n    /**\n     * @notice Sets a new priority array for a given token.\n     * @dev The priority array is a non-sequential list of `uint64`s, where the lowest value is considered highest\n     *  priority.\n     * @dev Value `0` of a priority is a special case equivalent to unitialized.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be approved to manage the token's assets\n     *  - `tokenId` must exist.\n     *  - The length of `priorities` must be equal the length of the active assets array.\n     * @dev Emits a {AssetPrioritySet} event.\n     * @param tokenId ID of the token to set the priorities for\n     * @param priorities An array of priorities of active assets. The succesion of items in the priorities array\n     *  matches that of the succesion of items in the active array\n     */\n    function setPriority(\n        uint256 tokenId,\n        uint64[] calldata priorities\n    ) external;\n\n    /**\n     * @notice Used to retrieve IDs of the active assets of given token.\n     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call\n     *  `getAssetMetadata(tokenId, assetId)`.\n     * @dev You can safely get 10k\n     * @param tokenId ID of the token to retrieve the IDs of the active assets\n     * @return assetIds An array of active asset IDs of the given token\n     */\n    function getActiveAssets(\n        uint256 tokenId\n    ) external view returns (uint64[] memory assetIds);\n\n    /**\n     * @notice Used to retrieve IDs of the pending assets of given token.\n     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call\n     *  `getAssetMetadata(tokenId, assetId)`.\n     * @param tokenId ID of the token to retrieve the IDs of the pending assets\n     * @return assetIds An array of pending asset IDs of the given token\n     */\n    function getPendingAssets(\n        uint256 tokenId\n    ) external view returns (uint64[] memory assetIds);\n\n    /**\n     * @notice Used to retrieve the priorities of the active resoources of a given token.\n     * @dev Asset priorities are a non-sequential array of uint64 values with an array size equal to active asset\n     *  priorites.\n     * @param tokenId ID of the token for which to retrieve the priorities of the active assets\n     * @return priorities An array of priorities of the active assets of the given token\n     */\n    function getActiveAssetPriorities(\n        uint256 tokenId\n    ) external view returns (uint64[] memory priorities);\n\n    /**\n     * @notice Used to retrieve the asset that will be replaced if a given asset from the token's pending array\n     *  is accepted.\n     * @dev Asset data is stored by reference, in order to access the data corresponding to the ID, call\n     *  `getAssetMetadata(tokenId, assetId)`.\n     * @param tokenId ID of the token to check\n     * @param newAssetId ID of the pending asset which will be accepted\n     * @return replacesAssetWithId ID of the asset which will be replaced\n     */\n    function getAssetReplacements(\n        uint256 tokenId,\n        uint64 newAssetId\n    ) external view returns (uint64 replacesAssetWithId);\n\n    /**\n     * @notice Used to fetch the asset metadata of the specified token's active asset with the given index.\n     * @dev Assets are stored by reference mapping `_assets[assetId]`.\n     * @dev Can be overriden to implement enumerate, fallback or other custom logic.\n     * @param tokenId ID of the token from which to retrieve the asset metadata\n     * @param assetId Asset Id, must be in the active assets array\n     * @return metadata The metadata of the asset belonging to the specified index in the token's active assets\n     *  array\n     */\n    function getAssetMetadata(\n        uint256 tokenId,\n        uint64 assetId\n    ) external view returns (string memory metadata);\n\n    // Approvals\n\n    /**\n     * @notice Used to grant permission to the user to manage token's assets.\n     * @dev This differs from transfer approvals, as approvals are not cleared when the approved party accepts or\n     *  rejects an asset, or sets asset priorities. This approval is cleared on token transfer.\n     * @dev Only a single account can be approved at a time, so approving the `0x0` address clears previous approvals.\n     * @dev Requirements:\n     *\n     *  - The caller must own the token or be an approved operator.\n     *  - `tokenId` must exist.\n     * @dev Emits an {ApprovalForAssets} event.\n     * @param to Address of the account to grant the approval to\n     * @param tokenId ID of the token for which the approval to manage the assets is granted\n     */\n    function approveForAssets(address to, uint256 tokenId) external;\n\n    /**\n     * @notice Used to retrieve the address of the account approved to manage assets of a given token.\n     * @dev Requirements:\n     *\n     *  - `tokenId` must exist.\n     * @param tokenId ID of the token for which to retrieve the approved address\n     * @return approved Address of the account that is approved to manage the specified token's assets\n     */\n    function getApprovedForAssets(\n        uint256 tokenId\n    ) external view returns (address approved);\n\n    /**\n     * @notice Used to add or remove an operator of assets for the caller.\n     * @dev Operators can call {acceptAsset}, {rejectAsset}, {rejectAllAssets} or {setPriority} for any token\n     *  owned by the caller.\n     * @dev Requirements:\n     *\n     *  - The `operator` cannot be the caller.\n     * @dev Emits an {ApprovalForAllForAssets} event.\n     * @param operator Address of the account to which the operator role is granted or revoked from\n     * @param approved The boolean value indicating whether the operator role is being granted (`true`) or revoked\n     *  (`false`)\n     */\n    function setApprovalForAllForAssets(\n        address operator,\n        bool approved\n    ) external;\n\n    /**\n     * @notice Used to check whether the address has been granted the operator role by a given address or not.\n     * @dev See {setApprovalForAllForAssets}.\n     * @param owner Address of the account that we are checking for whether it has granted the operator role\n     * @param operator Address of the account that we are checking whether it has the operator role or not\n     * @return isApproved A boolean value indicating whether the account we are checking has been granted the operator role\n     */\n    function isApprovedForAllForAssets(\n        address owner,\n        address operator\n    ) external view returns (bool isApproved);\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/nestable/IERC7401.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/**\n * @title IERC7401\n * @author RMRK team\n * @notice Interface smart contract of the RMRK nestable module.\n */\ninterface IERC7401 is IERC165 {\n    /**\n     * @notice The core struct of RMRK ownership.\n     * @dev The `DirectOwner` struct is used to store information of the next immediate owner, be it the parent token or\n     *  the externally owned account.\n     * @dev If the token is owned by the externally owned account, the `tokenId` should equal `0`.\n     * @param tokenId ID of the parent token\n     * @param ownerAddress Address of the owner of the token. If the owner is another token, then the address should be\n     *  the one of the parent token's collection smart contract. If the owner is externally owned account, the address\n     *  should be the address of this account\n     * @param isNft A boolean value signifying whether the token is owned by another token (`true`) or by an externally\n     *  owned account (`false`)\n     */\n    struct DirectOwner {\n        uint256 tokenId;\n        address ownerAddress;\n    }\n\n    /**\n     * @notice Used to notify listeners that the token is being transferred.\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     * @param from Address of the previous immediate owner, which is a smart contract if the token was nested.\n     * @param to Address of the new immediate owner, which is a smart contract if the token is being nested.\n     * @param fromTokenId ID of the previous parent token. If the token was not nested before, the value should be `0`\n     * @param toTokenId ID of the new parent token. If the token is not being nested, the value should be `0`\n     * @param tokenId ID of the token being transferred\n     */\n    event NestTransfer(\n        address indexed from,\n        address indexed to,\n        uint256 fromTokenId,\n        uint256 toTokenId,\n        uint256 indexed tokenId\n    );\n\n    /**\n     * @notice Used to notify listeners that a new token has been added to a given token's pending children array.\n     * @dev Emitted when a child NFT is added to a token's pending array.\n     * @param tokenId ID of the token that received a new pending child token\n     * @param childIndex Index of the proposed child token in the parent token's pending children array\n     * @param childAddress Address of the proposed child token's collection smart contract\n     * @param childId ID of the child token in the child token's collection smart contract\n     */\n    event ChildProposed(\n        uint256 indexed tokenId,\n        uint256 childIndex,\n        address indexed childAddress,\n        uint256 indexed childId\n    );\n\n    /**\n     * @notice Used to notify listeners that a new child token was accepted by the parent token.\n     * @dev Emitted when a parent token accepts a token from its pending array, migrating it to the active array.\n     * @param tokenId ID of the token that accepted a new child token\n     * @param childIndex Index of the newly accepted child token in the parent token's active children array\n     * @param childAddress Address of the child token's collection smart contract\n     * @param childId ID of the child token in the child token's collection smart contract\n     */\n    event ChildAccepted(\n        uint256 indexed tokenId,\n        uint256 childIndex,\n        address indexed childAddress,\n        uint256 indexed childId\n    );\n\n    /**\n     * @notice Used to notify listeners that all pending child tokens of a given token have been rejected.\n     * @dev Emitted when a token removes all a child tokens from its pending array.\n     * @param tokenId ID of the token that rejected all of the pending children\n     */\n    event AllChildrenRejected(uint256 indexed tokenId);\n\n    /**\n     * @notice Used to notify listeners a child token has been transferred from parent token.\n     * @dev Emitted when a token transfers a child from itself, transferring ownership to the root owner.\n     * @param tokenId ID of the token that transferred a child token\n     * @param childIndex Index of a child in the array from which it is being transferred\n     * @param childAddress Address of the child token's collection smart contract\n     * @param childId ID of the child token in the child token's collection smart contract\n     * @param fromPending A boolean value signifying whether the token was in the pending child tokens array (`true`) or\n     *  in the active child tokens array (`false`)\n     * @param toZero A boolean value signifying whether the token is being transferred to the `0x0` address (`true`) or\n     *  not (`false`)\n     */\n    event ChildTransferred(\n        uint256 indexed tokenId,\n        uint256 childIndex,\n        address indexed childAddress,\n        uint256 indexed childId,\n        bool fromPending,\n        bool toZero\n    );\n\n    /**\n     * @notice The core child token struct, holding the information about the child tokens.\n     * @return tokenId ID of the child token in the child token's collection smart contract\n     * @return contractAddress Address of the child token's smart contract\n     */\n    struct Child {\n        uint256 tokenId;\n        address contractAddress;\n    }\n\n    /**\n     * @notice Used to retrieve the *root* owner of a given token.\n     * @dev The *root* owner of the token is an externally owned account (EOA). If the given token is child of another\n     *  NFT, this will return an EOA address. Otherwise, if the token is owned by an EOA, this EOA will be returned.\n     * @param tokenId ID of the token for which the *root* owner has been retrieved\n     * @return owner_ The *root* owner of the token\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner_);\n\n    /**\n     * @notice Used to retrieve the immediate owner of the given token.\n     * @dev If the immediate owner is another token, the address returned will be the parent token's collection address.\n     * @param tokenId ID of the token for which the RMRK owner is being retrieved\n     * @return owner Address of the given token's owner\n     * @return parentId The ID of the parent token. Should be `0` if the owner is an externally owned account\n     * @return isNFT The boolean value signifying whether the owner is an NFT or not\n     */\n    function directOwnerOf(\n        uint256 tokenId\n    ) external view returns (address owner, uint256 parentId, bool isNFT);\n\n    /**\n     * @notice Used to burn a given token.\n     * @dev When a token is burned, all of its child tokens are recursively burned as well.\n     * @dev When specifying the maximum recursive burns, the execution will be reverted if there are more children to be\n     *  burned.\n     * @dev Setting the `maxRecursiveBurn` value to 0 will only attempt to burn the specified token and revert if there\n     *  are any child tokens present.\n     * @dev The approvals are cleared when the token is burned.\n     * @dev Requirements:\n     *\n     *  - `tokenId` must exist.\n     * @dev Emits a {Transfer} event.\n     * @param tokenId ID of the token to burn\n     * @param maxRecursiveBurns Maximum number of tokens to recursively burn\n     * @return burnedChildren Number of recursively burned children\n     */\n    function burn(\n        uint256 tokenId,\n        uint256 maxRecursiveBurns\n    ) external returns (uint256 burnedChildren);\n\n    /**\n     * @notice Used to add a child token to a given parent token.\n     * @dev This adds the child token into the given parent token's pending child tokens array.\n     * @dev Requirements:\n     *\n     *  - `directOwnerOf` on the child contract must resolve to the called contract.\n     *  - the pending array of the parent contract must not be full.\n     * @param parentId ID of the parent token to receive the new child token\n     * @param childId ID of the new proposed child token\n     * @param data Additional data with no specified format\n     */\n    function addChild(\n        uint256 parentId,\n        uint256 childId,\n        bytes memory data\n    ) external;\n\n    /**\n     * @notice Used to accept a pending child token for a given parent token.\n     * @dev This moves the child token from parent token's pending child tokens array into the active child tokens\n     *  array.\n     * @param parentId ID of the parent token for which the child token is being accepted\n     * @param childIndex Index of a child tokem in the given parent's pending children array\n     * @param childAddress Address of the collection smart contract of the child token expected to be located at the\n     *  specified index of the given parent token's pending children array\n     * @param childId ID of the child token expected to be located at the specified index of the given parent token's\n     *  pending children array\n     */\n    function acceptChild(\n        uint256 parentId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId\n    ) external;\n\n    /**\n     * @notice Used to reject all pending children of a given parent token.\n     * @dev Removes the children from the pending array mapping.\n     * @dev This does not update the ownership storage data on children. If necessary, ownership can be reclaimed by the\n     *  rootOwner of the previous parent.\n     * @dev Requirements:\n     *\n     * Requirements:\n     *\n     * - `parentId` must exist\n     * @param parentId ID of the parent token for which to reject all of the pending tokens.\n     * @param maxRejections Maximum number of expected children to reject, used to prevent from rejecting children which\n     *  arrive just before this operation.\n     */\n    function rejectAllChildren(\n        uint256 parentId,\n        uint256 maxRejections\n    ) external;\n\n    /**\n     * @notice Used to transfer a child token from a given parent token.\n     * @dev When transferring a child token, the owner of the token is set to `to`, or is not updated in the event of\n     *  `to` being the `0x0` address.\n     * @param tokenId ID of the parent token from which the child token is being transferred\n     * @param to Address to which to transfer the token to\n     * @param destinationId ID of the token to receive this child token (MUST be 0 if the destination is not a token)\n     * @param childIndex Index of a token we are transferring, in the array it belongs to (can be either active array or\n     *  pending array)\n     * @param childAddress Address of the child token's collection smart contract.\n     * @param childId ID of the child token in its own collection smart contract.\n     * @param isPending A boolean value indicating whether the child token being transferred is in the pending array of\n     *  the parent token (`true`) or in the active array (`false`)\n     * @param data Additional data with no specified format, sent in call to `_to`\n     */\n    function transferChild(\n        uint256 tokenId,\n        address to,\n        uint256 destinationId,\n        uint256 childIndex,\n        address childAddress,\n        uint256 childId,\n        bool isPending,\n        bytes memory data\n    ) external;\n\n    /**\n     * @notice Used to retrieve the active child tokens of a given parent token.\n     * @dev Returns array of Child structs existing for parent token.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param parentId ID of the parent token for which to retrieve the active child tokens\n     * @return children An array of Child structs containing the parent token's active child tokens\n     */\n    function childrenOf(\n        uint256 parentId\n    ) external view returns (Child[] memory children);\n\n    /**\n     * @notice Used to retrieve the pending child tokens of a given parent token.\n     * @dev Returns array of pending Child structs existing for given parent.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param parentId ID of the parent token for which to retrieve the pending child tokens\n     * @return children An array of Child structs containing the parent token's pending child tokens\n     */\n    function pendingChildrenOf(\n        uint256 parentId\n    ) external view returns (Child[] memory children);\n\n    /**\n     * @notice Used to retrieve a specific active child token for a given parent token.\n     * @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param parentId ID of the parent token for which the child is being retrieved\n     * @param index Index of the child token in the parent token's active child tokens array\n     * @return child A Child struct containing data about the specified child\n     */\n    function childOf(\n        uint256 parentId,\n        uint256 index\n    ) external view returns (Child memory child);\n\n    /**\n     * @notice Used to retrieve a specific pending child token from a given parent token.\n     * @dev Returns a single Child struct locating at `index` of parent token's active child tokens array.\n     * @dev The Child struct consists of the following values:\n     *  [\n     *      tokenId,\n     *      contractAddress\n     *  ]\n     * @param parentId ID of the parent token for which the pending child token is being retrieved\n     * @param index Index of the child token in the parent token's pending child tokens array\n     * @return child A Child struct containting data about the specified child\n     */\n    function pendingChildOf(\n        uint256 parentId,\n        uint256 index\n    ) external view returns (Child memory child);\n\n    /**\n     * @notice Used to transfer the token into another token.\n     * @param from Address of the direct owner of the token to be transferred\n     * @param to Address of the receiving token's collection smart contract\n     * @param tokenId ID of the token being transferred\n     * @param destinationId ID of the token to receive the token being transferred\n     * @param data Additional data with no specified format, sent in the addChild call\n     */\n    function nestTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        uint256 destinationId,\n        bytes memory data\n    ) external;\n}\n"
      },
      "@rmrk-team/evm-contracts/contracts/RMRK/security/ReentrancyGuard.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.21;\n\nerror RentrantCall();\n\n/**\n * @title ReentrancyGuard\n * @notice Smart contract used to guard against potential reentrancy exploits.\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @notice Initializes the ReentrancyGuard with the `_status` of `_NOT_ENTERED`.\n     */\n    constructor() {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @notice Used to ensure that the function it is applied to cannot be reentered.\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantIn();\n        _;\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @notice Used to ensure that the current call is not a reentrant call.\n     * @dev If reentrant call is detected, the execution will be reverted.\n     */\n    function _nonReentrantIn() private {\n        // On the first call to nonReentrant, _notEntered will be true\n        if (_status == _ENTERED) revert RentrantCall();\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n}\n"
      },
      "contracts/factory/premint/IRMRKPreMintFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.21;\n\ninterface IRMRKPreMintFactory {\n    function deployRMRKCollection(\n        string memory name,\n        string memory symbol,\n        string memory collectionMetadata,\n        uint256 maxSupply,\n        address royaltyRecipient,\n        uint16 royaltyPercentageBps\n    ) external;\n}\n"
      },
      "contracts/factory/premint/RMRKEquippablePreMintSoulboundFactory.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport \"../../implementations/premint/RMRKEquippablePreMintSoulboundMP.sol\";\nimport \"../../interfaces/IRMRKRegistry.sol\";\nimport \"./IRMRKPreMintFactory.sol\";\n\ncontract RMRKEquippablePreMintSoulboundFactory is IRMRKPreMintFactory {\n    IRMRKRegistry private _rmrkRegistry;\n\n    constructor(address rmrkRegistry) {\n        _rmrkRegistry = IRMRKRegistry(rmrkRegistry);\n    }\n\n    function deployRMRKCollection(\n        string memory name,\n        string memory symbol,\n        string memory collectionMetadata,\n        uint256 maxSupply,\n        address royaltyRecipient,\n        uint16 royaltyPercentageBps\n    ) external {\n        RMRKEquippablePreMintSoulboundMP equippableContract = new RMRKEquippablePreMintSoulboundMP(\n                name,\n                symbol,\n                collectionMetadata,\n                maxSupply,\n                royaltyRecipient,\n                royaltyPercentageBps\n            );\n\n        equippableContract.manageContributor(\n            _rmrkRegistry.getMetaFactoryAddress(),\n            true\n        );\n        equippableContract.transferOwnership(msg.sender);\n\n        _rmrkRegistry.addCollectionFromFactories(\n            address(equippableContract),\n            msg.sender,\n            maxSupply,\n            IRMRKRegistry.LegoCombination.Equippable,\n            IRMRKRegistry.MintingType.RMRKPreMint,\n            true\n        );\n    }\n}\n"
      },
      "contracts/implementations/abstract/CoreMP.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.21;\n\nimport {\n    RMRKImplementationBase\n} from \"@rmrk-team/evm-contracts/contracts/implementations/utils/RMRKImplementationBase.sol\";\n\nerror ContractURIFrozen();\n\n/**\n * @title CoreMP\n * @author RMRK team\n * @notice Smart contract of the CoreMP utils module.\n * @dev This smart contract contains methods shared by all of the marketplace implementations.\n */\nabstract contract CoreMP is RMRKImplementationBase {\n    /**\n     * @notice From ERC7572 (Draft) Emitted when the contract-level metadata is updated\n     */\n    event ContractURIUpdated();\n\n    uint256 private _contractURIFrozen; // Cheaper than a bool\n\n    /**\n     * @notice Sets the max supply of the collection to the current total supply, so no more tokens can be minted.\n     */\n    function lockSupply() external onlyOwner {\n        _maxSupply = _totalSupply;\n    }\n\n    /**\n     * @notice Used to get whether the contract-level metadata is frozen and cannot be further updated.\n     * @return isFrozen Whether the contract-level metadata is frozen\n     */\n    function isContractURIFrozen() external view returns (bool isFrozen) {\n        isFrozen = _contractURIFrozen == 1;\n    }\n\n    /**\n     * @notice Freezes the contract-level metadata, so it cannot be further updated.\n     */\n    function freezeContractURI() external onlyOwner {\n        _contractURIFrozen = 1;\n    }\n\n    /**\n     * @notice Sets the contract-level metadata URI to a new value and emits an event.\n     * @param contractURI_ The new contract-level metadata URI\n     */\n    function setContractURI(string memory contractURI_) external onlyOwner {\n        if (_contractURIFrozen == 1) {\n            revert ContractURIFrozen();\n        }\n        _contractURI = contractURI_;\n        emit ContractURIUpdated();\n    }\n}\n"
      },
      "contracts/implementations/premint/RMRKEquippablePreMintSoulboundMP.sol": {
        "content": "// SPDX-License-Identifier: Apache-2.0\n\npragma solidity ^0.8.21;\n\nimport \"@rmrk-team/evm-contracts/contracts/implementations/premint/RMRKEquippablePreMintSoulbound.sol\";\nimport \"../abstract/CoreMP.sol\";\n\ncontract RMRKEquippablePreMintSoulboundMP is\n    CoreMP,\n    RMRKEquippablePreMintSoulbound\n{\n    constructor(\n        string memory name,\n        string memory symbol,\n        string memory collectionMetadata,\n        uint256 maxSupply,\n        address royaltyRecipient,\n        uint16 royaltyPercentageBps\n    )\n        RMRKEquippablePreMintSoulbound(\n            name,\n            symbol,\n            collectionMetadata,\n            maxSupply,\n            royaltyRecipient,\n            royaltyPercentageBps\n        )\n    {}\n}\n"
      },
      "contracts/interfaces/IRMRKRegistry.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.21;\n\nerror CannotAddCollectionWithMintedTokens();\nerror CollectionAddressCannotBeZero();\nerror CollectionAlreadyExists();\nerror CollectionAlreadySponsored();\nerror CollectionAlreadyVerified();\nerror CollectionDoesNotExist(address collection);\nerror CollectionHasMintedTokens();\nerror CollectionMetadataNotAvailable();\nerror CollectionNotAllowedForIssuer();\nerror CollectionNotSponsored();\nerror CollectionNotSponsoredBySender();\nerror CollectionSymbolCannotBeEmpty();\nerror NotEnoughAllowance();\nerror NotEnoughBalance();\nerror OnlyCollectionOwnerCanAddCollection();\nerror OnlyCollectionOwnerCanRemoveCollection();\nerror NotFactory();\nerror UnsupportedCollection();\n\ninterface IRMRKRegistry {\n    enum LegoCombination {\n        None,\n        MultiAsset,\n        Nestable,\n        NestableMultiAsset,\n        Equippable,\n        ERC721,\n        ERC1155,\n        Custom\n    }\n\n    enum MintingType {\n        None,\n        RMRKPreMint,\n        RMRKLazyMintNativeToken,\n        RMRKLazyMintERC20,\n        Custom\n    }\n\n    struct CollectionConfig {\n        bool usesOwnable;\n        bool usesAccessControl;\n        bool usesRMRKContributor;\n        bool usesRMRKMintingUtils;\n        bool usesRMRKLockable;\n        bool hasStandardAssetManagement; // has addAssetEntry, addEquippableAssetEntry, addAssetToToken, etc\n        bool hasStandardMinting; // has mint(address to, uint256 numToMint)\n        bool hasStandardNestMinting; // has nestMint(address to, uint256 numToMint, uint256 destinationId)\n        bool autoAcceptsFirstAsset;\n        uint8 customLegoCombination;\n        uint8 customMintingType;\n        bytes32 adminRole; // Only for AccessControl users\n    }\n\n    struct Collection {\n        address collection;\n        address verificationSponsor;\n        uint256 verificationFeeBalance;\n        LegoCombination legoCombination;\n        MintingType mintingType;\n        bool isSoulbound;\n        bool visible;\n        bool verified;\n        CollectionConfig config;\n    }\n\n    event CollectionAdded(\n        address collection,\n        address deployer,\n        string name,\n        string symbol,\n        uint256 maxSupply,\n        string collectionMetadata,\n        LegoCombination legoCombination,\n        MintingType mintingType,\n        bool isSoulbound,\n        CollectionConfig config\n    );\n\n    event CollectionBlacklisted(address collection);\n    event CollectionRemoved(address collection);\n    event CollectionSponsorshipCancelled(address collection);\n    event CollectionSponsored(address collection, address sponsor);\n    event CollectionUnverified(address collection);\n    event CollectionVerified(address collection);\n\n    function addCollectionFromFactories(\n        address collection,\n        address deployer,\n        uint256 maxSupply,\n        LegoCombination legoCombination,\n        MintingType mintingType,\n        bool isSoulbound\n    ) external;\n\n    function addCollection(\n        address collection,\n        address deployer,\n        uint256 maxSupply,\n        LegoCombination legoCombination,\n        MintingType mintingType,\n        bool isSoulbound,\n        CollectionConfig memory config,\n        string memory collectionMetadata\n    ) external;\n\n    function getMetaFactoryAddress() external view returns (address);\n}\n"
      }
    },
    "settings": {
      "evmVersion": "london",
      "optimizer": {
        "enabled": true,
        "runs": 1
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}