Feature Tip: Add private address tag to any address under My Name Tag !
ERC-721
Overview
Max Total Supply
105 HONESTWORK
Holders
79
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 HONESTWORKLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Source Code Verified (Exact Match)
Contract Name:
HonestWork
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 2000000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSE pragma solidity 0.8.25; import "./libraries/Util.sol"; import "./HonestWorkAdmin.sol"; import "./IHonestWorkLogic.sol"; //////////////////////////////////////////////////////////////////////// // // // // // // // // // // // // // Honest Work // // ██████████████ // // █████████████████ // // Do Nothing // // ████████ // // // // // // // // // // 0xfff.eth // // // //////////////////////////////////////////////////////////////////////// contract HonestWork is HonestWorkAdmin { address immutable logicContract; constructor(address _logicContract) { logicContract = _logicContract; } /*////////////////////////////////////////////////////////////// ERC721 //////////////////////////////////////////////////////////////*/ function name() public pure override returns (string memory) { return "Honest Work by 0xfff"; } function symbol() public pure override returns (string memory) { return "HONESTWORK"; } function tokenURI(uint256 id) public view override returns (string memory) { if (!_exists(id)) revert TokenDoesNotExist(); return IHonestWorkLogic(logicContract).tokenURI(id); } function renderSVG(uint256 id) external view returns (string memory) { if (!_exists(id)) revert TokenDoesNotExist(); return IHonestWorkLogic(logicContract).renderSVG(id); } function renderSVGBase64(uint256 id) external view returns (string memory) { if (!_exists(id)) revert TokenDoesNotExist(); return IHonestWorkLogic(logicContract).renderSVGBase64(id); } /*////////////////////////////////////////////////////////////// VIEW //////////////////////////////////////////////////////////////*/ function getTodoState( uint256 id ) external view returns ( uint8 open, uint8 max, bool repeater, uint24 todoCount, uint24[3] memory activeTodosIndices, uint16[3] memory activeTodos, uint48 lastTransferTime, uint256[] memory todos ) { return IHonestWorkLogic(logicContract).getTodoState(id); } function resolveTask(uint256 id) external view returns (string memory) { return IHonestWorkLogic(logicContract).resolveTask(id); } /*////////////////////////////////////////////////////////////// LOGIC HOOK //////////////////////////////////////////////////////////////*/ function _beforeTokenTransfer(address from, address to, uint256 tokenId, bytes memory data) internal override { // We use the data field to pass on information about whether the transfer was initiated by safeTransferFrom // or by transferFrom. No data means transferFrom, data.length > 0 means safeTransferFrom if (data.length == 0) { uint isSafe; assembly { isSafe := tload(tokenId) } if (isSafe == 1) { data = abi.encode(true); } } IHonestWorkLogic(logicContract).beforeTokenTransfer{value: msg.value}( from, to, msg.sender, tokenId, balanceOf(from), data ); } /*////////////////////////////////////////////////////////////// MINT //////////////////////////////////////////////////////////////*/ function mintAllowlist( bytes32[] calldata proof, uint256 max, uint256 amount ) external payable allowlistMintChecks(proof, max, amount) nonReentrant { _mintTodo(msg.sender, editionCount + 1, amount); editionCount += amount; } function mint(uint256 amount) external payable publicMintCheck(amount) nonReentrant { _mintTodo(msg.sender, editionCount + 1, amount); editionCount += amount; } function mintAp(address to, uint256 amount) external apMintCheck(to, amount) onlyOwner nonReentrant { _mintTodo(to, MINT_SUPPLY + 1 + apCount, amount); apCount += amount; } function _mintTodo(address to, uint256 from, uint256 amount) internal { for (uint id = from; id < from + amount; ) { IHonestWorkLogic(logicContract).createTodo(id); _mintNoHooks(to, id); unchecked { ++id; } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Reentrancy guard mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol) abstract contract ReentrancyGuard { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unauthorized reentrant call. error Reentrancy(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`. /// 9 bytes is large enough to avoid collisions with lower slots, /// but not too large to result in excessive bytecode bloat. uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* REENTRANCY GUARD */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Guards a function from reentrancy. modifier nonReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } sstore(_REENTRANCY_GUARD_SLOT, address()) } _; /// @solidity memory-safe-assembly assembly { sstore(_REENTRANCY_GUARD_SLOT, codesize()) } } /// @dev Guards a view function from read-only reentrancy. modifier nonReadReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } } _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.25; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author 0xfff /// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-item log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _transferFrom(from, to, id, ""); } function _transferFrom(address from, address to, uint256 id, bytes memory data) internal { _beforeTokenTransfer(from, to, id, data); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id, data); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { uint isSafeTransfer = 1; assembly { // Seting a flag to indicate that safeTransferFrom is being called. tstore(id, isSafeTransfer) } _transferFrom(from, to, id, ""); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes calldata data) public payable virtual { _transferFrom(from, to, id, data); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id, ""); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mintNoHooks(address to, uint256 id) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeMint(address to, uint256 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id, ""); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id, ""); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Transfer} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id, data); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _beforeTokenTransfer(from, to, id, data); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id, data); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id, data); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id, bytes memory data) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id, bytes memory data) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: UNLICENSE pragma solidity 0.8.25; import "solady/src/auth/Ownable.sol"; import "solady/src/utils/MerkleProofLib.sol"; import "solady/src/utils/ReentrancyGuard.sol"; import "./3rd/SoladyHonestWorkERC721.sol"; error IncorrectPrice(); error MaxSupply(); error MaxAP(); error MintingPaused(); error MaxClaimed(); error NoDiscountForAddress(); error DontBeGreedy(); error InvalidProof(); error MaxAllowlistClaimed(); error PublicMintingNotYetOpen(); error AllowlistMintingNotYetOpen(); error TokenDoesNotExist(); abstract contract HonestWorkAdmin is ERC721, Ownable, ReentrancyGuard { uint256 public constant PRICE = 0.1 ether; uint256 public constant MINT_SUPPLY = 100; uint256 public constant ARTIST_ALLOTMENT = 12; uint256 public constant MAX_PER_TRANSACTION = 1; uint256 public editionCount; uint256 public apCount; bool public mintingPaused = true; mapping(address => uint256) public allowlistMinted; bytes32 public allowlistRoot; uint256 public allowlistFrom = 1713814200; // April 22, 2024 7.30pm UTC uint256 public publicFrom = 1713816000; // April 22, 2024 8.00pm UTC constructor() ERC721() { _initializeOwner(msg.sender); } function totalSupply() public view returns (uint256) { return editionCount + apCount; } /*////////////////////////////////////////////////////////////// CHECKS //////////////////////////////////////////////////////////////*/ modifier publicMintCheck(uint256 amount) { if (editionCount + amount > MINT_SUPPLY) revert MaxSupply(); if (mintingPaused) revert MintingPaused(); if (block.timestamp < publicFrom) revert PublicMintingNotYetOpen(); if (msg.value != amount * PRICE) revert IncorrectPrice(); if (amount > MAX_PER_TRANSACTION) revert DontBeGreedy(); _; } modifier allowlistMintChecks( bytes32[] calldata proof, uint256 max, uint256 amount ) { if (editionCount + amount > MINT_SUPPLY) revert MaxSupply(); if (mintingPaused) revert MintingPaused(); if (msg.value != amount * PRICE) revert IncorrectPrice(); if (amount > MAX_PER_TRANSACTION) revert DontBeGreedy(); if (block.timestamp < publicFrom) { if (block.timestamp < allowlistFrom) revert AllowlistMintingNotYetOpen(); bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(msg.sender, max)))); bool validProof = MerkleProofLib.verifyCalldata(proof, allowlistRoot, leaf); if (!validProof) revert InvalidProof(); if (allowlistMinted[msg.sender] + amount > max) revert MaxAllowlistClaimed(); allowlistMinted[msg.sender] += amount; } _; } modifier apMintCheck(address to, uint256 amount) { if (apCount + amount > ARTIST_ALLOTMENT) revert MaxAP(); _; } /*////////////////////////////////////////////////////////////// ADMIN //////////////////////////////////////////////////////////////*/ /// @notice Pause/Unpause minting function setPause(bool value) public onlyOwner { mintingPaused = value; } /// @notice Set allowlist mint timestamp function setAllowlistFrom(uint256 from) public onlyOwner { allowlistFrom = from; } /// @notice Set public mint timestamp function setPublicFrom(uint256 from) public onlyOwner { publicFrom = from; } /// @notice Set merkle root for reserve claims function setAllowlistRoot(bytes32 newRoot) public onlyOwner { allowlistRoot = newRoot; } /// @notice Withdraws balance to address function withdraw(address payable _to) public onlyOwner { require(_to != address(0)); (bool success, ) = _to.call{value: address(this).balance}(""); require(success); } /*////////////////////////////////////////////////////////////// UTILITY //////////////////////////////////////////////////////////////*/ /// @notice Returns the token IDs owned by the address function tokensOf(address owner) external view returns (uint256[] memory) { uint256[] memory tokens = new uint256[](balanceOf(owner)); uint256 counter; for (uint i = 1; i <= editionCount; i++) { if (_exists(i) && ownerOf(i) == owner) { tokens[counter] = i; counter++; } } for (uint i = MINT_SUPPLY + 1; i <= MINT_SUPPLY + 1 + apCount; i++) { if (_exists(i) && ownerOf(i) == owner) { tokens[counter] = i; counter++; } } return tokens; } /// @notice Returns all token owners and ids function tokenOwners() external view returns (address[] memory, uint256[] memory) { address[] memory owners = new address[](totalSupply()); uint256[] memory ids = new uint256[](totalSupply()); uint256 counter; for (uint i = 1; i <= editionCount; i++) { if (_exists(i)) { owners[counter] = ownerOf(i); ids[counter] = i; counter++; } } for (uint i = MINT_SUPPLY + 1; i <= MINT_SUPPLY + 1 + apCount; i++) { if (_exists(i)) { owners[counter] = ownerOf(i); ids[counter] = i; counter++; } } return (owners, ids); } }
// SPDX-License-Identifier: UNLICENSE pragma solidity 0.8.25; interface IHonestWorkLogic { function beforeTokenTransfer( address from, address to, address sender, uint256 tokenId, uint256 balanceOfFrom, bytes calldata data ) external payable; function tokenURI(uint256 tokenId) external view returns (string memory); function renderSVG(uint256 tokenId) external view returns (string memory); function renderSVGBase64(uint256 tokenId) external view returns (string memory); function createTodo(uint256 id) external; function getTodoState( uint256 tokenId ) external view returns ( uint8 open, uint8 max, bool repeater, uint24 todoCount, uint24[3] memory activeTodosIndices, uint16[3] memory activeTodos, uint48 lastTransferTime, uint256[] memory todos ); function resolveTask(uint256 taskId) external view returns (string memory); }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.0; library Util { error NumberHasTooManyDigits(); function getNumberOfDigits(uint256 number) internal pure returns (uint256) { if (number == 0) return 1; uint256 digits = 0; while (number != 0) { number /= 10; digits++; } return digits; } function getNumberOfDigits(int256 number) internal pure returns (uint256) { uint256 positiveNumber = uint256(number > 0 ? number : -number); return getNumberOfDigits(positiveNumber); } /// @notice wraps a string in quotes and adds a space after function quote(string memory value) internal pure returns (string memory) { return string.concat('"', value, '" '); } function keyValue(string memory _key, string memory _value) internal pure returns (string memory) { return string.concat('"', _key, '":"', _value, '"'); } function keyValueNoQuotes(string memory _key, string memory _value) internal pure returns (string memory) { return string.concat('"', _key, '":', _value); } /// @notice converts a uint256 to ascii representation, without leading zeroes /// @param _value, uint256, the value to convert /// @return result the resulting string function uint256ToString(uint256 _value) internal pure returns (string memory result) { if (_value == 0) return "0"; assembly { // largest uint = 2^256-1 has 78 digits // reserve 110 = 78 + 32 bytes of data in memory // (first 32 are for string length) // get 110 bytes of free memory result := add(mload(0x40), 110) mstore(0x40, result) // keep track of digits let digits := 0 for { } gt(_value, 0) { } { // increment digits digits := add(digits, 1) // go back one byte result := sub(result, 1) // compute ascii char let c := add(mod(_value, 10), 48) // store byte mstore8(result, c) // advance to next digit _value := div(_value, 10) } // go back 32 bytes result := sub(result, 32) // store the length mstore(result, digits) } } function int256ToString(int256 _value) internal pure returns (string memory) { if (_value < 0) { string memory unsignedValueStr = uint256ToString(uint256(-_value)); return string(abi.encodePacked("-", unsignedValueStr)); } else { return uint256ToString(uint256(_value)); } } function abs(int256 x) internal pure returns (int256) { if (x < 0) { return -x; } return x; } function bytes1ToString(bytes1 _value) internal pure returns (string memory) { return uint256ToString(uint8(_value)); } function uint8ToString(uint8 _value) internal pure returns (string memory) { return uint256ToString(_value); } /// @notice will revert in any characters are not in [0-9] function stringToUint256(string memory _value) internal pure returns (uint256 result) { // 0-9 are 48-57 bytes memory value = bytes(_value); if (value.length == 0) return 0; uint256 multiplier = 10 ** (value.length - 1); uint256 i; while (multiplier != 0) { result += uint256((uint8(value[i]) - 48)) * multiplier; unchecked { multiplier /= 10; ++i; } } } function bytes1ToHex(bytes1 _value) internal pure returns (string memory) { bytes memory result = new bytes(2); uint8 x = uint8(_value); result[0] = getHexChar(x >> 4); result[1] = getHexChar(x % 16); return string(result); } function bytes32ToBytes(bytes32 x) internal pure returns (bytes memory) { bytes memory bytesString = new bytes(32); for (uint i = 0; i < 32; i++) { if (x[i] == 0) { bytesString[i] = bytes1(0x20); } else { bytesString[i] = x[i]; } } return abi.encodePacked(bytesString); } function bytes32ToString(bytes32 x) internal pure returns (string memory) { return string(bytes32ToBytes(x)); } function bytes24ToBytes(bytes24 x) internal pure returns (bytes memory) { bytes memory bytesString = new bytes(24); for (uint i = 0; i < 24; i++) { if (x[i] == 0) { bytesString[i] = bytes1(0x20); } else { bytesString[i] = x[i]; } } return abi.encodePacked(bytesString); } function bytes24ToString(bytes24 x) internal pure returns (string memory) { return string(bytes24ToBytes(x)); } function bytes8ToBytes(bytes8 x) internal pure returns (bytes memory) { bytes memory bytesString = new bytes(8); for (uint i = 0; i < 8; i++) { if (x[i] == 0) { bytesString[i] = bytes1(0x20); } else { bytesString[i] = x[i]; } } return abi.encodePacked(bytesString); } function bytes8ToString(bytes8 x) internal pure returns (string memory) { return string(bytes8ToBytes(x)); } function getHexChar(uint8 _value) internal pure returns (bytes1) { if (_value < 10) { return bytes1(_value + 48); } _value -= 10; return bytes1(_value + 97); } function stringToBytes1(string memory _value) internal pure returns (bytes1 result) { return bytes1(uint8(stringToUint256(_value))); } function getRGBString(bytes memory _palette, uint256 _pos) internal pure returns (string memory result) { return string.concat( "#", Util.bytes1ToHex(_palette[3 * _pos]), Util.bytes1ToHex(_palette[3 * _pos + 1]), Util.bytes1ToHex(_palette[3 * _pos + 2]) ); } function getRGBString(bytes3 _color) internal pure returns (string memory result) { return string.concat("#", Util.bytes1ToHex(_color[0]), Util.bytes1ToHex(_color[1]), Util.bytes1ToHex(_color[2])); } }
{ "optimizer": { "enabled": true, "runs": 2000000 }, "evmVersion": "cancun", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_logicContract","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AllowlistMintingNotYetOpen","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"DontBeGreedy","type":"error"},{"inputs":[],"name":"IncorrectPrice","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"MaxAP","type":"error"},{"inputs":[],"name":"MaxAllowlistClaimed","type":"error"},{"inputs":[],"name":"MaxSupply","type":"error"},{"inputs":[],"name":"MintingPaused","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"PublicMintingNotYetOpen","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","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":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"ARTIST_ALLOTMENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PER_TRANSACTION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowlistFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowlistMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowlistRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"editionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getTodoState","outputs":[{"internalType":"uint8","name":"open","type":"uint8"},{"internalType":"uint8","name":"max","type":"uint8"},{"internalType":"bool","name":"repeater","type":"bool"},{"internalType":"uint24","name":"todoCount","type":"uint24"},{"internalType":"uint24[3]","name":"activeTodosIndices","type":"uint24[3]"},{"internalType":"uint16[3]","name":"activeTodos","type":"uint16[3]"},{"internalType":"uint48","name":"lastTransferTime","type":"uint48"},{"internalType":"uint256[]","name":"todos","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"},{"internalType":"uint256","name":"max","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintAllowlist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintAp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"renderSVG","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"renderSVGBase64","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"resolveTask","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":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"}],"name":"setAllowlistFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newRoot","type":"bytes32"}],"name":"setAllowlistRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"value","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"}],"name":"setPublicFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"tokenOwners","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOf","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040526002805460ff19166001179055636626bab8600555636626c1c060065534801561002c575f80fd5b50604051612b57380380612b5783398101604081905261004b916100a0565b61005433610065565b6001600160a01b03166080526100cd565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b5f602082840312156100b0575f80fd5b81516001600160a01b03811681146100c6575f80fd5b9392505050565b608051612a4861010f5f395f8181610c7201528181611089015281816111e8015281816119c501528181611aac01528181611f040152611fb70152612a485ff3fe6080604052600436106102ed575f3560e01c80638e0acd1211610186578063bedb86fb116100dc578063e6b0561311610087578063f04e283e11610062578063f04e283e14610845578063f2fde38b14610858578063fee81cf41461086b575f80fd5b8063e6b05613146107c7578063e81ed044146107e6578063e985e9c514610811575f80fd5b8063d12a4c98116100b7578063d12a4c981461077a578063e1a283d614610799578063e244fff0146107b2575f80fd5b8063bedb86fb14610728578063c87b56dd14610747578063cb14eb8714610766575f80fd5b80639dfbcde81161013c578063a5038c7411610117578063a5038c74146106d7578063b88d4fde146106f6578063be3723dd14610709575f80fd5b80639dfbcde814610691578063a0712d68146106a5578063a22cb465146106b8575f80fd5b806395d89b411161016c57806395d89b41146106245780639c9c6669146106695780639caa07c01461067e575f80fd5b80638e0acd12146105f15780639524bb4414610610575f80fd5b8063490b196b116102465780636352211e116101f157806372efa29f116101cc57806372efa29f146105705780638d859f3e146105a35780638da5cb5b146105be575f80fd5b80636352211e1461052a57806370a0823114610549578063715018a614610568575f80fd5b806354d1f13d1161022157806354d1f13d146104d75780635a3f2672146104df5780635ca2ddf11461050b575f80fd5b8063490b196b1461048f5780634bf44026146104a457806351cff8d9146104b8575f80fd5b806318160ddd116102a65780633defb819116102815780633defb8191461044857806342842e0e1461045d578063456d908e14610470575f80fd5b806318160ddd1461040b57806323b872dd1461042d5780632569296214610440575f80fd5b8063081812fc116102d6578063081812fc14610390578063095ea7b3146103d457806313e4f951146103e9575f80fd5b806301ffc9a7146102f157806306fdde0314610342575b5f80fd5b3480156102fc575f80fd5b5061032d61030b36600461213c565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561034d575f80fd5b5060408051808201909152601481527f486f6e65737420576f726b20627920307866666600000000000000000000000060208201525b60405161033991906121ce565b34801561039b575f80fd5b506103af6103aa3660046121e0565b61089c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610339565b6103e76103e2366004612218565b6108ec565b005b3480156103f4575f80fd5b506103fd6108fb565b60405161033992919061227c565b348015610416575f80fd5b5061041f610b79565b604051908152602001610339565b6103e761043b3660046122e9565b610b8e565b6103e7610bad565b348015610453575f80fd5b5061041f60065481565b6103e761046b3660046122e9565b610bfa565b34801561047b575f80fd5b5061038361048a3660046121e0565b610c40565b34801561049a575f80fd5b5061041f60055481565b3480156104af575f80fd5b5061041f5f5481565b3480156104c3575f80fd5b506103e76104d2366004612327565b610d17565b6103e7610da6565b3480156104ea575f80fd5b506104fe6104f9366004612327565b610ddf565b6040516103399190612342565b348015610516575f80fd5b506103836105253660046121e0565b610fe6565b348015610535575f80fd5b506103af6105443660046121e0565b6110cd565b348015610554575f80fd5b5061041f610563366004612327565b61112b565b6103e7611178565b34801561057b575f80fd5b5061058f61058a3660046121e0565b61118b565b60405161033998979695949392919061237a565b3480156105ae575f80fd5b5061041f67016345785d8a000081565b3480156105c9575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103af565b3480156105fc575f80fd5b506103e761060b3660046121e0565b61128c565b34801561061b575f80fd5b5061041f600c81565b34801561062f575f80fd5b5060408051808201909152600a81527f484f4e455354574f524b000000000000000000000000000000000000000000006020820152610383565b348015610674575f80fd5b5061041f60045481565b6103e761068c36600461240c565b611299565b34801561069c575f80fd5b5061041f606481565b6103e76106b33660046121e0565b611583565b3480156106c3575f80fd5b506103e76106d2366004612494565b611730565b3480156106e2575f80fd5b506103e76106f13660046121e0565b611783565b6103e76107043660046124cb565b611790565b348015610714575f80fd5b506103e7610723366004612218565b611820565b348015610733575f80fd5b506103e7610742366004612562565b6118e9565b348015610752575f80fd5b506103836107613660046121e0565b611922565b348015610771575f80fd5b5061041f600181565b348015610785575f80fd5b506103836107943660046121e0565b611a09565b3480156107a4575f80fd5b5060025461032d9060ff1681565b3480156107bd575f80fd5b5061041f60015481565b3480156107d2575f80fd5b506103e76107e13660046121e0565b611af0565b3480156107f1575f80fd5b5061041f610800366004612327565b60036020525f908152604090205481565b34801561081c575f80fd5b5061032d61082b36600461257d565b601c52670a5a2e7a000000006008525f526030600c205490565b6103e7610853366004612327565b611afd565b6103e7610866366004612327565b611b3a565b348015610876575f80fd5b5061041f610885366004612327565b63389a75e1600c9081525f91909152602090205490565b5f815f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f2082018201805460601b6108e25763ceea21b65f526004601cfd5b6001015492915050565b6108f7338383611b60565b5050565b6060805f610907610b79565b67ffffffffffffffff81111561091f5761091f6125a9565b604051908082528060200260200182016040528015610948578160200160208202803683370190505b5090505f610954610b79565b67ffffffffffffffff81111561096c5761096c6125a9565b604051908082528060200260200182016040528015610995578160200160208202803683370190505b5090505f60015b5f548111610a70575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15610a5e576109e6816110cd565b8483815181106109f8576109f86125d6565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080838381518110610a4557610a456125d6565b602090810291909101015281610a5a81612630565b9250505b80610a6881612630565b91505061099c565b505f610a7e60646001612667565b90505b60015460646001610a929190612667565b610a9c9190612667565b8111610b6e575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15610b5c57610ae4816110cd565b848381518110610af657610af66125d6565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080838381518110610b4357610b436125d6565b602090810291909101015281610b5881612630565b9250505b80610b6681612630565b915050610a81565b509194909350915050565b5f6001545f54610b899190612667565b905090565b610ba883838360405180602001604052805f815250611c0f565b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b600180825d610c1984848460405180602001604052805f815250611c0f565b823b15610c3a57610c3a84848460405180602001604052805f815250611d67565b50505050565b6040517f456d908e000000000000000000000000000000000000000000000000000000008152600481018290526060907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063456d908e906024015b5f60405180830381865afa158015610ccc573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d1191908101906126f2565b92915050565b610d1f611df0565b73ffffffffffffffffffffffffffffffffffffffff8116610d3e575f80fd5b5f8173ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f8114610d94576040519150601f19603f3d011682016040523d82523d5f602084013e610d99565b606091505b50509050806108f7575f80fd5b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b60605f610deb8361112b565b67ffffffffffffffff811115610e0357610e036125a9565b604051908082528060200260200182016040528015610e2c578160200160208202803683370190505b5090505f60015b5f548111610ef3575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15158015610eb057508473ffffffffffffffffffffffffffffffffffffffff16610e98826110cd565b73ffffffffffffffffffffffffffffffffffffffff16145b15610ee15780838381518110610ec857610ec86125d6565b602090810291909101015281610edd81612630565b9250505b80610eeb81612630565b915050610e33565b505f610f0160646001612667565b90505b60015460646001610f159190612667565b610f1f9190612667565b8111610fdd575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15158015610f9a57508473ffffffffffffffffffffffffffffffffffffffff16610f82826110cd565b73ffffffffffffffffffffffffffffffffffffffff16145b15610fcb5780838381518110610fb257610fb26125d6565b602090810291909101015281610fc781612630565b9250505b80610fd581612630565b915050610f04565b50909392505050565b6060611024825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b61105a576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5ca2ddf1000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635ca2ddf190602401610cb2565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806111265763ceea21b65f526004601cfd5b919050565b5f8161113e57638f4eb6045f526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52815f5263ffffffff601c600c2054169050919050565b611180611df0565b6111895f611e25565b565b5f805f8061119761211e565b61119f61211e565b6040517f72efa29f000000000000000000000000000000000000000000000000000000008152600481018890525f9060609073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906372efa29f906024015f60405180830381865afa15801561122c573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261127191908101906128af565b97509750975097509750975097509750919395975091939597565b611294611df0565b600455565b838383836064815f546112ac9190612667565b11156112e4576040517fb36c128400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460ff1615611321576040517feb56075600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61133367016345785d8a0000826129a3565b341461136b576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018111156113a6576040517f6b66329000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654421015611516576005544210156113ec576040517f2d5d416100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513360208201529081018390525f90606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830152016040516020818303038152906040528051906020012090505f611463868660045485611e8a565b90508061149c576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526003602052604090205484906114b8908590612667565b11156114f0576040517f58fd142e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152600360205260408120805485929061150e908490612667565b909155505050505b3068929eee149b4bd2126854036115345763ab143c065f526004601cfd5b3068929eee149b4bd2126855611558335f5460016115529190612667565b87611ec2565b845f808282546115689190612667565b90915550503868929eee149b4bd21268555050505050505050565b806064815f546115939190612667565b11156115cb576040517fb36c128400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460ff1615611608576040517feb56075600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654421015611644576040517fb0eab5a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61165667016345785d8a0000826129a3565b341461168e576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018111156116c9576040517f6b66329000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3068929eee149b4bd2126854036116e75763ab143c065f526004601cfd5b3068929eee149b4bd212685561170b335f5460016117059190612667565b84611ec2565b815f8082825461171b9190612667565b90915550503868929eee149b4bd21268555050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b61178b611df0565b600555565b6117d185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c0f92505050565b833b156118195761181985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611d6792505050565b5050505050565b8181600c816001546118329190612667565b111561186a576040517fc98cb7ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611872611df0565b3068929eee149b4bd2126854036118905763ab143c065f526004601cfd5b3068929eee149b4bd21268556118c184600154606460016118b19190612667565b6118bb9190612667565b85611ec2565b8260015f8282546118d29190612667565b90915550503868929eee149b4bd212685550505050565b6118f1611df0565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6060611960825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b611996576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc87b56dd000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401610cb2565b6060611a47825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b611a7d576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd12a4c98000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d12a4c9890602401610cb2565b611af8611df0565b600655565b611b05611df0565b63389a75e1600c52805f526020600c208054421115611b2b57636f5e88185f526004601cfd5b5f9055611b3781611e25565b50565b611b42611df0565b8060601b611b5757637448fbae5f526004601cfd5b611b3781611e25565b5f1960601c82811692508381169350815f52837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c5260205f208201820180548216915081611bb85763ceea21b65f526004601cfd5b818514851517611bdc57815f526030600c2054611bdc57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b611c1b84848484611f82565b5f8281527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902082018201805473ffffffffffffffffffffffffffffffffffffffff9586169594851694811691908287148302611c985782611c8b5763ceea21b65f526004601cfd5b63a11481005f526004601cfd5b85611caa5763ea553b345f526004601cfd5b865f528160010154925082331487331417611cd6576030600c2054611cd657634b6e7f185f526004601cfd5b8215611ce3575f82600101555b86861818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555f85905220805460010163ffffffff8116611d39576301336cea5f526004601cfd5b90558183857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4610c3a565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611dae578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611dcf573d15611dcf573d5f843e3d83fd5b508060e01b825114611de85763d1a57ed65f526004601cfd5b505050505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611189576382b429005f526004601cfd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f8315611eba578360051b8501855b803580851160051b94855260209485185260405f209301818110611e995750505b501492915050565b815b611ece8284612667565b811015610c3a576040517f48d8afd5000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906348d8afd5906024015f604051808303815f87803b158015611f5a575f80fd5b505af1158015611f6c573d5f803e3d5ffd5b50505050611f7a8482612055565b600101611ec4565b80515f03611fb557815c6001819003611fb35760408051600160208201520160405160208183030381529060405291505b505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c3c3a2f03486863387611fff8b61112b565b886040518863ffffffff1660e01b8152600401612021969594939291906129ba565b5f604051808303818588803b158015612038575f80fd5b505af115801561204a573d5f803e3d5ffd5b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff90911690816120805763ea553b345f526004601cfd5b805f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f208101810180548060601b156120c75763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff81166120f1576301336cea5f526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60405180606001604052806003906020820280368337509192915050565b5f6020828403121561214c575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461217b575f80fd5b9392505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f61217b6020830184612182565b5f602082840312156121f0575f80fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114611b37575f80fd5b5f8060408385031215612229575f80fd5b8235612234816121f7565b946020939093013593505050565b5f815180845260208085019450602084015f5b8381101561227157815187529582019590820190600101612255565b509495945050505050565b604080825283519082018190525f906020906060840190828701845b828110156122ca57815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101612298565b50505083810360208501526122df8186612242565b9695505050505050565b5f805f606084860312156122fb575f80fd5b8335612306816121f7565b92506020840135612316816121f7565b929592945050506040919091013590565b5f60208284031215612337575f80fd5b813561217b816121f7565b602081525f61217b6020830184612242565b805f5b6003811015610c3a57815161ffff16845260209384019390910190600101612357565b5f61018060ff8b168352602060ff8b166020850152891515604085015262ffffff808a16606086015260808501895f5b60038110156123c95781518416835291840191908401906001016123aa565b50505050506123db60e0840187612354565b65ffffffffffff8516610140840152806101608401526123fd81840185612242565b9b9a5050505050505050505050565b5f805f806060858703121561241f575f80fd5b843567ffffffffffffffff80821115612436575f80fd5b818701915087601f830112612449575f80fd5b813581811115612457575f80fd5b8860208260051b850101111561246b575f80fd5b6020928301999098509187013596604001359550909350505050565b8015158114611b37575f80fd5b5f80604083850312156124a5575f80fd5b82356124b0816121f7565b915060208301356124c081612487565b809150509250929050565b5f805f805f608086880312156124df575f80fd5b85356124ea816121f7565b945060208601356124fa816121f7565b935060408601359250606086013567ffffffffffffffff8082111561251d575f80fd5b818801915088601f830112612530575f80fd5b81358181111561253e575f80fd5b89602082850101111561254f575f80fd5b9699959850939650602001949392505050565b5f60208284031215612572575f80fd5b813561217b81612487565b5f806040838503121561258e575f80fd5b8235612599816121f7565b915060208301356124c0816121f7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361266057612660612603565b5060010190565b80820180821115610d1157610d11612603565b6040516060810167ffffffffffffffff8111828210171561269d5761269d6125a9565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126ea576126ea6125a9565b604052919050565b5f6020808385031215612703575f80fd5b825167ffffffffffffffff8082111561271a575f80fd5b818501915085601f83011261272d575f80fd5b81518181111561273f5761273f6125a9565b61276f847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016126a3565b91508082528684828501011115612784575f80fd5b808484018584015e5f90820190930192909252509392505050565b805160ff81168114611126575f80fd5b805162ffffff81168114611126575f80fd5b5f82601f8301126127d0575f80fd5b6127d861267a565b8060608401858111156127e9575f80fd5b845b8181101561281257805161ffff81168114612804575f80fd5b8452602093840193016127eb565b509095945050505050565b805165ffffffffffff81168114611126575f80fd5b5f82601f830112612841575f80fd5b8151602067ffffffffffffffff82111561285d5761285d6125a9565b8160051b61286c8282016126a3565b9283528481018201928281019087851115612885575f80fd5b83870192505b848310156128a45782518252918301919083019061288b565b979650505050505050565b5f805f805f805f80610180898b0312156128c7575f80fd5b6128d08961279f565b975060206128e060208b0161279f565b975060408a01516128f081612487565b96506128fe60608b016127af565b95508a609f8b011261290e575f80fd5b61291661267a565b8060e08c018d811115612927575f80fd5b60808d015b8181101561294a5761293d816127af565b845292840192840161292c565b508197506129588e826127c1565b96505050505061296b6101408a0161281d565b915061016089015167ffffffffffffffff811115612987575f80fd5b6129938b828c01612832565b9150509295985092959890939650565b8082028115828204841417610d1157610d11612603565b5f73ffffffffffffffffffffffffffffffffffffffff8089168352808816602084015280871660408401525084606083015283608083015260c060a0830152612a0660c0830184612182565b9897505050505050505056fea26469706673582212208cb32335db069a4ae77416009056bef357279ea99a705379cdf940ae3525125364736f6c63430008190033000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e
Deployed Bytecode
0x6080604052600436106102ed575f3560e01c80638e0acd1211610186578063bedb86fb116100dc578063e6b0561311610087578063f04e283e11610062578063f04e283e14610845578063f2fde38b14610858578063fee81cf41461086b575f80fd5b8063e6b05613146107c7578063e81ed044146107e6578063e985e9c514610811575f80fd5b8063d12a4c98116100b7578063d12a4c981461077a578063e1a283d614610799578063e244fff0146107b2575f80fd5b8063bedb86fb14610728578063c87b56dd14610747578063cb14eb8714610766575f80fd5b80639dfbcde81161013c578063a5038c7411610117578063a5038c74146106d7578063b88d4fde146106f6578063be3723dd14610709575f80fd5b80639dfbcde814610691578063a0712d68146106a5578063a22cb465146106b8575f80fd5b806395d89b411161016c57806395d89b41146106245780639c9c6669146106695780639caa07c01461067e575f80fd5b80638e0acd12146105f15780639524bb4414610610575f80fd5b8063490b196b116102465780636352211e116101f157806372efa29f116101cc57806372efa29f146105705780638d859f3e146105a35780638da5cb5b146105be575f80fd5b80636352211e1461052a57806370a0823114610549578063715018a614610568575f80fd5b806354d1f13d1161022157806354d1f13d146104d75780635a3f2672146104df5780635ca2ddf11461050b575f80fd5b8063490b196b1461048f5780634bf44026146104a457806351cff8d9146104b8575f80fd5b806318160ddd116102a65780633defb819116102815780633defb8191461044857806342842e0e1461045d578063456d908e14610470575f80fd5b806318160ddd1461040b57806323b872dd1461042d5780632569296214610440575f80fd5b8063081812fc116102d6578063081812fc14610390578063095ea7b3146103d457806313e4f951146103e9575f80fd5b806301ffc9a7146102f157806306fdde0314610342575b5f80fd5b3480156102fc575f80fd5b5061032d61030b36600461213c565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561034d575f80fd5b5060408051808201909152601481527f486f6e65737420576f726b20627920307866666600000000000000000000000060208201525b60405161033991906121ce565b34801561039b575f80fd5b506103af6103aa3660046121e0565b61089c565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610339565b6103e76103e2366004612218565b6108ec565b005b3480156103f4575f80fd5b506103fd6108fb565b60405161033992919061227c565b348015610416575f80fd5b5061041f610b79565b604051908152602001610339565b6103e761043b3660046122e9565b610b8e565b6103e7610bad565b348015610453575f80fd5b5061041f60065481565b6103e761046b3660046122e9565b610bfa565b34801561047b575f80fd5b5061038361048a3660046121e0565b610c40565b34801561049a575f80fd5b5061041f60055481565b3480156104af575f80fd5b5061041f5f5481565b3480156104c3575f80fd5b506103e76104d2366004612327565b610d17565b6103e7610da6565b3480156104ea575f80fd5b506104fe6104f9366004612327565b610ddf565b6040516103399190612342565b348015610516575f80fd5b506103836105253660046121e0565b610fe6565b348015610535575f80fd5b506103af6105443660046121e0565b6110cd565b348015610554575f80fd5b5061041f610563366004612327565b61112b565b6103e7611178565b34801561057b575f80fd5b5061058f61058a3660046121e0565b61118b565b60405161033998979695949392919061237a565b3480156105ae575f80fd5b5061041f67016345785d8a000081565b3480156105c9575f80fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103af565b3480156105fc575f80fd5b506103e761060b3660046121e0565b61128c565b34801561061b575f80fd5b5061041f600c81565b34801561062f575f80fd5b5060408051808201909152600a81527f484f4e455354574f524b000000000000000000000000000000000000000000006020820152610383565b348015610674575f80fd5b5061041f60045481565b6103e761068c36600461240c565b611299565b34801561069c575f80fd5b5061041f606481565b6103e76106b33660046121e0565b611583565b3480156106c3575f80fd5b506103e76106d2366004612494565b611730565b3480156106e2575f80fd5b506103e76106f13660046121e0565b611783565b6103e76107043660046124cb565b611790565b348015610714575f80fd5b506103e7610723366004612218565b611820565b348015610733575f80fd5b506103e7610742366004612562565b6118e9565b348015610752575f80fd5b506103836107613660046121e0565b611922565b348015610771575f80fd5b5061041f600181565b348015610785575f80fd5b506103836107943660046121e0565b611a09565b3480156107a4575f80fd5b5060025461032d9060ff1681565b3480156107bd575f80fd5b5061041f60015481565b3480156107d2575f80fd5b506103e76107e13660046121e0565b611af0565b3480156107f1575f80fd5b5061041f610800366004612327565b60036020525f908152604090205481565b34801561081c575f80fd5b5061032d61082b36600461257d565b601c52670a5a2e7a000000006008525f526030600c205490565b6103e7610853366004612327565b611afd565b6103e7610866366004612327565b611b3a565b348015610876575f80fd5b5061041f610885366004612327565b63389a75e1600c9081525f91909152602090205490565b5f815f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f2082018201805460601b6108e25763ceea21b65f526004601cfd5b6001015492915050565b6108f7338383611b60565b5050565b6060805f610907610b79565b67ffffffffffffffff81111561091f5761091f6125a9565b604051908082528060200260200182016040528015610948578160200160208202803683370190505b5090505f610954610b79565b67ffffffffffffffff81111561096c5761096c6125a9565b604051908082528060200260200182016040528015610995578160200160208202803683370190505b5090505f60015b5f548111610a70575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15610a5e576109e6816110cd565b8483815181106109f8576109f86125d6565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080838381518110610a4557610a456125d6565b602090810291909101015281610a5a81612630565b9250505b80610a6881612630565b91505061099c565b505f610a7e60646001612667565b90505b60015460646001610a929190612667565b610a9c9190612667565b8111610b6e575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15610b5c57610ae4816110cd565b848381518110610af657610af66125d6565b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080838381518110610b4357610b436125d6565b602090810291909101015281610b5881612630565b9250505b80610b6681612630565b915050610a81565b509194909350915050565b5f6001545f54610b899190612667565b905090565b610ba883838360405180602001604052805f815250611c0f565b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b600180825d610c1984848460405180602001604052805f815250611c0f565b823b15610c3a57610c3a84848460405180602001604052805f815250611d67565b50505050565b6040517f456d908e000000000000000000000000000000000000000000000000000000008152600481018290526060907f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff169063456d908e906024015b5f60405180830381865afa158015610ccc573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d1191908101906126f2565b92915050565b610d1f611df0565b73ffffffffffffffffffffffffffffffffffffffff8116610d3e575f80fd5b5f8173ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f8114610d94576040519150601f19603f3d011682016040523d82523d5f602084013e610d99565b606091505b50509050806108f7575f80fd5b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b60605f610deb8361112b565b67ffffffffffffffff811115610e0357610e036125a9565b604051908082528060200260200182016040528015610e2c578160200160208202803683370190505b5090505f60015b5f548111610ef3575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15158015610eb057508473ffffffffffffffffffffffffffffffffffffffff16610e98826110cd565b73ffffffffffffffffffffffffffffffffffffffff16145b15610ee15780838381518110610ec857610ec86125d6565b602090810291909101015281610edd81612630565b9250505b80610eeb81612630565b915050610e33565b505f610f0160646001612667565b90505b60015460646001610f159190612667565b610f1f9190612667565b8111610fdd575f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015460601b15158015610f9a57508473ffffffffffffffffffffffffffffffffffffffff16610f82826110cd565b73ffffffffffffffffffffffffffffffffffffffff16145b15610fcb5780838381518110610fb257610fb26125d6565b602090810291909101015281610fc781612630565b9250505b80610fd581612630565b915050610f04565b50909392505050565b6060611024825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b61105a576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f5ca2ddf1000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff1690635ca2ddf190602401610cb2565b5f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806111265763ceea21b65f526004601cfd5b919050565b5f8161113e57638f4eb6045f526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52815f5263ffffffff601c600c2054169050919050565b611180611df0565b6111895f611e25565b565b5f805f8061119761211e565b61119f61211e565b6040517f72efa29f000000000000000000000000000000000000000000000000000000008152600481018890525f9060609073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e16906372efa29f906024015f60405180830381865afa15801561122c573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261127191908101906128af565b97509750975097509750975097509750919395975091939597565b611294611df0565b600455565b838383836064815f546112ac9190612667565b11156112e4576040517fb36c128400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460ff1615611321576040517feb56075600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61133367016345785d8a0000826129a3565b341461136b576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018111156113a6576040517f6b66329000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654421015611516576005544210156113ec576040517f2d5d416100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513360208201529081018390525f90606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012090830152016040516020818303038152906040528051906020012090505f611463868660045485611e8a565b90508061149c576040517f09bde33900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526003602052604090205484906114b8908590612667565b11156114f0576040517f58fd142e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152600360205260408120805485929061150e908490612667565b909155505050505b3068929eee149b4bd2126854036115345763ab143c065f526004601cfd5b3068929eee149b4bd2126855611558335f5460016115529190612667565b87611ec2565b845f808282546115689190612667565b90915550503868929eee149b4bd21268555050505050505050565b806064815f546115939190612667565b11156115cb576040517fb36c128400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460ff1615611608576040517feb56075600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600654421015611644576040517fb0eab5a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61165667016345785d8a0000826129a3565b341461168e576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018111156116c9576040517f6b66329000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3068929eee149b4bd2126854036116e75763ab143c065f526004601cfd5b3068929eee149b4bd212685561170b335f5460016117059190612667565b84611ec2565b815f8082825461171b9190612667565b90915550503868929eee149b4bd21268555050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b61178b611df0565b600555565b6117d185858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c0f92505050565b833b156118195761181985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611d6792505050565b5050505050565b8181600c816001546118329190612667565b111561186a576040517fc98cb7ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611872611df0565b3068929eee149b4bd2126854036118905763ab143c065f526004601cfd5b3068929eee149b4bd21268556118c184600154606460016118b19190612667565b6118bb9190612667565b85611ec2565b8260015f8282546118d29190612667565b90915550503868929eee149b4bd212685550505050565b6118f1611df0565b600280547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6060611960825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b611996576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc87b56dd000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff169063c87b56dd90602401610cb2565b6060611a47825f8181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b611a7d576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd12a4c98000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff169063d12a4c9890602401610cb2565b611af8611df0565b600655565b611b05611df0565b63389a75e1600c52805f526020600c208054421115611b2b57636f5e88185f526004601cfd5b5f9055611b3781611e25565b50565b611b42611df0565b8060601b611b5757637448fbae5f526004601cfd5b611b3781611e25565b5f1960601c82811692508381169350815f52837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c5260205f208201820180548216915081611bb85763ceea21b65f526004601cfd5b818514851517611bdc57815f526030600c2054611bdc57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b611c1b84848484611f82565b5f8281527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902082018201805473ffffffffffffffffffffffffffffffffffffffff9586169594851694811691908287148302611c985782611c8b5763ceea21b65f526004601cfd5b63a11481005f526004601cfd5b85611caa5763ea553b345f526004601cfd5b865f528160010154925082331487331417611cd6576030600c2054611cd657634b6e7f185f526004601cfd5b8215611ce3575f82600101555b86861818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190555f85905220805460010163ffffffff8116611d39576301336cea5f526004601cfd5b90558183857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4610c3a565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611dae578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611dcf573d15611dcf573d5f843e3d83fd5b508060e01b825114611de85763d1a57ed65f526004601cfd5b505050505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927543314611189576382b429005f526004601cfd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f8315611eba578360051b8501855b803580851160051b94855260209485185260405f209301818110611e995750505b501492915050565b815b611ece8284612667565b811015610c3a576040517f48d8afd5000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff16906348d8afd5906024015f604051808303815f87803b158015611f5a575f80fd5b505af1158015611f6c573d5f803e3d5ffd5b50505050611f7a8482612055565b600101611ec4565b80515f03611fb557815c6001819003611fb35760408051600160208201520160405160208183030381529060405291505b505b7f000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e73ffffffffffffffffffffffffffffffffffffffff1663c3c3a2f03486863387611fff8b61112b565b886040518863ffffffff1660e01b8152600401612021969594939291906129ba565b5f604051808303818588803b158015612038575f80fd5b505af115801561204a573d5f803e3d5ffd5b505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff90911690816120805763ea553b345f526004601cfd5b805f527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260205f208101810180548060601b156120c75763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff81166120f1576301336cea5f526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b60405180606001604052806003906020820280368337509192915050565b5f6020828403121561214c575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461217b575f80fd5b9392505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f61217b6020830184612182565b5f602082840312156121f0575f80fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114611b37575f80fd5b5f8060408385031215612229575f80fd5b8235612234816121f7565b946020939093013593505050565b5f815180845260208085019450602084015f5b8381101561227157815187529582019590820190600101612255565b509495945050505050565b604080825283519082018190525f906020906060840190828701845b828110156122ca57815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101612298565b50505083810360208501526122df8186612242565b9695505050505050565b5f805f606084860312156122fb575f80fd5b8335612306816121f7565b92506020840135612316816121f7565b929592945050506040919091013590565b5f60208284031215612337575f80fd5b813561217b816121f7565b602081525f61217b6020830184612242565b805f5b6003811015610c3a57815161ffff16845260209384019390910190600101612357565b5f61018060ff8b168352602060ff8b166020850152891515604085015262ffffff808a16606086015260808501895f5b60038110156123c95781518416835291840191908401906001016123aa565b50505050506123db60e0840187612354565b65ffffffffffff8516610140840152806101608401526123fd81840185612242565b9b9a5050505050505050505050565b5f805f806060858703121561241f575f80fd5b843567ffffffffffffffff80821115612436575f80fd5b818701915087601f830112612449575f80fd5b813581811115612457575f80fd5b8860208260051b850101111561246b575f80fd5b6020928301999098509187013596604001359550909350505050565b8015158114611b37575f80fd5b5f80604083850312156124a5575f80fd5b82356124b0816121f7565b915060208301356124c081612487565b809150509250929050565b5f805f805f608086880312156124df575f80fd5b85356124ea816121f7565b945060208601356124fa816121f7565b935060408601359250606086013567ffffffffffffffff8082111561251d575f80fd5b818801915088601f830112612530575f80fd5b81358181111561253e575f80fd5b89602082850101111561254f575f80fd5b9699959850939650602001949392505050565b5f60208284031215612572575f80fd5b813561217b81612487565b5f806040838503121561258e575f80fd5b8235612599816121f7565b915060208301356124c0816121f7565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361266057612660612603565b5060010190565b80820180821115610d1157610d11612603565b6040516060810167ffffffffffffffff8111828210171561269d5761269d6125a9565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156126ea576126ea6125a9565b604052919050565b5f6020808385031215612703575f80fd5b825167ffffffffffffffff8082111561271a575f80fd5b818501915085601f83011261272d575f80fd5b81518181111561273f5761273f6125a9565b61276f847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016126a3565b91508082528684828501011115612784575f80fd5b808484018584015e5f90820190930192909252509392505050565b805160ff81168114611126575f80fd5b805162ffffff81168114611126575f80fd5b5f82601f8301126127d0575f80fd5b6127d861267a565b8060608401858111156127e9575f80fd5b845b8181101561281257805161ffff81168114612804575f80fd5b8452602093840193016127eb565b509095945050505050565b805165ffffffffffff81168114611126575f80fd5b5f82601f830112612841575f80fd5b8151602067ffffffffffffffff82111561285d5761285d6125a9565b8160051b61286c8282016126a3565b9283528481018201928281019087851115612885575f80fd5b83870192505b848310156128a45782518252918301919083019061288b565b979650505050505050565b5f805f805f805f80610180898b0312156128c7575f80fd5b6128d08961279f565b975060206128e060208b0161279f565b975060408a01516128f081612487565b96506128fe60608b016127af565b95508a609f8b011261290e575f80fd5b61291661267a565b8060e08c018d811115612927575f80fd5b60808d015b8181101561294a5761293d816127af565b845292840192840161292c565b508197506129588e826127c1565b96505050505061296b6101408a0161281d565b915061016089015167ffffffffffffffff811115612987575f80fd5b6129938b828c01612832565b9150509295985092959890939650565b8082028115828204841417610d1157610d11612603565b5f73ffffffffffffffffffffffffffffffffffffffff8089168352808816602084015280871660408401525084606083015283608083015260c060a0830152612a0660c0830184612182565b9897505050505050505056fea26469706673582212208cb32335db069a4ae77416009056bef357279ea99a705379cdf940ae3525125364736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e
-----Decoded View---------------
Arg [0] : _logicContract (address): 0xce37b9cA1604A30013fd540e13d793d13075B57E
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ce37b9ca1604a30013fd540e13d793d13075b57e
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.