ETH Price: $2,873.32 (-9.23%)
Gas: 13 Gwei

Token

Honest Work by 0xfff (HONESTWORK)
 

Overview

Max Total Supply

104 HONESTWORK

Holders

76

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
hot.sdv.eth
Balance
1 HONESTWORK
0x34db35639eafe2712ae1f69dfa298b06a5c25053
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# 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
File 1 of 8 : Ownable.sol
// 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();
        _;
    }
}

File 2 of 8 : MerkleProofLib.sol
// 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
        }
    }
}

File 3 of 8 : ReentrancyGuard.sol
// 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)
            }
        }
        _;
    }
}

File 4 of 8 : SoladyHonestWorkERC721.sol
// 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)
            }
        }
    }
}

File 5 of 8 : HonestWork.sol
// 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;
            }
        }
    }
}

File 6 of 8 : HonestWorkAdmin.sol
// 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);
    }
}

File 7 of 8 : IHonestWorkLogic.sol
// 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);
}

File 8 of 8 : Util.sol
// 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]));
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 2000000
  },
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"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"}]

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.