More Info
Private Name Tags
ContractCreator
TokenTracker
Sponsored
Latest 25 from a total of 27 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Add Self Reputat... | 40981807 | 564 days ago | IN | 0 POL | 0.10762435 | ||||
Add Self Reputat... | 40943541 | 565 days ago | IN | 0 POL | 0.11635189 | ||||
Add Self Reputat... | 40899405 | 566 days ago | IN | 0 POL | 0.08586203 | ||||
Add Reputation | 40897045 | 566 days ago | IN | 0 POL | 0.05787709 | ||||
Add Self Reputat... | 40877448 | 566 days ago | IN | 0 POL | 0.04306596 | ||||
Add Reputation | 40871664 | 567 days ago | IN | 0 POL | 0.06682959 | ||||
Add Reputation | 40871139 | 567 days ago | IN | 0 POL | 0.05801168 | ||||
Add Self Reputat... | 40858334 | 567 days ago | IN | 0 POL | 0.35024402 | ||||
Add Self Reputat... | 40858278 | 567 days ago | IN | 0 POL | 0.14225824 | ||||
Add Self Reputat... | 40840251 | 567 days ago | IN | 0 POL | 0.04807081 | ||||
Add Self Reputat... | 40838747 | 567 days ago | IN | 0 POL | 0.04791586 | ||||
Add Reputation | 40835992 | 567 days ago | IN | 0 POL | 0.0505909 | ||||
Add Reputation | 40835965 | 567 days ago | IN | 0 POL | 0.05164787 | ||||
Add Reputation | 40835963 | 567 days ago | IN | 0 POL | 0.05164787 | ||||
Add Reputation | 40832384 | 568 days ago | IN | 0 POL | 0.06222748 | ||||
Add Reputation | 40832382 | 568 days ago | IN | 0 POL | 0.06490651 | ||||
Add Self Reputat... | 40831659 | 568 days ago | IN | 0 POL | 0.07016545 | ||||
Add Self Reputat... | 40831166 | 568 days ago | IN | 0 POL | 0.47051771 | ||||
Add Self Reputat... | 40830876 | 568 days ago | IN | 0 POL | 0.26140108 | ||||
Add Reputation | 40801802 | 568 days ago | IN | 0 POL | 0.03178513 | ||||
Add Reputation | 40801659 | 568 days ago | IN | 0 POL | 0.04769516 | ||||
Add Reputation | 40800184 | 568 days ago | IN | 0 POL | 0.06667881 | ||||
Create Profile | 40795968 | 569 days ago | IN | 0 POL | 0.02766767 | ||||
Add Self Reputat... | 40793033 | 569 days ago | IN | 0 POL | 0.26150492 | ||||
Add Self Reputat... | 40791101 | 569 days ago | IN | 0 POL | 0.54208329 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
40789200 | 569 days ago | Contract Creation | 0 POL |
Loading...
Loading
Contract Name:
Profile
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.1; import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol"; import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; import {Ownable} from "./utils/Ownable.sol"; import {Reputation} from "./Reputation.sol"; contract Profile is RMRKNestable, Ownable { struct ProfileDetails { uint256 parentId; bytes32 twitterUidHash; bool isOrg; mapping(string reputationTokenId => bool) selfRep; } // address constant ENS_ADDRESS = 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e; bytes32 public merkleRoot; // merkle root of whitelisted users uint256 public tokenCounter; Reputation public immutable reputationContract; // ENS internal ens; mapping(address profile => ProfileDetails profileDetails) public profiles; mapping(bytes32 twitterUidHash => bool exists) internal twitterUidHashes; event MerkleRootUpdated(bytes32 merkleRoot); event ProfileCreated(address indexed owner, uint256 indexed tokenId); event OrganizationApproved(uint256 indexed profileId); error InvalidOrganization(address profile); error ProfileAlreadyExists(address profile); error TwitterProfileAlreadyConnected(bytes32 twitterUidHash); constructor( string memory name, string memory symbol, address multisigOwner // bytes32 _merkleRoot ) RMRKNestable(name, symbol) Ownable(multisigOwner, address(0)) { // merkleRoot = _merkleRoot; tokenCounter = 1; // Id cannot be zero, because of https://github.com/rmrk-team/evm/blob/dev/contracts/RMRK/nestable/RMRKNestable.sol#LL512-L512C56 reputationContract = new Reputation("BLSM Reputation", "BLSMR", address(this)); } function createProfile( bytes32 twitterUidHash, bytes32 whitelistedOrgLeaf, bytes32[] memory proof ) external { if (merkleRoot != "" && !MerkleProof.verify(proof, merkleRoot, whitelistedOrgLeaf)) { revert InvalidOrganization(msg.sender); } if(profiles[msg.sender].twitterUidHash != 0x0) { revert ProfileAlreadyExists(msg.sender); } if(twitterUidHashes[twitterUidHash]) { revert TwitterProfileAlreadyConnected(twitterUidHash); } _safeMint(msg.sender, tokenCounter, "0x0"); // we could pass additional data here profiles[msg.sender].parentId = tokenCounter; profiles[msg.sender].twitterUidHash = twitterUidHash; twitterUidHashes[twitterUidHash] = true; emit ProfileCreated(msg.sender, tokenCounter); unchecked { tokenCounter++; } } function getReputations(address profile) external view returns (Child[] memory) { return childrenOf(profiles[profile].parentId); } function addSelfReputations(string[] memory reputationTokenIds) external { uint256 parentId = profiles[msg.sender].parentId; require(parentId != 0, "Profile does not exist"); for(uint256 i = 0; i < reputationTokenIds.length; i++) { reputationContract.giveCred(parentId, parentId, reputationTokenIds[i], ''); Child[] memory children = pendingChildrenOf(parentId); Child memory lastChild = children[children.length - 1]; _acceptChild(parentId, children.length - 1, lastChild.contractAddress, lastChild.tokenId); profiles[msg.sender].selfRep[reputationTokenIds[i]] = true; } } function addReputation(address receiver, string memory reputationTokenIds, string memory message) external { uint256 senderId = profiles[msg.sender].parentId; require(senderId != 0, "Sender does not exist"); uint256 receiverId = profiles[receiver].parentId; require(receiverId != 0, "Receiver does not exist"); reputationContract.giveCred(senderId, receiverId, reputationTokenIds, message); Child[] memory children = pendingChildrenOf(receiverId); Child memory lastChild = children[children.length - 1]; _acceptChild(receiverId, children.length - 1, lastChild.contractAddress, lastChild.tokenId); } function displayReputationInProfile(uint256 childIndex, uint256 childId) external { _acceptChild(profiles[msg.sender].parentId, childIndex, address(reputationContract), childId); } function hideReputationFromProfile(string memory reputationTokenId) external { profiles[msg.sender].selfRep[reputationTokenId] = false; } function approveOrganization(uint256 profileId) external onlyOwner { (address directOwner,,) = directOwnerOf(profileId); profiles[directOwner].isOrg = true; emit OrganizationApproved(profileId); } function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner { merkleRoot = _merkleRoot; emit MerkleRootUpdated(_merkleRoot); } // // helper function // function computeNamehash(string memory name) public pure returns (bytes32 namehash) { // namehash = 0x0000000000000000000000000000000000000000000000000000000000000000; // namehash = keccak256(abi.encodePacked(namehash, keccak256(abi.encodePacked("eth")))); // namehash = keccak256(abi.encodePacked(namehash, keccak256(abi.encodePacked(name)))); // } // helper function // Today, Twitter IDs are unique 64-bit unsigned integers, function hashTwitterUid(uint64 twitterUid) public pure returns (bytes32) { return keccak256(abi.encodePacked(twitterUid)); } function _beforeNestedTokenTransfer( address from, address to, uint256 fromTokenId, uint256 toTokenId, uint256 tokenId, bytes memory data ) internal pure override { require(from == address(0) || to == address(0), "Soulbound token"); } // ovo isto treba i za _beforeBurn da se preventuje burning }
// 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 (last updated v4.7.0) (utils/Base64.sol) pragma solidity ^0.8.0; /** * @dev Provides a set of functions to operate with Base64 strings. * * _Available since v4.5._ */ library Base64 { /** * @dev Base64 Encoding/Decoding Table */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { /** * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol */ if (data.length == 0) return ""; // Loads the table into memory string memory table = _TABLE; // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter // and split into 4 numbers of 6 bits. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up // - `data.length + 2` -> Round up // - `/ 3` -> Number of 3-bytes chunks // - `4 *` -> 4 characters for each chunk string memory result = new string(4 * ((data.length + 2) / 3)); /// @solidity memory-safe-assembly assembly { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 32) // Run over the input, 3 bytes at a time for { let dataPtr := data let endPtr := add(data, mload(data)) } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 bytes (18 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F which is the number of // the previous character in the ASCII table prior to the Base64 Table // The result is then added to the table to get the character to write, // and finally write it in the result pointer but with a left shift // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) resultPtr := add(resultPtr, 1) // Advance } // When data `bytes` is not exactly 3 bytes long // it is padded with `=` characters at the end switch mod(mload(data), 3) case 1 { mstore8(sub(resultPtr, 1), 0x3d) mstore8(sub(resultPtr, 2), 0x3d) } case 2 { mstore8(sub(resultPtr, 1), 0x3d) } } return result; } }
// 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 (last updated v4.8.0) (utils/cryptography/MerkleProof.sol) pragma solidity ^0.8.0; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify( bytes32[] memory proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} * * _Available since v4.7._ */ function verifyCalldata( bytes32[] calldata proof, bytes32 root, bytes32 leaf ) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. * * _Available since v4.4._ */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} * * _Available since v4.7._ */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). * * _Available since v4.7._ */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. * * _Available since v4.7._ */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the merkle tree. uint256 leavesLen = leaves.length; uint256 totalHashes = proofFlags.length; // Check proof validity. require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { return hashes[totalHashes - 1]; } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
// 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.18; /** * @title IRMRKCore * @author RMRK team * @notice Interface smart contract for RMRK core module. */ interface IRMRKCore { /** * @notice Used to retrieve the collection name. * @return Name of the collection */ function name() external view returns (string memory); /** * @notice Used to retrieve the collection symbol. * @return Symbol of the collection */ function symbol() external view returns (string memory); }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; import "./IRMRKCore.sol"; /** * @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 is IRMRKCore { /** * @notice Version of the @rmrk-team/evm-contracts package * @return Version identifier of the smart contract */ string public constant VERSION = "0.27.1"; /** * @notice Used to initialize the smart contract. * @param name_ Name of the token collection * @param symbol_ Symbol of the token collection */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /// Token name string private _name; /// Token symbol string private _symbol; /** * @notice Used to retrieve the collection name. * @return Name of the collection */ function name() public view virtual override returns (string memory) { return _name; } /** * @notice Used to retrieve the collection symbol. * @return Symbol of the collection */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @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 {} }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; /// @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 equip a `Part` with a child not approved by the Catalog error RMRKEquippableEquipNotAllowedByCatalog(); /// Attempting to use ID 0, which is not supported /// @dev The ID 0 in RMRK suite is reserved for empty values. Guarding against its use ensures the expected operation error RMRKIdZeroForbidden(); /// Attempting to interact with an asset, using index greater than number of assets error RMRKIndexOutOfRange(); /// Attempting to reclaim a child that can't be reclaimed error RMRKInvalidChildReclaim(); /// Attempting to interact with an end-user account when the contract account is expected error RMRKIsNotContract(); /// Attempting to interact with a contract that had its operation locked error RMRKLocked(); /// Attempting to add a pending child after the number of pending children has reached the limit (default limit is 128) error RMRKMaxPendingChildrenReached(); /// Attempting to add a pending asset after the number of pending assets has reached the limit (default limit is /// 128) error RMRKMaxPendingAssetsReached(); /// Attempting to burn a total number of recursive children higher than maximum set /// @param childContract Address of the collection smart contract in which the maximum number of recursive burns was reached /// @param childId ID of the child token at which the maximum number of recursive burns was reached error RMRKMaxRecursiveBurnsReached(address childContract, uint256 childId); /// Attempting to mint a number of tokens that would cause the total supply to be greater than maximum supply error RMRKMintOverMax(); /// Attempting to mint a nested token to a smart contract that doesn't support nesting error RMRKMintToNonRMRKNestableImplementer(); /// Attempting to transfer a child before it is unequipped error RMRKMustUnequipFirst(); /// Attempting to nest a child over the nestable limit (current limit is 100 levels of nesting) error RMRKNestableTooDeep(); /// Attempting to nest the token to own descendant, which would create a loop and leave the looped tokens in limbo error RMRKNestableTransferToDescendant(); /// Attempting to nest the token to a smart contract that doesn't support nesting error RMRKNestableTransferToNonRMRKNestableImplementer(); /// Attempting to nest the token into itself error RMRKNestableTransferToSelf(); /// Attempting to interact with an asset that can not be found error RMRKNoAssetMatchingId(); /// Attempting to manage an asset without owning it or having been granted permission by the owner to do so error RMRKNotApprovedForAssetsOrOwner(); /// Attempting to interact with a token without being its owner or having been granted permission by the /// owner to do so /// @dev When a token is nested, only the direct owner (NFT parent) can mange it. In that case, approved addresses are /// not allowed to manage it, in order to ensure the expected behaviour error RMRKNotApprovedOrDirectOwner(); /// Attempting to compose an asset wihtout having an associated Catalog error RMRKNotComposableAsset(); /// Attempting to unequip an item that isn't equipped error RMRKNotEquipped(); /// Attempting to interact with a management function without being the smart contract's owner error RMRKNotOwner(); /// Attempting to interact with a function without being the owner or contributor of the collection error RMRKNotOwnerOrContributor(); /// Attempting to transfer the ownership to the 0x0 address error RMRKNewOwnerIsZeroAddress(); /// Attempting to assign a 0x0 address as a contributor error RMRKNewContributorIsZeroAddress(); /// Attempting an operation requiring the token being nested, while it is not error RMRKParentIsNotNFT(); /// Attempting to add a `Part` with an ID that is already used error RMRKPartAlreadyExists(); /// Attempting to use a `Part` that doesn't exist error RMRKPartDoesNotExist(); /// Attempting to use a `Part` that is `Fixed` when `Slot` kind of `Part` should be used error RMRKPartIsNotSlot(); /// Attempting to interact with a pending child using an index greater than the size of pending array error RMRKPendingChildIndexOutOfRange(); /// Attempting to add an asset using an ID that has already been used error RMRKAssetAlreadyExists(); /// Attempting to equip an item into a slot that already has an item equipped error RMRKSlotAlreadyUsed(); /// Attempting to equip an item into a `Slot` that the target asset does not implement error RMRKTargetAssetCannotReceiveSlot(); /// Attempting to equip a child into a `Slot` and parent that the child's collection doesn't support error RMRKTokenCannotBeEquippedWithAssetIntoSlot(); /// Attempting to compose a NFT of a token without active assets error RMRKTokenDoesNotHaveAsset(); /// Attempting to determine the asset with the top priority on a token without assets error RMRKTokenHasNoAssets(); /// Attempting to accept or transfer a child which does not match the one at the specified index error RMRKUnexpectedChildId(); /// Attempting to reject all pending assets but more assets than expected are pending error RMRKUnexpectedNumberOfAssets(); /// Attempting to reject all pending children but children assets than expected are pending error RMRKUnexpectedNumberOfChildren(); /// Attempting to accept or reject an asset which does not match the one at the specified index error RMRKUnexpectedAssetId(); /// Attempting an operation expecting a parent to the token which is not the actual one error RMRKUnexpectedParent(); /// Attempting not to pass an empty array of equippable addresses when adding or setting the equippable addresses error RMRKZeroLengthIdsPassed(); /// Attempting to set the royalties to a value higher than 100% (10000 in base points) error RMRKRoyaltiesTooHigh();
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title IRMRKNestable * @author RMRK team * @notice Interface smart contract of the RMRK nestable module. */ interface IRMRKNestable 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; bool isNft; } /** * @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: Apache-2.0 //Generally all interactions should propagate downstream pragma solidity ^0.8.18; import "./IRMRKNestable.sol"; import "../core/RMRKCore.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; 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 "../library/RMRKErrors.sol"; /** * @title RMRKNestable * @author RMRK team * @notice Smart contract of the RMRK Nestable module. * @dev This contract is hierarchy agnostic and can support an arbitrary number of nested levels up and down, as long as * gas limits allow it. */ contract RMRKNestable is Context, IERC165, IERC721, IRMRKNestable, RMRKCore { 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)) private _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 { if (!_isApprovedOrOwner(_msgSender(), tokenId)) 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 { if (!_isApprovedOrDirectOwner(_msgSender(), tokenId)) 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); _; } // ----------------------------- CONSTRUCTOR ------------------------------ /** * @notice Initializes the contract by setting a `name` and a `symbol` to the token collection. * @param name_ Name of the token collection * @param symbol_ Symbol of the token collection */ constructor( string memory name_, string memory symbol_ ) RMRKCore(name_, symbol_) {} // ------------------------------- ERC721 --------------------------------- /** * @inheritdoc IERC165 */ function supportsInterface( bytes4 interfaceId ) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || interfaceId == type(IRMRKNestable).interfaceId; } /** * @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) { _safeTransfer(from, to, tokenId, data); } /** * @inheritdoc IRMRKNestable */ function nestTransferFrom( address from, address to, uint256 tokenId, uint256 destinationId, bytes memory data ) public virtual onlyApprovedOrDirectOwner(tokenId) { _nestTransfer(from, to, tokenId, destinationId, data); } /** * @notice Used to safely transfer the token form `from` to `to`. * @dev The function checks that contract recipients are aware of the ERC721 protocol to prevent tokens from being * forever locked. * @dev This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. implement alternative * mechanisms to perform token transfer, such as signature-based. * @dev Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - 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 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 _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId, data); if (!_checkOnERC721Received(from, to, tokenId, data)) revert ERC721TransferToNonReceiverImplementer(); } /** * @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( immediateOwner, to, parentId, 0, tokenId, data ); _balances[from] -= 1; _updateOwnerAndClearApprovals(tokenId, 0, to, false); _balances[to] += 1; emit Transfer(from, to, tokenId); emit NestTransfer(immediateOwner, to, parentId, 0, tokenId); _afterTokenTransfer(from, to, tokenId); _afterNestedTokenTransfer( immediateOwner, to, parentId, 0, tokenId, data ); } /** * @notice Used to transfer a token into another token. * @dev Attempting to nest a token into `0x0` address will result in reverted transaction. * @dev Attempting to nest a token into itself will result in reverted transaction. * @param from Address of the account currently owning the given token * @param to Address of the receiving token's collection smart contract * @param tokenId ID of the token to transfer * @param destinationId ID of the token receiving the given token * @param data Additional data with no specified format, sent in the addChild call */ function _nestTransfer( address from, address to, uint256 tokenId, uint256 destinationId, bytes memory data ) internal virtual { (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(IRMRKNestable).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, true); _balances[to] += 1; // Sending to NFT: _sendToNFT(immediateOwner, to, parentId, destinationId, 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 { IRMRKNestable destContract = IRMRKNestable(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 ) = IRMRKNestable(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 { _mint(to, tokenId, data); if (!_checkOnERC721Received(address(0), to, tokenId, data)) revert ERC721TransferToNonReceiverImplementer(); } /** * @notice Used to mint a specified token to a given address. * @dev WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible. * @dev Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * @dev Emits a {Transfer} event. * @dev Emits a {NestTransfer} event. * @param to Address to mint the token to * @param tokenId ID of the token to mint * @param data Additional data with no specified format, sent in call to `to` */ function _mint( 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); } /** * @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(IRMRKNestable).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 == 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, isNft: destinationId != 0 }); } //////////////////////////////////////// // Ownership //////////////////////////////////////// /** * @inheritdoc IRMRKNestable */ function ownerOf( uint256 tokenId ) public view virtual override(IRMRKNestable, IERC721) returns (address) { (address owner, uint256 ownerTokenId, bool isNft) = directOwnerOf( tokenId ); if (isNft) { owner = IRMRKNestable(owner).ownerOf(ownerTokenId); } return owner; } /** * @inheritdoc IRMRKNestable */ 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.isNft); } //////////////////////////////////////// // 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 IRMRKNestable */ function burn( uint256 tokenId, uint256 maxChildrenBurns ) public virtual onlyApprovedOrDirectOwner(tokenId) returns (uint256) { return _burn(tokenId, maxChildrenBurns); } /** * @notice Used to burn a token. * @dev When a token is burned, its children are recursively burned as well. * @dev The approvals are cleared when the token is burned. * @dev Requirements: * * - `tokenId` must exist. * @dev Emits a {Transfer} event. * @dev Emits a {NestTransfer} event. * @param tokenId ID of the token to burn * @param maxChildrenBurns Maximum children to recursively burn * @return The number of recursive burns it took to burn all of the children */ function _burn( uint256 tokenId, uint256 maxChildrenBurns ) internal virtual returns (uint256) { (address immediateOwner, uint256 parentId, ) = directOwnerOf(tokenId); address owner = ownerOf(tokenId); _balances[immediateOwner] -= 1; _beforeTokenTransfer(owner, address(0), tokenId); _beforeNestedTokenTransfer( immediateOwner, address(0), parentId, 0, tokenId, "" ); _approve(address(0), tokenId); _cleanApprovals(tokenId); Child[] memory children = childrenOf(tokenId); delete _activeChildren[tokenId]; delete _pendingChildren[tokenId]; delete _tokenApprovals[tokenId][owner]; 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 += IRMRKNestable(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(owner, address(0), tokenId); emit NestTransfer(immediateOwner, address(0), parentId, 0, tokenId); _afterTokenTransfer(owner, 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 * @param isNft A boolean value signifying whether the new owner is a token (`true`) or externally owned account * (`false`) */ function _updateOwnerAndClearApprovals( uint256 tokenId, uint256 destinationId, address to, bool isNft ) internal { _RMRKOwners[tokenId] = DirectOwner({ ownerAddress: to, tokenId: destinationId, isNft: isNft }); // Clear approvals from the previous owner _approve(address(0), tokenId); _cleanApprovals(tokenId); } /** * @notice Used to remove approvals for the current owner of the given token. * @param tokenId ID of the token to clear the approvals for */ function _cleanApprovals(uint256 tokenId) internal virtual {} //////////////////////////////////////// // UTILS //////////////////////////////////////// /** * @notice Used to check whether the given account is allowed to manage the given token. * @dev Requirements: * * - `tokenId` must exist. * @param spender Address that is being checked for approval * @param tokenId ID of the token being checked * @return A boolean value indicating whether the `spender` is approved to manage the given token */ function _isApprovedOrOwner( address spender, uint256 tokenId ) internal view virtual returns (bool) { address owner = ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @notice Used to check whether the account is approved to manage the token or its direct owner. * @param spender Address that is being checked for approval or direct ownership * @param tokenId ID of the token being checked * @return A boolean value indicating whether the `spender` is approved to manage the given token or its * direct owner */ function _isApprovedOrDirectOwner( address spender, uint256 tokenId ) internal view virtual returns (bool) { (address owner, uint256 parentId, ) = directOwnerOf(tokenId); // When the parent is an NFT, only it can do operations if (parentId != 0) { return (spender == owner); } // Otherwise, the owner or approved address can return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @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 == 0) { revert ERC721TransferToNonReceiverImplementer(); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } //////////////////////////////////////// // CHILD MANAGEMENT PUBLIC //////////////////////////////////////// /** * @inheritdoc IRMRKNestable */ 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 IRMRKNestable */ 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 IRMRKNestable */ function rejectAllChildren( uint256 tokenId, uint256 maxRejections ) public virtual onlyApprovedOrOwner(tokenId) { _rejectAllChildren(tokenId, maxRejections); } /** * @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: * * - `tokenId` must exist * @dev Emits ***AllChildrenRejected*** event. * @param tokenId 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 tokenId, uint256 maxRejections ) internal virtual { if (_pendingChildren[tokenId].length > maxRejections) revert RMRKUnexpectedNumberOfChildren(); _beforeRejectAllChildren(tokenId); delete _pendingChildren[tokenId]; emit AllChildrenRejected(tokenId); _afterRejectAllChildren(tokenId); } /** * @inheritdoc IRMRKNestable */ function transferChild( uint256 tokenId, address to, uint256 destinationId, uint256 childIndex, address childAddress, uint256 childId, bool isPending, bytes memory data ) public virtual onlyApprovedOrOwner(tokenId) { _transferChild( tokenId, to, destinationId, childIndex, childAddress, childId, isPending, data ); } /** * @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. * @dev Requirements: * * - `tokenId` must exist. * @dev Emits {ChildTransferred} event. * @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, // newParentId uint256 childIndex, address childAddress, uint256 childId, bool isPending, bytes memory data ) internal virtual { Child memory child; if (isPending) { child = pendingChildOf(tokenId, childIndex); } else { 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 == 0) { IERC721(childAddress).safeTransferFrom( address(this), to, childId, data ); } else { // Destination is an NFT IRMRKNestable(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 IRMRKNestable */ function childrenOf( uint256 parentId ) public view virtual returns (Child[] memory) { Child[] memory children = _activeChildren[parentId]; return children; } /** * @inheritdoc IRMRKNestable */ function pendingChildrenOf( uint256 parentId ) public view virtual returns (Child[] memory) { Child[] memory pendingChildren = _pendingChildren[parentId]; return pendingChildren; } /** * @inheritdoc IRMRKNestable */ 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 IRMRKNestable */ 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; } /** * @notice Used to verify that the given child tokwn is included in an active array of a token. * @param childAddress Address of the given token's collection smart contract * @param childId ID of the child token being checked * @return A boolean value signifying whether the given child token is included in an active child tokens array of a * token (`true`) or not (`false`) */ function childIsInActive( address childAddress, uint256 childId ) public view virtual returns (bool) { return _childIsInActive[childAddress][childId] != 0; } // HOOKS /** * @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(); } }
// SPDX-License-Identifier: Apache-2.0 import "@rmrk-team/evm-contracts/contracts/RMRK/nestable/RMRKNestable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@openzeppelin/contracts/utils/Base64.sol"; import {Ownable} from "./utils/Ownable.sol"; pragma solidity ^0.8.18; // gatekeeping // optional emits // categories logic // optional comment from issuer contract Reputation is RMRKNestable, Ownable { uint256 private tokenCounter; /* ===================================== Things we wanna have in ReputationNFT ===================================== issuerNftId - id of profile nft that gave cred receiverNftId - id of profile NFT that gets cred categoryId - id of category this person is getting cred for bytes message - comment related to the reputation, better to store on ipfs */ struct Cred { uint256 credTokenId; uint256 issuerNftId; uint256 receiverNftId; string categoryId; string message; } mapping(uint256 credTokenId => Cred givenCreds) public givenCreds; mapping(uint256 tokenId => string tokenUri) public tokenUris; mapping(bytes32 hashed => bool used) internal usedHashes; event ReputationMinted(address indexed recipient, uint256 indexed tokenId); // // TODO // string public constant TOKEN_URI = // "ipfs://bafybeig37ioir76s7mg5oobetncojcm3c3hxasyd4rvid4jqhy4gkaheg4/?filename=0-PUG.json"; constructor( string memory name, string memory symbol, address owner ) RMRKNestable(name, symbol) Ownable(owner, address(0)) { // Custom optional: constructor logic tokenCounter = 1; } // minting reputation NFT as nested NFT function giveCred(uint256 issuerId, uint256 recipientId, string memory categoryId, string memory message) public { _checkOwner(); bytes32 hashInput = hash(issuerId, recipientId, categoryId); require(!usedHashes[hashInput], "Reputation already minted"); usedHashes[hashInput] = true; _nestMint(owner(), tokenCounter, recipientId, bytes(message)); string memory json = Base64.encode( bytes( string( abi.encodePacked( '{"name": "', categoryId, // #TODO: check if we want this for name '", "description": "Blossoms", "image": "https://ipfs.io/ipfs/QmSsYRx3LpDAb1GZQm7zZ1AuHZjfbPkD6J7s9r41xu1mf8?filename=pug.png"}' ) ) ) ); string memory tokenUri = string( abi.encodePacked("data:application/json;base64,", json) ); tokenUris[tokenCounter] = tokenUri; givenCreds[tokenCounter] = Cred(tokenCounter, issuerId, recipientId, categoryId, message); emit ReputationMinted(owner(), tokenCounter); unchecked {tokenCounter++;} } function hash(uint256 issuerId, uint256 reciverId, string memory categoryId) internal pure returns(bytes32) { return keccak256(abi.encodePacked(issuerId, reciverId, categoryId)); } function getTokenUri(uint256 tokenId) public view returns (string memory) { return tokenUris[tokenId]; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; /** * @title The Ownable contract * @notice An abstract contract for ownership managment */ abstract contract Ownable { address private _owner; address private _pendingOwner; event OwnershipTransferRequested(address indexed from, address indexed to); event OwnershipTransferred(address indexed from, address indexed to); event OwnershipTransferCanceled(address indexed from, address indexed to); error CannotSetOwnerToZeroAddress(); error MustBeProposedOwner(); error CallerIsNotOwner(); error CannotTransferToSelf(); modifier onlyOwner() { _checkOwner(); _; } constructor(address newOwner, address pendingOwner) { if (newOwner == address(0)) revert CannotSetOwnerToZeroAddress(); _owner = newOwner; if (pendingOwner != address(0)) _transferOwnership(pendingOwner); } /** * @notice Requests ownership transfer to the new address which needs to accept it. * * @dev Only owner can call. * * @param newOwner - address of proposed new owner * * No return, reverts on error. */ function transferOwnership(address newOwner) external onlyOwner { _transferOwnership(newOwner); } /** * @notice Accepts pending ownership transfer request. * * @dev Only proposed new owner can call. * * No return, revets on error. */ function acceptOwnership() external { if (msg.sender != _pendingOwner) revert MustBeProposedOwner(); address oldOwner = _owner; _owner = msg.sender; _pendingOwner = address(0); emit OwnershipTransferred(oldOwner, msg.sender); } /** * @notice Cancels ownership request transfer. * * @dev Only owner can call. * * No return, reverts on error. */ function cancelOwnershipTransfer() external onlyOwner { address oldPendingOwner = _pendingOwner; _pendingOwner = address(0); emit OwnershipTransferCanceled(msg.sender, oldPendingOwner); } /** * @notice Gets current owner address. * * @return owner */ function owner() public view returns (address) { return _owner; } /** * @notice Gets pending owner address. * * @return pendingOwner */ function getPendingOwner() public view returns (address) { return _pendingOwner; } function _checkOwner() internal view { if (msg.sender != owner()) revert CallerIsNotOwner(); } function _transferOwnership(address newOwner) private { if (newOwner == address(0)) revert CannotSetOwnerToZeroAddress(); if (newOwner == msg.sender) revert CannotTransferToSelf(); _pendingOwner = newOwner; emit OwnershipTransferRequested(msg.sender, newOwner); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"multisigOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerIsNotOwner","type":"error"},{"inputs":[],"name":"CannotSetOwnerToZeroAddress","type":"error"},{"inputs":[],"name":"CannotTransferToSelf","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":[{"internalType":"address","name":"profile","type":"address"}],"name":"InvalidOrganization","type":"error"},{"inputs":[],"name":"MustBeProposedOwner","type":"error"},{"inputs":[{"internalType":"address","name":"profile","type":"address"}],"name":"ProfileAlreadyExists","type":"error"},{"inputs":[],"name":"RMRKChildAlreadyExists","type":"error"},{"inputs":[],"name":"RMRKChildIndexOutOfRange","type":"error"},{"inputs":[],"name":"RMRKIdZeroForbidden","type":"error"},{"inputs":[],"name":"RMRKIsNotContract","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":"RMRKNestableTooDeep","type":"error"},{"inputs":[],"name":"RMRKNestableTransferToDescendant","type":"error"},{"inputs":[],"name":"RMRKNestableTransferToNonRMRKNestableImplementer","type":"error"},{"inputs":[],"name":"RMRKNestableTransferToSelf","type":"error"},{"inputs":[],"name":"RMRKNotApprovedOrDirectOwner","type":"error"},{"inputs":[],"name":"RMRKPendingChildIndexOutOfRange","type":"error"},{"inputs":[],"name":"RMRKUnexpectedChildId","type":"error"},{"inputs":[],"name":"RMRKUnexpectedNumberOfChildren","type":"error"},{"inputs":[{"internalType":"bytes32","name":"twitterUidHash","type":"bytes32"}],"name":"TwitterProfileAlreadyConnected","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":"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":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":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"MerkleRootUpdated","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":"uint256","name":"profileId","type":"uint256"}],"name":"OrganizationApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ProfileCreated","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"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":[],"name":"acceptOwnership","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":"address","name":"receiver","type":"address"},{"internalType":"string","name":"reputationTokenIds","type":"string"},{"internalType":"string","name":"message","type":"string"}],"name":"addReputation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"reputationTokenIds","type":"string[]"}],"name":"addSelfReputations","outputs":[],"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":"uint256","name":"profileId","type":"uint256"}],"name":"approveOrganization","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":[{"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":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"childAddress","type":"address"},{"internalType":"uint256","name":"childId","type":"uint256"}],"name":"childIsInActive","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 IRMRKNestable.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 IRMRKNestable.Child[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"twitterUidHash","type":"bytes32"},{"internalType":"bytes32","name":"whitelistedOrgLeaf","type":"bytes32"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"createProfile","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"childIndex","type":"uint256"},{"internalType":"uint256","name":"childId","type":"uint256"}],"name":"displayReputationInProfile","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"profile","type":"address"}],"name":"getReputations","outputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"contractAddress","type":"address"}],"internalType":"struct IRMRKNestable.Child[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"twitterUid","type":"uint64"}],"name":"hashTwitterUid","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"reputationTokenId","type":"string"}],"name":"hideReputationFromProfile","outputs":[],"stateMutability":"nonpayable","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":[],"name":"merkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","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":"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 IRMRKNestable.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 IRMRKNestable.Child[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"profile","type":"address"}],"name":"profiles","outputs":[{"internalType":"uint256","name":"parentId","type":"uint256"},{"internalType":"bytes32","name":"twitterUidHash","type":"bytes32"},{"internalType":"bool","name":"isOrg","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"maxRejections","type":"uint256"}],"name":"rejectAllChildren","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reputationContract","outputs":[{"internalType":"contract Reputation","name":"","type":"address"}],"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":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMerkleRoot","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":[],"name":"tokenCounter","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"}]
Contract Creation Code
60a06040523480156200001157600080fd5b5060405162006f8638038062006f868339810160408190526200003491620002c8565b8060008484818184620000488382620003e4565b506001620000578282620003e4565b5050506001600160a01b0384169150620000869050576040516342b66a3d60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0384811691909117909155811615620000b957620000b98162000157565b50506001600c556040513090620000d090620001f5565b6060808252600f908201526e212629a6902932b83aba30ba34b7b760891b608082015260a06020820181905260059082015264212629a6a960d91b60c08201526001600160a01b03909116604082015260e001604051809103906000f08015801562000140573d6000803e3d6000fd5b506001600160a01b031660805250620004b0915050565b6001600160a01b0381166200017f576040516342b66a3d60e01b815260040160405180910390fd5b336001600160a01b03821603620001a957604051636d6c4ee560e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b03831690811790915560405133907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b61368a80620038fc83390190565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200022b57600080fd5b81516001600160401b038082111562000248576200024862000203565b604051601f8301601f19908116603f0116810190828211818310171562000273576200027362000203565b816040528381526020925086838588010111156200029057600080fd5b600091505b83821015620002b4578582018301518183018401529082019062000295565b600093810190920192909252949350505050565b600080600060608486031215620002de57600080fd5b83516001600160401b0380821115620002f657600080fd5b620003048783880162000219565b945060208601519150808211156200031b57600080fd5b506200032a8682870162000219565b604086015190935090506001600160a01b03811681146200034a57600080fd5b809150509250925092565b600181811c908216806200036a57607f821691505b6020821081036200038b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003df57600081815260208120601f850160051c81016020861015620003ba5750805b601f850160051c820191505b81811015620003db57828155600101620003c6565b5050505b505050565b81516001600160401b0381111562000400576200040062000203565b620004188162000411845462000355565b8462000391565b602080601f831160018114620004505760008415620004375750858301515b600019600386901b1c1916600185901b178555620003db565b600085815260208120601f198616915b82811015620004815788860151825594840194600190910190840162000460565b5085821015620004a05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161341b620004e1600039600081816104b70152818161095601528181610b2b0152611082015261341b6000f3fe608060405234801561001057600080fd5b50600436106102745760003560e01c8063736d7f8811610151578063b390c0ab116100c3578063defa80c311610087578063defa80c314610615578063e97ceaa814610628578063e985e9c51461063b578063f2fde38b1461064e578063fb25fb7a14610661578063ffa1ad741461069b57600080fd5b8063b390c0ab14610584578063b88d4fde14610597578063bbe15627146105aa578063d082e381146105f9578063d7e29cd51461060257600080fd5b806393596c7b1161011557806393596c7b146104ea57806395d89b41146104fb57806397961336146105035780639813c5b614610516578063a22cb4651461055e578063a898e3641461057157600080fd5b8063736d7f881461048457806379ba5097146104975780637cb647591461049f57806387bc1425146104b25780638da5cb5b146104d957600080fd5b80632f32f937116101ea57806344ec9344116101ae57806344ec9344146104125780636352211e14610425578063635490cc146104385780636bed127f1461044b5780636f19951c1461045e57806370a082311461047157600080fd5b80632f32f937146103815780634182e4a3146103a157806342842e0e146103d957806342966c68146103ec57806344305f2c146103ff57600080fd5b8063095ea7b31161023c578063095ea7b3146103165780630dddf0631461032957806321a8be9d1461033c57806323452b9c1461034f57806323b872dd146103575780632eb4a7ab1461036a57600080fd5b806301ffc9a714610279578063064c0a3a146102a157806306fdde03146102b6578063081812fc146102cb5780630846b3bc146102f6575b600080fd5b61028c6102873660046129be565b6106c0565b60405190151581526020015b60405180910390f35b6102b46102af366004612aa7565b61072d565b005b6102be61074c565b6040516102989190612b6d565b6102de6102d9366004612b80565b6107de565b6040516001600160a01b039091168152602001610298565b610309610304366004612b99565b610824565b6040516102989190612bb6565b6102b4610324366004612c16565b610849565b6102b4610337366004612b80565b6108d5565b6102b461034a366004612c42565b61093f565b6102b461097f565b6102b4610365366004612c64565b6109d5565b610373600b5481565b604051908152602001610298565b61039461038f366004612c42565b610a00565b6040516102989190612ca5565b61028c6103af366004612c16565b6001600160a01b039190911660009081526008602090815260408083209383529290522054151590565b6102b46103e7366004612c64565b610a99565b6102b46103fa366004612b80565b610ab4565b6102b461040d366004612ce9565b610abf565b610309610420366004612b80565b610c8e565b6102de610433366004612b80565b610d0d565b6102b4610446366004612d92565b610d9d565b6102b4610459366004612de2565b610eaf565b61030961046c366004612b80565b610ef5565b61037361047f366004612b99565b610f65565b6102b4610492366004612e17565b610faa565b6102b4611142565b6102b46104ad366004612b80565b6111c8565b6102de7f000000000000000000000000000000000000000000000000000000000000000081565b6009546001600160a01b03166102de565b600a546001600160a01b03166102de565b6102be61120b565b6102b4610511366004612c42565b61121a565b610373610524366004612e83565b6040516001600160c01b031960c083901b166020820152600090602801604051602081830303815290604052805190602001209050919050565b6102b461056c366004612ebb565b61122e565b61039461057f366004612c42565b6112c3565b610373610592366004612c42565b611320565b6102b46105a5366004612ef4565b61133e565b6105dc6105b8366004612b99565b600d6020526000908152604090208054600182015460029092015490919060ff1683565b604080519384526020840192909252151590820152606001610298565b610373600c5481565b6102b4610610366004612f60565b61135b565b6102b4610623366004613006565b611496565b6102b46106363660046130a2565b6114bb565b61028c6106493660046130e1565b6114d1565b6102b461065c366004612b99565b6114ff565b61067461066f366004612b80565b611513565b604080516001600160a01b0390941684526020840192909252151590820152606001610298565b6102be60405180604001604052806006815260200165302e32372e3160d01b81525081565b60006001600160e01b031982166301ffc9a760e01b14806106f157506001600160e01b031982166380ac58cd60e01b145b8061070c57506001600160e01b03198216635b5e139f60e01b145b8061072757506001600160e01b031982166342b0e56f60e01b145b92915050565b8261073781611594565b61074486868686866115bb565b505050505050565b60606000805461075b9061310f565b80601f01602080910402602001604051908101604052809291908181526020018280546107879061310f565b80156107d45780601f106107a9576101008083540402835291602001916107d4565b820191906000526020600020905b8154815290600101906020018083116107b757829003601f168201915b5050505050905090565b60006107e9826117a0565b60008281526003602052604081209061080184610d0d565b6001600160a01b0390811682526020820192909252604001600020541692915050565b6001600160a01b0381166000908152600d602052604090205460609061072790610ef5565b600061085482610d0d565b9050806001600160a01b0316836001600160a01b03160361088857604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b038216148015906108a857506108a681336114d1565b155b156108c657604051634c12315960e11b815260040160405180910390fd5b6108d083836117d8565b505050565b6108dd611851565b60006108e882611513565b50506001600160a01b0381166000908152600d6020526040808220600201805460ff191660011790555191925083917f574b2683ce92a856b9955684fd27d399f1c64effd906c166d1939864c24b07299190a25050565b336000908152600d602052604090205461097b90837f00000000000000000000000000000000000000000000000000000000000000008461187e565b5050565b610987611851565b600a80546001600160a01b031981169091556040516001600160a01b0390911690819033907fe83a760af9d3c86797ea13c8979010086f067cfe3c985b2d03d951248600c50f90600090a350565b806109df81611594565b6109fa8484846040518060200160405280600081525061198c565b50505050565b604080518082019091526000808252602082015281610a1e84610ef5565b5111610a3d5760405163653e642560e11b815260040160405180910390fd5b6000838152600660205260408120805484908110610a5d57610a5d613149565b60009182526020918290206040805180820190915260029092020180548252600101546001600160a01b03169181019190915291505092915050565b6108d08383836040518060200160405280600081525061133e565b61097b816000611320565b336000908152600d602052604081205490819003610b1d5760405162461bcd60e51b8152602060048201526016602482015275141c9bd99a5b1948191bd95cc81b9bdd08195e1a5cdd60521b60448201526064015b60405180910390fd5b60005b82518110156108d0577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631ffeaf968384868581518110610b6c57610b6c613149565b60200260200101516040518463ffffffff1660e01b8152600401610b929392919061315f565b600060405180830381600087803b158015610bac57600080fd5b505af1158015610bc0573d6000803e3d6000fd5b505050506000610bcf83610c8e565b905060008160018351610be291906131af565b81518110610bf257610bf2613149565b60200260200101519050610c1a8460018451610c0e91906131af565b6020840151845161187e565b336000908152600d60205260409020855160019160030190879086908110610c4457610c44613149565b6020026020010151604051610c5991906131c2565b908152604051908190036020019020805491151560ff1990921691909117905550819050610c86816131de565b915050610b20565b6000818152600760209081526040808320805482518185028101850190935280835260609493849084015b82821015610d015760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610cb9565b50929695505050505050565b600080600080610d1c85611513565b9250925092508015610d94576040516331a9108f60e11b8152600481018390526001600160a01b03841690636352211e90602401602060405180830381865afa158015610d6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9191906131f7565b92505b50909392505050565b610da6836117a0565b33803b610dc65760405163b9d3114760e01b815260040160405180910390fd5b604080518082019091528381526001600160a01b03821660208201526000610ded86610c8e565b5190506080811015610e4c576000868152600760209081526040822080546001808201835591845292829020855160029094020192835590840151910180546001600160a01b0319166001600160a01b03909216919091179055610e65565b60405163a53c8c0560e01b815260040160405180910390fd5b84836001600160a01b0316877fe65085e689b77b126ba0bac3b079aa8288f19f4d5445af11c76003f8ab3075dd84604051610ea291815260200190565b60405180910390a4610744565b336000908152600d60205260408082209051600390910190610ed29084906131c2565b908152604051908190036020019020805491151560ff1990921691909117905550565b6000818152600660209081526040808320805482518185028101850190935280835260609493849084018215610d015760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610cb9565b60006001600160a01b038216610f8e57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b031660009081526002602052604090205490565b336000908152600d6020526040812054908190036110025760405162461bcd60e51b815260206004820152601560248201527414d95b99195c88191bd95cc81b9bdd08195e1a5cdd605a1b6044820152606401610b14565b6001600160a01b0384166000908152600d60205260408120549081900361106b5760405162461bcd60e51b815260206004820152601760248201527f526563656976657220646f6573206e6f742065786973740000000000000000006044820152606401610b14565b604051630fff57cb60e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631ffeaf96906110bd908590859089908990600401613214565b600060405180830381600087803b1580156110d757600080fd5b505af11580156110eb573d6000803e3d6000fd5b5050505060006110fa82610c8e565b90506000816001835161110d91906131af565b8151811061111d5761111d613149565b602002602001015190506111398360018451610c0e91906131af565b50505050505050565b600a546001600160a01b0316331461116d5760405163015aa1e360e11b815260040160405180910390fd5b600980546001600160a01b031980821633908117909355600a805490911690556040516001600160a01b03909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6111d0611851565b600b8190556040518181527f90004c04698bc3322499a575ed3752dd4abf33e0a7294c06a787a0fe01bea9419060200160405180910390a150565b60606001805461075b9061310f565b8161122481611ad6565b6108d08383611afd565b6001600160a01b038216330361125757604051630b7b99b960e21b815260040160405180910390fd5b3360008181526004602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6040805180820190915260008082526020820152816112e184610c8e565b51116113005760405163da22687f60e01b815260040160405180910390fd5b6000838152600760205260408120805484908110610a5d57610a5d613149565b60008261132c81611594565b6113368484611b72565b949350505050565b8161134881611594565b61135485858585611ecc565b5050505050565b600b5415801590611376575061137481600b5484611f01565b155b15611396576040516313e5138760e01b8152336004820152602401610b14565b336000908152600d6020526040902060010154156113c95760405163a760ecd560e01b8152336004820152602401610b14565b6000838152600e602052604090205460ff16156113fc576040516306a4b6d160e51b815260048101849052602401610b14565b61142433600c546040518060400160405280600381526020016203078360ec1b815250611f17565b600c8054336000818152600d602090815260408083209485556001948501899055888352600e909152808220805460ff191690941790935592549151919290917fcb939889322fed25104a5d8945bde5162563412a1fd718946cdcacb03088ea089190a35050600c8054600101905550565b876114a081611ad6565b6114b08989898989898989611f4c565b505050505050505050565b836114c581611ad6565b6113548585858561187e565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b611507611851565b61151081612130565b50565b60008181526005602090815260408083208151606081018352815481526001909101546001600160a01b038116938201849052600160a01b900460ff16151591810191909152829182919061157b5760405163089ba7e160e41b815260040160405180910390fd5b6020810151815160409092015190969195509350915050565b61159e33826121cc565b611510576040516345f3c98360e11b815260040160405180910390fd5b6000806115c785611513565b5091509150866001600160a01b0316826001600160a01b0316146115fe5760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038616611625576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b0386163014801561163c57508385145b1561165a57604051633d76b10760e01b815260040160405180910390fd5b6001600160a01b0386163b6116825760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526342b0e56f60e01b60048201526001600160a01b038716906301ffc9a790602401602060405180830381865afa1580156116cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f19190613250565b61170e57604051631784ec7360e21b815260040160405180910390fd5b61171985878661224f565b611727828783878988612340565b6001600160a01b03871660009081526002602052604081208054600192906117509084906131af565b909155506117639050858588600161239b565b6001600160a01b038616600090815260026020526040812080546001929061178c90849061326d565b909155506111399050828783878988612412565b6000818152600560205260409020600101546001600160a01b03166115105760405163089ba7e160e41b815260040160405180910390fd5b60006117e382610d0d565b60008381526003602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b6009546001600160a01b0316331461187c57604051636db2465f60e01b815260040160405180910390fd5b565b600061188a85856112c3565b90506118978184846124ef565b6001600160a01b0383166000908152600860209081526040808320858452909152902054156118d95760405163188a497360e01b815260040160405180910390fd5b60008581526007602052604090206118f19085612533565b600085815260066020908152604080832080546001808201835591855283852086516002909202019081558584015190820180546001600160a01b0319166001600160a01b03928316179055871680855260088452828520878652845293829020555186815284929188917f29486b9e2ae569b440933a9b1b421467306fa21f3dcad439c262910a634963a9910160405180910390a4611354565b60008061199884611513565b5091509150856001600160a01b0316826001600160a01b0316146119cf5760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b0385166119f6576040516338f646ff60e21b815260040160405180910390fd5b611a0582868360008888612340565b6001600160a01b0386166000908152600260205260408120805460019290611a2e9084906131af565b90915550611a419050846000878161239b565b6001600160a01b0385166000908152600260205260408120805460019290611a6a90849061326d565b909155505060405184906001600160a01b0380881691908916906000805160206133c683398151915290600090a483856001600160a01b0316836001600160a01b03166000805160206133a6833981519152846000604051610ea2929190918252602082015260400190565b611ae033826125ed565b611510576040516302728a9d60e41b815260040160405180910390fd5b600082815260076020526040902054811015611b2c57604051631e73178b60e11b815260040160405180910390fd5b6000828152600760205260408120611b4391612961565b60405182907f8ac4a0d65950c3e40448afb2260e2e0ec36ea15644d9b39e37e85472e5f9445190600090a25050565b6000806000611b8085611513565b50915091506000611b9086610d0d565b6001600160a01b03841660009081526002602052604081208054929350600192909190611bbe9084906131af565b90915550611bc99050565b611be88360008460008a60405180602001604052806000815250612340565b611bf36000876117d8565b6000611bfe87610ef5565b6000888152600660205260408120919250611c199190612961565b6000878152600760205260408120611c3091612961565b60008781526003602090815260408083206001600160a01b0386168452909152812080546001600160a01b031916905581518190815b81811015611e3157898310611cdb57848181518110611c8757611c87613149565b602002602001015160200151858281518110611ca557611ca5613149565b6020908102919091010151516040516306177b2560e41b81526001600160a01b0390921660048301526024820152604401610b14565b60086000868381518110611cf157611cf1613149565b6020026020010151602001516001600160a01b03166001600160a01b031681526020019081526020016000206000868381518110611d3157611d31613149565b602002602001015160000151815260200190815260200160002060009055828a039350848181518110611d6657611d66613149565b6020026020010151602001516001600160a01b031663b390c0ab868381518110611d9257611d92613149565b602002602001015160000151600187611dab91906131af565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015611dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e129190613280565b611e1d90600161326d565b611e27908461326d565b9250600101611c66565b5060008a81526005602052604080822082815560010180546001600160a81b0319169055518b91906001600160a01b038816906000805160206133c6833981519152908390a4604080518781526000602082018190528c9290916001600160a01b038b16916000805160206133a6833981519152910160405180910390a46040805160208101909152600090525b5098975050505050505050565b611ed88484848461198c565b611ee48484848461264b565b6109fa5760405163bcb5663760e01b815260040160405180910390fd5b600082611f0e858461274d565b14949350505050565b611f2283838361279a565b611f2f600084848461264b565b6108d05760405163bcb5663760e01b815260040160405180910390fd5b60408051808201909152600080825260208201528215611f7757611f7089876112c3565b9050611f84565b611f818987610a00565b90505b611f8f8186866124ef565b8215611fb2576000898152600760205260409020611fad9087612533565b611fec565b6001600160a01b038516600090815260086020908152604080832087845282528083208390558b835260069091529020611fec9087612533565b6001600160a01b038816156120d9578660000361206c57604051635c46a7ef60e11b81526001600160a01b0386169063b88d4fde906120359030908c9089908890600401613299565b600060405180830381600087803b15801561204f57600080fd5b505af1158015612063573d6000803e3d6000fd5b505050506120d9565b60208101518151604051630326051d60e11b81526001600160a01b039092169163064c0a3a916120a69130918d918d9089906004016132d6565b600060405180830381600087803b1580156120c057600080fd5b505af11580156120d4573d6000803e3d6000fd5b505050505b6040805187815284151560208201526001600160a01b038a81161582840152915186928816918c917f02d6d6dbcb604d5e1e8c7886456e82a9cdce88b0a580071358f206b5a4d58f709181900360600190a46114b0565b6001600160a01b038116612157576040516342b66a3d60e01b815260040160405180910390fd5b336001600160a01b0382160361218057604051636d6c4ee560e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b03831690811790915560405133907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60008060006121da84611513565b5091509150806000146121fd57506001600160a01b038481169116149050610727565b816001600160a01b0316856001600160a01b03161480612222575061222282866114d1565b806122465750846001600160a01b031661223b856107de565b6001600160a01b0316145b95945050505050565b60005b6064811015612326576000806000856001600160a01b031663fb25fb7a866040518263ffffffff1660e01b815260040161228e91815260200190565b606060405180830381865afa1580156122ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cf9190613310565b925092509250806122e35750505050505050565b6001600160a01b038316301480156122fa57508682145b15612318576040516324543e6d60e11b815260040160405180910390fd5b509093509150600101612252565b50604051630349a6bd60e51b815260040160405180910390fd5b6001600160a01b038616158061235d57506001600160a01b038516155b6107445760405162461bcd60e51b815260206004820152600f60248201526e29b7bab63137bab732103a37b5b2b760891b6044820152606401610b14565b604080516060810182528481526001600160a01b03808516602080840191825285151584860190815260008a815260059092529481209351845590516001909301805494511515600160a01b026001600160a81b031990951693909216929092179290921790915561240d90856117d8565b6109fa565b6040516318d5243360e21b815285906001600160a01b0382169063635490cc9061244490879087908790600401613353565b600060405180830381600087803b15801561245e57600080fd5b505af1158015612472573d6000803e3d6000fd5b5050505082866001600160a01b0316886001600160a01b03166000805160206133c683398151915260405160405180910390a482866001600160a01b0316886001600160a01b03166000805160206133a683398151915288886040516124e2929190918252602082015260400190565b60405180910390a4611139565b82602001516001600160a01b0316826001600160a01b0316141580612515575082518114155b156108d057604051637383f2c160e11b815260040160405180910390fd5b81548290612543906001906131af565b8154811061255357612553613149565b906000526020600020906002020182828154811061257357612573613149565b600091825260209091208254600290920201908155600191820154910180546001600160a01b0319166001600160a01b0390921691909117905581548290806125be576125be613372565b60008281526020812060026000199093019283020190815560010180546001600160a01b031916905590555050565b6000806125f983610d0d565b9050806001600160a01b0316846001600160a01b03161480612620575061262081856114d1565b806113365750836001600160a01b0316612639846107de565b6001600160a01b031614949350505050565b60006001600160a01b0384163b1561274257604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061268f903390899088908890600401613299565b6020604051808303816000875af19250505080156126ca575060408051601f3d908101601f191682019092526126c791810190613388565b60015b612728573d8080156126f8576040519150601f19603f3d011682016040523d82523d6000602084013e6126fd565b606091505b5080516000036127205760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611336565b506001949350505050565b600081815b84518110156127925761277e8286838151811061277157612771613149565b6020026020010151612808565b91508061278a816131de565b915050612752565b509392505050565b6127a7838360008461283a565b60405182906001600160a01b038516906000906000805160206133c6833981519152908290a46040805160008082526020820181905284926001600160a01b038716926000805160206133a6833981519152910160405180910390a4505050565b6000818310612824576000828152602084905260409020612833565b60008381526020839052604090205b9392505050565b6001600160a01b038416612861576040516325bd6bd360e01b815260040160405180910390fd5b6000838152600560205260409020600101546001600160a01b03161561289a5760405163c5a8d37160e01b815260040160405180910390fd5b826000036128bb576040516312c33ce360e01b815260040160405180910390fd5b6128cb6000856000858786612340565b6001600160a01b03841660009081526002602052604081208054600192906128f490849061326d565b9091555050604080516060810182528381526001600160a01b039586166020808301918252941515828401908152600096875260059095529190942093518455516001909301805492511515600160a01b026001600160a81b031990931693909416929092171790915550565b508054600082556002029060005260206000209081019061151091905b808211156129a457600081556001810180546001600160a01b031916905560020161297e565b5090565b6001600160e01b03198116811461151057600080fd5b6000602082840312156129d057600080fd5b8135612833816129a8565b6001600160a01b038116811461151057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612a2f57612a2f6129f0565b604052919050565b600082601f830112612a4857600080fd5b813567ffffffffffffffff811115612a6257612a626129f0565b612a75601f8201601f1916602001612a06565b818152846020838601011115612a8a57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612abf57600080fd5b8535612aca816129db565b94506020860135612ada816129db565b93506040860135925060608601359150608086013567ffffffffffffffff811115612b0457600080fd5b612b1088828901612a37565b9150509295509295909350565b60005b83811015612b38578181015183820152602001612b20565b50506000910152565b60008151808452612b59816020860160208601612b1d565b601f01601f19169290920160200192915050565b6020815260006128336020830184612b41565b600060208284031215612b9257600080fd5b5035919050565b600060208284031215612bab57600080fd5b8135612833816129db565b602080825282518282018190526000919060409081850190868401855b82811015612c0957612bf9848351805182526020908101516001600160a01b0316910152565b9284019290850190600101612bd3565b5091979650505050505050565b60008060408385031215612c2957600080fd5b8235612c34816129db565b946020939093013593505050565b60008060408385031215612c5557600080fd5b50508035926020909101359150565b600080600060608486031215612c7957600080fd5b8335612c84816129db565b92506020840135612c94816129db565b929592945050506040919091013590565b815181526020808301516001600160a01b03169082015260408101610727565b600067ffffffffffffffff821115612cdf57612cdf6129f0565b5060051b60200190565b60006020808385031215612cfc57600080fd5b823567ffffffffffffffff80821115612d1457600080fd5b818501915085601f830112612d2857600080fd5b8135612d3b612d3682612cc5565b612a06565b81815260059190911b83018401908481019088831115612d5a57600080fd5b8585015b83811015611ebf57803585811115612d765760008081fd5b612d848b89838a0101612a37565b845250918601918601612d5e565b600080600060608486031215612da757600080fd5b8335925060208401359150604084013567ffffffffffffffff811115612dcc57600080fd5b612dd886828701612a37565b9150509250925092565b600060208284031215612df457600080fd5b813567ffffffffffffffff811115612e0b57600080fd5b61133684828501612a37565b600080600060608486031215612e2c57600080fd5b8335612e37816129db565b9250602084013567ffffffffffffffff80821115612e5457600080fd5b612e6087838801612a37565b93506040860135915080821115612e7657600080fd5b50612dd886828701612a37565b600060208284031215612e9557600080fd5b813567ffffffffffffffff8116811461283357600080fd5b801515811461151057600080fd5b60008060408385031215612ece57600080fd5b8235612ed9816129db565b91506020830135612ee981612ead565b809150509250929050565b60008060008060808587031215612f0a57600080fd5b8435612f15816129db565b93506020850135612f25816129db565b925060408501359150606085013567ffffffffffffffff811115612f4857600080fd5b612f5487828801612a37565b91505092959194509250565b600080600060608486031215612f7557600080fd5b833592506020808501359250604085013567ffffffffffffffff811115612f9b57600080fd5b8501601f81018713612fac57600080fd5b8035612fba612d3682612cc5565b81815260059190911b82018301908381019089831115612fd957600080fd5b928401925b82841015612ff757833582529284019290840190612fde565b80955050505050509250925092565b600080600080600080600080610100898b03121561302357600080fd5b883597506020890135613035816129db565b965060408901359550606089013594506080890135613053816129db565b935060a0890135925060c089013561306a81612ead565b915060e089013567ffffffffffffffff81111561308657600080fd5b6130928b828c01612a37565b9150509295985092959890939650565b600080600080608085870312156130b857600080fd5b843593506020850135925060408501356130d1816129db565b9396929550929360600135925050565b600080604083850312156130f457600080fd5b82356130ff816129db565b91506020830135612ee9816129db565b600181811c9082168061312357607f821691505b60208210810361314357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b83815282602082015260806040820152600061317e6080830184612b41565b82810360608401526000815260208101915050949350505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561072757610727613199565b600082516131d4818460208701612b1d565b9190910192915050565b6000600182016131f0576131f0613199565b5060010190565b60006020828403121561320957600080fd5b8151612833816129db565b8481528360208201526080604082015260006132336080830185612b41565b82810360608401526132458185612b41565b979650505050505050565b60006020828403121561326257600080fd5b815161283381612ead565b8082018082111561072757610727613199565b60006020828403121561329257600080fd5b5051919050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906132cc90830184612b41565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061324590830184612b41565b60008060006060848603121561332557600080fd5b8351613330816129db565b60208501516040860151919450925061334881612ead565b809150509250925092565b8381528260208201526060604082015260006122466060830184612b41565b634e487b7160e01b600052603160045260246000fd5b60006020828403121561339a57600080fd5b8151612833816129a856fe04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552dddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220cc09a863b0d2bb13cb76e1f7d2dc71b68e2e23f891786da65fa3d78561e30e4d64736f6c6343000812003360806040523480156200001157600080fd5b506040516200368a3803806200368a83398101604081905262000034916200022d565b806000848481818462000048838262000349565b50600162000057828262000349565b5050506001600160a01b0384169150620000869050576040516342b66a3d60e01b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0384811691909117909155811615620000b957620000b981620000ca565b50506001600b555062000415915050565b6001600160a01b038116620000f2576040516342b66a3d60e01b815260040160405180910390fd5b336001600160a01b038216036200011c57604051636d6c4ee560e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b03831690811790915560405133907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200019057600080fd5b81516001600160401b0380821115620001ad57620001ad62000168565b604051601f8301601f19908116603f01168101908282118183101715620001d857620001d862000168565b81604052838152602092508683858801011115620001f557600080fd5b600091505b83821015620002195785820183015181830184015290820190620001fa565b600093810190920192909252949350505050565b6000806000606084860312156200024357600080fd5b83516001600160401b03808211156200025b57600080fd5b62000269878388016200017e565b945060208601519150808211156200028057600080fd5b506200028f868287016200017e565b604086015190935090506001600160a01b0381168114620002af57600080fd5b809150509250925092565b600181811c90821680620002cf57607f821691505b602082108103620002f057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200034457600081815260208120601f850160051c810160208610156200031f5750805b601f850160051c820191505b8181101562000340578281556001016200032b565b5050505b505050565b81516001600160401b0381111562000365576200036562000168565b6200037d81620003768454620002ba565b84620002f6565b602080601f831160018114620003b557600084156200039c5750858301515b600019600386901b1c1916600185901b17855562000340565b600085815260208120601f198616915b82811015620003e657888601518255948401946001909101908401620003c5565b5085821015620004055787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61326580620004256000396000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c806379ba509711610125578063b390c0ab116100ad578063e97ceaa81161007c578063e97ceaa8146104ba578063e985e9c5146104cd578063f2fde38b146104e0578063fb25fb7a146104f3578063ffa1ad741461052d57600080fd5b8063b390c0ab1461045d578063b88d4fde14610470578063defa80c314610483578063e343537d1461049657600080fd5b806395d89b41116100f457806395d89b41146104095780639796133614610411578063a22cb46514610424578063a898e36414610437578063ae882b651461044a57600080fd5b806379ba5097146103cc5780638ad91345146103d45780638da5cb5b146103e757806393596c7b146103f857600080fd5b80632f32f937116101a857806344ec93441161017757806344ec9344146103525780636352211e14610372578063635490cc146103855780636f19951c1461039857806370a08231146103ab57600080fd5b80632f32f937146102d45780634182e4a3146102f457806342842e0e1461032c57806342966c681461033f57600080fd5b8063095ea7b3116101e4578063095ea7b3146102935780631ffeaf96146102a657806323452b9c146102b957806323b872dd146102c157600080fd5b806301ffc9a714610216578063064c0a3a1461023e57806306fdde0314610253578063081812fc14610268575b600080fd5b6102296102243660046127c8565b610552565b60405190151581526020015b60405180910390f35b61025161024c3660046128a4565b6105bf565b005b61025b6105de565b604051610235919061296a565b61027b61027636600461297d565b610670565b6040516001600160a01b039091168152602001610235565b6102516102a1366004612996565b6106b6565b6102516102b43660046129c2565b610742565b610251610936565b6102516102cf366004612a39565b61098c565b6102e76102e2366004612a7a565b6109b7565b6040516102359190612a9c565b610229610302366004612996565b6001600160a01b039190911660009081526008602090815260408083209383529290522054151590565b61025161033a366004612a39565b610a50565b61025161034d36600461297d565b610a6b565b61036561036036600461297d565b610a7a565b6040516102359190612abc565b61027b61038036600461297d565b610af9565b610251610393366004612b1c565b610b89565b6103656103a636600461297d565b610c9b565b6103be6103b9366004612b6c565b610d0b565b604051908152602001610235565b610251610d50565b61025b6103e236600461297d565b610dd6565b6009546001600160a01b031661027b565b600a546001600160a01b031661027b565b61025b610e78565b61025161041f366004612a7a565b610e87565b610251610432366004612b97565b610e9b565b6102e7610445366004612a7a565b610f30565b61025b61045836600461297d565b610f8d565b6103be61046b366004612a7a565b611027565b61025161047e366004612bd0565b611045565b610251610491366004612c30565b611062565b6104a96104a436600461297d565b611087565b604051610235959493929190612ccc565b6102516104c8366004612d0f565b6111c8565b6102296104db366004612d4e565b6111de565b6102516104ee366004612b6c565b61120c565b61050661050136600461297d565b611220565b604080516001600160a01b0390941684526020840192909252151590820152606001610235565b61025b60405180604001604052806006815260200165302e32372e3160d01b81525081565b60006001600160e01b031982166301ffc9a760e01b148061058357506001600160e01b031982166380ac58cd60e01b145b8061059e57506001600160e01b03198216635b5e139f60e01b145b806105b957506001600160e01b031982166342b0e56f60e01b145b92915050565b826105c9816112a1565b6105d686868686866112c8565b505050505050565b6060600080546105ed90612d7c565b80601f016020809104026020016040519081016040528092919081815260200182805461061990612d7c565b80156106665780601f1061063b57610100808354040283529160200191610666565b820191906000526020600020905b81548152906001019060200180831161064957829003601f168201915b5050505050905090565b600061067b826114a8565b60008281526003602052604081209061069384610af9565b6001600160a01b0390811682526020820192909252604001600020541692915050565b60006106c182610af9565b9050806001600160a01b0316836001600160a01b0316036106f557604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b03821614801590610715575061071381336111de565b155b1561073357604051634c12315960e11b815260040160405180910390fd5b61073d83836114e0565b505050565b61074a611559565b6000610757858585611586565b6000818152600e602052604090205490915060ff16156107be5760405162461bcd60e51b815260206004820152601960248201527f52657075746174696f6e20616c7265616479206d696e7465640000000000000060448201526064015b60405180910390fd5b6000818152600e60205260409020805460ff191660011790556107f66107ec6009546001600160a01b031690565b600b5486856115bc565b60006108208460405160200161080c9190612db6565b60405160208183030381529060405261168c565b90506000816040516020016108359190612e82565b60408051601f19818403018152918152600b546000908152600d602052209091506108608282612f0d565b506040805160a081018252600b5480825260208083018b81528385018b8152606085018b8152608086018b90526000948552600c90935294909220835181559151600183015592516002820155915190919060038201906108c19082612f0d565b50608082015160048201906108d69082612f0d565b50905050600b546108ef6009546001600160a01b031690565b6001600160a01b03167f42bcf4689d0211adce4e556ee455319d34e671e8b8a762034e146461fb1be82d60405160405180910390a35050600b805460010190555050505050565b61093e611559565b600a80546001600160a01b031981169091556040516001600160a01b0390911690819033907fe83a760af9d3c86797ea13c8979010086f067cfe3c985b2d03d951248600c50f90600090a350565b80610996816112a1565b6109b1848484604051806020016040528060008152506117df565b50505050565b6040805180820190915260008082526020820152816109d584610c9b565b51116109f45760405163653e642560e11b815260040160405180910390fd5b6000838152600660205260408120805484908110610a1457610a14612fcd565b60009182526020918290206040805180820190915260029092020180548252600101546001600160a01b03169181019190915291505092915050565b61073d83838360405180602001604052806000815250611045565b610a76816000611027565b5050565b6000818152600760209081526040808320805482518185028101850190935280835260609493849084015b82821015610aed5760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610aa5565b50929695505050505050565b600080600080610b0885611220565b9250925092508015610b80576040516331a9108f60e11b8152600481018390526001600160a01b03841690636352211e90602401602060405180830381865afa158015610b59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7d9190612fe3565b92505b50909392505050565b610b92836114a8565b33803b610bb25760405163b9d3114760e01b815260040160405180910390fd5b604080518082019091528381526001600160a01b03821660208201526000610bd986610a7a565b5190506080811015610c38576000868152600760209081526040822080546001808201835591845292829020855160029094020192835590840151910180546001600160a01b0319166001600160a01b03909216919091179055610c51565b60405163a53c8c0560e01b815260040160405180910390fd5b84836001600160a01b0316877fe65085e689b77b126ba0bac3b079aa8288f19f4d5445af11c76003f8ab3075dd84604051610c8e91815260200190565b60405180910390a46105d6565b6000818152600660209081526040808320805482518185028101850190935280835260609493849084018215610aed5760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610aa5565b60006001600160a01b038216610d3457604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b031660009081526002602052604090205490565b600a546001600160a01b03163314610d7b5760405163015aa1e360e11b815260040160405180910390fd5b600980546001600160a01b031980821633908117909355600a805490911690556040516001600160a01b03909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000818152600d60205260409020805460609190610df390612d7c565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1f90612d7c565b8015610e6c5780601f10610e4157610100808354040283529160200191610e6c565b820191906000526020600020905b815481529060010190602001808311610e4f57829003601f168201915b50505050509050919050565b6060600180546105ed90612d7c565b81610e918161193e565b61073d8383611965565b6001600160a01b0382163303610ec457604051630b7b99b960e21b815260040160405180910390fd5b3360008181526004602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b604080518082019091526000808252602082015281610f4e84610a7a565b5111610f6d5760405163da22687f60e01b815260040160405180910390fd5b6000838152600760205260408120805484908110610a1457610a14612fcd565b600d6020526000908152604090208054610fa690612d7c565b80601f0160208091040260200160405190810160405280929190818152602001828054610fd290612d7c565b801561101f5780601f10610ff45761010080835404028352916020019161101f565b820191906000526020600020905b81548152906001019060200180831161100257829003601f168201915b505050505081565b600082611033816112a1565b61103d84846119da565b949350505050565b8161104f816112a1565b61105b85858585611d47565b5050505050565b8761106c8161193e565b61107c8989898989898989611d7c565b505050505050505050565b600c602052600090815260409020805460018201546002830154600384018054939492939192916110b790612d7c565b80601f01602080910402602001604051908101604052809291908181526020018280546110e390612d7c565b80156111305780601f1061110557610100808354040283529160200191611130565b820191906000526020600020905b81548152906001019060200180831161111357829003601f168201915b50505050509080600401805461114590612d7c565b80601f016020809104026020016040519081016040528092919081815260200182805461117190612d7c565b80156111be5780601f10611193576101008083540402835291602001916111be565b820191906000526020600020905b8154815290600101906020018083116111a157829003601f168201915b5050505050905085565b836111d28161193e565b61105b85858585611f60565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b611214611559565b61121d8161206e565b50565b60008181526005602090815260408083208151606081018352815481526001909101546001600160a01b038116938201849052600160a01b900460ff1615159181019190915282918291906112885760405163089ba7e160e41b815260040160405180910390fd5b6020810151815160409092015190969195509350915050565b6112ab338261210a565b61121d576040516345f3c98360e11b815260040160405180910390fd5b6000806112d485611220565b5091509150866001600160a01b0316826001600160a01b03161461130b5760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038616611332576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b0386163014801561134957508385145b1561136757604051633d76b10760e01b815260040160405180910390fd5b6001600160a01b0386163b61138f5760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526342b0e56f60e01b60048201526001600160a01b038716906301ffc9a790602401602060405180830381865afa1580156113da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113fe9190613000565b61141b57604051631784ec7360e21b815260040160405180910390fd5b61142685878661218d565b6001600160a01b038716600090815260026020526040812080546001929061144f908490613033565b909155506114629050858588600161227e565b6001600160a01b038616600090815260026020526040812080546001929061148b908490613046565b9091555061149f90508287838789886122f5565b50505050505050565b6000818152600560205260409020600101546001600160a01b031661121d5760405163089ba7e160e41b815260040160405180910390fd5b60006114eb82610af9565b60008381526003602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b6009546001600160a01b0316331461158457604051636db2465f60e01b815260040160405180910390fd5b565b600083838360405160200161159d93929190613059565b6040516020818303038152906040528051906020012090509392505050565b6001600160a01b0384163b6115e45760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526342b0e56f60e01b60048201526001600160a01b038516906301ffc9a790602401602060405180830381865afa15801561162f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116539190613000565b6116705760405163fbd5d8b960e01b815260040160405180910390fd5b61167c848484846123f6565b6109b160008560008587866122f5565b606081516000036116ab57505060408051602081019091526000815290565b60006040518060600160405280604081526020016131f060409139905060006003845160026116da9190613046565b6116e49190613086565b6116ef9060046130a8565b67ffffffffffffffff81111561170757611707612801565b6040519080825280601f01601f191660200182016040528015611731576020820181803683370190505b509050600182016020820185865187015b8082101561179d576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611742565b50506003865106600181146117b957600281146117cc576117d4565b603d6001830353603d60028303536117d4565b603d60018303535b509195945050505050565b6000806117eb84611220565b5091509150856001600160a01b0316826001600160a01b0316146118225760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038516611849576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b0386166000908152600260205260408120805460019290611872908490613033565b909155506118859050846000878161227e565b6001600160a01b03851660009081526002602052604081208054600192906118ae908490613046565b909155505060405184906001600160a01b0380881691908916907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a483856001600160a01b0316836001600160a01b03167f04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552d846000604051610c8e929190918252602082015260400190565b611948338261250d565b61121d576040516302728a9d60e41b815260040160405180910390fd5b60008281526007602052604090205481101561199457604051631e73178b60e11b815260040160405180910390fd5b60008281526007602052604081206119ab9161276b565b60405182907f8ac4a0d65950c3e40448afb2260e2e0ec36ea15644d9b39e37e85472e5f9445190600090a25050565b60008060006119e885611220565b509150915060006119f886610af9565b6001600160a01b03841660009081526002602052604081208054929350600192909190611a26908490613033565b90915550611a319050565b604080516020810190915260009052611a4b6000876114e0565b6000611a5687610c9b565b6000888152600660205260408120919250611a71919061276b565b6000878152600760205260408120611a889161276b565b60008781526003602090815260408083206001600160a01b0386168452909152812080546001600160a01b031916905581518190815b81811015611c8957898310611b3357848181518110611adf57611adf612fcd565b602002602001015160200151858281518110611afd57611afd612fcd565b6020908102919091010151516040516306177b2560e41b81526001600160a01b03909216600483015260248201526044016107b5565b60086000868381518110611b4957611b49612fcd565b6020026020010151602001516001600160a01b03166001600160a01b031681526020019081526020016000206000868381518110611b8957611b89612fcd565b602002602001015160000151815260200190815260200160002060009055828a039350848181518110611bbe57611bbe612fcd565b6020026020010151602001516001600160a01b031663b390c0ab868381518110611bea57611bea612fcd565b602002602001015160000151600187611c039190613033565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015611c46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c6a91906130bf565b611c75906001613046565b611c7f9084613046565b9250600101611abe565b5060008a81526005602052604080822082815560010180546001600160a81b0319169055518b91906001600160a01b038816907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a4604080518781526000602082018190528c9290916001600160a01b038b16917f04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552d910160405180910390a46040805160208101909152600090525098975050505050505050565b611d53848484846117df565b611d5f8484848461256b565b6109b15760405163bcb5663760e01b815260040160405180910390fd5b60408051808201909152600080825260208201528215611da757611da08987610f30565b9050611db4565b611db189876109b7565b90505b611dbf81868661266d565b8215611de2576000898152600760205260409020611ddd90876126b1565b611e1c565b6001600160a01b038516600090815260086020908152604080832087845282528083208390558b835260069091529020611e1c90876126b1565b6001600160a01b03881615611f095786600003611e9c57604051635c46a7ef60e11b81526001600160a01b0386169063b88d4fde90611e659030908c90899088906004016130d8565b600060405180830381600087803b158015611e7f57600080fd5b505af1158015611e93573d6000803e3d6000fd5b50505050611f09565b60208101518151604051630326051d60e11b81526001600160a01b039092169163064c0a3a91611ed69130918d918d908990600401613115565b600060405180830381600087803b158015611ef057600080fd5b505af1158015611f04573d6000803e3d6000fd5b505050505b6040805187815284151560208201526001600160a01b038a81161582840152915186928816918c917f02d6d6dbcb604d5e1e8c7886456e82a9cdce88b0a580071358f206b5a4d58f709181900360600190a461107c565b6000611f6c8585610f30565b9050611f7981848461266d565b6001600160a01b038316600090815260086020908152604080832085845290915290205415611fbb5760405163188a497360e01b815260040160405180910390fd5b6000858152600760205260409020611fd390856126b1565b600085815260066020908152604080832080546001808201835591855283852086516002909202019081558584015190820180546001600160a01b0319166001600160a01b03928316179055871680855260088452828520878652845293829020555186815284929188917f29486b9e2ae569b440933a9b1b421467306fa21f3dcad439c262910a634963a9910160405180910390a461105b565b6001600160a01b038116612095576040516342b66a3d60e01b815260040160405180910390fd5b336001600160a01b038216036120be57604051636d6c4ee560e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b03831690811790915560405133907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600080600061211884611220565b50915091508060001461213b57506001600160a01b0384811691161490506105b9565b816001600160a01b0316856001600160a01b03161480612160575061216082866111de565b806121845750846001600160a01b031661217985610670565b6001600160a01b0316145b95945050505050565b60005b6064811015612264576000806000856001600160a01b031663fb25fb7a866040518263ffffffff1660e01b81526004016121cc91815260200190565b606060405180830381865afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d919061315a565b925092509250806122215750505050505050565b6001600160a01b0383163014801561223857508682145b15612256576040516324543e6d60e11b815260040160405180910390fd5b509093509150600101612190565b50604051630349a6bd60e51b815260040160405180910390fd5b604080516060810182528481526001600160a01b03808516602080840191825285151584860190815260008a815260059092529481209351845590516001909301805494511515600160a01b026001600160a81b03199095169390921692909217929092179091556122f090856114e0565b6109b1565b6040516318d5243360e21b815285906001600160a01b0382169063635490cc906123279087908790879060040161319d565b600060405180830381600087803b15801561234157600080fd5b505af1158015612355573d6000803e3d6000fd5b5050505082866001600160a01b0316886001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a482866001600160a01b0316886001600160a01b03167f04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552d88886040516123e9929190918252602082015260400190565b60405180910390a461149f565b6001600160a01b03841661241d576040516325bd6bd360e01b815260040160405180910390fd5b6000838152600560205260409020600101546001600160a01b0316156124565760405163c5a8d37160e01b815260040160405180910390fd5b82600003612477576040516312c33ce360e01b815260040160405180910390fd5b6001600160a01b03841660009081526002602052604081208054600192906124a0908490613046565b9091555050604080516060810182528381526001600160a01b039586166020808301918252941515828401908152600096875260059095529190942093518455516001909301805492511515600160a01b026001600160a81b031990931693909416929092171790915550565b60008061251983610af9565b9050806001600160a01b0316846001600160a01b03161480612540575061254081856111de565b8061103d5750836001600160a01b031661255984610670565b6001600160a01b031614949350505050565b60006001600160a01b0384163b1561266257604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906125af9033908990889088906004016130d8565b6020604051808303816000875af19250505080156125ea575060408051601f3d908101601f191682019092526125e7918101906131bc565b60015b612648573d808015612618576040519150601f19603f3d011682016040523d82523d6000602084013e61261d565b606091505b5080516000036126405760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061103d565b506001949350505050565b82602001516001600160a01b0316826001600160a01b0316141580612693575082518114155b1561073d57604051637383f2c160e11b815260040160405180910390fd5b815482906126c190600190613033565b815481106126d1576126d1612fcd565b90600052602060002090600202018282815481106126f1576126f1612fcd565b600091825260209091208254600290920201908155600191820154910180546001600160a01b0319166001600160a01b03909216919091179055815482908061273c5761273c6131d9565b60008281526020812060026000199093019283020190815560010180546001600160a01b031916905590555050565b508054600082556002029060005260206000209081019061121d91905b808211156127ae57600081556001810180546001600160a01b0319169055600201612788565b5090565b6001600160e01b03198116811461121d57600080fd5b6000602082840312156127da57600080fd5b81356127e5816127b2565b9392505050565b6001600160a01b038116811461121d57600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261282857600080fd5b813567ffffffffffffffff8082111561284357612843612801565b604051601f8301601f19908116603f0116810190828211818310171561286b5761286b612801565b8160405283815286602085880101111561288457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060a086880312156128bc57600080fd5b85356128c7816127ec565b945060208601356128d7816127ec565b93506040860135925060608601359150608086013567ffffffffffffffff81111561290157600080fd5b61290d88828901612817565b9150509295509295909350565b60005b8381101561293557818101518382015260200161291d565b50506000910152565b6000815180845261295681602086016020860161291a565b601f01601f19169290920160200192915050565b6020815260006127e5602083018461293e565b60006020828403121561298f57600080fd5b5035919050565b600080604083850312156129a957600080fd5b82356129b4816127ec565b946020939093013593505050565b600080600080608085870312156129d857600080fd5b8435935060208501359250604085013567ffffffffffffffff808211156129fe57600080fd5b612a0a88838901612817565b93506060870135915080821115612a2057600080fd5b50612a2d87828801612817565b91505092959194509250565b600080600060608486031215612a4e57600080fd5b8335612a59816127ec565b92506020840135612a69816127ec565b929592945050506040919091013590565b60008060408385031215612a8d57600080fd5b50508035926020909101359150565b815181526020808301516001600160a01b031690820152604081016105b9565b602080825282518282018190526000919060409081850190868401855b82811015612b0f57612aff848351805182526020908101516001600160a01b0316910152565b9284019290850190600101612ad9565b5091979650505050505050565b600080600060608486031215612b3157600080fd5b8335925060208401359150604084013567ffffffffffffffff811115612b5657600080fd5b612b6286828701612817565b9150509250925092565b600060208284031215612b7e57600080fd5b81356127e5816127ec565b801515811461121d57600080fd5b60008060408385031215612baa57600080fd5b8235612bb5816127ec565b91506020830135612bc581612b89565b809150509250929050565b60008060008060808587031215612be657600080fd5b8435612bf1816127ec565b93506020850135612c01816127ec565b925060408501359150606085013567ffffffffffffffff811115612c2457600080fd5b612a2d87828801612817565b600080600080600080600080610100898b031215612c4d57600080fd5b883597506020890135612c5f816127ec565b965060408901359550606089013594506080890135612c7d816127ec565b935060a0890135925060c0890135612c9481612b89565b915060e089013567ffffffffffffffff811115612cb057600080fd5b612cbc8b828c01612817565b9150509295985092959890939650565b85815284602082015283604082015260a060608201526000612cf160a083018561293e565b8281036080840152612d03818561293e565b98975050505050505050565b60008060008060808587031215612d2557600080fd5b84359350602085013592506040850135612d3e816127ec565b9396929550929360600135925050565b60008060408385031215612d6157600080fd5b8235612d6c816127ec565b91506020830135612bc5816127ec565b600181811c90821680612d9057607f821691505b602082108103612db057634e487b7160e01b600052602260045260246000fd5b50919050565b693d913730b6b2911d101160b11b81528151600090612ddc81600a85016020870161291a565b7f222c20226465736372697074696f6e223a2022426c6f73736f6d73222c202269600a9390910192830152507f6d616765223a202268747470733a2f2f697066732e696f2f697066732f516d53602a8201527f73595278334c7044416231475a516d377a5a314175485a6a6662506b44364a37604a8201527f73397234317875316d66383f66696c656e616d653d7075672e706e67227d0000606a820152608801919050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612eba81601d85016020870161291a565b91909101601d0192915050565b601f82111561073d57600081815260208120601f850160051c81016020861015612eee5750805b601f850160051c820191505b818110156105d657828155600101612efa565b815167ffffffffffffffff811115612f2757612f27612801565b612f3b81612f358454612d7c565b84612ec7565b602080601f831160018114612f705760008415612f585750858301515b600019600386901b1c1916600185901b1785556105d6565b600085815260208120601f198616915b82811015612f9f57888601518255948401946001909101908401612f80565b5085821015612fbd5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b600060208284031215612ff557600080fd5b81516127e5816127ec565b60006020828403121561301257600080fd5b81516127e581612b89565b634e487b7160e01b600052601160045260246000fd5b818103818111156105b9576105b961301d565b808201808211156105b9576105b961301d565b8381528260208201526000825161307781604085016020870161291a565b91909101604001949350505050565b6000826130a357634e487b7160e01b600052601260045260246000fd5b500490565b80820281158282048414176105b9576105b961301d565b6000602082840312156130d157600080fd5b5051919050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061310b9083018461293e565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061314f9083018461293e565b979650505050505050565b60008060006060848603121561316f57600080fd5b835161317a816127ec565b60208501516040860151919450925061319281612b89565b809150509250925092565b838152826020820152606060408201526000612184606083018461293e565b6000602082840312156131ce57600080fd5b81516127e5816127b2565b634e487b7160e01b600052603160045260246000fdfe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa26469706673582212200fb860fb98ef181780626a0702f4c0a4c8e29b9735703edb49d2f5bdd1b5ffcd64736f6c63430008120033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000003425514b0d1e6b4583cee39fee8cfcaa13960626000000000000000000000000000000000000000000000000000000000000000c424c534d2d50726f66696c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005424c534d50000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102745760003560e01c8063736d7f8811610151578063b390c0ab116100c3578063defa80c311610087578063defa80c314610615578063e97ceaa814610628578063e985e9c51461063b578063f2fde38b1461064e578063fb25fb7a14610661578063ffa1ad741461069b57600080fd5b8063b390c0ab14610584578063b88d4fde14610597578063bbe15627146105aa578063d082e381146105f9578063d7e29cd51461060257600080fd5b806393596c7b1161011557806393596c7b146104ea57806395d89b41146104fb57806397961336146105035780639813c5b614610516578063a22cb4651461055e578063a898e3641461057157600080fd5b8063736d7f881461048457806379ba5097146104975780637cb647591461049f57806387bc1425146104b25780638da5cb5b146104d957600080fd5b80632f32f937116101ea57806344ec9344116101ae57806344ec9344146104125780636352211e14610425578063635490cc146104385780636bed127f1461044b5780636f19951c1461045e57806370a082311461047157600080fd5b80632f32f937146103815780634182e4a3146103a157806342842e0e146103d957806342966c68146103ec57806344305f2c146103ff57600080fd5b8063095ea7b31161023c578063095ea7b3146103165780630dddf0631461032957806321a8be9d1461033c57806323452b9c1461034f57806323b872dd146103575780632eb4a7ab1461036a57600080fd5b806301ffc9a714610279578063064c0a3a146102a157806306fdde03146102b6578063081812fc146102cb5780630846b3bc146102f6575b600080fd5b61028c6102873660046129be565b6106c0565b60405190151581526020015b60405180910390f35b6102b46102af366004612aa7565b61072d565b005b6102be61074c565b6040516102989190612b6d565b6102de6102d9366004612b80565b6107de565b6040516001600160a01b039091168152602001610298565b610309610304366004612b99565b610824565b6040516102989190612bb6565b6102b4610324366004612c16565b610849565b6102b4610337366004612b80565b6108d5565b6102b461034a366004612c42565b61093f565b6102b461097f565b6102b4610365366004612c64565b6109d5565b610373600b5481565b604051908152602001610298565b61039461038f366004612c42565b610a00565b6040516102989190612ca5565b61028c6103af366004612c16565b6001600160a01b039190911660009081526008602090815260408083209383529290522054151590565b6102b46103e7366004612c64565b610a99565b6102b46103fa366004612b80565b610ab4565b6102b461040d366004612ce9565b610abf565b610309610420366004612b80565b610c8e565b6102de610433366004612b80565b610d0d565b6102b4610446366004612d92565b610d9d565b6102b4610459366004612de2565b610eaf565b61030961046c366004612b80565b610ef5565b61037361047f366004612b99565b610f65565b6102b4610492366004612e17565b610faa565b6102b4611142565b6102b46104ad366004612b80565b6111c8565b6102de7f00000000000000000000000027dba89e927d708cb276a98f71236f8222ec278f81565b6009546001600160a01b03166102de565b600a546001600160a01b03166102de565b6102be61120b565b6102b4610511366004612c42565b61121a565b610373610524366004612e83565b6040516001600160c01b031960c083901b166020820152600090602801604051602081830303815290604052805190602001209050919050565b6102b461056c366004612ebb565b61122e565b61039461057f366004612c42565b6112c3565b610373610592366004612c42565b611320565b6102b46105a5366004612ef4565b61133e565b6105dc6105b8366004612b99565b600d6020526000908152604090208054600182015460029092015490919060ff1683565b604080519384526020840192909252151590820152606001610298565b610373600c5481565b6102b4610610366004612f60565b61135b565b6102b4610623366004613006565b611496565b6102b46106363660046130a2565b6114bb565b61028c6106493660046130e1565b6114d1565b6102b461065c366004612b99565b6114ff565b61067461066f366004612b80565b611513565b604080516001600160a01b0390941684526020840192909252151590820152606001610298565b6102be60405180604001604052806006815260200165302e32372e3160d01b81525081565b60006001600160e01b031982166301ffc9a760e01b14806106f157506001600160e01b031982166380ac58cd60e01b145b8061070c57506001600160e01b03198216635b5e139f60e01b145b8061072757506001600160e01b031982166342b0e56f60e01b145b92915050565b8261073781611594565b61074486868686866115bb565b505050505050565b60606000805461075b9061310f565b80601f01602080910402602001604051908101604052809291908181526020018280546107879061310f565b80156107d45780601f106107a9576101008083540402835291602001916107d4565b820191906000526020600020905b8154815290600101906020018083116107b757829003601f168201915b5050505050905090565b60006107e9826117a0565b60008281526003602052604081209061080184610d0d565b6001600160a01b0390811682526020820192909252604001600020541692915050565b6001600160a01b0381166000908152600d602052604090205460609061072790610ef5565b600061085482610d0d565b9050806001600160a01b0316836001600160a01b03160361088857604051630591db6d60e01b815260040160405180910390fd5b336001600160a01b038216148015906108a857506108a681336114d1565b155b156108c657604051634c12315960e11b815260040160405180910390fd5b6108d083836117d8565b505050565b6108dd611851565b60006108e882611513565b50506001600160a01b0381166000908152600d6020526040808220600201805460ff191660011790555191925083917f574b2683ce92a856b9955684fd27d399f1c64effd906c166d1939864c24b07299190a25050565b336000908152600d602052604090205461097b90837f00000000000000000000000027dba89e927d708cb276a98f71236f8222ec278f8461187e565b5050565b610987611851565b600a80546001600160a01b031981169091556040516001600160a01b0390911690819033907fe83a760af9d3c86797ea13c8979010086f067cfe3c985b2d03d951248600c50f90600090a350565b806109df81611594565b6109fa8484846040518060200160405280600081525061198c565b50505050565b604080518082019091526000808252602082015281610a1e84610ef5565b5111610a3d5760405163653e642560e11b815260040160405180910390fd5b6000838152600660205260408120805484908110610a5d57610a5d613149565b60009182526020918290206040805180820190915260029092020180548252600101546001600160a01b03169181019190915291505092915050565b6108d08383836040518060200160405280600081525061133e565b61097b816000611320565b336000908152600d602052604081205490819003610b1d5760405162461bcd60e51b8152602060048201526016602482015275141c9bd99a5b1948191bd95cc81b9bdd08195e1a5cdd60521b60448201526064015b60405180910390fd5b60005b82518110156108d0577f00000000000000000000000027dba89e927d708cb276a98f71236f8222ec278f6001600160a01b0316631ffeaf968384868581518110610b6c57610b6c613149565b60200260200101516040518463ffffffff1660e01b8152600401610b929392919061315f565b600060405180830381600087803b158015610bac57600080fd5b505af1158015610bc0573d6000803e3d6000fd5b505050506000610bcf83610c8e565b905060008160018351610be291906131af565b81518110610bf257610bf2613149565b60200260200101519050610c1a8460018451610c0e91906131af565b6020840151845161187e565b336000908152600d60205260409020855160019160030190879086908110610c4457610c44613149565b6020026020010151604051610c5991906131c2565b908152604051908190036020019020805491151560ff1990921691909117905550819050610c86816131de565b915050610b20565b6000818152600760209081526040808320805482518185028101850190935280835260609493849084015b82821015610d015760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610cb9565b50929695505050505050565b600080600080610d1c85611513565b9250925092508015610d94576040516331a9108f60e11b8152600481018390526001600160a01b03841690636352211e90602401602060405180830381865afa158015610d6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9191906131f7565b92505b50909392505050565b610da6836117a0565b33803b610dc65760405163b9d3114760e01b815260040160405180910390fd5b604080518082019091528381526001600160a01b03821660208201526000610ded86610c8e565b5190506080811015610e4c576000868152600760209081526040822080546001808201835591845292829020855160029094020192835590840151910180546001600160a01b0319166001600160a01b03909216919091179055610e65565b60405163a53c8c0560e01b815260040160405180910390fd5b84836001600160a01b0316877fe65085e689b77b126ba0bac3b079aa8288f19f4d5445af11c76003f8ab3075dd84604051610ea291815260200190565b60405180910390a4610744565b336000908152600d60205260408082209051600390910190610ed29084906131c2565b908152604051908190036020019020805491151560ff1990921691909117905550565b6000818152600660209081526040808320805482518185028101850190935280835260609493849084018215610d015760008481526020908190206040805180820190915260028502909101805482526001908101546001600160a01b0316828401529083529092019101610cb9565b60006001600160a01b038216610f8e57604051633bb9143360e11b815260040160405180910390fd5b506001600160a01b031660009081526002602052604090205490565b336000908152600d6020526040812054908190036110025760405162461bcd60e51b815260206004820152601560248201527414d95b99195c88191bd95cc81b9bdd08195e1a5cdd605a1b6044820152606401610b14565b6001600160a01b0384166000908152600d60205260408120549081900361106b5760405162461bcd60e51b815260206004820152601760248201527f526563656976657220646f6573206e6f742065786973740000000000000000006044820152606401610b14565b604051630fff57cb60e11b81526001600160a01b037f00000000000000000000000027dba89e927d708cb276a98f71236f8222ec278f1690631ffeaf96906110bd908590859089908990600401613214565b600060405180830381600087803b1580156110d757600080fd5b505af11580156110eb573d6000803e3d6000fd5b5050505060006110fa82610c8e565b90506000816001835161110d91906131af565b8151811061111d5761111d613149565b602002602001015190506111398360018451610c0e91906131af565b50505050505050565b600a546001600160a01b0316331461116d5760405163015aa1e360e11b815260040160405180910390fd5b600980546001600160a01b031980821633908117909355600a805490911690556040516001600160a01b03909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6111d0611851565b600b8190556040518181527f90004c04698bc3322499a575ed3752dd4abf33e0a7294c06a787a0fe01bea9419060200160405180910390a150565b60606001805461075b9061310f565b8161122481611ad6565b6108d08383611afd565b6001600160a01b038216330361125757604051630b7b99b960e21b815260040160405180910390fd5b3360008181526004602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6040805180820190915260008082526020820152816112e184610c8e565b51116113005760405163da22687f60e01b815260040160405180910390fd5b6000838152600760205260408120805484908110610a5d57610a5d613149565b60008261132c81611594565b6113368484611b72565b949350505050565b8161134881611594565b61135485858585611ecc565b5050505050565b600b5415801590611376575061137481600b5484611f01565b155b15611396576040516313e5138760e01b8152336004820152602401610b14565b336000908152600d6020526040902060010154156113c95760405163a760ecd560e01b8152336004820152602401610b14565b6000838152600e602052604090205460ff16156113fc576040516306a4b6d160e51b815260048101849052602401610b14565b61142433600c546040518060400160405280600381526020016203078360ec1b815250611f17565b600c8054336000818152600d602090815260408083209485556001948501899055888352600e909152808220805460ff191690941790935592549151919290917fcb939889322fed25104a5d8945bde5162563412a1fd718946cdcacb03088ea089190a35050600c8054600101905550565b876114a081611ad6565b6114b08989898989898989611f4c565b505050505050505050565b836114c581611ad6565b6113548585858561187e565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205460ff1690565b611507611851565b61151081612130565b50565b60008181526005602090815260408083208151606081018352815481526001909101546001600160a01b038116938201849052600160a01b900460ff16151591810191909152829182919061157b5760405163089ba7e160e41b815260040160405180910390fd5b6020810151815160409092015190969195509350915050565b61159e33826121cc565b611510576040516345f3c98360e11b815260040160405180910390fd5b6000806115c785611513565b5091509150866001600160a01b0316826001600160a01b0316146115fe5760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b038616611625576040516338f646ff60e21b815260040160405180910390fd5b6001600160a01b0386163014801561163c57508385145b1561165a57604051633d76b10760e01b815260040160405180910390fd5b6001600160a01b0386163b6116825760405163b9d3114760e01b815260040160405180910390fd5b6040516301ffc9a760e01b81526342b0e56f60e01b60048201526001600160a01b038716906301ffc9a790602401602060405180830381865afa1580156116cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f19190613250565b61170e57604051631784ec7360e21b815260040160405180910390fd5b61171985878661224f565b611727828783878988612340565b6001600160a01b03871660009081526002602052604081208054600192906117509084906131af565b909155506117639050858588600161239b565b6001600160a01b038616600090815260026020526040812080546001929061178c90849061326d565b909155506111399050828783878988612412565b6000818152600560205260409020600101546001600160a01b03166115105760405163089ba7e160e41b815260040160405180910390fd5b60006117e382610d0d565b60008381526003602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b6009546001600160a01b0316331461187c57604051636db2465f60e01b815260040160405180910390fd5b565b600061188a85856112c3565b90506118978184846124ef565b6001600160a01b0383166000908152600860209081526040808320858452909152902054156118d95760405163188a497360e01b815260040160405180910390fd5b60008581526007602052604090206118f19085612533565b600085815260066020908152604080832080546001808201835591855283852086516002909202019081558584015190820180546001600160a01b0319166001600160a01b03928316179055871680855260088452828520878652845293829020555186815284929188917f29486b9e2ae569b440933a9b1b421467306fa21f3dcad439c262910a634963a9910160405180910390a4611354565b60008061199884611513565b5091509150856001600160a01b0316826001600160a01b0316146119cf5760405163e146af6f60e01b815260040160405180910390fd5b6001600160a01b0385166119f6576040516338f646ff60e21b815260040160405180910390fd5b611a0582868360008888612340565b6001600160a01b0386166000908152600260205260408120805460019290611a2e9084906131af565b90915550611a419050846000878161239b565b6001600160a01b0385166000908152600260205260408120805460019290611a6a90849061326d565b909155505060405184906001600160a01b0380881691908916906000805160206133c683398151915290600090a483856001600160a01b0316836001600160a01b03166000805160206133a6833981519152846000604051610ea2929190918252602082015260400190565b611ae033826125ed565b611510576040516302728a9d60e41b815260040160405180910390fd5b600082815260076020526040902054811015611b2c57604051631e73178b60e11b815260040160405180910390fd5b6000828152600760205260408120611b4391612961565b60405182907f8ac4a0d65950c3e40448afb2260e2e0ec36ea15644d9b39e37e85472e5f9445190600090a25050565b6000806000611b8085611513565b50915091506000611b9086610d0d565b6001600160a01b03841660009081526002602052604081208054929350600192909190611bbe9084906131af565b90915550611bc99050565b611be88360008460008a60405180602001604052806000815250612340565b611bf36000876117d8565b6000611bfe87610ef5565b6000888152600660205260408120919250611c199190612961565b6000878152600760205260408120611c3091612961565b60008781526003602090815260408083206001600160a01b0386168452909152812080546001600160a01b031916905581518190815b81811015611e3157898310611cdb57848181518110611c8757611c87613149565b602002602001015160200151858281518110611ca557611ca5613149565b6020908102919091010151516040516306177b2560e41b81526001600160a01b0390921660048301526024820152604401610b14565b60086000868381518110611cf157611cf1613149565b6020026020010151602001516001600160a01b03166001600160a01b031681526020019081526020016000206000868381518110611d3157611d31613149565b602002602001015160000151815260200190815260200160002060009055828a039350848181518110611d6657611d66613149565b6020026020010151602001516001600160a01b031663b390c0ab868381518110611d9257611d92613149565b602002602001015160000151600187611dab91906131af565b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015611dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e129190613280565b611e1d90600161326d565b611e27908461326d565b9250600101611c66565b5060008a81526005602052604080822082815560010180546001600160a81b0319169055518b91906001600160a01b038816906000805160206133c6833981519152908390a4604080518781526000602082018190528c9290916001600160a01b038b16916000805160206133a6833981519152910160405180910390a46040805160208101909152600090525b5098975050505050505050565b611ed88484848461198c565b611ee48484848461264b565b6109fa5760405163bcb5663760e01b815260040160405180910390fd5b600082611f0e858461274d565b14949350505050565b611f2283838361279a565b611f2f600084848461264b565b6108d05760405163bcb5663760e01b815260040160405180910390fd5b60408051808201909152600080825260208201528215611f7757611f7089876112c3565b9050611f84565b611f818987610a00565b90505b611f8f8186866124ef565b8215611fb2576000898152600760205260409020611fad9087612533565b611fec565b6001600160a01b038516600090815260086020908152604080832087845282528083208390558b835260069091529020611fec9087612533565b6001600160a01b038816156120d9578660000361206c57604051635c46a7ef60e11b81526001600160a01b0386169063b88d4fde906120359030908c9089908890600401613299565b600060405180830381600087803b15801561204f57600080fd5b505af1158015612063573d6000803e3d6000fd5b505050506120d9565b60208101518151604051630326051d60e11b81526001600160a01b039092169163064c0a3a916120a69130918d918d9089906004016132d6565b600060405180830381600087803b1580156120c057600080fd5b505af11580156120d4573d6000803e3d6000fd5b505050505b6040805187815284151560208201526001600160a01b038a81161582840152915186928816918c917f02d6d6dbcb604d5e1e8c7886456e82a9cdce88b0a580071358f206b5a4d58f709181900360600190a46114b0565b6001600160a01b038116612157576040516342b66a3d60e01b815260040160405180910390fd5b336001600160a01b0382160361218057604051636d6c4ee560e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b03831690811790915560405133907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60008060006121da84611513565b5091509150806000146121fd57506001600160a01b038481169116149050610727565b816001600160a01b0316856001600160a01b03161480612222575061222282866114d1565b806122465750846001600160a01b031661223b856107de565b6001600160a01b0316145b95945050505050565b60005b6064811015612326576000806000856001600160a01b031663fb25fb7a866040518263ffffffff1660e01b815260040161228e91815260200190565b606060405180830381865afa1580156122ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cf9190613310565b925092509250806122e35750505050505050565b6001600160a01b038316301480156122fa57508682145b15612318576040516324543e6d60e11b815260040160405180910390fd5b509093509150600101612252565b50604051630349a6bd60e51b815260040160405180910390fd5b6001600160a01b038616158061235d57506001600160a01b038516155b6107445760405162461bcd60e51b815260206004820152600f60248201526e29b7bab63137bab732103a37b5b2b760891b6044820152606401610b14565b604080516060810182528481526001600160a01b03808516602080840191825285151584860190815260008a815260059092529481209351845590516001909301805494511515600160a01b026001600160a81b031990951693909216929092179290921790915561240d90856117d8565b6109fa565b6040516318d5243360e21b815285906001600160a01b0382169063635490cc9061244490879087908790600401613353565b600060405180830381600087803b15801561245e57600080fd5b505af1158015612472573d6000803e3d6000fd5b5050505082866001600160a01b0316886001600160a01b03166000805160206133c683398151915260405160405180910390a482866001600160a01b0316886001600160a01b03166000805160206133a683398151915288886040516124e2929190918252602082015260400190565b60405180910390a4611139565b82602001516001600160a01b0316826001600160a01b0316141580612515575082518114155b156108d057604051637383f2c160e11b815260040160405180910390fd5b81548290612543906001906131af565b8154811061255357612553613149565b906000526020600020906002020182828154811061257357612573613149565b600091825260209091208254600290920201908155600191820154910180546001600160a01b0319166001600160a01b0390921691909117905581548290806125be576125be613372565b60008281526020812060026000199093019283020190815560010180546001600160a01b031916905590555050565b6000806125f983610d0d565b9050806001600160a01b0316846001600160a01b03161480612620575061262081856114d1565b806113365750836001600160a01b0316612639846107de565b6001600160a01b031614949350505050565b60006001600160a01b0384163b1561274257604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061268f903390899088908890600401613299565b6020604051808303816000875af19250505080156126ca575060408051601f3d908101601f191682019092526126c791810190613388565b60015b612728573d8080156126f8576040519150601f19603f3d011682016040523d82523d6000602084013e6126fd565b606091505b5080516000036127205760405163bcb5663760e01b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611336565b506001949350505050565b600081815b84518110156127925761277e8286838151811061277157612771613149565b6020026020010151612808565b91508061278a816131de565b915050612752565b509392505050565b6127a7838360008461283a565b60405182906001600160a01b038516906000906000805160206133c6833981519152908290a46040805160008082526020820181905284926001600160a01b038716926000805160206133a6833981519152910160405180910390a4505050565b6000818310612824576000828152602084905260409020612833565b60008381526020839052604090205b9392505050565b6001600160a01b038416612861576040516325bd6bd360e01b815260040160405180910390fd5b6000838152600560205260409020600101546001600160a01b03161561289a5760405163c5a8d37160e01b815260040160405180910390fd5b826000036128bb576040516312c33ce360e01b815260040160405180910390fd5b6128cb6000856000858786612340565b6001600160a01b03841660009081526002602052604081208054600192906128f490849061326d565b9091555050604080516060810182528381526001600160a01b039586166020808301918252941515828401908152600096875260059095529190942093518455516001909301805492511515600160a01b026001600160a81b031990931693909416929092171790915550565b508054600082556002029060005260206000209081019061151091905b808211156129a457600081556001810180546001600160a01b031916905560020161297e565b5090565b6001600160e01b03198116811461151057600080fd5b6000602082840312156129d057600080fd5b8135612833816129a8565b6001600160a01b038116811461151057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612a2f57612a2f6129f0565b604052919050565b600082601f830112612a4857600080fd5b813567ffffffffffffffff811115612a6257612a626129f0565b612a75601f8201601f1916602001612a06565b818152846020838601011115612a8a57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612abf57600080fd5b8535612aca816129db565b94506020860135612ada816129db565b93506040860135925060608601359150608086013567ffffffffffffffff811115612b0457600080fd5b612b1088828901612a37565b9150509295509295909350565b60005b83811015612b38578181015183820152602001612b20565b50506000910152565b60008151808452612b59816020860160208601612b1d565b601f01601f19169290920160200192915050565b6020815260006128336020830184612b41565b600060208284031215612b9257600080fd5b5035919050565b600060208284031215612bab57600080fd5b8135612833816129db565b602080825282518282018190526000919060409081850190868401855b82811015612c0957612bf9848351805182526020908101516001600160a01b0316910152565b9284019290850190600101612bd3565b5091979650505050505050565b60008060408385031215612c2957600080fd5b8235612c34816129db565b946020939093013593505050565b60008060408385031215612c5557600080fd5b50508035926020909101359150565b600080600060608486031215612c7957600080fd5b8335612c84816129db565b92506020840135612c94816129db565b929592945050506040919091013590565b815181526020808301516001600160a01b03169082015260408101610727565b600067ffffffffffffffff821115612cdf57612cdf6129f0565b5060051b60200190565b60006020808385031215612cfc57600080fd5b823567ffffffffffffffff80821115612d1457600080fd5b818501915085601f830112612d2857600080fd5b8135612d3b612d3682612cc5565b612a06565b81815260059190911b83018401908481019088831115612d5a57600080fd5b8585015b83811015611ebf57803585811115612d765760008081fd5b612d848b89838a0101612a37565b845250918601918601612d5e565b600080600060608486031215612da757600080fd5b8335925060208401359150604084013567ffffffffffffffff811115612dcc57600080fd5b612dd886828701612a37565b9150509250925092565b600060208284031215612df457600080fd5b813567ffffffffffffffff811115612e0b57600080fd5b61133684828501612a37565b600080600060608486031215612e2c57600080fd5b8335612e37816129db565b9250602084013567ffffffffffffffff80821115612e5457600080fd5b612e6087838801612a37565b93506040860135915080821115612e7657600080fd5b50612dd886828701612a37565b600060208284031215612e9557600080fd5b813567ffffffffffffffff8116811461283357600080fd5b801515811461151057600080fd5b60008060408385031215612ece57600080fd5b8235612ed9816129db565b91506020830135612ee981612ead565b809150509250929050565b60008060008060808587031215612f0a57600080fd5b8435612f15816129db565b93506020850135612f25816129db565b925060408501359150606085013567ffffffffffffffff811115612f4857600080fd5b612f5487828801612a37565b91505092959194509250565b600080600060608486031215612f7557600080fd5b833592506020808501359250604085013567ffffffffffffffff811115612f9b57600080fd5b8501601f81018713612fac57600080fd5b8035612fba612d3682612cc5565b81815260059190911b82018301908381019089831115612fd957600080fd5b928401925b82841015612ff757833582529284019290840190612fde565b80955050505050509250925092565b600080600080600080600080610100898b03121561302357600080fd5b883597506020890135613035816129db565b965060408901359550606089013594506080890135613053816129db565b935060a0890135925060c089013561306a81612ead565b915060e089013567ffffffffffffffff81111561308657600080fd5b6130928b828c01612a37565b9150509295985092959890939650565b600080600080608085870312156130b857600080fd5b843593506020850135925060408501356130d1816129db565b9396929550929360600135925050565b600080604083850312156130f457600080fd5b82356130ff816129db565b91506020830135612ee9816129db565b600181811c9082168061312357607f821691505b60208210810361314357634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b83815282602082015260806040820152600061317e6080830184612b41565b82810360608401526000815260208101915050949350505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561072757610727613199565b600082516131d4818460208701612b1d565b9190910192915050565b6000600182016131f0576131f0613199565b5060010190565b60006020828403121561320957600080fd5b8151612833816129db565b8481528360208201526080604082015260006132336080830185612b41565b82810360608401526132458185612b41565b979650505050505050565b60006020828403121561326257600080fd5b815161283381612ead565b8082018082111561072757610727613199565b60006020828403121561329257600080fd5b5051919050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906132cc90830184612b41565b9695505050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061324590830184612b41565b60008060006060848603121561332557600080fd5b8351613330816129db565b60208501516040860151919450925061334881612ead565b809150509250925092565b8381528260208201526060604082015260006122466060830184612b41565b634e487b7160e01b600052603160045260246000fd5b60006020828403121561339a57600080fd5b8151612833816129a856fe04444026cefd1b05506559cab59d1b865ae3ba4ed2fe5c894f04e522776c552dddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220cc09a863b0d2bb13cb76e1f7d2dc71b68e2e23f891786da65fa3d78561e30e4d64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000003425514b0d1e6b4583cee39fee8cfcaa13960626000000000000000000000000000000000000000000000000000000000000000c424c534d2d50726f66696c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005424c534d50000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name (string): BLSM-Profile
Arg [1] : symbol (string): BLSMP
Arg [2] : multisigOwner (address): 0x3425514B0d1E6b4583cEE39feE8CFcAa13960626
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 0000000000000000000000003425514b0d1e6b4583cee39fee8cfcaa13960626
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [4] : 424c534d2d50726f66696c650000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 424c534d50000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.