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