ETH Price: $1,872.66 (-0.29%)

Transaction Decoder

Block:
17257206 at May-14-2023 09:23:23 AM +UTC
Transaction Fee:
0.003381079464729712 ETH $6.33
Gas Used:
81,814 Gas / 41.326416808 Gwei

Emitted Events:

257 FundropPass.MinterReferred( referrer=0x9D1CB67F...F71988e9e )
258 FundropPass.Transfer( from=0x00000000...000000000, to=[Sender] 0xa287a56789747796e93783b7f8dc4137be788668, tokenId=122463 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...895470803
(Coinbase: MEV Builder)
0.651520209938756065 Eth0.651528391338756065 Eth0.0000081814
0xA287a567...7bE788668
0.004 Eth
Nonce: 184
0.000618920535270288 Eth
Nonce: 185
0.003381079464729712

Execution Trace

FundropPass.mint( referrer=0x9D1CB67Fd65Fa0B842a873ebDc269f6F71988e9e, signature=0x7A8B16988E07C8AAA7FD00CE9764AF4A90A806A0D874551DC68DB02103B6020E3FCAD230ECB363742645BFC9798C11E1851DB26D2CD0DF0F1719168BFD6860801B )
  • Null: 0x000...001.e812c025( )
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes calldata data
        ) external;
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
         * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
         * understand this adds an external call which potentially creates a reentrancy vulnerability.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
    pragma solidity ^0.8.0;
    import "../IERC721.sol";
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Metadata is IERC721 {
        /**
         * @dev Returns the token collection name.
         */
        function name() external view returns (string memory);
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() external view returns (string memory);
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) external view returns (string memory);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    /// @notice Gas optimized ECDSA wrapper.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
    /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
    /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
    library ECDSA {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                        CUSTOM ERRORS                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The signature is invalid.
        error InvalidSignature();
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         CONSTANTS                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The number which `s` must not exceed in order for
        /// the signature to be non-malleable.
        bytes32 private constant _MALLEABILITY_THRESHOLD =
            0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                    RECOVERY OPERATIONS                     */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        // Note: as of Solady version 0.0.68, these functions will
        // revert upon recovery failure for more safety by default.
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the `signature`.
        ///
        /// This function does NOT accept EIP-2098 short form signatures.
        /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
        /// short form signatures instead.
        function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
            /// @solidity memory-safe-assembly
            assembly {
                // Copy the free memory pointer so that we can restore it later.
                let m := mload(0x40)
                // Copy `r` and `s`.
                mstore(0x40, mload(add(signature, 0x20))) // `r`.
                let s := mload(add(signature, 0x40))
                mstore(0x60, s)
                // Store the `hash` in the scratch space.
                mstore(0x00, hash)
                // Compute `v` and store it in the scratch space.
                mstore(0x20, byte(0, mload(add(signature, 0x60))))
                pop(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        and(
                            // If the signature is exactly 65 bytes in length.
                            eq(mload(signature), 65),
                            // If `s` in lower half order, such that the signature is not malleable.
                            lt(s, add(_MALLEABILITY_THRESHOLD, 1))
                        ), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x00, // Start of output.
                        0x20 // Size of output.
                    )
                )
                result := mload(0x00)
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(returndatasize()) {
                    // Store the function selector of `InvalidSignature()`.
                    mstore(0x00, 0x8baa579f)
                    // Revert with (offset, size).
                    revert(0x1c, 0x04)
                }
                // Restore the zero slot.
                mstore(0x60, 0)
                // Restore the free memory pointer.
                mstore(0x40, m)
            }
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the `signature`.
        ///
        /// This function does NOT accept EIP-2098 short form signatures.
        /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
        /// short form signatures instead.
        function recoverCalldata(bytes32 hash, bytes calldata signature)
            internal
            view
            returns (address result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                // Copy the free memory pointer so that we can restore it later.
                let m := mload(0x40)
                // Directly copy `r` and `s` from the calldata.
                calldatacopy(0x40, signature.offset, 0x40)
                // Store the `hash` in the scratch space.
                mstore(0x00, hash)
                // Compute `v` and store it in the scratch space.
                mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40))))
                pop(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        and(
                            // If the signature is exactly 65 bytes in length.
                            eq(signature.length, 65),
                            // If `s` in lower half order, such that the signature is not malleable.
                            lt(mload(0x60), add(_MALLEABILITY_THRESHOLD, 1))
                        ), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x00, // Start of output.
                        0x20 // Size of output.
                    )
                )
                result := mload(0x00)
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(returndatasize()) {
                    // Store the function selector of `InvalidSignature()`.
                    mstore(0x00, 0x8baa579f)
                    // Revert with (offset, size).
                    revert(0x1c, 0x04)
                }
                // Restore the zero slot.
                mstore(0x60, 0)
                // Restore the free memory pointer.
                mstore(0x40, m)
            }
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the EIP-2098 short form signature defined by `r` and `vs`.
        ///
        /// This function only accepts EIP-2098 short form signatures.
        /// See: https://eips.ethereum.org/EIPS/eip-2098
        ///
        /// To be honest, I do not recommend using EIP-2098 signatures
        /// for simplicity, performance, and security reasons. Most if not
        /// all clients support traditional non EIP-2098 signatures by default.
        /// As such, this method is intentionally not fully inlined.
        /// It is merely included for completeness.
        function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
            uint8 v;
            bytes32 s;
            /// @solidity memory-safe-assembly
            assembly {
                s := shr(1, shl(1, vs))
                v := add(shr(255, vs), 27)
            }
            result = recover(hash, v, r, s);
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the signature defined by `v`, `r`, `s`.
        function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
            internal
            view
            returns (address result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                // Copy the free memory pointer so that we can restore it later.
                let m := mload(0x40)
                mstore(0x00, hash)
                mstore(0x20, and(v, 0xff))
                mstore(0x40, r)
                mstore(0x60, s)
                pop(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        // If `s` in lower half order, such that the signature is not malleable.
                        lt(s, add(_MALLEABILITY_THRESHOLD, 1)), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x00, // Start of output.
                        0x20 // Size of output.
                    )
                )
                result := mload(0x00)
                // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                if iszero(returndatasize()) {
                    // Store the function selector of `InvalidSignature()`.
                    mstore(0x00, 0x8baa579f)
                    // Revert with (offset, size).
                    revert(0x1c, 0x04)
                }
                // Restore the zero slot.
                mstore(0x60, 0)
                // Restore the free memory pointer.
                mstore(0x40, m)
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                   TRY-RECOVER OPERATIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        // WARNING!
        // These functions will NOT revert upon recovery failure.
        // Instead, they will return the zero address upon recovery failure.
        // It is critical that the returned address is NEVER compared against
        // a zero address (e.g. an uninitialized address variable).
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the `signature`.
        ///
        /// This function does NOT accept EIP-2098 short form signatures.
        /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
        /// short form signatures instead.
        function tryRecover(bytes32 hash, bytes memory signature)
            internal
            view
            returns (address result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(xor(mload(signature), 65)) {
                    // Copy the free memory pointer so that we can restore it later.
                    let m := mload(0x40)
                    // Copy `r` and `s`.
                    mstore(0x40, mload(add(signature, 0x20))) // `r`.
                    let s := mload(add(signature, 0x40))
                    mstore(0x60, s)
                    // If `s` in lower half order, such that the signature is not malleable.
                    if iszero(gt(s, _MALLEABILITY_THRESHOLD)) {
                        // Store the `hash` in the scratch space.
                        mstore(0x00, hash)
                        // Compute `v` and store it in the scratch space.
                        mstore(0x20, byte(0, mload(add(signature, 0x60))))
                        pop(
                            staticcall(
                                gas(), // Amount of gas left for the transaction.
                                0x01, // Address of `ecrecover`.
                                0x00, // Start of input.
                                0x80, // Size of input.
                                0x40, // Start of output.
                                0x20 // Size of output.
                            )
                        )
                        // Restore the zero slot.
                        mstore(0x60, 0)
                        // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                        result := mload(xor(0x60, returndatasize()))
                    }
                    // Restore the free memory pointer.
                    mstore(0x40, m)
                }
            }
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the `signature`.
        ///
        /// This function does NOT accept EIP-2098 short form signatures.
        /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
        /// short form signatures instead.
        function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
            internal
            view
            returns (address result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                if iszero(xor(signature.length, 65)) {
                    // Copy the free memory pointer so that we can restore it later.
                    let m := mload(0x40)
                    // Directly copy `r` and `s` from the calldata.
                    calldatacopy(0x40, signature.offset, 0x40)
                    // If `s` in lower half order, such that the signature is not malleable.
                    if iszero(gt(mload(0x60), _MALLEABILITY_THRESHOLD)) {
                        // Store the `hash` in the scratch space.
                        mstore(0x00, hash)
                        // Compute `v` and store it in the scratch space.
                        mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40))))
                        pop(
                            staticcall(
                                gas(), // Amount of gas left for the transaction.
                                0x01, // Address of `ecrecover`.
                                0x00, // Start of input.
                                0x80, // Size of input.
                                0x40, // Start of output.
                                0x20 // Size of output.
                            )
                        )
                        // Restore the zero slot.
                        mstore(0x60, 0)
                        // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                        result := mload(xor(0x60, returndatasize()))
                    }
                    // Restore the free memory pointer.
                    mstore(0x40, m)
                }
            }
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the EIP-2098 short form signature defined by `r` and `vs`.
        ///
        /// This function only accepts EIP-2098 short form signatures.
        /// See: https://eips.ethereum.org/EIPS/eip-2098
        ///
        /// To be honest, I do not recommend using EIP-2098 signatures
        /// for simplicity, performance, and security reasons. Most if not
        /// all clients support traditional non EIP-2098 signatures by default.
        /// As such, this method is intentionally not fully inlined.
        /// It is merely included for completeness.
        function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
            internal
            view
            returns (address result)
        {
            uint8 v;
            bytes32 s;
            /// @solidity memory-safe-assembly
            assembly {
                s := shr(1, shl(1, vs))
                v := add(shr(255, vs), 27)
            }
            result = tryRecover(hash, v, r, s);
        }
        /// @dev Recovers the signer's address from a message digest `hash`,
        /// and the signature defined by `v`, `r`, `s`.
        function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
            internal
            view
            returns (address result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                // Copy the free memory pointer so that we can restore it later.
                let m := mload(0x40)
                // If `s` in lower half order, such that the signature is not malleable.
                if iszero(gt(s, _MALLEABILITY_THRESHOLD)) {
                    // Store the `hash`, `v`, `r`, `s` in the scratch space.
                    mstore(0x00, hash)
                    mstore(0x20, and(v, 0xff))
                    mstore(0x40, r)
                    mstore(0x60, s)
                    pop(
                        staticcall(
                            gas(), // Amount of gas left for the transaction.
                            0x01, // Address of `ecrecover`.
                            0x00, // Start of input.
                            0x80, // Size of input.
                            0x40, // Start of output.
                            0x20 // Size of output.
                        )
                    )
                    // Restore the zero slot.
                    mstore(0x60, 0)
                    // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
                    result := mload(xor(0x60, returndatasize()))
                }
                // Restore the free memory pointer.
                mstore(0x40, m)
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                     HASHING OPERATIONS                     */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns an Ethereum Signed Message, created from a `hash`.
        /// This produces a hash corresponding to the one signed with the
        /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
        /// JSON-RPC method as part of EIP-191.
        function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                // Store into scratch space for keccak256.
                mstore(0x20, hash)
                mstore(0x00, "\\x00\\x00\\x00\\x00\\x19Ethereum Signed Message:\
    32")
                // 0x40 - 0x04 = 0x3c
                result := keccak256(0x04, 0x3c)
            }
        }
        /// @dev Returns an Ethereum Signed Message, created from `s`.
        /// This produces a hash corresponding to the one signed with the
        /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
        /// JSON-RPC method as part of EIP-191.
        function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
            assembly {
                // The length of "\\x19Ethereum Signed Message:\
    " is 26 bytes (i.e. 0x1a).
                // If we reserve 2 words, we'll have 64 - 26 = 38 bytes to store the
                // ASCII decimal representation of the length of `s` up to about 2 ** 126.
                // Instead of allocating, we temporarily copy the 64 bytes before the
                // start of `s` data to some variables.
                let m := mload(sub(s, 0x20))
                // The length of `s` is in bytes.
                let sLength := mload(s)
                let ptr := add(s, 0x20)
                let w := not(0)
                // `end` marks the end of the memory which we will compute the keccak256 of.
                let end := add(ptr, sLength)
                // Convert the length of the bytes to ASCII decimal representation
                // and store it into the memory.
                for { let temp := sLength } 1 {} {
                    ptr := add(ptr, w) // `sub(ptr, 1)`.
                    mstore8(ptr, add(48, mod(temp, 10)))
                    temp := div(temp, 10)
                    if iszero(temp) { break }
                }
                // Copy the header over to the memory.
                mstore(sub(ptr, 0x20), "\\x00\\x00\\x00\\x00\\x00\\x00\\x19Ethereum Signed Message:\
    ")
                // Compute the keccak256 of the memory.
                result := keccak256(sub(ptr, 0x1a), sub(end, sub(ptr, 0x1a)))
                // Restore the previous memory.
                mstore(s, sLength)
                mstore(sub(s, 0x20), m)
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                   EMPTY CALLDATA HELPERS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns an empty calldata bytes.
        function emptySignature() internal pure returns (bytes calldata signature) {
            /// @solidity memory-safe-assembly
            assembly {
                signature.length := 0
            }
        }
    }
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.17;
    import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol";
    import {IERC721} from "openzeppelin/token/ERC721/IERC721.sol";
    import {IERC721Metadata} from "openzeppelin/token/ERC721/extensions/IERC721Metadata.sol";
    import {ECDSA} from "solady/utils/ECDSA.sol";
    import {Ownable} from "openzeppelin/access/Ownable.sol";
    import "./NonTransferrableERC721.sol";
    import "./IERC4906.sol";
    import "./IFundropRewards.sol";
    import "./IMetadataRenderer.sol";
    contract FundropPass is NonTransferrableERC721, IERC4906, Ownable {
        address public metadataRenderer;
        address public rewardsDistributor;
        address public metadataUpdater;
        address public signer;
        bool public mintOpen;
        error InvalidSignature();
        error MintClosed();
        error OnlyOwnerOrMetadataUpdater();
        event MinterReferred(address referrer);
        constructor() NonTransferrableERC721("mint.fun !fundrop pass", "FUNPASS") {
            if (msg.sender != tx.origin) {
                transferOwnership(tx.origin);
            }
        }
        function mint(address referrer, bytes calldata signature) public {
            if (!mintOpen) revert MintClosed();
            address recovered = ECDSA.tryRecoverCalldata(keccak256(abi.encodePacked(msg.sender, referrer)), signature);
            if (recovered != signer) revert InvalidSignature();
            if (referrer != address(0)) emit MinterReferred(referrer);
            _mint(msg.sender);
        }
        function tokenURI(uint256 id) public view override returns (string memory) {
            if (!_exists(id)) revert InvalidTokenId();
            return IMetadataRenderer(metadataRenderer).tokenURI(id);
        }
        // Admin functions
        function refreshMetadata() public {
            if (msg.sender != metadataUpdater && msg.sender != owner()) {
                revert OnlyOwnerOrMetadataUpdater();
            }
            emit BatchMetadataUpdate(0, type(uint256).max);
        }
        function setMetadataRenderer(address _metadataRenderer) public onlyOwner {
            metadataRenderer = _metadataRenderer;
            refreshMetadata();
        }
        function setMetadataUpdater(address _metadataUpdater) public onlyOwner {
            metadataUpdater = _metadataUpdater;
        }
        function setSigner(address _signer) public onlyOwner {
            signer = _signer;
        }
        function setRewardsDistributor(address _rewardsDistributor) public onlyOwner {
            rewardsDistributor = _rewardsDistributor;
        }
        function setMintOpen(bool _mintOpen) public onlyOwner {
            mintOpen = _mintOpen;
        }
        function adminBurn(uint256[] calldata ids) public onlyOwner {
            for (uint256 i = 0; i < ids.length; i++) {
                _burn(ids[i]);
            }
        }
        function supportsInterface(bytes4 interfaceId) public pure virtual override returns (bool) {
            return interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC721).interfaceId
                || interfaceId == type(IERC4906).interfaceId || interfaceId == type(IERC721Metadata).interfaceId;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.17;
    interface IERC4906 {
        /// @dev This event emits when the metadata of a token is changed.
        /// So that the third-party platforms such as NFT market could
        /// timely update the images and related attributes of the NFT.
        event MetadataUpdate(uint256 _tokenId);
        /// @dev This event emits when the metadata of a range of tokens is changed.
        /// So that the third-party platforms such as NFT market could
        /// timely update the images and related attributes of the NFTs.
        event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
    }
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.17;
    interface IFundropRewards {
        function getRewardsBalance(address _minter) external view returns (uint256);
        function claimRewards(address _minter, bytes memory _args) external;
    }
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.17;
    interface IMetadataRenderer {
        function tokenURI(uint256 id) external view returns (string memory);
    }
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.17;
    import {IERC721} from "openzeppelin/token/ERC721/IERC721.sol";
    import {IERC721Metadata} from "openzeppelin/token/ERC721/extensions/IERC721Metadata.sol";
    import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol";
    abstract contract NonTransferrableERC721 is IERC721, IERC721Metadata {
        string public override name;
        string public override symbol;
        mapping(uint256 => address) private _owners;
        mapping(address => uint256) private _tokens;
        uint256 private _nextTokenId = 1;
        uint256 private _burnedTokenCount;
        error AlreadyMinted();
        error InvalidAddress();
        error InvalidTokenId();
        error NonTransferrable();
        constructor(string memory _name, string memory _symbol) {
            name = _name;
            symbol = _symbol;
        }
        function _mint(address to) internal {
            if (to == address(0)) revert InvalidAddress();
            if (_tokens[to] != 0) revert AlreadyMinted();
            unchecked {
                uint256 tokenId = _nextTokenId++;
                _owners[tokenId] = to;
                _tokens[to] = tokenId;
                emit Transfer(address(0), to, tokenId);
            }
        }
        function _burn(uint256 tokenId) internal {
            address owner = _owners[tokenId];
            if (owner == address(0)) revert InvalidTokenId();
            _owners[tokenId] = address(0);
            _tokens[owner] = 0;
            unchecked {
                _burnedTokenCount++;
            }
            emit Transfer(owner, address(0), tokenId);
        }
        function _burn(address owner) internal {
            uint256 tokenId = _tokens[owner];
            if (tokenId == 0) revert InvalidAddress();
            _owners[tokenId] = address(0);
            _tokens[owner] = 0;
            unchecked {
                _burnedTokenCount++;
            }
            emit Transfer(owner, address(0), tokenId);
        }
        function _exists(uint256 tokenId) internal view returns (bool) {
            return _owners[tokenId] != address(0);
        }
        function supportsInterface(bytes4 interfaceID) external pure virtual override returns (bool) {
            return interfaceID == type(IERC165).interfaceId || interfaceID == type(IERC721).interfaceId
                || interfaceID == type(IERC721Metadata).interfaceId;
        }
        function balanceOf(address _owner) external view override returns (uint256) {
            if (_owner == address(0)) revert InvalidAddress();
            return _tokens[_owner] > 0 ? 1 : 0;
        }
        function ownerOf(uint256 _tokenId) external view override returns (address) {
            address owner = _owners[_tokenId];
            if (owner == address(0)) revert InvalidTokenId();
            return owner;
        }
        function safeTransferFrom(address, address, uint256) external pure override {
            revert NonTransferrable();
        }
        function safeTransferFrom(address, address, uint256, bytes calldata) external pure override {
            revert NonTransferrable();
        }
        function transferFrom(address, address, uint256) external pure override {
            revert NonTransferrable();
        }
        function approve(address, uint256) external pure override {
            revert NonTransferrable();
        }
        function setApprovalForAll(address, bool) external pure override {
            revert NonTransferrable();
        }
        function getApproved(uint256) external pure override returns (address) {
            revert NonTransferrable();
        }
        function isApprovedForAll(address, address) external pure override returns (bool) {
            return false;
        }
        function totalSupply() external view returns (uint256) {
            return _nextTokenId - 1 - _burnedTokenCount;
        }
    }