Token
Skybreach Land Deed (SBLD)
ERC-721
Overview
Max Total Supply
25,000 SBLD
Holders
1,912
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract
Balance
9 SBLDLoading...
Loading
Loading...
Loading
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xB13695ae...F55D14075 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
SkyBreachLands
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 30 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 "@rmrk-team/evm-contracts/contracts/implementations/abstract/RMRKAbstractEquippable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; error AssetForLandCharacteristicsAlreadyExists(); error CannotBurnLands(); error LengthMismatch(); error OnlyLandManager(); error OnlyLandOwner(); contract SkyBreachLands is RMRKAbstractEquippable { // Variables mapping(address collection => bool autoaccept) private _autoAcceptCollection; mapping(uint256 landId => uint64 customAsset) private _customAssets; // These are the assets that the land owner can change. One per land mapping(uint256 landDataId => uint64 assetId) private _assetPerLandData; // Each land is mapped to an Id according to its characteristics. address private _landManager; // This contract will be able to claim lands for decay and harbtax. string private _baseURI; // For token URI event CustomAssetSet( uint256 indexed landId, uint64 assetId, string metadataURI ); event LandClaimed(uint256 indexed landId); enum Rarity { None, Common, Rare, Epic, Harb, Premium } enum Entropy { None, Seldom, Infrequent, Uncommon, Common, Frequent, Constant } enum LandMass { None, Low, Mid, High, Full } // 0, 25%, 50%, 75%, 100% struct LandData { LandMass cyber; LandMass steampunk; LandMass wind; LandMass volcano; LandMass fire; LandMass water; LandMass necro; LandMass mecha; LandMass dragon; LandMass meadow; Rarity rarity; Entropy entropy; bool isShore; // 0 = no, 1 = yes bool isCliff; // 0 = no, 1 = yes bool isIsland; // 0 = mainland, 1 = island bool isMountainFoot; // 0 = no, 1 = yes } // Constructor constructor( string memory baseURI, string memory collectionMetadata, uint256 maxSupply, address royaltyRecipient, uint16 royaltyPercentageBps ) RMRKImplementationBase( "Skybreach Land Deed", "SBLD", collectionMetadata, maxSupply, royaltyRecipient, royaltyPercentageBps ) { _baseURI = baseURI; } function getLandManager() public view returns (address) { return _landManager; } function setLandManager(address landManager) public onlyOwner { _landManager = landManager; } function takeLands(uint256[] memory landIds) public { if (msg.sender != _landManager) revert OnlyLandManager(); for (uint256 i; i < landIds.length; ) { uint256 landId = landIds[i]; _transfer(ownerOf(landId), _landManager, landId, ""); unchecked { ++i; } emit LandClaimed(landId); } } function setCustomAssets( uint256[] memory landIds, string[] memory customAssetMetadataURIs ) public { _setCustomAssets(landIds, customAssetMetadataURIs, true); } function migrateCustomAssets( uint256[] memory landIds, string[] memory customAssetMetadataURIs ) public onlyOwnerOrContributor { _setCustomAssets(landIds, customAssetMetadataURIs, false); } function _setCustomAssets( uint256[] memory landIds, string[] memory customAssetMetadataURIs, bool checkOwner ) public { uint256 total = landIds.length; if (total != customAssetMetadataURIs.length) revert LengthMismatch(); for (uint256 i; i < total; ) { if (checkOwner && ownerOf(landIds[i]) != msg.sender) revert OnlyLandOwner(); unchecked { ++_totalAssets; } uint256 landId = landIds[i]; uint64 newCustomAssetId = uint64(_totalAssets); uint64 oldCustomAssetId = _customAssets[landId]; _addAssetEntry(newCustomAssetId, customAssetMetadataURIs[i]); _addAssetToToken(landId, newCustomAssetId, oldCustomAssetId); _acceptAsset( landId, _pendingAssets[landId].length - 1, newCustomAssetId ); _customAssets[landId] = newCustomAssetId; emit CustomAssetSet( landId, newCustomAssetId, customAssetMetadataURIs[i] ); unchecked { ++i; } } } function getCustomAssetsMetadataURIs( uint256[] memory landIds ) public view returns (string[] memory customAssetMetadataURIs) { uint256 length = landIds.length; customAssetMetadataURIs = new string[](length); for (uint256 i; i < length; ) { if (_customAssets[landIds[i]] != 0) { customAssetMetadataURIs[i] = getAssetMetadata( landIds[i], _customAssets[landIds[i]] ); } unchecked { ++i; } } } function ownersOf( uint256[] memory landIds ) public view returns (address[] memory owners) { uint256 length = landIds.length; owners = new address[](length); for (uint256 i; i < length; ) { owners[i] = ownerOf(landIds[i]); unchecked { ++i; } } } // Methods function tokenURI(uint256 tokenId) public view returns (string memory) { _requireMinted(tokenId); // Since we add an asset on minting, it will always have at least one, no need to check.[] return string( abi.encodePacked(_baseURI, Strings.toString(tokenId), ".json") ); } function updateBaseURI( string memory baseURI ) public onlyOwnerOrContributor { _baseURI = baseURI; } function getUniqueIdForLandData( LandData memory plotdata ) public pure returns (uint256 id) { // Using bit shifting create and id which includes all the data id = (uint256(plotdata.cyber) << 0); id |= (uint256(plotdata.steampunk) << 4); id |= (uint256(plotdata.wind) << 8); id |= (uint256(plotdata.volcano) << 12); id |= (uint256(plotdata.fire) << 16); id |= (uint256(plotdata.water) << 20); id |= (uint256(plotdata.necro) << 24); id |= (uint256(plotdata.mecha) << 28); id |= (uint256(plotdata.dragon) << 32); id |= (uint256(plotdata.meadow) << 36); id |= (uint256(plotdata.rarity) << 40); id |= (uint256(plotdata.entropy) << 44); id |= (plotdata.isShore ? 1 << 46 : 0); id |= (plotdata.isCliff ? 1 << 48 : 0); id |= (plotdata.isIsland ? 1 << 50 : 0); id |= (plotdata.isMountainFoot ? 1 << 52 : 0); return id; } function getAssetIdForLandData( LandData memory plotdata ) public view returns (uint64) { uint256 landDataId = getUniqueIdForLandData(plotdata); return _assetPerLandData[landDataId]; } function getAssetMetadataForLandData( LandData memory plotdata ) public view returns (string memory) { uint64 assetId = getAssetIdForLandData(plotdata); return _assets[assetId]; } function batchAddAssets( LandData[] memory landData, string[] memory metadataURIs ) public onlyOwnerOrContributor { uint256 total = landData.length; if (total != metadataURIs.length) revert LengthMismatch(); for (uint256 i; i < total; ) { unchecked { ++_totalAssets; } uint64 assetId = uint64(_totalAssets); uint256 landDataId = getUniqueIdForLandData(landData[i]); if (_assetPerLandData[landDataId] != 0) revert AssetForLandCharacteristicsAlreadyExists(); _assetPerLandData[landDataId] = assetId; _addAssetEntry(assetId, metadataURIs[i]); unchecked { ++i; } } } function batchMint( uint256[] memory landIds, LandData[] memory landData, address[] memory tos ) public onlyOwnerOrContributor { uint256 total = landIds.length; if (total != tos.length || total != landData.length) revert LengthMismatch(); _totalSupply += total; for (uint256 i; i < total; ) { uint256 landDataId = getUniqueIdForLandData(landData[i]); uint64 assetId = _assetPerLandData[landDataId]; _safeMint(tos[i], landIds[i], ""); _addAssetToToken(landIds[i], assetId, 0); _acceptAsset(landIds[i], 0, assetId); unchecked { ++i; } } } function getAutoAcceptCollection( address collection ) public view returns (bool) { return _autoAcceptCollection[collection]; } function setAutoAcceptCollection( address collection, bool autoAccept ) public virtual onlyOwnerOrContributor { _autoAcceptCollection[collection] = autoAccept; } function _afterAddChild( uint256 tokenId, address childAddress, uint256 childId, bytes memory ) internal override { // Auto accept children if they are from known collections if (_autoAcceptCollection[childAddress]) { _acceptChild( tokenId, _pendingChildren[tokenId].length - 1, childAddress, childId ); } } function _beforeTokenTransfer( address, address to, uint256 ) internal override { if (to == address(0)) { // Burning revert CannotBurnLands(); } } function _afterAddAssetToToken( uint256 tokenId, uint64 assetId, uint64 replacesAssetWithId ) internal virtual override { // Remove auto accept from AbstractEquippable. We handle it here. } function lockSupply() public onlyOwnerOrContributor { _maxSupply = _totalSupply; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) pragma solidity ^0.8.0; import "../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. * * _Available since v4.5._ */ 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 v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../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 v4.8.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: 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 caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @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 v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import "../../RMRK/equippable/RMRKMinifiedEquippable.sol"; import "../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 The total number of assets after this asset has been added */ function addEquippableAssetEntry( uint64 equippableGroupId, address catalogAddress, string memory metadataURI, uint64[] memory partIds ) public virtual onlyOwnerOrContributor returns (uint256) { unchecked { ++_totalAssets; } _addAssetEntry( uint64(_totalAssets), equippableGroupId, catalogAddress, metadataURI, partIds ); return _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 ID of the newly added asset */ function addAssetEntry( string memory metadataURI ) public virtual onlyOwnerOrContributor returns (uint256) { unchecked { ++_totalAssets; } _addAssetEntry(uint64(_totalAssets), metadataURI); return _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 "../../RMRK/access/Ownable.sol"; import "../../RMRK/library/RMRKErrors.sol"; import "../../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 The number of tokens in a collection */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @notice Used to retrieve the maximum supply of the collection. * @return The maximum supply of tokens in the collection */ function maxSupply() public view virtual returns (uint256) { return _maxSupply; } /** * @notice Used to retrieve the total number of assets. * @return The total number of assets */ function totalAssets() public view virtual returns (uint256) { return _totalAssets; } /** * @notice Used to retrieve the metadata of the collection. * @return string The metadata URI of the collection */ function collectionMetadata() public view virtual returns (string memory) { return _collectionMetadata; } /** * @notice Used to retrieve the collection name. * @return Name of the collection */ function name() public view virtual returns (string memory) { return _name; } /** * @notice Used to retrieve the collection symbol. * @return Symbol of the collection */ function symbol() public view virtual returns (string memory) { return _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; import "@openzeppelin/contracts/utils/Context.sol"; import "../library/RMRKErrors.sol"; /** * @title Ownable * @author RMRK team * @notice A minimal ownable smart contractf 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 Address of the current owner */ function owner() public view virtual returns (address) { return _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 Boolean value indicating whether the address is a contributor or not */ function isContributor(address contributor) public view returns (bool) { return _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 "@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 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); /** * @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 The status indicating whether the part with `partId` can be equipped by any address or not */ function checkIsEquippableToAll(uint64 partId) external view returns (bool); /** * @notice Used to retrieve a `Part` with id `partId` * @param partId ID of the part that we are retrieving * @return The `Part` struct associated with given `partId` */ function getPart(uint64 partId) external view returns (Part memory); /** * @notice Used to retrieve multiple parts at the same time. * @param partIds An array of part IDs that we want to retrieve * @return An array of `Part` structs associated with given `partIds` */ function getParts( uint64[] memory partIds ) external view returns (Part[] memory); }
// 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 { /** * @notice Version of the @rmrk-team/evm-contracts package * @return Version identifier of the smart contract */ string public constant VERSION = "2.1.1"; bytes4 public constant RMRK_INTERFACE = 0x524D524B; // "RMRK" in ASCII hex }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.21; import "../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 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); /** * @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 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); /** * @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 The `Equipment` struct containing data about the equipped object */ function getEquipment( uint256 tokenId, address targetCatalogAddress, uint64 slotPartId ) external view returns (Equipment memory); /** * @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 "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/Context.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "../catalog/IRMRKCatalog.sol"; import "../core/RMRKCore.sol"; import "../equippable/IERC6220.sol"; import "../library/RMRKErrors.sol"; import "../library/RMRKLib.sol"; import "../nestable/IERC7401.sol"; import "../security/ReentrancyGuard.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[]; using Address for address; 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) private 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) private 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 The balance of the given account */ function balanceOf(address owner) public view virtual returns (uint256) { if (owner == address(0)) revert ERC721AddressZeroIsNotaValidOwner(); return _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(0)) revert ERC721TransferToTheZeroAddress(); if (to == address(this) && tokenId == destinationId) revert RMRKNestableTransferToSelf(); // Destination contract checks: // It seems redundant, but otherwise it would revert with no error if (!to.isContract()) revert RMRKIsNotContract(); if (!IERC165(to).supportsInterface(type(IERC7401).interfaceId)) revert RMRKNestableTransferToNonRMRKNestableImplementer(); _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 { // It seems redundant, but otherwise it would revert with no error if (!to.isContract()) revert RMRKIsNotContract(); if (!IERC165(to).supportsInterface(type(IERC7401).interfaceId)) revert RMRKMintToNonRMRKNestableImplementer(); _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) { (address owner, uint256 ownerTokenId, bool isNft) = directOwnerOf( tokenId ); if (isNft) { owner = IERC7401(owner).ownerOf(ownerTokenId); } return owner; } /** * @inheritdoc IERC7401 */ function directOwnerOf( uint256 tokenId ) public view virtual returns (address, uint256, bool) { DirectOwner memory owner = _RMRKOwners[tokenId]; if (owner.ownerAddress == address(0)) revert ERC721InvalidTokenId(); return (owner.ownerAddress, owner.tokenId, 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) { (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 totalChildBurns; uint256 length = children.length; //gas savings for (uint256 i; i < length; ) { if (totalChildBurns >= 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 - totalChildBurns; } // 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. totalChildBurns += 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, "" ); return totalChildBurns; } //////////////////////////////////////// // 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 Address of the account approved to manage the token */ function getApproved( uint256 tokenId ) public view virtual returns (address) { _requireMinted(tokenId); return _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 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) { return _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 A boolean value signifying whether the token exists */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _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 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) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received( _msgSender(), from, tokenId, data ) returns (bytes4 retval) { return 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 { return true; } } //////////////////////////////////////// // CHILD MANAGEMENT PUBLIC //////////////////////////////////////// /** * @inheritdoc IERC7401 */ function addChild( uint256 parentId, uint256 childId, bytes memory data ) public virtual { _requireMinted(parentId); address childAddress = _msgSender(); if (!childAddress.isContract()) 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) { Child[] memory children = _activeChildren[parentId]; return children; } /** * @inheritdoc IERC7401 */ function pendingChildrenOf( uint256 parentId ) public view virtual returns (Child[] memory) { Child[] memory pendingChildren = _pendingChildren[parentId]; return pendingChildren; } /** * @inheritdoc IERC7401 */ function childOf( uint256 parentId, uint256 index ) public view virtual returns (Child memory) { if (childrenOf(parentId).length <= index) revert RMRKChildIndexOutOfRange(); Child memory child = _activeChildren[parentId][index]; return child; } /** * @inheritdoc IERC7401 */ function pendingChildOf( uint256 parentId, uint256 index ) public view virtual returns (Child memory) { if (pendingChildrenOf(parentId).length <= index) revert RMRKPendingChildIndexOutOfRange(); Child memory child = _pendingChildren[parentId][index]; return child; } // 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) { if (!_tokenAssets[tokenId][assetId]) revert RMRKTokenDoesNotHaveAsset(); return _assets[assetId]; } /** * @inheritdoc IERC5773 */ function getActiveAssets( uint256 tokenId ) public view virtual returns (uint64[] memory) { return _activeAssets[tokenId]; } /** * @inheritdoc IERC5773 */ function getPendingAssets( uint256 tokenId ) public view virtual returns (uint64[] memory) { return _pendingAssets[tokenId]; } /** * @inheritdoc IERC5773 */ function getActiveAssetPriorities( uint256 tokenId ) public view virtual returns (uint64[] memory) { return _activeAssetPriorities[tokenId]; } /** * @inheritdoc IERC5773 */ function getAssetReplacements( uint256 tokenId, uint64 newAssetId ) public view virtual returns (uint64) { return _assetReplacements[tokenId][newAssetId]; } /** * @inheritdoc IERC5773 */ function isApprovedForAllForAssets( address owner, address operator ) public view virtual returns (bool) { return _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) private 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 Address of the account that is approved to manage the token */ function getApprovedForAssets( uint256 tokenId ) public view virtual returns (address) { _requireMinted(tokenId); return _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) { return _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) { uint64 equippableGroupId = _equippableGroupIds[assetId]; uint64 equippableSlot = _validParentSlots[equippableGroupId][parent]; if (equippableSlot == slotId) { (, bool found) = getActiveAssets(tokenId).indexOf(assetId); return found; } return false; } // --------------------- Getting Extended Assets --------------------- /** * @inheritdoc IERC6220 */ function getAssetAndEquippableData( uint256 tokenId, uint64 assetId ) public view virtual returns (string memory, uint64, address, uint64[] memory) { return ( getAssetMetadata(tokenId, assetId), _equippableGroupIds[assetId], _catalogAddresses[assetId], _partIds[assetId] ); } //////////////////////////////////////// // UTILS //////////////////////////////////////// /** * @inheritdoc IERC6220 */ function getEquipment( uint256 tokenId, address targetCatalogAddress, uint64 slotPartId ) public view virtual returns (Equipment memory) { return _equipments[tokenId][targetCatalogAddress][slotPartId]; } // 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 "@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 Address of the recipient of royalties */ function getRoyaltyRecipient() public view virtual returns (address) { return _royaltyRecipient; } /** * @notice Used to retrieve the specified royalty percentage. * @return The royalty percentage expressed in the basis points */ function getRoyaltyPercentage() public view virtual returns (uint256) { return _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) { 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 get approvals for a token owned by 0x0 (considered non-existent) error ERC721ApprovedQueryForNonexistentToken(); /// 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 pass collaborator address array and collaborator permission array of different lengths error RMRKCollaboratorArraysNotEqualLength(); /// Attempting to register a collection that is already registered error RMRKCollectionAlreadyRegistered(); /// Attempting to manage or interact with colleciton that is not registered error RMRKCollectionNotRegistered(); /// Attempting to equip a `Part` with a child not approved by the Catalog error RMRKEquippableEquipNotAllowedByCatalog(); /// Attempting to pass an epired ECDSA deadline error RMRKExpiredDeadline(); /// 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 use and invalid ECDSA signature error RMRKInvalidSignature(); /// 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 a nested token to a smart contract that doesn't support nesting error RMRKMintToNonRMRKNestableImplementer(); /// 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 manage a collection without being the collection's collaborator error RMRKNotCollectionCollaborator(); /// Attemting to manage a collection without being the collection's issuer error RMRKNotCollectionIssuer(); /// Attempting to manage a collection without being the collection's issuer or collaborator error RMRKNotCollectionIssuerOrCollaborator(); /// 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 manage a collection without being the specific address error RMRKNotSpecificAddress(); /// Attempting to manage a token without being its owner error RMRKNotTokenOwner(); /// Attempting to transfer the ownership to the 0x0 address error RMRKNewOwnerIsZeroAddress(); /// Attempting to assign a 0x0 address as a contributor error RMRKNewContributorIsZeroAddress(); /// Attemtping to use `Ownable` interface without implementing it error RMRKOwnableNotImplemented(); /// 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();
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.21; /** * @title RMRKLib * @author RMRK team * @notice RMRK library smart contract. */ library RMRKLib { /** * @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 require(index < array.length); 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 "@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 An array of active asset IDs of the given token */ function getActiveAssets( uint256 tokenId ) external view returns (uint64[] memory); /** * @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 An array of pending asset IDs of the given token */ function getPendingAssets( uint256 tokenId ) external view returns (uint64[] memory); /** * @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 An array of priorities of the active assets of the given token */ function getActiveAssetPriorities( uint256 tokenId ) external view returns (uint64[] memory); /** * @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 ID of the asset which will be replaced */ function getAssetReplacements( uint256 tokenId, uint64 newAssetId ) external view returns (uint64); /** * @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 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); // 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 Address of the account that is approved to manage the specified token's assets */ function getApprovedForAssets( uint256 tokenId ) external view returns (address); /** * @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 A boolean value indicating wehter the account we are checking has been granted the operator role */ function isApprovedForAllForAssets( address owner, address operator ) external view returns (bool); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.21; import "@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 wil 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 Address of the given token's owner * @return The ID of the parent token. Should be `0` if the owner is an externally owned account * @return The boolean value signifying whether the owner is an NFT or not */ function directOwnerOf( uint256 tokenId ) external view returns (address, uint256, bool); /** * @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 Number of recursively burned children */ function burn( uint256 tokenId, uint256 maxRecursiveBurns ) external returns (uint256); /** * @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 An array of Child structs containing the parent token's active child tokens */ function childrenOf( uint256 parentId ) external view returns (Child[] memory); /** * @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 An array of Child structs containing the parent token's pending child tokens */ function pendingChildrenOf( uint256 parentId ) external view returns (Child[] memory); /** * @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 A Child struct containing data about the specified child */ function childOf( uint256 parentId, uint256 index ) external view returns (Child memory); /** * @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 A Child struct containting data about the specified child */ function pendingChildOf( uint256 parentId, uint256 index ) external view returns (Child memory); /** * @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": 30 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"string","name":"baseURI","type":"string"},{"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":"AssetForLandCharacteristicsAlreadyExists","type":"error"},{"inputs":[],"name":"CannotBurnLands","type":"error"},{"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":"LengthMismatch","type":"error"},{"inputs":[],"name":"OnlyLandManager","type":"error"},{"inputs":[],"name":"OnlyLandOwner","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":"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":"uint256","name":"landId","type":"uint256"},{"indexed":false,"internalType":"uint64","name":"assetId","type":"uint64"},{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"CustomAssetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"landId","type":"uint256"}],"name":"LandClaimed","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":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"string[]","name":"customAssetMetadataURIs","type":"string[]"},{"internalType":"bool","name":"checkOwner","type":"bool"}],"name":"_setCustomAssets","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":"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":"","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":"","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":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum SkyBreachLands.LandMass","name":"cyber","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"steampunk","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"wind","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"volcano","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"fire","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"water","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"necro","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"mecha","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"dragon","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"meadow","type":"uint8"},{"internalType":"enum SkyBreachLands.Rarity","name":"rarity","type":"uint8"},{"internalType":"enum SkyBreachLands.Entropy","name":"entropy","type":"uint8"},{"internalType":"bool","name":"isShore","type":"bool"},{"internalType":"bool","name":"isCliff","type":"bool"},{"internalType":"bool","name":"isIsland","type":"bool"},{"internalType":"bool","name":"isMountainFoot","type":"bool"}],"internalType":"struct SkyBreachLands.LandData[]","name":"landData","type":"tuple[]"},{"internalType":"string[]","name":"metadataURIs","type":"string[]"}],"name":"batchAddAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"components":[{"internalType":"enum SkyBreachLands.LandMass","name":"cyber","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"steampunk","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"wind","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"volcano","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"fire","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"water","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"necro","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"mecha","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"dragon","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"meadow","type":"uint8"},{"internalType":"enum SkyBreachLands.Rarity","name":"rarity","type":"uint8"},{"internalType":"enum SkyBreachLands.Entropy","name":"entropy","type":"uint8"},{"internalType":"bool","name":"isShore","type":"bool"},{"internalType":"bool","name":"isCliff","type":"bool"},{"internalType":"bool","name":"isIsland","type":"bool"},{"internalType":"bool","name":"isMountainFoot","type":"bool"}],"internalType":"struct SkyBreachLands.LandData[]","name":"landData","type":"tuple[]"},{"internalType":"address[]","name":"tos","type":"address[]"}],"name":"batchMint","outputs":[],"stateMutability":"nonpayable","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":"","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":"","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":"","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":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectionMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"directOwnerOf","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","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":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getActiveAssets","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApprovedForAssets","outputs":[{"internalType":"address","name":"","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":"","type":"string"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum SkyBreachLands.LandMass","name":"cyber","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"steampunk","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"wind","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"volcano","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"fire","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"water","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"necro","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"mecha","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"dragon","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"meadow","type":"uint8"},{"internalType":"enum SkyBreachLands.Rarity","name":"rarity","type":"uint8"},{"internalType":"enum SkyBreachLands.Entropy","name":"entropy","type":"uint8"},{"internalType":"bool","name":"isShore","type":"bool"},{"internalType":"bool","name":"isCliff","type":"bool"},{"internalType":"bool","name":"isIsland","type":"bool"},{"internalType":"bool","name":"isMountainFoot","type":"bool"}],"internalType":"struct SkyBreachLands.LandData","name":"plotdata","type":"tuple"}],"name":"getAssetIdForLandData","outputs":[{"internalType":"uint64","name":"","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":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum SkyBreachLands.LandMass","name":"cyber","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"steampunk","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"wind","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"volcano","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"fire","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"water","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"necro","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"mecha","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"dragon","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"meadow","type":"uint8"},{"internalType":"enum SkyBreachLands.Rarity","name":"rarity","type":"uint8"},{"internalType":"enum SkyBreachLands.Entropy","name":"entropy","type":"uint8"},{"internalType":"bool","name":"isShore","type":"bool"},{"internalType":"bool","name":"isCliff","type":"bool"},{"internalType":"bool","name":"isIsland","type":"bool"},{"internalType":"bool","name":"isMountainFoot","type":"bool"}],"internalType":"struct SkyBreachLands.LandData","name":"plotdata","type":"tuple"}],"name":"getAssetMetadataForLandData","outputs":[{"internalType":"string","name":"","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":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"getAutoAcceptCollection","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"}],"name":"getCustomAssetsMetadataURIs","outputs":[{"internalType":"string[]","name":"customAssetMetadataURIs","type":"string[]"}],"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":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLandManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getPendingAssets","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRoyaltyRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"enum SkyBreachLands.LandMass","name":"cyber","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"steampunk","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"wind","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"volcano","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"fire","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"water","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"necro","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"mecha","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"dragon","type":"uint8"},{"internalType":"enum SkyBreachLands.LandMass","name":"meadow","type":"uint8"},{"internalType":"enum SkyBreachLands.Rarity","name":"rarity","type":"uint8"},{"internalType":"enum SkyBreachLands.Entropy","name":"entropy","type":"uint8"},{"internalType":"bool","name":"isShore","type":"bool"},{"internalType":"bool","name":"isCliff","type":"bool"},{"internalType":"bool","name":"isIsland","type":"bool"},{"internalType":"bool","name":"isMountainFoot","type":"bool"}],"internalType":"struct SkyBreachLands.LandData","name":"plotdata","type":"tuple"}],"name":"getUniqueIdForLandData","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","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":"","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":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"isContributor","outputs":[{"internalType":"bool","name":"","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":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"string[]","name":"customAssetMetadataURIs","type":"string[]"}],"name":"migrateCustomAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","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":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"}],"name":"ownersOf","outputs":[{"internalType":"address[]","name":"owners","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":"","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":"","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":"address","name":"collection","type":"address"},{"internalType":"bool","name":"autoAccept","type":"bool"}],"name":"setAutoAcceptCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"},{"internalType":"string[]","name":"customAssetMetadataURIs","type":"string[]"}],"name":"setCustomAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"landManager","type":"address"}],"name":"setLandManager","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":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"landIds","type":"uint256[]"}],"name":"takeLands","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","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":"string","name":"baseURI","type":"string"}],"name":"updateBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRoyaltyRecipient","type":"address"}],"name":"updateRoyaltyRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506040516200644738038062006447833981016040819052620000349162000263565b6040518060400160405280601381526020017f536b79627265616368204c616e642044656564000000000000000000000000008152506040518060400160405280600481526020016314d0931160e21b8152508585858561ffff168181620000a2826200012a60201b60201c565b6127108110620000c557604051634006185d60e11b815260040160405180910390fd5b600190815560025550620000d9336200014c565b6006620000e78782620003a5565b506007620000f68682620003a5565b506005620001058582620003a5565b505050600a5550602591506200011e90508682620003a5565b50505050505062000471565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001c657600080fd5b81516001600160401b0380821115620001e357620001e36200019e565b604051601f8301601f19908116603f011681019082821181831017156200020e576200020e6200019e565b816040528381526020925086838588010111156200022b57600080fd5b600091505b838210156200024f578582018301518183018401529082019062000230565b600093810190920192909252949350505050565b600080600080600060a086880312156200027c57600080fd5b85516001600160401b03808211156200029457600080fd5b620002a289838a01620001b4565b96506020880151915080821115620002b957600080fd5b50620002c888828901620001b4565b60408801516060890151919650945090506001600160a01b0381168114620002ef57600080fd5b608087015190925061ffff811681146200030857600080fd5b809150509295509295909350565b600181811c908216806200032b57607f821691505b6020821081036200034c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003a057600081815260208120601f850160051c810160208610156200037b5750805b601f850160051c820191505b818110156200039c5782815560010162000387565b5050505b505050565b81516001600160401b03811115620003c157620003c16200019e565b620003d981620003d2845462000316565b8462000352565b602080601f831160018114620004115760008415620003f85750858301515b600019600386901b1c1916600185901b1785556200039c565b600085815260208120601f198616915b82811015620004425788860151825594840194600190910190840162000421565b5085821015620004615787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b615fc680620004816000396000f3fe608060405234801561001057600080fd5b50600436106103c05760003560e01c806365b67eb9116101f7578063b2a11d1c11610116578063b2a11d1c14610985578063b390c0ab14610998578063b88d4fde146109ab578063bc82fbac146109be578063c259a988146109de578063c87b56dd146109f1578063c89da7a514610a04578063d5abeb0114610a17578063de8e602c14610a1f578063defa80c314610a32578063df6f556b14610a45578063e467a48f14610a7c578063e7de4de414610a8f578063e97ceaa814610aa2578063e985e9c514610ab5578063ee1dffcf14610af1578063f2fde38b14610b04578063fb25fb7a14610b17578063fc3517c814610b51578063ffa1ad7414610b6457600080fd5b806365b67eb9146107665780636f19951c1461077957806370a082311461078c578063715018a61461079f5780637280281e146107a75780637507e2ae146107ba57806379e8ca9e146108a157806381eaf99b146108b45780638507dc28146108bc57806387eb985d146108cf57806389ed2edf146108e25780638d4f3bf5146108ea5780638da5cb5b14610905578063931688cb1461090d57806395d89b411461092057806395edc18c146109285780639796133614610939578063a22cb4651461094c578063a898e3641461095f578063addfc2f51461097257600080fd5b80632f32f937116102e35780632f32f9371461059957806330ffb1d6146105b957806338dcf74c146105cc5780633ce67a4a146105df57806342842e0e146105f257806342966c681461060557806343cf64e71461061857806344ec93441461062b57806348f5f11c1461064b5780634e60edba146106765780634fc060081461069957806351532e5a146106ac57806358f0fcd4146106cc57806359c8b7dd146106df5780635e2e3292146106e75780635e94354a146106fa5780635ea72f361461070d5780635ff2f2e8146107205780636352211e14610740578063635490cc1461075357600080fd5b806301e1d114146103c557806301ffc9a7146103dc578063064c0a3a146103ff57806306fdde0314610414578063074334fb1461042957806307e67e571461043c578063081812fc1461044f578063095ea7b31461046f5780630fc499f51461048257806318160ddd146104955780631c7bb4611461049d5780631d0d35f5146104b0578063217f2bfe146104dc57806322e6d160146104ef57806322f6da9c1461050257806323669b011461051557806323b872dd146105265780632452cd91146105395780632a55205a1461054c5780632d9b34591461056d575b600080fd5b600b545b6040519081526020015b60405180910390f35b6103ef6103ea366004614bd4565b610b88565b60405190151581526020016103d3565b61041261040d366004614ceb565b610bea565b005b61041c610dea565b6040516103d39190614db0565b6103ef610437366004614dda565b610e7c565b61041261044a366004614f36565b610ef5565b61046261045d366004614f99565b610f05565b6040516103d39190614fb2565b61041261047d366004614fc6565b610f4b565b610412610490366004614ff2565b610fd7565b6009546103c9565b6104126104ab36600461500f565b611000565b6103ef6104be366004614ff2565b6001600160a01b031660009081526004602052604090205460011490565b6104126104ea36600461504b565b611013565b6103ef6104fd36600461507f565b6110d0565b6104126105103660046150b8565b6110fe565b6024546001600160a01b0316610462565b6104126105343660046150e4565b611179565b6103c9610547366004615187565b61119e565b61055f61055a36600461520d565b6111cc565b6040516103d392919061522f565b6103ef61057b366004614ff2565b6001600160a01b031660009081526021602052604090205460ff1690565b6105ac6105a736600461520d565b611201565b6040516103d39190615260565b6103c96105c736600461526e565b61128e565b6104126105da3660046152a2565b6112b7565b6104126105ed36600461533c565b61161b565b6104126106003660046150e4565b61164e565b610412610613366004614f99565b611669565b61041c6106263660046154cc565b611674565b61063e610639366004614f99565b61172e565b6040516103d391906154e9565b61065e6106593660046154cc565b6117ad565b6040516001600160401b0390911681526020016103d3565b610689610684366004615536565b6117d8565b6040516103d3949392919061559d565b6104126106a7366004614f36565b6118b5565b6106bf6106ba366004614f99565b6118c9565b6040516103d391906155eb565b6104126106da3660046155fe565b61195d565b6001546103c9565b61041c6106f5366004615536565b611b25565b6106bf610708366004614f99565b611c14565b61041261071b366004614fc6565b611c7d565b61073361072e36600461504b565b611d04565b6040516103d39190615675565b61046261074e366004614f99565b611da6565b6104126107613660046156c2565b611e36565b610412610774366004615711565b611f5e565b61063e610787366004614f99565b611f71565b6103c961079a366004614ff2565b611fe1565b610412612026565b6106bf6107b5366004614f99565b61203a565b6108576107c836600461573f565b6040805160808082018352600080835260208084018290528385018290526060938401829052968152601e87528381206001600160a01b03968716825287528381206001600160401b03958616825287528390208351918201845280548086168352600160401b9004909416958101959095526001830154918501919091526002909101549091169082015290565b6040516103d3919081516001600160401b03908116825260208084015190911690820152604080830151908201526060918201516001600160a01b03169181019190915260800190565b6104126108af36600461533c565b6120a3565b610412612160565b6104126108ca36600461533c565b612170565b6104126108dd3660046157cb565b612206565b61041c6122f6565b6108f863524d524b60e01b81565b6040516103d39190615801565b610462612305565b61041261091b36600461526e565b612314565b61041c612328565b6000546001600160a01b0316610462565b61041261094736600461520d565b612337565b61041261095a36600461533c565b6123b7565b6105ac61096d36600461520d565b612445565b610412610980366004615816565b612496565b6103c96109933660046154cc565b6125cb565b6103c96109a636600461520d565b6127c7565b6104126109b93660046158fc565b612b24565b6109d16109cc36600461504b565b612b63565b6040516103d3919061595b565b6104126109ec36600461500f565b612c82565b61041c6109ff366004614f99565b612e28565b610412610a12366004614ff2565b612e65565b600a546103c9565b610412610a2d3660046159bd565b612e8f565b610412610a403660046159f9565b612f19565b61065e610a53366004615536565b60009182526014602090815260408084206001600160401b039384168552909152909120541690565b610462610a8a366004614f99565b613128565b610412610a9d36600461520d565b61314b565b610412610ab0366004615a94565b61324c565b6103ef610ac336600461507f565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205460ff1690565b6103ef610aff366004615ad3565b613262565b610412610b12366004614ff2565b613293565b610b2a610b25366004614f99565b6132cb565b604080516001600160a01b03909416845260208401929092521515908201526060016103d3565b610412610b5f3660046150b8565b613333565b61041c60405180604001604052806005815260200164322e312e3160d81b81525081565b6000610b9382613348565b80610bae57506001600160e01b0319821663152a902d60e11b145b80610bc957506001600160e01b03198216635b5e139f60e01b145b80610be457506001600160e01b0319821663524d524b60e01b145b92915050565b82610bf4816133cf565b600080610c00866132cb565b5091509150876001600160a01b0316826001600160a01b031614610c375760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038716610c5e576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b03871630148015610c7557508486145b15610c9357604051633d76b10760e01b815260040160405180910390fd5b610ca5876001600160a01b0316613457565b610cc25760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a790610cf5906342b0e56f60e01b90600401615801565b602060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190615afa565b610d5357604051631784ec7360e21b815260040160405180910390fd5b610d5e868887613466565b610d69888888613557565b6001600160a01b0388166000908152600c60205260408120805460019290610d92908490615b2d565b90915550610da3905086868961357e565b6001600160a01b0387166000908152600c60205260408120805460019290610dcc908490615b40565b90915550610de09050828883888a896135df565b5050505050505050565b606060068054610df990615b53565b80601f0160208091040260200160405190810160405280929190818152602001828054610e2590615b53565b8015610e725780601f10610e4757610100808354040283529160200191610e72565b820191906000526020600020905b815481529060010190602001808311610e5557829003601f168201915b5050505050905090565b6001600160401b038083166000908152601c602090815260408083205484168084528280528184206001600160a01b038a1685529092528220549192909181169084168103610ee6576000610eda86610ed48961203a565b906136c0565b9450610eed9350505050565b6000925050505b949350505050565b610f018282600161195d565b5050565b6000610f1082613729565b6000828152600d6020526040812090610f2884611da6565b6001600160a01b0390811682526020820192909252604001600020541692915050565b6000610f5682611da6565b9050806001600160a01b0316836001600160a01b031603610f8a57604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b03821614801590610faa5750610fa88133610ac3565b155b15610fc857604051634c12315960e11b815260040160405180910390fd5b610fd2838361374f565b505050565b610fdf6137c8565b600080546001600160a01b0319166001600160a01b03831617905550565b50565b6110086137f8565b610fd283838361383c565b6024546001600160a01b0316331461103e57604051631cbb33dd60e31b815260040160405180910390fd5b60005b8151811015610f0157600082828151811061105e5761105e615b8d565b6020026020010151905061109961107482611da6565b6024546040805160208101909152600081526001600160a01b03909116908490613a31565b60405160019092019181907fbe5015635c34cbee4ad5d6b34f0bc4757e44efcb9ab330114167d493badcc00290600090a250611041565b6001600160a01b03918216600090815260196020908152604080832093909416825291909152205460ff1690565b8261110881613b76565b611113848484613bd7565b61111e848484613c7f565b60008481526018602090815260408083206001600160401b0386168085529252808320805460ff1916905551909186917f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb1249190a35b50505050565b80611183816133cf565b61117384848460405180602001604052806000815250613a31565b60006111a86137f8565b600b8054600101908190556111c09086868686613ccc565b50600b54949350505050565b600080546001546001600160a01b039091169190612710906111ee9085615ba3565b6111f89190615bba565b90509250929050565b611209614a6d565b8161121384611f71565b51116112325760405163653e642560e11b815260040160405180910390fd5b600083815260106020526040812080548490811061125257611252615b8d565b60009182526020918290206040805180820190915260029092020180548252600101546001600160a01b03169181019190915291505092915050565b60006112986137f8565b600b8054600101908190556112ad9083613d72565b50600b545b919050565b80516112c281613b76565b6112ca613e38565b6040808301516001600160401b039081166000908152601b602090815283822054606087015187518452601e83528584206001600160a01b0392831680865290845286852095821685529490925293909120600201549192909116156113435760405163bd0650ab60e01b815260040160405180910390fd5b611351846040015182613e60565b600061136585600001518660200151611201565b60208101518151608088015160405163074334fb60e01b815230600482015260248101929092526001600160401b039081166044830152851660648201529192506001600160a01b03169063074334fb90608401602060405180830381865afa1580156113d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fa9190615afa565b61141757604051632c36cd3360e01b815260040160405180910390fd5b6020810151604051636e5bceab60e11b81526001600160401b03841660048201526001600160a01b0391821660248201529084169063dcb79d5690604401602060405180830381865afa158015611472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114969190615afa565b6114b357604051637228eff560e11b815260040160405180910390fd5b6040805160808082018352878301516001600160401b0390811683529088015181166020808401918252855184860190815286820180516001600160a01b03908116606088019081528d516000908152601e86528981208d8416825286528981208c8916825286528981208951815498518a16600160401b026001600160801b031990991699169890981796909617875592516001808801919091559251600290960180549682166001600160a01b0319909716969096179095558b518452601f8352868420905190941683529281528482208651835290529283208054929391929091906115a3908490615b40565b92505081905550826001600160401b031686604001516001600160401b031687600001517f1f5de02b1d9c93ca468f54630e1daf13f6dc458a63f8061ff73e85bf9bc38884856000015186602001518b6080015160405161160693929190615bdc565b60405180910390a45050600160025550505050565b6116236137f8565b6001600160a01b03919091166000908152602160205260409020805460ff1916911515919091179055565b610fd283838360405180602001604052806000815250612b24565b610f018160006127c7565b60606000611681836117ad565b6001600160401b03811660009081526013602052604090208054919250906116a890615b53565b80601f01602080910402602001604051908101604052809291908181526020018280546116d490615b53565b80156117215780601f106116f657610100808354040283529160200191611721565b820191906000526020600020905b81548152906001019060200180831161170457829003601f168201915b5050505050915050919050565b6000818152601160209081526040808320805482518185028101850190935280835260609493849084015b828210156117a15760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611759565b50929695505050505050565b6000806117b9836125cb565b6000908152602360205260409020546001600160401b03169392505050565b606060008060606117e98686611b25565b6001600160401b038087166000908152601c6020908152604080832054601b835281842054601d845293829020805483518186028101860190945280845291909516946001600160a01b03909416939283919083018282801561189d57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161185a5790505b50505050509050935093509350935092959194509250565b6118bd6137f8565b610f018282600061195d565b60008181526016602090815260409182902080548351818402810184019094528084526060939283018282801561195157602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161190e5790505b50505050509050919050565b825182518114611983576040516001621398b960e31b0319815260040160405180910390fd5b60005b81811015611b1e578280156119ce5750336001600160a01b03166119c28683815181106119b5576119b5615b8d565b6020026020010151611da6565b6001600160a01b031614155b156119ec57604051630ea1efa960e11b815260040160405180910390fd5b600b805460010190558451600090869083908110611a0c57611a0c615b8d565b602090810291909101810151600b546000828152602290935260409092205487519193506001600160401b031690611a5f908390899087908110611a5257611a52615b8d565b6020026020010151613d72565b611a6a83838361383c565b600083815260166020526040902054611a91908490611a8b90600190615b2d565b84613f2a565b600083815260226020526040902080546001600160401b0319166001600160401b038416179055865183907f5420f4b2cf82228035982e5a0811d6cb888647331d194482f54744f4471637119084908a9088908110611af257611af2615b8d565b6020026020010151604051611b08929190615c04565b60405180910390a2836001019350505050611986565b5050505050565b60008281526018602090815260408083206001600160401b038516845290915290205460609060ff16611b6b57604051631b9928fd60e31b815260040160405180910390fd5b6001600160401b03821660009081526013602052604090208054611b8e90615b53565b80601f0160208091040260200160405190810160405280929190818152602001828054611bba90615b53565b8015611c075780601f10611bdc57610100808354040283529160200191611c07565b820191906000526020600020905b815481529060010190602001808311611bea57829003601f168201915b5050505050905092915050565b60008181526017602090815260409182902080548351818402810184019094528084526060939283018282801561195157600091825260209182902080546001600160401b0316845290820283019290916008910180841161190e575094979650505050505050565b6000611c8882611da6565b9050806001600160a01b0316836001600160a01b031603611cbc576040516375f45abd60e01b815260040160405180910390fd5b336001600160a01b03821614801590611cdc5750611cda81336110d0565b155b15611cfa576040516357a2e94960e11b815260040160405180910390fd5b610fd28383614140565b8051606090806001600160401b03811115611d2157611d21614c0d565b604051908082528060200260200182016040528015611d4a578160200160208202803683370190505b50915060005b81811015611d9f57611d6d8482815181106119b5576119b5615b8d565b838281518110611d7f57611d7f615b8d565b6001600160a01b0390921660209283029190910190910152600101611d50565b5050919050565b600080600080611db5856132cb565b9250925092508015611e2d576040516331a9108f60e11b8152600481018390526001600160a01b03841690636352211e90602401602060405180830381865afa158015611e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2a9190615c26565b92505b50909392505050565b611e3f83613729565b33611e4981613457565b611e665760405163b9d3114760e01b815260040160405180910390fd5b604080518082019091528381526001600160a01b03821660208201526000611e8d8661172e565b5190506080811015611eec576000868152601160209081526040822080546001808201835591845292829020855160029094020192835590840151910180546001600160a01b0319166001600160a01b03909216919091179055611f05565b60405163a53c8c0560e01b815260040160405180910390fd5b84836001600160a01b0316877fe65085e689b77b126ba0bac3b079aa8288f19f4d5445af11c76003f8ab3075dd84604051611f4291815260200190565b60405180910390a4611f56868487876141b9565b505050505050565b611f666137f8565b610fd2838383614202565b60008181526010602090815260408083208054825181850281018501909352808352606094938490840182156117a15760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611759565b60006001600160a01b03821661200a57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b03166000908152600c602052604090205490565b61202e6137c8565b61203860006142b9565b565b60008181526015602090815260409182902080548351818402810184019094528084526060939283018282801561195157600091825260209182902080546001600160401b0316845290820283019290916008910180841161190e575094979650505050505050565b6120ab6137c8565b6001600160a01b0382166120d25760405163016b812760e71b815260040160405180910390fd5b806120f7576001600160a01b0382166000908152600460205260408120819055612116565b6001600160a01b03821660009081526004602052604090206001908190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051612154911515815260200190565b60405180910390a25050565b6121686137f8565b600954600a55565b6001600160a01b0382163303612199576040516375f45abd60e01b815260040160405180910390fd5b3360008181526019602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f0cff4fcf777050010027190b8061fd8bfd1de16d81b1f94e9752df1427a2623591015b60405180910390a35050565b61220e6137f8565b815181518114612234576040516001621398b960e31b0319815260040160405180910390fd5b60005b8181101561117357600b80546001019081905584516000906122729087908590811061226557612265615b8d565b60200260200101516125cb565b6000818152602360205260409020549091506001600160401b0316156122ab5760405163050b37b960e51b815260040160405180910390fd5b600081815260236020526040902080546001600160401b0319166001600160401b03841617905584516122ec908390879086908110611a5257611a52615b8d565b5050600101612237565b606060058054610df990615b53565b6003546001600160a01b031690565b61231c6137f8565b6025610f018282615c89565b606060078054610df990615b53565b816123418161430b565b60008381526011602052604090205482101561237057604051631e73178b60e11b815260040160405180910390fd5b600083815260116020526040812061238791614a84565b60405183907f8ac4a0d65950c3e40448afb2260e2e0ec36ea15644d9b39e37e85472e5f9445190600090a2505050565b6001600160a01b03821633036123e057604051630b7b99b960e21b815260040160405180910390fd5b336000818152600e602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191016121fa565b61244d614a6d565b816124578461172e565b51116124765760405163da22687f60e01b815260040160405180910390fd5b600083815260116020526040812080548490811061125257611252615b8d565b61249e6137f8565b82518151811415806124b1575082518114155b156124d2576040516001621398b960e31b0319815260040160405180910390fd5b80600960008282546124e49190615b40565b90915550600090505b81811015611b1e57600061250c85838151811061226557612265615b8d565b60008181526023602052604090205485519192506001600160401b0316906125779086908590811061254057612540615b8d565b602002602001015188858151811061255a5761255a615b8d565b60200260200101516040518060200160405280600081525061436c565b61259c87848151811061258c5761258c615b8d565b602002602001015182600061383c565b6125c18784815181106125b1576125b1615b8d565b6020026020010151600083613f2a565b50506001016124ed565b600080826000015160048111156125e4576125e4615d48565b901b905060048260200151600481111561260057612600615d48565b901b8117905060088260400151600481111561261e5761261e615d48565b901b81179050600c8260600151600481111561263c5761263c615d48565b901b8117905060108260800151600481111561265a5761265a615d48565b901b8117905060148260a00151600481111561267857612678615d48565b901b8117905060188260c00151600481111561269657612696615d48565b901b81179050601c8260e0015160048111156126b4576126b4615d48565b901b81179050602082610100015160048111156126d3576126d3615d48565b901b81179050602482610120015160048111156126f2576126f2615d48565b901b811790506028826101400151600581111561271157612711615d48565b901b81179050602c826101600151600681111561273057612730615d48565b901b8117905081610180015161274757600061274d565b6001602e1b5b65ffffffffffff1681179050816101a0015161276a576000612770565b600160301b5b66ffffffffffffff1681179050816101c0015161278e576000612794565b600160321b5b66ffffffffffffff1681179050816101e001516127b25760006127b8565b600160341b5b66ffffffffffffff1617919050565b6000826127d3816133cf565b6000806127df866132cb565b509150915060006127ef87611da6565b90506127fd83600089613557565b6040805160208101909152600090526001600160a01b0383166000908152600c60205260408120805460019290612835908490615b2d565b90915550612846905060008861374f565b612851600088614140565b600061285c88611f71565b60008981526010602052604081209192506128779190614a84565b600088815260116020526040812061288e91614a84565b6000888152600d602090815260408083206001600160a01b0386168452909152812080546001600160a01b031916905581518190815b81811015612a89578a8310612933578481815181106128e5576128e5615b8d565b60200260200101516020015185828151811061290357612903615b8d565b6020026020010151600001516040516306177b2560e41b815260040161292a92919061522f565b60405180910390fd5b6012600086838151811061294957612949615b8d565b6020026020010151602001516001600160a01b03166001600160a01b03168152602001908152602001600020600086838151811061298957612989615b8d565b602002602001015160000151815260200190815260200160002060009055828b0393508481815181106129be576129be615b8d565b6020026020010151602001516001600160a01b031663b390c0ab8683815181106129ea576129ea615b8d565b602002602001015160000151600187612a039190615b2d565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015612a46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6a9190615d5e565b612a75906001615b40565b612a7f9084615b40565b92506001016128c4565b5060008b8152600f602052604080822082815560010180546001600160a01b0319169055518c91906001600160a01b038a1690600080516020615f71833981519152908390a4604080518781526000602082018190528d9290916001600160a01b038b1691600080516020615f51833981519152910160405180910390a4604080516020810190915260009052509998505050505050505050565b81612b2e816133cf565b612b3a85858585613a31565b612b46858585856143ff565b611b1e5760405163bcb5663760e01b815260040160405180910390fd5b8051606090806001600160401b03811115612b8057612b80614c0d565b604051908082528060200260200182016040528015612bb357816020015b6060815260200190600190039081612b9e5790505b50915060005b81811015611d9f5760226000858381518110612bd757612bd7615b8d565b6020908102919091018101518252810191909152604001600020546001600160401b031615612c7a57612c5c848281518110612c1557612c15615b8d565b602002602001015160226000878581518110612c3357612c33615b8d565b6020908102919091018101518252810191909152604001600020546001600160401b0316611b25565b838281518110612c6e57612c6e615b8d565b60200260200101819052505b600101612bb9565b82612c8c81613b76565b6001600160401b038084166000908152601b6020908152604080832054888452601e83528184206001600160a01b039182168086529084528285208887168652845293829020825160808101845281548088168252600160401b9004909616938601939093526001830154918501919091526002909101541660608301819052909190612d2c576040516317de7dd760e21b815260040160405180910390fd5b6000868152601e602090815260408083206001600160a01b0380871685529083528184206001600160401b0389168552835281842080546001600160801b03191681556001808201869055600290910180546001600160a01b03191690558a8552601f8452828520606087015190921685529083528184208583015185529092528220805491929091612dc0908490615b2d565b92505081905550836001600160401b0316856001600160401b0316877f438e039ebbba8f290f3b5d41aaf3295eccc9b5e6b0e1d52ace700772afb7da13846040015185606001518660200151604051612e1b93929190615bdc565b60405180910390a4611f56565b6060612e3382613729565b6025612e3e83614502565b604051602001612e4f929190615d77565b6040516020818303038152906040529050919050565b612e6d6137c8565b602480546001600160a01b0319166001600160a01b0392909216919091179055565b81612e9981613b76565b81516000848152601560205260409020548114612ec957604051633581be1d60e11b815260040160405180910390fd5b60008481526017602090815260409091208451612ee892860190614aa5565b5060405184907ff0bfd70b0068f973d58178846ca67112671ec45e060838f7de5662036bcf801790600090a2611173565b87612f238161430b565b612f2b614a6d565b8315612f4257612f3b8a88612445565b9050612f78565b612f4d8a8787613262565b15612f6b57604051630619dc9d60e21b815260040160405180910390fd5b612f758a88611201565b90505b612f83818787614594565b8315612fa65760008a8152601160205260409020612fa190886145d8565b612fe0565b6001600160a01b038616600090815260126020908152604080832088845282528083208390558c835260109091529020612fe090886145d8565b6001600160a01b038916156130ca578761305d57604051635c46a7ef60e11b81526001600160a01b0387169063b88d4fde906130269030908d908a908990600401615e0e565b600060405180830381600087803b15801561304057600080fd5b505af1158015613054573d6000803e3d6000fd5b505050506130ca565b60208101518151604051630326051d60e11b81526001600160a01b039092169163064c0a3a916130979130918e918e908a90600401615e4b565b600060405180830381600087803b1580156130b157600080fd5b505af11580156130c5573d6000803e3d6000fd5b505050505b6040805188815285151560208201526001600160a01b038b81161582840152915187928916918d917f02d6d6dbcb604d5e1e8c7886456e82a9cdce88b0a580071358f206b5a4d58f709181900360600190a450505050505050505050565b600061313382613729565b6000828152601a6020526040812090610f2884611da6565b8161315581613b76565b6000838152601660205260409020548281111561318557604051635134ce8960e01b815260040160405180910390fd5b60005b818110156132025760008581526016602052604081208054839081106131b0576131b0615b8d565b6000918252602080832060048304015489845260148252604080852060039094166008026101000a9091046001600160401b03168452919052902080546001600160401b031916905550600101613188565b50600084815260166020526040812061321a91614b5d565b60405160009085907f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb124908390a3611173565b836132568161430b565b611b1e85858585614692565b6000928352601f602090815260408085206001600160a01b0394909416855292815282842091845252902054151590565b61329b6137c8565b6001600160a01b0381166132c257604051634ece6ecf60e01b815260040160405180910390fd5b610ffd816142b9565b6000818152600f60209081526040808320815180830190925280548252600101546001600160a01b0316918101829052829182919061331d5760405163089ba7e160e41b815260040160405180910390fd5b6020810151905190959094508415159350915050565b8261333d81613b76565b611173848484613f2a565b60006001600160e01b031982166301ffc9a760e01b148061337957506001600160e01b031982166380ac58cd60e01b145b8061339457506001600160e01b031982166342b0e56f60e01b145b806133af57506001600160e01b0319821663035a194d60e11b145b80610be457506001600160e01b03198216630a2f26b960e21b1492915050565b6000806133db836132cb565b5091509150806000141580156133fa5750336001600160a01b03831614155b806134395750336001600160a01b038316148061341c575061341c8233610ac3565b8061343757503361342c84610f05565b6001600160a01b0316145b155b15610fd2576040516345f3c98360e11b815260040160405180910390fd5b6001600160a01b03163b151590565b60005b606481101561353d576000806000856001600160a01b031663fb25fb7a866040518263ffffffff1660e01b81526004016134a591815260200190565b606060405180830381865afa1580156134c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e69190615e85565b925092509250806134fa5750505050505050565b6001600160a01b0383163014801561351157508682145b1561352f576040516324543e6d60e11b815260040160405180910390fd5b509093509150600101613469565b50604051630349a6bd60e51b815260040160405180910390fd5b6001600160a01b038216610fd2576040516303c24bc160e11b815260040160405180910390fd5b6040805180820182528381526001600160a01b0383811660208084019182526000888152600f9091529384209251835551600190920180546001600160a01b031916929091169190911790556135d4908461374f565b610fd2600084614140565b6040516318d5243360e21b815285906001600160a01b0382169063635490cc9061361190879087908790600401615ebd565b600060405180830381600087803b15801561362b57600080fd5b505af115801561363f573d6000803e3d6000fd5b5050505082866001600160a01b0316886001600160a01b0316600080516020615f7183398151915260405160405180910390a482866001600160a01b0316886001600160a01b0316600080516020615f5183398151915288886040516136af929190918252602082015260400190565b60405180910390a450505050505050565b81516000908190815b8181101561371857846001600160401b03168682815181106136ed576136ed615b8d565b60200260200101516001600160401b031603613710579250600191506137229050565b6001016136c9565b5060008092509250505b9250929050565b613732816147a0565b610ffd5760405163089ba7e160e41b815260040160405180910390fd5b600061375a82611da6565b6000838152600d602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b336137d1612305565b6001600160a01b03161461203857604051631c62d58f60e11b815260040160405180910390fd5b33613801612305565b6001600160a01b03161415801561381e575061381c336104be565b155b15612038576040516301eca16760e41b815260040160405180910390fd5b60008381526018602090815260408083206001600160401b038616845290915290205460ff1615613880576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b038216600090815260136020526040812080546138a390615b53565b9050036138c357604051632aa5eff960e11b815260040160405180910390fd5b6000838152601660205260409020546080116138f25760405163bade3a7b60e01b815260040160405180910390fd5b60008381526018602090815260408083206001600160401b038681168086529184528285208054600160ff19909116811790915588865260168552928520805493840181558552929093206004820401805460039092166008026101000a80840219909216919093021790915581161561399f5760008381526014602090815260408083206001600160401b038681168552925290912080546001600160401b0319169183169190911790555b6040805160018082528183019092526000916020808301908036833701905050905083816000815181106139d5576139d5615b8d565b602002602001018181525050816001600160401b0316836001600160401b03167f4a85a0221f784dbe75db7c29c422f474c15bde9211a98e50a30018fa8dfa937b83604051613a249190615ee5565b60405180910390a3611173565b600080613a3d846132cb565b5091509150856001600160a01b0316826001600160a01b031614613a745760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038516613a9b576040516338f646ff60e21b815260040160405180910390fd5b613aa6868686613557565b6001600160a01b0386166000908152600c60205260408120805460019290613acf908490615b2d565b90915550613ae190508460008761357e565b6001600160a01b0385166000908152600c60205260408120805460019290613b0a908490615b40565b909155505060405184906001600160a01b038088169190891690600080516020615f7183398151915290600090a483856001600160a01b0316876001600160a01b0316600080516020615f51833981519152846000604051612e1b929190918252602082015260400190565b6000613b8182611da6565b9050336001600160a01b0382161480613b9f5750613b9f81336110d0565b80613bba575033613baf83613128565b6001600160a01b0316145b610f0157604051635d64832960e01b815260040160405180910390fd5b6000838152601660205260409020548210613c0557604051630757d52160e01b815260040160405180910390fd5b6000838152601660205260409020805483908110613c2557613c25615b8d565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03166001600160401b0316816001600160401b031614610fd2576040516378eeeecf60e01b815260040160405180910390fd5b6000838152601660205260409020613c9790836147c0565b60009283526014602090815260408085206001600160401b03909316855291905290912080546001600160401b031916905550565b613cd68583613d72565b6001600160a01b038316158015613ced5750805115155b15613d0b57604051631035ad0760e11b815260040160405180910390fd5b6001600160401b038581166000908152601b6020908152604080832080546001600160a01b0319166001600160a01b038916179055601c825280832080546001600160401b03191694891694909417909355601d81529190208251611f5692840190614aa5565b6001600160401b038216613d99576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b03821660009081526013602052604081208054613dbc90615b53565b90501115613ddd576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152601360205260409020613dff8282615c89565b506040516001600160401b038316907f3cd061096eaf881067d936308fbd8b81d060c45ab2ec910c02b953162befc10990600090a25050565b6002805403613e5a576040516362bfeae960e11b815260040160405180910390fd5b60028055565b6001600160401b0382166000908152601d602090815260408083208054825181850281018501909352808352613f09938693929190830182828015613ef657602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613eb35790505b50505050506136c090919063ffffffff16565b91505080610fd257604051634ef44ed560e01b815260040160405180910390fd5b613f35838383613bd7565b60008381526014602090815260408083206001600160401b03808616855292528220541690808215613fe357613fdd8360156000898152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015613ef657600091825260209182902080546001600160401b03168452908202830192909160089101808411613eb357905050505050506136c090919063ffffffff16565b90925090505b801561406457600086815260156020526040902080548591908490811061400c5761400c615b8d565b600091825260208083206004830401805460039093166008026101000a6001600160401b038181021990941695841602949094179093558882526018835260408083209187168352925220805460ff191690556140ef565b6000868152601760209081526040808320601583529083208054825460018181018555938652848620600480830490910180546001600160401b0394851660086003958616810261010090810a9283029288021990931691909117909255855496870186559488529587209085040180548b84169590921690950290920a9283029202191617905592505b6140fa868686613c7f565b826001600160401b0316846001600160401b0316877f3f2709a99f6c06b4e57bbb38eb0134332f96f51a3da314f41a515adbb28b17cc60405160405180910390a4611f56565b600061414b82611da6565b6000838152601a602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917fb90cc0d925ac3511ab6af2d7ca73ffcf7ec4bd871fff36b958ecf440079c463e9190a4505050565b6001600160a01b03831660009081526021602052604090205460ff1615611173576000848152601160205260409020546111739085906141fb90600190615b2d565b8585614692565b6001600160401b038316158061421f57506001600160401b038116155b1561423d576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b038381166000818152602080805260408083206001600160a01b03881684529091529081902080546001600160401b0319169385169384179055517f5b5af0622001a9b735a56357ddc1abd65e6a640126498674daf9d2fb05160725906142ac908690614fb2565b60405180910390a3505050565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600061431682611da6565b9050336001600160a01b038216148061433457506143348133610ac3565b8061434f57503361434483610f05565b6001600160a01b0316145b610f01576040516302728a9d60e41b815260040160405180910390fd5b61437983836000846148a6565b60405182906001600160a01b03851690600090600080516020615f71833981519152908290a46040805160008082526020820181905284926001600160a01b03871692600080516020615f51833981519152910160405180910390a46143e260008484846143ff565b610fd25760405163bcb5663760e01b815260040160405180910390fd5b6000614413846001600160a01b0316613457565b156144fa57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061444a903390899088908890600401615e0e565b6020604051808303816000875af1925050508015614485575060408051601f3d908101601f1916820190925261448291810190615f1d565b60015b6144e0573d8080156144b3576040519150601f19603f3d011682016040523d82523d6000602084013e6144b8565b606091505b5080516144d85760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610eed565b506001610eed565b6060600061450f83614997565b60010190506000816001600160401b0381111561452e5761452e614c0d565b6040519080825280601f01601f191660200182016040528015614558576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461456257509392505050565b82602001516001600160a01b0316826001600160a01b03161415806145ba575082518114155b15610fd257604051637383f2c160e11b815260040160405180910390fd5b815482906145e890600190615b2d565b815481106145f8576145f8615b8d565b906000526020600020906002020182828154811061461857614618615b8d565b600091825260209091208254600290920201908155600191820154910180546001600160a01b0319166001600160a01b03909216919091179055815482908061466357614663615f3a565b60008281526020812060026000199093019283020190815560010180546001600160a01b031916905590555050565b600061469e8585612445565b90506146ab818484614594565b6001600160a01b0383166000908152601260209081526040808320858452909152902054156146ed5760405163188a497360e01b815260040160405180910390fd5b600085815260116020526040902061470590856145d8565b600085815260106020908152604080832080546001808201835591855283852086516002909202019081558584015190820180546001600160a01b0319166001600160a01b03928316179055871680855260128452828520878652845293829020555186815284929188917f29486b9e2ae569b440933a9b1b421467306fa21f3dcad439c262910a634963a9910160405180910390a4611b1e565b6000908152600f60205260409020600101546001600160a01b0316151590565b815481106147cd57600080fd5b815482906147dd90600190615b2d565b815481106147ed576147ed615b8d565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b031682828154811061482857614828615b8d565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508180548061487157614871615f3a565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a021916905590555050565b6001600160a01b0384166148cd576040516325bd6bd360e01b815260040160405180910390fd5b6148d6836147a0565b156148f45760405163c5a8d37160e01b815260040160405180910390fd5b82614912576040516312c33ce360e01b815260040160405180910390fd5b61491e60008585613557565b6001600160a01b0384166000908152600c60205260408120805460019290614947908490615b40565b90915550506040805180820182529283526001600160a01b0394851660208085019182526000958652600f9052932091518255509051600190910180546001600160a01b03191691909216179055565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106149d65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b8310614a00576904ee2d6d415b85acef8160201b830492506020015b662386f26fc100008310614a1e57662386f26fc10000830492506010015b6305f5e1008310614a36576305f5e100830492506008015b6127108310614a4a57612710830492506004015b60648310614a5c576064830492506002015b600a8310610be45760010192915050565b604080518082019091526000808252602082015290565b5080546000825560020290600052602060002090810190610ffd9190614b82565b82805482825590600052602060002090600301600490048101928215614b4d5791602002820160005b83821115614b1857835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614ace565b8015614b4b5782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614b18565b505b50614b59929150614ba9565b5090565b508054600082556003016004900490600052602060002090810190610ffd9190614ba9565b5b80821115614b5957600081556001810180546001600160a01b0319169055600201614b83565b5b80821115614b595760008155600101614baa565b6001600160e01b031981168114610ffd57600080fd5b600060208284031215614be657600080fd5b8135614bf181614bbe565b9392505050565b6001600160a01b0381168114610ffd57600080fd5b634e487b7160e01b600052604160045260246000fd5b60405161020081016001600160401b0381118282101715614c4657614c46614c0d565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614c7457614c74614c0d565b604052919050565b600082601f830112614c8d57600080fd5b81356001600160401b03811115614ca657614ca6614c0d565b614cb9601f8201601f1916602001614c4c565b818152846020838601011115614cce57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614d0357600080fd5b8535614d0e81614bf8565b94506020860135614d1e81614bf8565b9350604086013592506060860135915060808601356001600160401b03811115614d4757600080fd5b614d5388828901614c7c565b9150509295509295909350565b60005b83811015614d7b578181015183820152602001614d63565b50506000910152565b60008151808452614d9c816020860160208601614d60565b601f01601f19169290920160200192915050565b602081526000614bf16020830184614d84565b80356001600160401b03811681146112b257600080fd5b60008060008060808587031215614df057600080fd5b8435614dfb81614bf8565b935060208501359250614e1060408601614dc3565b9150614e1e60608601614dc3565b905092959194509250565b60006001600160401b03821115614e4257614e42614c0d565b5060051b60200190565b600082601f830112614e5d57600080fd5b81356020614e72614e6d83614e29565b614c4c565b82815260059290921b84018101918181019086841115614e9157600080fd5b8286015b84811015614eac5780358352918301918301614e95565b509695505050505050565b600082601f830112614ec857600080fd5b81356020614ed8614e6d83614e29565b82815260059290921b84018101918181019086841115614ef757600080fd5b8286015b84811015614eac5780356001600160401b03811115614f1a5760008081fd5b614f288986838b0101614c7c565b845250918301918301614efb565b60008060408385031215614f4957600080fd5b82356001600160401b0380821115614f6057600080fd5b614f6c86838701614e4c565b93506020850135915080821115614f8257600080fd5b50614f8f85828601614eb7565b9150509250929050565b600060208284031215614fab57600080fd5b5035919050565b6001600160a01b0391909116815260200190565b60008060408385031215614fd957600080fd5b8235614fe481614bf8565b946020939093013593505050565b60006020828403121561500457600080fd5b8135614bf181614bf8565b60008060006060848603121561502457600080fd5b8335925061503460208501614dc3565b915061504260408501614dc3565b90509250925092565b60006020828403121561505d57600080fd5b81356001600160401b0381111561507357600080fd5b610eed84828501614e4c565b6000806040838503121561509257600080fd5b823561509d81614bf8565b915060208301356150ad81614bf8565b809150509250929050565b6000806000606084860312156150cd57600080fd5b833592506020840135915061504260408501614dc3565b6000806000606084860312156150f957600080fd5b833561510481614bf8565b9250602084013561511481614bf8565b929592945050506040919091013590565b600082601f83011261513657600080fd5b81356020615146614e6d83614e29565b82815260059290921b8401810191818101908684111561516557600080fd5b8286015b84811015614eac5761517a81614dc3565b8352918301918301615169565b6000806000806080858703121561519d57600080fd5b6151a685614dc3565b935060208501356151b681614bf8565b925060408501356001600160401b03808211156151d257600080fd5b6151de88838901614c7c565b935060608701359150808211156151f457600080fd5b5061520187828801615125565b91505092959194509250565b6000806040838503121561522057600080fd5b50508035926020909101359150565b6001600160a01b03929092168252602082015260400190565b805182526020908101516001600160a01b0316910152565b60408101610be48284615248565b60006020828403121561528057600080fd5b81356001600160401b0381111561529657600080fd5b610eed84828501614c7c565b600060a082840312156152b457600080fd5b60405160a081018181106001600160401b03821117156152d6576152d6614c0d565b806040525082358152602083013560208201526152f560408401614dc3565b604082015261530660608401614dc3565b606082015261531760808401614dc3565b60808201529392505050565b8015158114610ffd57600080fd5b80356112b281615323565b6000806040838503121561534f57600080fd5b823561535a81614bf8565b915060208301356150ad81615323565b8035600581106112b257600080fd5b8035600681106112b257600080fd5b8035600781106112b257600080fd5b600061020082840312156153aa57600080fd5b6153b2614c23565b90506153bd8261536a565b81526153cb6020830161536a565b60208201526153dc6040830161536a565b60408201526153ed6060830161536a565b60608201526153fe6080830161536a565b608082015261540f60a0830161536a565b60a082015261542060c0830161536a565b60c082015261543160e0830161536a565b60e082015261010061544481840161536a565b9082015261012061545683820161536a565b90820152610140615468838201615379565b9082015261016061547a838201615388565b9082015261018061548c838201615331565b908201526101a061549e838201615331565b908201526101c06154b0838201615331565b908201526101e06154c2838201615331565b9082015292915050565b600061020082840312156154df57600080fd5b614bf18383615397565b602080825282518282018190526000919060409081850190868401855b8281101561552957615519848351615248565b9284019290850190600101615506565b5091979650505050505050565b6000806040838503121561554957600080fd5b823591506111f860208401614dc3565b600081518084526020808501945080840160005b838110156155925781516001600160401b03168752958201959082019060010161556d565b509495945050505050565b6080815260006155b06080830187614d84565b6001600160401b03861660208401526001600160a01b038516604084015282810360608401526155e08185615559565b979650505050505050565b602081526000614bf16020830184615559565b60008060006060848603121561561357600080fd5b83356001600160401b038082111561562a57600080fd5b61563687838801614e4c565b9450602086013591508082111561564c57600080fd5b5061565986828701614eb7565b925050604084013561566a81615323565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156156b65783516001600160a01b031683529284019291840191600101615691565b50909695505050505050565b6000806000606084860312156156d757600080fd5b833592506020840135915060408401356001600160401b038111156156fb57600080fd5b61570786828701614c7c565b9150509250925092565b60008060006060848603121561572657600080fd5b61572f84614dc3565b9250602084013561503481614bf8565b60008060006060848603121561575457600080fd5b83359250602084013561503481614bf8565b600082601f83011261577757600080fd5b81356020615787614e6d83614e29565b82815260099290921b840181019181810190868411156157a657600080fd5b8286015b84811015614eac576157bc8882615397565b835291830191610200016157aa565b600080604083850312156157de57600080fd5b82356001600160401b03808211156157f557600080fd5b614f6c86838701615766565b6001600160e01b031991909116815260200190565b60008060006060848603121561582b57600080fd5b83356001600160401b038082111561584257600080fd5b61584e87838801614e4c565b945060209150818601358181111561586557600080fd5b61587188828901615766565b94505060408601358181111561588657600080fd5b86019050601f8101871361589957600080fd5b80356158a7614e6d82614e29565b81815260059190911b820183019083810190898311156158c657600080fd5b928401925b828410156158ed5783356158de81614bf8565b825292840192908401906158cb565b80955050505050509250925092565b6000806000806080858703121561591257600080fd5b843561591d81614bf8565b9350602085013561592d81614bf8565b92506040850135915060608501356001600160401b0381111561594f57600080fd5b61520187828801614c7c565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156159b057603f1988860301845261599e858351614d84565b94509285019290850190600101615982565b5092979650505050505050565b600080604083850312156159d057600080fd5b8235915060208301356001600160401b038111156159ed57600080fd5b614f8f85828601615125565b600080600080600080600080610100898b031215615a1657600080fd5b883597506020890135615a2881614bf8565b965060408901359550606089013594506080890135615a4681614bf8565b935060a0890135925060c0890135615a5d81615323565b915060e08901356001600160401b03811115615a7857600080fd5b615a848b828c01614c7c565b9150509295985092959890939650565b60008060008060808587031215615aaa57600080fd5b84359350602085013592506040850135615ac381614bf8565b9396929550929360600135925050565b600080600060608486031215615ae857600080fd5b83359250602084013561511481614bf8565b600060208284031215615b0c57600080fd5b8151614bf181615323565b634e487b7160e01b600052601160045260246000fd5b81810381811115610be457610be4615b17565b80820180821115610be457610be4615b17565b600181811c90821680615b6757607f821691505b602082108103615b8757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b8082028115828204841417610be457610be4615b17565b600082615bd757634e487b7160e01b600052601260045260246000fd5b500490565b9283526001600160a01b039190911660208301526001600160401b0316604082015260600190565b6001600160401b0383168152604060208201526000610eed6040830184614d84565b600060208284031215615c3857600080fd5b8151614bf181614bf8565b601f821115610fd257600081815260208120601f850160051c81016020861015615c6a5750805b601f850160051c820191505b81811015611f5657828155600101615c76565b81516001600160401b03811115615ca257615ca2614c0d565b615cb681615cb08454615b53565b84615c43565b602080601f831160018114615ceb5760008415615cd35750858301515b600019600386901b1c1916600185901b178555611f56565b600085815260208120601f198616915b82811015615d1a57888601518255948401946001909101908401615cfb565b5085821015615d385787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fd5b600060208284031215615d7057600080fd5b5051919050565b6000808454615d8581615b53565b60018281168015615d9d5760018114615db257615de1565b60ff1984168752821515830287019450615de1565b8860005260208060002060005b85811015615dd85781548a820152908401908201615dbf565b50505082870194505b505050508351615df5818360208801614d60565b64173539b7b760d91b9101908152600501949350505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e4190830184614d84565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906155e090830184614d84565b600080600060608486031215615e9a57600080fd5b8351615ea581614bf8565b60208501516040860151919450925061566a81615323565b838152826020820152606060408201526000615edc6060830184614d84565b95945050505050565b6020808252825182820181905260009190848201906040850190845b818110156156b657835183529284019291840191600101615f01565b600060208284031215615f2f57600080fd5b8151614bf181614bbe565b634e487b7160e01b600052603160045260246000fdfe04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552dddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122039952d4782a7e4b932f08c2bbc8c389155a817876d8085102224ed5dcc1a3bf164736f6c6343000815003300000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000085ab410a50a3d85f1a26d9e4efcaa520a39b9cd6000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000003f697066733a2f2f516d52744871413961744d577932593567477176556156515a7338737a3244664d6e5275474a596f4e4e4c68635a2f7065725f6c616e642f00000000000000000000000000000000000000000000000000000000000000004f697066733a2f2f516d5777754a5463484c7769514b75586a78615a757956586d4467463156537035647a773674506274784a6474392f736b796272656163682f636f6c6c656374696f6e2e6a736f6e0000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103c05760003560e01c806365b67eb9116101f7578063b2a11d1c11610116578063b2a11d1c14610985578063b390c0ab14610998578063b88d4fde146109ab578063bc82fbac146109be578063c259a988146109de578063c87b56dd146109f1578063c89da7a514610a04578063d5abeb0114610a17578063de8e602c14610a1f578063defa80c314610a32578063df6f556b14610a45578063e467a48f14610a7c578063e7de4de414610a8f578063e97ceaa814610aa2578063e985e9c514610ab5578063ee1dffcf14610af1578063f2fde38b14610b04578063fb25fb7a14610b17578063fc3517c814610b51578063ffa1ad7414610b6457600080fd5b806365b67eb9146107665780636f19951c1461077957806370a082311461078c578063715018a61461079f5780637280281e146107a75780637507e2ae146107ba57806379e8ca9e146108a157806381eaf99b146108b45780638507dc28146108bc57806387eb985d146108cf57806389ed2edf146108e25780638d4f3bf5146108ea5780638da5cb5b14610905578063931688cb1461090d57806395d89b411461092057806395edc18c146109285780639796133614610939578063a22cb4651461094c578063a898e3641461095f578063addfc2f51461097257600080fd5b80632f32f937116102e35780632f32f9371461059957806330ffb1d6146105b957806338dcf74c146105cc5780633ce67a4a146105df57806342842e0e146105f257806342966c681461060557806343cf64e71461061857806344ec93441461062b57806348f5f11c1461064b5780634e60edba146106765780634fc060081461069957806351532e5a146106ac57806358f0fcd4146106cc57806359c8b7dd146106df5780635e2e3292146106e75780635e94354a146106fa5780635ea72f361461070d5780635ff2f2e8146107205780636352211e14610740578063635490cc1461075357600080fd5b806301e1d114146103c557806301ffc9a7146103dc578063064c0a3a146103ff57806306fdde0314610414578063074334fb1461042957806307e67e571461043c578063081812fc1461044f578063095ea7b31461046f5780630fc499f51461048257806318160ddd146104955780631c7bb4611461049d5780631d0d35f5146104b0578063217f2bfe146104dc57806322e6d160146104ef57806322f6da9c1461050257806323669b011461051557806323b872dd146105265780632452cd91146105395780632a55205a1461054c5780632d9b34591461056d575b600080fd5b600b545b6040519081526020015b60405180910390f35b6103ef6103ea366004614bd4565b610b88565b60405190151581526020016103d3565b61041261040d366004614ceb565b610bea565b005b61041c610dea565b6040516103d39190614db0565b6103ef610437366004614dda565b610e7c565b61041261044a366004614f36565b610ef5565b61046261045d366004614f99565b610f05565b6040516103d39190614fb2565b61041261047d366004614fc6565b610f4b565b610412610490366004614ff2565b610fd7565b6009546103c9565b6104126104ab36600461500f565b611000565b6103ef6104be366004614ff2565b6001600160a01b031660009081526004602052604090205460011490565b6104126104ea36600461504b565b611013565b6103ef6104fd36600461507f565b6110d0565b6104126105103660046150b8565b6110fe565b6024546001600160a01b0316610462565b6104126105343660046150e4565b611179565b6103c9610547366004615187565b61119e565b61055f61055a36600461520d565b6111cc565b6040516103d392919061522f565b6103ef61057b366004614ff2565b6001600160a01b031660009081526021602052604090205460ff1690565b6105ac6105a736600461520d565b611201565b6040516103d39190615260565b6103c96105c736600461526e565b61128e565b6104126105da3660046152a2565b6112b7565b6104126105ed36600461533c565b61161b565b6104126106003660046150e4565b61164e565b610412610613366004614f99565b611669565b61041c6106263660046154cc565b611674565b61063e610639366004614f99565b61172e565b6040516103d391906154e9565b61065e6106593660046154cc565b6117ad565b6040516001600160401b0390911681526020016103d3565b610689610684366004615536565b6117d8565b6040516103d3949392919061559d565b6104126106a7366004614f36565b6118b5565b6106bf6106ba366004614f99565b6118c9565b6040516103d391906155eb565b6104126106da3660046155fe565b61195d565b6001546103c9565b61041c6106f5366004615536565b611b25565b6106bf610708366004614f99565b611c14565b61041261071b366004614fc6565b611c7d565b61073361072e36600461504b565b611d04565b6040516103d39190615675565b61046261074e366004614f99565b611da6565b6104126107613660046156c2565b611e36565b610412610774366004615711565b611f5e565b61063e610787366004614f99565b611f71565b6103c961079a366004614ff2565b611fe1565b610412612026565b6106bf6107b5366004614f99565b61203a565b6108576107c836600461573f565b6040805160808082018352600080835260208084018290528385018290526060938401829052968152601e87528381206001600160a01b03968716825287528381206001600160401b03958616825287528390208351918201845280548086168352600160401b9004909416958101959095526001830154918501919091526002909101549091169082015290565b6040516103d3919081516001600160401b03908116825260208084015190911690820152604080830151908201526060918201516001600160a01b03169181019190915260800190565b6104126108af36600461533c565b6120a3565b610412612160565b6104126108ca36600461533c565b612170565b6104126108dd3660046157cb565b612206565b61041c6122f6565b6108f863524d524b60e01b81565b6040516103d39190615801565b610462612305565b61041261091b36600461526e565b612314565b61041c612328565b6000546001600160a01b0316610462565b61041261094736600461520d565b612337565b61041261095a36600461533c565b6123b7565b6105ac61096d36600461520d565b612445565b610412610980366004615816565b612496565b6103c96109933660046154cc565b6125cb565b6103c96109a636600461520d565b6127c7565b6104126109b93660046158fc565b612b24565b6109d16109cc36600461504b565b612b63565b6040516103d3919061595b565b6104126109ec36600461500f565b612c82565b61041c6109ff366004614f99565b612e28565b610412610a12366004614ff2565b612e65565b600a546103c9565b610412610a2d3660046159bd565b612e8f565b610412610a403660046159f9565b612f19565b61065e610a53366004615536565b60009182526014602090815260408084206001600160401b039384168552909152909120541690565b610462610a8a366004614f99565b613128565b610412610a9d36600461520d565b61314b565b610412610ab0366004615a94565b61324c565b6103ef610ac336600461507f565b6001600160a01b039182166000908152600e6020908152604080832093909416825291909152205460ff1690565b6103ef610aff366004615ad3565b613262565b610412610b12366004614ff2565b613293565b610b2a610b25366004614f99565b6132cb565b604080516001600160a01b03909416845260208401929092521515908201526060016103d3565b610412610b5f3660046150b8565b613333565b61041c60405180604001604052806005815260200164322e312e3160d81b81525081565b6000610b9382613348565b80610bae57506001600160e01b0319821663152a902d60e11b145b80610bc957506001600160e01b03198216635b5e139f60e01b145b80610be457506001600160e01b0319821663524d524b60e01b145b92915050565b82610bf4816133cf565b600080610c00866132cb565b5091509150876001600160a01b0316826001600160a01b031614610c375760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038716610c5e576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b03871630148015610c7557508486145b15610c9357604051633d76b10760e01b815260040160405180910390fd5b610ca5876001600160a01b0316613457565b610cc25760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526001600160a01b038816906301ffc9a790610cf5906342b0e56f60e01b90600401615801565b602060405180830381865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190615afa565b610d5357604051631784ec7360e21b815260040160405180910390fd5b610d5e868887613466565b610d69888888613557565b6001600160a01b0388166000908152600c60205260408120805460019290610d92908490615b2d565b90915550610da3905086868961357e565b6001600160a01b0387166000908152600c60205260408120805460019290610dcc908490615b40565b90915550610de09050828883888a896135df565b5050505050505050565b606060068054610df990615b53565b80601f0160208091040260200160405190810160405280929190818152602001828054610e2590615b53565b8015610e725780601f10610e4757610100808354040283529160200191610e72565b820191906000526020600020905b815481529060010190602001808311610e5557829003601f168201915b5050505050905090565b6001600160401b038083166000908152601c602090815260408083205484168084528280528184206001600160a01b038a1685529092528220549192909181169084168103610ee6576000610eda86610ed48961203a565b906136c0565b9450610eed9350505050565b6000925050505b949350505050565b610f018282600161195d565b5050565b6000610f1082613729565b6000828152600d6020526040812090610f2884611da6565b6001600160a01b0390811682526020820192909252604001600020541692915050565b6000610f5682611da6565b9050806001600160a01b0316836001600160a01b031603610f8a57604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b03821614801590610faa5750610fa88133610ac3565b155b15610fc857604051634c12315960e11b815260040160405180910390fd5b610fd2838361374f565b505050565b610fdf6137c8565b600080546001600160a01b0319166001600160a01b03831617905550565b50565b6110086137f8565b610fd283838361383c565b6024546001600160a01b0316331461103e57604051631cbb33dd60e31b815260040160405180910390fd5b60005b8151811015610f0157600082828151811061105e5761105e615b8d565b6020026020010151905061109961107482611da6565b6024546040805160208101909152600081526001600160a01b03909116908490613a31565b60405160019092019181907fbe5015635c34cbee4ad5d6b34f0bc4757e44efcb9ab330114167d493badcc00290600090a250611041565b6001600160a01b03918216600090815260196020908152604080832093909416825291909152205460ff1690565b8261110881613b76565b611113848484613bd7565b61111e848484613c7f565b60008481526018602090815260408083206001600160401b0386168085529252808320805460ff1916905551909186917f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb1249190a35b50505050565b80611183816133cf565b61117384848460405180602001604052806000815250613a31565b60006111a86137f8565b600b8054600101908190556111c09086868686613ccc565b50600b54949350505050565b600080546001546001600160a01b039091169190612710906111ee9085615ba3565b6111f89190615bba565b90509250929050565b611209614a6d565b8161121384611f71565b51116112325760405163653e642560e11b815260040160405180910390fd5b600083815260106020526040812080548490811061125257611252615b8d565b60009182526020918290206040805180820190915260029092020180548252600101546001600160a01b03169181019190915291505092915050565b60006112986137f8565b600b8054600101908190556112ad9083613d72565b50600b545b919050565b80516112c281613b76565b6112ca613e38565b6040808301516001600160401b039081166000908152601b602090815283822054606087015187518452601e83528584206001600160a01b0392831680865290845286852095821685529490925293909120600201549192909116156113435760405163bd0650ab60e01b815260040160405180910390fd5b611351846040015182613e60565b600061136585600001518660200151611201565b60208101518151608088015160405163074334fb60e01b815230600482015260248101929092526001600160401b039081166044830152851660648201529192506001600160a01b03169063074334fb90608401602060405180830381865afa1580156113d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fa9190615afa565b61141757604051632c36cd3360e01b815260040160405180910390fd5b6020810151604051636e5bceab60e11b81526001600160401b03841660048201526001600160a01b0391821660248201529084169063dcb79d5690604401602060405180830381865afa158015611472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114969190615afa565b6114b357604051637228eff560e11b815260040160405180910390fd5b6040805160808082018352878301516001600160401b0390811683529088015181166020808401918252855184860190815286820180516001600160a01b03908116606088019081528d516000908152601e86528981208d8416825286528981208c8916825286528981208951815498518a16600160401b026001600160801b031990991699169890981796909617875592516001808801919091559251600290960180549682166001600160a01b0319909716969096179095558b518452601f8352868420905190941683529281528482208651835290529283208054929391929091906115a3908490615b40565b92505081905550826001600160401b031686604001516001600160401b031687600001517f1f5de02b1d9c93ca468f54630e1daf13f6dc458a63f8061ff73e85bf9bc38884856000015186602001518b6080015160405161160693929190615bdc565b60405180910390a45050600160025550505050565b6116236137f8565b6001600160a01b03919091166000908152602160205260409020805460ff1916911515919091179055565b610fd283838360405180602001604052806000815250612b24565b610f018160006127c7565b60606000611681836117ad565b6001600160401b03811660009081526013602052604090208054919250906116a890615b53565b80601f01602080910402602001604051908101604052809291908181526020018280546116d490615b53565b80156117215780601f106116f657610100808354040283529160200191611721565b820191906000526020600020905b81548152906001019060200180831161170457829003601f168201915b5050505050915050919050565b6000818152601160209081526040808320805482518185028101850190935280835260609493849084015b828210156117a15760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611759565b50929695505050505050565b6000806117b9836125cb565b6000908152602360205260409020546001600160401b03169392505050565b606060008060606117e98686611b25565b6001600160401b038087166000908152601c6020908152604080832054601b835281842054601d845293829020805483518186028101860190945280845291909516946001600160a01b03909416939283919083018282801561189d57602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161185a5790505b50505050509050935093509350935092959194509250565b6118bd6137f8565b610f018282600061195d565b60008181526016602090815260409182902080548351818402810184019094528084526060939283018282801561195157602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b03168152602001906008019060208260070104928301926001038202915080841161190e5790505b50505050509050919050565b825182518114611983576040516001621398b960e31b0319815260040160405180910390fd5b60005b81811015611b1e578280156119ce5750336001600160a01b03166119c28683815181106119b5576119b5615b8d565b6020026020010151611da6565b6001600160a01b031614155b156119ec57604051630ea1efa960e11b815260040160405180910390fd5b600b805460010190558451600090869083908110611a0c57611a0c615b8d565b602090810291909101810151600b546000828152602290935260409092205487519193506001600160401b031690611a5f908390899087908110611a5257611a52615b8d565b6020026020010151613d72565b611a6a83838361383c565b600083815260166020526040902054611a91908490611a8b90600190615b2d565b84613f2a565b600083815260226020526040902080546001600160401b0319166001600160401b038416179055865183907f5420f4b2cf82228035982e5a0811d6cb888647331d194482f54744f4471637119084908a9088908110611af257611af2615b8d565b6020026020010151604051611b08929190615c04565b60405180910390a2836001019350505050611986565b5050505050565b60008281526018602090815260408083206001600160401b038516845290915290205460609060ff16611b6b57604051631b9928fd60e31b815260040160405180910390fd5b6001600160401b03821660009081526013602052604090208054611b8e90615b53565b80601f0160208091040260200160405190810160405280929190818152602001828054611bba90615b53565b8015611c075780601f10611bdc57610100808354040283529160200191611c07565b820191906000526020600020905b815481529060010190602001808311611bea57829003601f168201915b5050505050905092915050565b60008181526017602090815260409182902080548351818402810184019094528084526060939283018282801561195157600091825260209182902080546001600160401b0316845290820283019290916008910180841161190e575094979650505050505050565b6000611c8882611da6565b9050806001600160a01b0316836001600160a01b031603611cbc576040516375f45abd60e01b815260040160405180910390fd5b336001600160a01b03821614801590611cdc5750611cda81336110d0565b155b15611cfa576040516357a2e94960e11b815260040160405180910390fd5b610fd28383614140565b8051606090806001600160401b03811115611d2157611d21614c0d565b604051908082528060200260200182016040528015611d4a578160200160208202803683370190505b50915060005b81811015611d9f57611d6d8482815181106119b5576119b5615b8d565b838281518110611d7f57611d7f615b8d565b6001600160a01b0390921660209283029190910190910152600101611d50565b5050919050565b600080600080611db5856132cb565b9250925092508015611e2d576040516331a9108f60e11b8152600481018390526001600160a01b03841690636352211e90602401602060405180830381865afa158015611e06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2a9190615c26565b92505b50909392505050565b611e3f83613729565b33611e4981613457565b611e665760405163b9d3114760e01b815260040160405180910390fd5b604080518082019091528381526001600160a01b03821660208201526000611e8d8661172e565b5190506080811015611eec576000868152601160209081526040822080546001808201835591845292829020855160029094020192835590840151910180546001600160a01b0319166001600160a01b03909216919091179055611f05565b60405163a53c8c0560e01b815260040160405180910390fd5b84836001600160a01b0316877fe65085e689b77b126ba0bac3b079aa8288f19f4d5445af11c76003f8ab3075dd84604051611f4291815260200190565b60405180910390a4611f56868487876141b9565b505050505050565b611f666137f8565b610fd2838383614202565b60008181526010602090815260408083208054825181850281018501909352808352606094938490840182156117a15760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101611759565b60006001600160a01b03821661200a57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b03166000908152600c602052604090205490565b61202e6137c8565b61203860006142b9565b565b60008181526015602090815260409182902080548351818402810184019094528084526060939283018282801561195157600091825260209182902080546001600160401b0316845290820283019290916008910180841161190e575094979650505050505050565b6120ab6137c8565b6001600160a01b0382166120d25760405163016b812760e71b815260040160405180910390fd5b806120f7576001600160a01b0382166000908152600460205260408120819055612116565b6001600160a01b03821660009081526004602052604090206001908190555b50816001600160a01b03167f4b5657e84cf8a17ac5587bbeb3cc2bab9826c4c67b8bad81b4849de49d37aac282604051612154911515815260200190565b60405180910390a25050565b6121686137f8565b600954600a55565b6001600160a01b0382163303612199576040516375f45abd60e01b815260040160405180910390fd5b3360008181526019602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f0cff4fcf777050010027190b8061fd8bfd1de16d81b1f94e9752df1427a2623591015b60405180910390a35050565b61220e6137f8565b815181518114612234576040516001621398b960e31b0319815260040160405180910390fd5b60005b8181101561117357600b80546001019081905584516000906122729087908590811061226557612265615b8d565b60200260200101516125cb565b6000818152602360205260409020549091506001600160401b0316156122ab5760405163050b37b960e51b815260040160405180910390fd5b600081815260236020526040902080546001600160401b0319166001600160401b03841617905584516122ec908390879086908110611a5257611a52615b8d565b5050600101612237565b606060058054610df990615b53565b6003546001600160a01b031690565b61231c6137f8565b6025610f018282615c89565b606060078054610df990615b53565b816123418161430b565b60008381526011602052604090205482101561237057604051631e73178b60e11b815260040160405180910390fd5b600083815260116020526040812061238791614a84565b60405183907f8ac4a0d65950c3e40448afb2260e2e0ec36ea15644d9b39e37e85472e5f9445190600090a2505050565b6001600160a01b03821633036123e057604051630b7b99b960e21b815260040160405180910390fd5b336000818152600e602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3191016121fa565b61244d614a6d565b816124578461172e565b51116124765760405163da22687f60e01b815260040160405180910390fd5b600083815260116020526040812080548490811061125257611252615b8d565b61249e6137f8565b82518151811415806124b1575082518114155b156124d2576040516001621398b960e31b0319815260040160405180910390fd5b80600960008282546124e49190615b40565b90915550600090505b81811015611b1e57600061250c85838151811061226557612265615b8d565b60008181526023602052604090205485519192506001600160401b0316906125779086908590811061254057612540615b8d565b602002602001015188858151811061255a5761255a615b8d565b60200260200101516040518060200160405280600081525061436c565b61259c87848151811061258c5761258c615b8d565b602002602001015182600061383c565b6125c18784815181106125b1576125b1615b8d565b6020026020010151600083613f2a565b50506001016124ed565b600080826000015160048111156125e4576125e4615d48565b901b905060048260200151600481111561260057612600615d48565b901b8117905060088260400151600481111561261e5761261e615d48565b901b81179050600c8260600151600481111561263c5761263c615d48565b901b8117905060108260800151600481111561265a5761265a615d48565b901b8117905060148260a00151600481111561267857612678615d48565b901b8117905060188260c00151600481111561269657612696615d48565b901b81179050601c8260e0015160048111156126b4576126b4615d48565b901b81179050602082610100015160048111156126d3576126d3615d48565b901b81179050602482610120015160048111156126f2576126f2615d48565b901b811790506028826101400151600581111561271157612711615d48565b901b81179050602c826101600151600681111561273057612730615d48565b901b8117905081610180015161274757600061274d565b6001602e1b5b65ffffffffffff1681179050816101a0015161276a576000612770565b600160301b5b66ffffffffffffff1681179050816101c0015161278e576000612794565b600160321b5b66ffffffffffffff1681179050816101e001516127b25760006127b8565b600160341b5b66ffffffffffffff1617919050565b6000826127d3816133cf565b6000806127df866132cb565b509150915060006127ef87611da6565b90506127fd83600089613557565b6040805160208101909152600090526001600160a01b0383166000908152600c60205260408120805460019290612835908490615b2d565b90915550612846905060008861374f565b612851600088614140565b600061285c88611f71565b60008981526010602052604081209192506128779190614a84565b600088815260116020526040812061288e91614a84565b6000888152600d602090815260408083206001600160a01b0386168452909152812080546001600160a01b031916905581518190815b81811015612a89578a8310612933578481815181106128e5576128e5615b8d565b60200260200101516020015185828151811061290357612903615b8d565b6020026020010151600001516040516306177b2560e41b815260040161292a92919061522f565b60405180910390fd5b6012600086838151811061294957612949615b8d565b6020026020010151602001516001600160a01b03166001600160a01b03168152602001908152602001600020600086838151811061298957612989615b8d565b602002602001015160000151815260200190815260200160002060009055828b0393508481815181106129be576129be615b8d565b6020026020010151602001516001600160a01b031663b390c0ab8683815181106129ea576129ea615b8d565b602002602001015160000151600187612a039190615b2d565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015612a46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a6a9190615d5e565b612a75906001615b40565b612a7f9084615b40565b92506001016128c4565b5060008b8152600f602052604080822082815560010180546001600160a01b0319169055518c91906001600160a01b038a1690600080516020615f71833981519152908390a4604080518781526000602082018190528d9290916001600160a01b038b1691600080516020615f51833981519152910160405180910390a4604080516020810190915260009052509998505050505050505050565b81612b2e816133cf565b612b3a85858585613a31565b612b46858585856143ff565b611b1e5760405163bcb5663760e01b815260040160405180910390fd5b8051606090806001600160401b03811115612b8057612b80614c0d565b604051908082528060200260200182016040528015612bb357816020015b6060815260200190600190039081612b9e5790505b50915060005b81811015611d9f5760226000858381518110612bd757612bd7615b8d565b6020908102919091018101518252810191909152604001600020546001600160401b031615612c7a57612c5c848281518110612c1557612c15615b8d565b602002602001015160226000878581518110612c3357612c33615b8d565b6020908102919091018101518252810191909152604001600020546001600160401b0316611b25565b838281518110612c6e57612c6e615b8d565b60200260200101819052505b600101612bb9565b82612c8c81613b76565b6001600160401b038084166000908152601b6020908152604080832054888452601e83528184206001600160a01b039182168086529084528285208887168652845293829020825160808101845281548088168252600160401b9004909616938601939093526001830154918501919091526002909101541660608301819052909190612d2c576040516317de7dd760e21b815260040160405180910390fd5b6000868152601e602090815260408083206001600160a01b0380871685529083528184206001600160401b0389168552835281842080546001600160801b03191681556001808201869055600290910180546001600160a01b03191690558a8552601f8452828520606087015190921685529083528184208583015185529092528220805491929091612dc0908490615b2d565b92505081905550836001600160401b0316856001600160401b0316877f438e039ebbba8f290f3b5d41aaf3295eccc9b5e6b0e1d52ace700772afb7da13846040015185606001518660200151604051612e1b93929190615bdc565b60405180910390a4611f56565b6060612e3382613729565b6025612e3e83614502565b604051602001612e4f929190615d77565b6040516020818303038152906040529050919050565b612e6d6137c8565b602480546001600160a01b0319166001600160a01b0392909216919091179055565b81612e9981613b76565b81516000848152601560205260409020548114612ec957604051633581be1d60e11b815260040160405180910390fd5b60008481526017602090815260409091208451612ee892860190614aa5565b5060405184907ff0bfd70b0068f973d58178846ca67112671ec45e060838f7de5662036bcf801790600090a2611173565b87612f238161430b565b612f2b614a6d565b8315612f4257612f3b8a88612445565b9050612f78565b612f4d8a8787613262565b15612f6b57604051630619dc9d60e21b815260040160405180910390fd5b612f758a88611201565b90505b612f83818787614594565b8315612fa65760008a8152601160205260409020612fa190886145d8565b612fe0565b6001600160a01b038616600090815260126020908152604080832088845282528083208390558c835260109091529020612fe090886145d8565b6001600160a01b038916156130ca578761305d57604051635c46a7ef60e11b81526001600160a01b0387169063b88d4fde906130269030908d908a908990600401615e0e565b600060405180830381600087803b15801561304057600080fd5b505af1158015613054573d6000803e3d6000fd5b505050506130ca565b60208101518151604051630326051d60e11b81526001600160a01b039092169163064c0a3a916130979130918e918e908a90600401615e4b565b600060405180830381600087803b1580156130b157600080fd5b505af11580156130c5573d6000803e3d6000fd5b505050505b6040805188815285151560208201526001600160a01b038b81161582840152915187928916918d917f02d6d6dbcb604d5e1e8c7886456e82a9cdce88b0a580071358f206b5a4d58f709181900360600190a450505050505050505050565b600061313382613729565b6000828152601a6020526040812090610f2884611da6565b8161315581613b76565b6000838152601660205260409020548281111561318557604051635134ce8960e01b815260040160405180910390fd5b60005b818110156132025760008581526016602052604081208054839081106131b0576131b0615b8d565b6000918252602080832060048304015489845260148252604080852060039094166008026101000a9091046001600160401b03168452919052902080546001600160401b031916905550600101613188565b50600084815260166020526040812061321a91614b5d565b60405160009085907f1010837a46db9510cad56c9b63e97183557a136e9d4ddbec309ce52c99afb124908390a3611173565b836132568161430b565b611b1e85858585614692565b6000928352601f602090815260408085206001600160a01b0394909416855292815282842091845252902054151590565b61329b6137c8565b6001600160a01b0381166132c257604051634ece6ecf60e01b815260040160405180910390fd5b610ffd816142b9565b6000818152600f60209081526040808320815180830190925280548252600101546001600160a01b0316918101829052829182919061331d5760405163089ba7e160e41b815260040160405180910390fd5b6020810151905190959094508415159350915050565b8261333d81613b76565b611173848484613f2a565b60006001600160e01b031982166301ffc9a760e01b148061337957506001600160e01b031982166380ac58cd60e01b145b8061339457506001600160e01b031982166342b0e56f60e01b145b806133af57506001600160e01b0319821663035a194d60e11b145b80610be457506001600160e01b03198216630a2f26b960e21b1492915050565b6000806133db836132cb565b5091509150806000141580156133fa5750336001600160a01b03831614155b806134395750336001600160a01b038316148061341c575061341c8233610ac3565b8061343757503361342c84610f05565b6001600160a01b0316145b155b15610fd2576040516345f3c98360e11b815260040160405180910390fd5b6001600160a01b03163b151590565b60005b606481101561353d576000806000856001600160a01b031663fb25fb7a866040518263ffffffff1660e01b81526004016134a591815260200190565b606060405180830381865afa1580156134c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134e69190615e85565b925092509250806134fa5750505050505050565b6001600160a01b0383163014801561351157508682145b1561352f576040516324543e6d60e11b815260040160405180910390fd5b509093509150600101613469565b50604051630349a6bd60e51b815260040160405180910390fd5b6001600160a01b038216610fd2576040516303c24bc160e11b815260040160405180910390fd5b6040805180820182528381526001600160a01b0383811660208084019182526000888152600f9091529384209251835551600190920180546001600160a01b031916929091169190911790556135d4908461374f565b610fd2600084614140565b6040516318d5243360e21b815285906001600160a01b0382169063635490cc9061361190879087908790600401615ebd565b600060405180830381600087803b15801561362b57600080fd5b505af115801561363f573d6000803e3d6000fd5b5050505082866001600160a01b0316886001600160a01b0316600080516020615f7183398151915260405160405180910390a482866001600160a01b0316886001600160a01b0316600080516020615f5183398151915288886040516136af929190918252602082015260400190565b60405180910390a450505050505050565b81516000908190815b8181101561371857846001600160401b03168682815181106136ed576136ed615b8d565b60200260200101516001600160401b031603613710579250600191506137229050565b6001016136c9565b5060008092509250505b9250929050565b613732816147a0565b610ffd5760405163089ba7e160e41b815260040160405180910390fd5b600061375a82611da6565b6000838152600d602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b336137d1612305565b6001600160a01b03161461203857604051631c62d58f60e11b815260040160405180910390fd5b33613801612305565b6001600160a01b03161415801561381e575061381c336104be565b155b15612038576040516301eca16760e41b815260040160405180910390fd5b60008381526018602090815260408083206001600160401b038616845290915290205460ff1615613880576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b038216600090815260136020526040812080546138a390615b53565b9050036138c357604051632aa5eff960e11b815260040160405180910390fd5b6000838152601660205260409020546080116138f25760405163bade3a7b60e01b815260040160405180910390fd5b60008381526018602090815260408083206001600160401b038681168086529184528285208054600160ff19909116811790915588865260168552928520805493840181558552929093206004820401805460039092166008026101000a80840219909216919093021790915581161561399f5760008381526014602090815260408083206001600160401b038681168552925290912080546001600160401b0319169183169190911790555b6040805160018082528183019092526000916020808301908036833701905050905083816000815181106139d5576139d5615b8d565b602002602001018181525050816001600160401b0316836001600160401b03167f4a85a0221f784dbe75db7c29c422f474c15bde9211a98e50a30018fa8dfa937b83604051613a249190615ee5565b60405180910390a3611173565b600080613a3d846132cb565b5091509150856001600160a01b0316826001600160a01b031614613a745760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038516613a9b576040516338f646ff60e21b815260040160405180910390fd5b613aa6868686613557565b6001600160a01b0386166000908152600c60205260408120805460019290613acf908490615b2d565b90915550613ae190508460008761357e565b6001600160a01b0385166000908152600c60205260408120805460019290613b0a908490615b40565b909155505060405184906001600160a01b038088169190891690600080516020615f7183398151915290600090a483856001600160a01b0316876001600160a01b0316600080516020615f51833981519152846000604051612e1b929190918252602082015260400190565b6000613b8182611da6565b9050336001600160a01b0382161480613b9f5750613b9f81336110d0565b80613bba575033613baf83613128565b6001600160a01b0316145b610f0157604051635d64832960e01b815260040160405180910390fd5b6000838152601660205260409020548210613c0557604051630757d52160e01b815260040160405180910390fd5b6000838152601660205260409020805483908110613c2557613c25615b8d565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b03166001600160401b0316816001600160401b031614610fd2576040516378eeeecf60e01b815260040160405180910390fd5b6000838152601660205260409020613c9790836147c0565b60009283526014602090815260408085206001600160401b03909316855291905290912080546001600160401b031916905550565b613cd68583613d72565b6001600160a01b038316158015613ced5750805115155b15613d0b57604051631035ad0760e11b815260040160405180910390fd5b6001600160401b038581166000908152601b6020908152604080832080546001600160a01b0319166001600160a01b038916179055601c825280832080546001600160401b03191694891694909417909355601d81529190208251611f5692840190614aa5565b6001600160401b038216613d99576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b03821660009081526013602052604081208054613dbc90615b53565b90501115613ddd576040516308fe3c3160e41b815260040160405180910390fd5b6001600160401b0382166000908152601360205260409020613dff8282615c89565b506040516001600160401b038316907f3cd061096eaf881067d936308fbd8b81d060c45ab2ec910c02b953162befc10990600090a25050565b6002805403613e5a576040516362bfeae960e11b815260040160405180910390fd5b60028055565b6001600160401b0382166000908152601d602090815260408083208054825181850281018501909352808352613f09938693929190830182828015613ef657602002820191906000526020600020906000905b82829054906101000a90046001600160401b03166001600160401b031681526020019060080190602082600701049283019260010382029150808411613eb35790505b50505050506136c090919063ffffffff16565b91505080610fd257604051634ef44ed560e01b815260040160405180910390fd5b613f35838383613bd7565b60008381526014602090815260408083206001600160401b03808616855292528220541690808215613fe357613fdd8360156000898152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015613ef657600091825260209182902080546001600160401b03168452908202830192909160089101808411613eb357905050505050506136c090919063ffffffff16565b90925090505b801561406457600086815260156020526040902080548591908490811061400c5761400c615b8d565b600091825260208083206004830401805460039093166008026101000a6001600160401b038181021990941695841602949094179093558882526018835260408083209187168352925220805460ff191690556140ef565b6000868152601760209081526040808320601583529083208054825460018181018555938652848620600480830490910180546001600160401b0394851660086003958616810261010090810a9283029288021990931691909117909255855496870186559488529587209085040180548b84169590921690950290920a9283029202191617905592505b6140fa868686613c7f565b826001600160401b0316846001600160401b0316877f3f2709a99f6c06b4e57bbb38eb0134332f96f51a3da314f41a515adbb28b17cc60405160405180910390a4611f56565b600061414b82611da6565b6000838152601a602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917fb90cc0d925ac3511ab6af2d7ca73ffcf7ec4bd871fff36b958ecf440079c463e9190a4505050565b6001600160a01b03831660009081526021602052604090205460ff1615611173576000848152601160205260409020546111739085906141fb90600190615b2d565b8585614692565b6001600160401b038316158061421f57506001600160401b038116155b1561423d576040516312c33ce360e01b815260040160405180910390fd5b6001600160401b038381166000818152602080805260408083206001600160a01b03881684529091529081902080546001600160401b0319169385169384179055517f5b5af0622001a9b735a56357ddc1abd65e6a640126498674daf9d2fb05160725906142ac908690614fb2565b60405180910390a3505050565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600061431682611da6565b9050336001600160a01b038216148061433457506143348133610ac3565b8061434f57503361434483610f05565b6001600160a01b0316145b610f01576040516302728a9d60e41b815260040160405180910390fd5b61437983836000846148a6565b60405182906001600160a01b03851690600090600080516020615f71833981519152908290a46040805160008082526020820181905284926001600160a01b03871692600080516020615f51833981519152910160405180910390a46143e260008484846143ff565b610fd25760405163bcb5663760e01b815260040160405180910390fd5b6000614413846001600160a01b0316613457565b156144fa57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061444a903390899088908890600401615e0e565b6020604051808303816000875af1925050508015614485575060408051601f3d908101601f1916820190925261448291810190615f1d565b60015b6144e0573d8080156144b3576040519150601f19603f3d011682016040523d82523d6000602084013e6144b8565b606091505b5080516144d85760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610eed565b506001610eed565b6060600061450f83614997565b60010190506000816001600160401b0381111561452e5761452e614c0d565b6040519080825280601f01601f191660200182016040528015614558576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461456257509392505050565b82602001516001600160a01b0316826001600160a01b03161415806145ba575082518114155b15610fd257604051637383f2c160e11b815260040160405180910390fd5b815482906145e890600190615b2d565b815481106145f8576145f8615b8d565b906000526020600020906002020182828154811061461857614618615b8d565b600091825260209091208254600290920201908155600191820154910180546001600160a01b0319166001600160a01b03909216919091179055815482908061466357614663615f3a565b60008281526020812060026000199093019283020190815560010180546001600160a01b031916905590555050565b600061469e8585612445565b90506146ab818484614594565b6001600160a01b0383166000908152601260209081526040808320858452909152902054156146ed5760405163188a497360e01b815260040160405180910390fd5b600085815260116020526040902061470590856145d8565b600085815260106020908152604080832080546001808201835591855283852086516002909202019081558584015190820180546001600160a01b0319166001600160a01b03928316179055871680855260128452828520878652845293829020555186815284929188917f29486b9e2ae569b440933a9b1b421467306fa21f3dcad439c262910a634963a9910160405180910390a4611b1e565b6000908152600f60205260409020600101546001600160a01b0316151590565b815481106147cd57600080fd5b815482906147dd90600190615b2d565b815481106147ed576147ed615b8d565b90600052602060002090600491828204019190066008029054906101000a90046001600160401b031682828154811061482857614828615b8d565b90600052602060002090600491828204019190066008026101000a8154816001600160401b0302191690836001600160401b031602179055508180548061487157614871615f3a565b60008281526020902060046000199092019182040180546001600160401b03600860038516026101000a021916905590555050565b6001600160a01b0384166148cd576040516325bd6bd360e01b815260040160405180910390fd5b6148d6836147a0565b156148f45760405163c5a8d37160e01b815260040160405180910390fd5b82614912576040516312c33ce360e01b815260040160405180910390fd5b61491e60008585613557565b6001600160a01b0384166000908152600c60205260408120805460019290614947908490615b40565b90915550506040805180820182529283526001600160a01b0394851660208085019182526000958652600f9052932091518255509051600190910180546001600160a01b03191691909216179055565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106149d65772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6904ee2d6d415b85acef8160201b8310614a00576904ee2d6d415b85acef8160201b830492506020015b662386f26fc100008310614a1e57662386f26fc10000830492506010015b6305f5e1008310614a36576305f5e100830492506008015b6127108310614a4a57612710830492506004015b60648310614a5c576064830492506002015b600a8310610be45760010192915050565b604080518082019091526000808252602082015290565b5080546000825560020290600052602060002090810190610ffd9190614b82565b82805482825590600052602060002090600301600490048101928215614b4d5791602002820160005b83821115614b1857835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302614ace565b8015614b4b5782816101000a8154906001600160401b030219169055600801602081600701049283019260010302614b18565b505b50614b59929150614ba9565b5090565b508054600082556003016004900490600052602060002090810190610ffd9190614ba9565b5b80821115614b5957600081556001810180546001600160a01b0319169055600201614b83565b5b80821115614b595760008155600101614baa565b6001600160e01b031981168114610ffd57600080fd5b600060208284031215614be657600080fd5b8135614bf181614bbe565b9392505050565b6001600160a01b0381168114610ffd57600080fd5b634e487b7160e01b600052604160045260246000fd5b60405161020081016001600160401b0381118282101715614c4657614c46614c0d565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614c7457614c74614c0d565b604052919050565b600082601f830112614c8d57600080fd5b81356001600160401b03811115614ca657614ca6614c0d565b614cb9601f8201601f1916602001614c4c565b818152846020838601011115614cce57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614d0357600080fd5b8535614d0e81614bf8565b94506020860135614d1e81614bf8565b9350604086013592506060860135915060808601356001600160401b03811115614d4757600080fd5b614d5388828901614c7c565b9150509295509295909350565b60005b83811015614d7b578181015183820152602001614d63565b50506000910152565b60008151808452614d9c816020860160208601614d60565b601f01601f19169290920160200192915050565b602081526000614bf16020830184614d84565b80356001600160401b03811681146112b257600080fd5b60008060008060808587031215614df057600080fd5b8435614dfb81614bf8565b935060208501359250614e1060408601614dc3565b9150614e1e60608601614dc3565b905092959194509250565b60006001600160401b03821115614e4257614e42614c0d565b5060051b60200190565b600082601f830112614e5d57600080fd5b81356020614e72614e6d83614e29565b614c4c565b82815260059290921b84018101918181019086841115614e9157600080fd5b8286015b84811015614eac5780358352918301918301614e95565b509695505050505050565b600082601f830112614ec857600080fd5b81356020614ed8614e6d83614e29565b82815260059290921b84018101918181019086841115614ef757600080fd5b8286015b84811015614eac5780356001600160401b03811115614f1a5760008081fd5b614f288986838b0101614c7c565b845250918301918301614efb565b60008060408385031215614f4957600080fd5b82356001600160401b0380821115614f6057600080fd5b614f6c86838701614e4c565b93506020850135915080821115614f8257600080fd5b50614f8f85828601614eb7565b9150509250929050565b600060208284031215614fab57600080fd5b5035919050565b6001600160a01b0391909116815260200190565b60008060408385031215614fd957600080fd5b8235614fe481614bf8565b946020939093013593505050565b60006020828403121561500457600080fd5b8135614bf181614bf8565b60008060006060848603121561502457600080fd5b8335925061503460208501614dc3565b915061504260408501614dc3565b90509250925092565b60006020828403121561505d57600080fd5b81356001600160401b0381111561507357600080fd5b610eed84828501614e4c565b6000806040838503121561509257600080fd5b823561509d81614bf8565b915060208301356150ad81614bf8565b809150509250929050565b6000806000606084860312156150cd57600080fd5b833592506020840135915061504260408501614dc3565b6000806000606084860312156150f957600080fd5b833561510481614bf8565b9250602084013561511481614bf8565b929592945050506040919091013590565b600082601f83011261513657600080fd5b81356020615146614e6d83614e29565b82815260059290921b8401810191818101908684111561516557600080fd5b8286015b84811015614eac5761517a81614dc3565b8352918301918301615169565b6000806000806080858703121561519d57600080fd5b6151a685614dc3565b935060208501356151b681614bf8565b925060408501356001600160401b03808211156151d257600080fd5b6151de88838901614c7c565b935060608701359150808211156151f457600080fd5b5061520187828801615125565b91505092959194509250565b6000806040838503121561522057600080fd5b50508035926020909101359150565b6001600160a01b03929092168252602082015260400190565b805182526020908101516001600160a01b0316910152565b60408101610be48284615248565b60006020828403121561528057600080fd5b81356001600160401b0381111561529657600080fd5b610eed84828501614c7c565b600060a082840312156152b457600080fd5b60405160a081018181106001600160401b03821117156152d6576152d6614c0d565b806040525082358152602083013560208201526152f560408401614dc3565b604082015261530660608401614dc3565b606082015261531760808401614dc3565b60808201529392505050565b8015158114610ffd57600080fd5b80356112b281615323565b6000806040838503121561534f57600080fd5b823561535a81614bf8565b915060208301356150ad81615323565b8035600581106112b257600080fd5b8035600681106112b257600080fd5b8035600781106112b257600080fd5b600061020082840312156153aa57600080fd5b6153b2614c23565b90506153bd8261536a565b81526153cb6020830161536a565b60208201526153dc6040830161536a565b60408201526153ed6060830161536a565b60608201526153fe6080830161536a565b608082015261540f60a0830161536a565b60a082015261542060c0830161536a565b60c082015261543160e0830161536a565b60e082015261010061544481840161536a565b9082015261012061545683820161536a565b90820152610140615468838201615379565b9082015261016061547a838201615388565b9082015261018061548c838201615331565b908201526101a061549e838201615331565b908201526101c06154b0838201615331565b908201526101e06154c2838201615331565b9082015292915050565b600061020082840312156154df57600080fd5b614bf18383615397565b602080825282518282018190526000919060409081850190868401855b8281101561552957615519848351615248565b9284019290850190600101615506565b5091979650505050505050565b6000806040838503121561554957600080fd5b823591506111f860208401614dc3565b600081518084526020808501945080840160005b838110156155925781516001600160401b03168752958201959082019060010161556d565b509495945050505050565b6080815260006155b06080830187614d84565b6001600160401b03861660208401526001600160a01b038516604084015282810360608401526155e08185615559565b979650505050505050565b602081526000614bf16020830184615559565b60008060006060848603121561561357600080fd5b83356001600160401b038082111561562a57600080fd5b61563687838801614e4c565b9450602086013591508082111561564c57600080fd5b5061565986828701614eb7565b925050604084013561566a81615323565b809150509250925092565b6020808252825182820181905260009190848201906040850190845b818110156156b65783516001600160a01b031683529284019291840191600101615691565b50909695505050505050565b6000806000606084860312156156d757600080fd5b833592506020840135915060408401356001600160401b038111156156fb57600080fd5b61570786828701614c7c565b9150509250925092565b60008060006060848603121561572657600080fd5b61572f84614dc3565b9250602084013561503481614bf8565b60008060006060848603121561575457600080fd5b83359250602084013561503481614bf8565b600082601f83011261577757600080fd5b81356020615787614e6d83614e29565b82815260099290921b840181019181810190868411156157a657600080fd5b8286015b84811015614eac576157bc8882615397565b835291830191610200016157aa565b600080604083850312156157de57600080fd5b82356001600160401b03808211156157f557600080fd5b614f6c86838701615766565b6001600160e01b031991909116815260200190565b60008060006060848603121561582b57600080fd5b83356001600160401b038082111561584257600080fd5b61584e87838801614e4c565b945060209150818601358181111561586557600080fd5b61587188828901615766565b94505060408601358181111561588657600080fd5b86019050601f8101871361589957600080fd5b80356158a7614e6d82614e29565b81815260059190911b820183019083810190898311156158c657600080fd5b928401925b828410156158ed5783356158de81614bf8565b825292840192908401906158cb565b80955050505050509250925092565b6000806000806080858703121561591257600080fd5b843561591d81614bf8565b9350602085013561592d81614bf8565b92506040850135915060608501356001600160401b0381111561594f57600080fd5b61520187828801614c7c565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156159b057603f1988860301845261599e858351614d84565b94509285019290850190600101615982565b5092979650505050505050565b600080604083850312156159d057600080fd5b8235915060208301356001600160401b038111156159ed57600080fd5b614f8f85828601615125565b600080600080600080600080610100898b031215615a1657600080fd5b883597506020890135615a2881614bf8565b965060408901359550606089013594506080890135615a4681614bf8565b935060a0890135925060c0890135615a5d81615323565b915060e08901356001600160401b03811115615a7857600080fd5b615a848b828c01614c7c565b9150509295985092959890939650565b60008060008060808587031215615aaa57600080fd5b84359350602085013592506040850135615ac381614bf8565b9396929550929360600135925050565b600080600060608486031215615ae857600080fd5b83359250602084013561511481614bf8565b600060208284031215615b0c57600080fd5b8151614bf181615323565b634e487b7160e01b600052601160045260246000fd5b81810381811115610be457610be4615b17565b80820180821115610be457610be4615b17565b600181811c90821680615b6757607f821691505b602082108103615b8757634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b8082028115828204841417610be457610be4615b17565b600082615bd757634e487b7160e01b600052601260045260246000fd5b500490565b9283526001600160a01b039190911660208301526001600160401b0316604082015260600190565b6001600160401b0383168152604060208201526000610eed6040830184614d84565b600060208284031215615c3857600080fd5b8151614bf181614bf8565b601f821115610fd257600081815260208120601f850160051c81016020861015615c6a5750805b601f850160051c820191505b81811015611f5657828155600101615c76565b81516001600160401b03811115615ca257615ca2614c0d565b615cb681615cb08454615b53565b84615c43565b602080601f831160018114615ceb5760008415615cd35750858301515b600019600386901b1c1916600185901b178555611f56565b600085815260208120601f198616915b82811015615d1a57888601518255948401946001909101908401615cfb565b5085821015615d385787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052602160045260246000fd5b600060208284031215615d7057600080fd5b5051919050565b6000808454615d8581615b53565b60018281168015615d9d5760018114615db257615de1565b60ff1984168752821515830287019450615de1565b8860005260208060002060005b85811015615dd85781548a820152908401908201615dbf565b50505082870194505b505050508351615df5818360208801614d60565b64173539b7b760d91b9101908152600501949350505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090615e4190830184614d84565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190526000906155e090830184614d84565b600080600060608486031215615e9a57600080fd5b8351615ea581614bf8565b60208501516040860151919450925061566a81615323565b838152826020820152606060408201526000615edc6060830184614d84565b95945050505050565b6020808252825182820181905260009190848201906040850190845b818110156156b657835183529284019291840191600101615f01565b600060208284031215615f2f57600080fd5b8151614bf181614bbe565b634e487b7160e01b600052603160045260246000fdfe04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552dddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122039952d4782a7e4b932f08c2bbc8c389155a817876d8085102224ed5dcc1a3bf164736f6c63430008150033
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.