ETH Price: $2,906.44 (-3.27%)
Gas: 2 Gwei

Token

Mornings (GKAM)
 

Overview

Max Total Supply

0 GKAM

Holders

133

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
0x96b215ceb2c5118141bc0c94c1401e377c6f2bfd
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:
MorningsOpenEditions

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 21 : OperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Optimized and flexible operator filterer to abide to OpenSea's
/// mandatory on-chain royalty enforcement in order for new collections to
/// receive royalties.
/// For more information, see:
/// See: https://github.com/ProjectOpenSea/operator-filter-registry
abstract contract OperatorFilterer {
    /// @dev The default OpenSea operator blocklist subscription.
    address internal constant _DEFAULT_SUBSCRIPTION = 0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6;

    /// @dev The OpenSea operator filter registry.
    address internal constant _OPERATOR_FILTER_REGISTRY = 0x000000000000AAeB6D7670E522A718067333cd4E;

    /// @dev Registers the current contract to OpenSea's operator filter,
    /// and subscribe to the default OpenSea operator blocklist.
    /// Note: Will not revert nor update existing settings for repeated registration.
    function _registerForOperatorFiltering() internal virtual {
        _registerForOperatorFiltering(_DEFAULT_SUBSCRIPTION, true);
    }

    /// @dev Registers the current contract to OpenSea's operator filter.
    /// Note: Will not revert nor update existing settings for repeated registration.
    function _registerForOperatorFiltering(address subscriptionOrRegistrantToCopy, bool subscribe)
        internal
        virtual
    {
        /// @solidity memory-safe-assembly
        assembly {
            let functionSelector := 0x7d3e3dbe // `registerAndSubscribe(address,address)`.

            // Clean the upper 96 bits of `subscriptionOrRegistrantToCopy` in case they are dirty.
            subscriptionOrRegistrantToCopy := shr(96, shl(96, subscriptionOrRegistrantToCopy))

            for {} iszero(subscribe) {} {
                if iszero(subscriptionOrRegistrantToCopy) {
                    functionSelector := 0x4420e486 // `register(address)`.
                    break
                }
                functionSelector := 0xa0af2903 // `registerAndCopyEntries(address,address)`.
                break
            }
            // Store the function selector.
            mstore(0x00, shl(224, functionSelector))
            // Store the `address(this)`.
            mstore(0x04, address())
            // Store the `subscriptionOrRegistrantToCopy`.
            mstore(0x24, subscriptionOrRegistrantToCopy)
            // Register into the registry.
            if iszero(call(gas(), _OPERATOR_FILTER_REGISTRY, 0, 0x00, 0x44, 0x00, 0x04)) {
                // If the function selector has not been overwritten,
                // it is an out-of-gas error.
                if eq(shr(224, mload(0x00)), functionSelector) {
                    // To prevent gas under-estimation.
                    revert(0, 0)
                }
            }
            // Restore the part of the free memory pointer that was overwritten,
            // which is guaranteed to be zero, because of Solidity's memory size limits.
            mstore(0x24, 0)
        }
    }

    /// @dev Modifier to guard a function and revert if the caller is a blocked operator.
    modifier onlyAllowedOperator(address from) virtual {
        if (from != msg.sender) {
            if (!_isPriorityOperator(msg.sender)) {
                if (_operatorFilteringEnabled()) _revertIfBlocked(msg.sender);
            }
        }
        _;
    }

    /// @dev Modifier to guard a function from approving a blocked operator..
    modifier onlyAllowedOperatorApproval(address operator) virtual {
        if (!_isPriorityOperator(operator)) {
            if (_operatorFilteringEnabled()) _revertIfBlocked(operator);
        }
        _;
    }

    /// @dev Helper function that reverts if the `operator` is blocked by the registry.
    function _revertIfBlocked(address operator) private view {
        /// @solidity memory-safe-assembly
        assembly {
            // Store the function selector of `isOperatorAllowed(address,address)`,
            // shifted left by 6 bytes, which is enough for 8tb of memory.
            // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL).
            mstore(0x00, 0xc6171134001122334455)
            // Store the `address(this)`.
            mstore(0x1a, address())
            // Store the `operator`.
            mstore(0x3a, operator)

            // `isOperatorAllowed` always returns true if it does not revert.
            if iszero(staticcall(gas(), _OPERATOR_FILTER_REGISTRY, 0x16, 0x44, 0x00, 0x00)) {
                // Bubble up the revert if the staticcall reverts.
                returndatacopy(0x00, 0x00, returndatasize())
                revert(0x00, returndatasize())
            }

            // We'll skip checking if `from` is inside the blacklist.
            // Even though that can block transferring out of wrapper contracts,
            // we don't want tokens to be stuck.

            // Restore the part of the free memory pointer that was overwritten,
            // which is guaranteed to be zero, if less than 8tb of memory is used.
            mstore(0x3a, 0)
        }
    }

    /// @dev For deriving contracts to override, so that operator filtering
    /// can be turned on / off.
    /// Returns true by default.
    function _operatorFilteringEnabled() internal view virtual returns (bool) {
        return true;
    }

    /// @dev For deriving contracts to override, so that preferred marketplaces can
    /// skip operator filtering, helping users save gas.
    /// Returns false for all inputs by default.
    function _isPriorityOperator(address) internal view virtual returns (bool) {
        return false;
    }
}

File 2 of 21 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

File 3 of 21 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 4 of 21 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 5 of 21 : IERC721.sol
// 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);
}

File 6 of 21 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 7 of 21 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 8 of 21 : EIP712.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;
    address private immutable _CACHED_THIS;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _CACHED_THIS = address(this);
        _TYPE_HASH = typeHash;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

File 9 of 21 : IERC165.sol
// 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);
}

File 10 of 21 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 11 of 21 : Auth.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

/**
 * @author Sam King (samkingstudio.eth) for Fount Gallery
 * @title  Simple owner and admin authentication
 * @notice Allows the management of a contract by using simple ownership and admin modifiers.
 */
abstract contract Auth {
    /* ------------------------------------------------------------------------
                                   S T O R A G E
    ------------------------------------------------------------------------ */

    /// @notice Current owner of the contract
    address public owner;

    /// @notice Current admins of the contract
    mapping(address => bool) public admins;

    /* ------------------------------------------------------------------------
                                    E V E N T S
    ------------------------------------------------------------------------ */

    /**
     * @notice When the contract owner is updated
     * @param user The account that updated the new owner
     * @param newOwner The new owner of the contract
     */
    event OwnerUpdated(address indexed user, address indexed newOwner);

    /**
     * @notice When an admin is added to the contract
     * @param user The account that added the new admin
     * @param newAdmin The admin that was added
     */
    event AdminAdded(address indexed user, address indexed newAdmin);

    /**
     * @notice When an admin is removed from the contract
     * @param user The account that removed an admin
     * @param prevAdmin The admin that got removed
     */
    event AdminRemoved(address indexed user, address indexed prevAdmin);

    /* ------------------------------------------------------------------------
                                 M O D I F I E R S
    ------------------------------------------------------------------------ */

    /**
     * @dev Only the owner can call
     */
    modifier onlyOwner() {
        require(msg.sender == owner, "UNAUTHORIZED");
        _;
    }

    /**
     * @dev Only an admin can call
     */
    modifier onlyAdmin() {
        require(admins[msg.sender], "UNAUTHORIZED");
        _;
    }

    /**
     * @dev Only the owner or an admin can call
     */
    modifier onlyOwnerOrAdmin() {
        require((msg.sender == owner || admins[msg.sender]), "UNAUTHORIZED");
        _;
    }

    /* ------------------------------------------------------------------------
                                      I N I T
    ------------------------------------------------------------------------ */

    /**
     * @dev Sets the initial owner and a first admin upon creation.
     * @param owner_ The initial owner of the contract
     * @param admin_ An initial admin of the contract
     */
    constructor(address owner_, address admin_) {
        owner = owner_;
        emit OwnerUpdated(address(0), owner_);

        admins[admin_] = true;
        emit AdminAdded(address(0), admin_);
    }

    /* ------------------------------------------------------------------------
                                     A D M I N
    ------------------------------------------------------------------------ */

    /**
     * @notice Transfers ownership of the contract to `newOwner`
     * @dev Can only be called by the current owner or an admin
     * @param newOwner The new owner of the contract
     */
    function setOwner(address newOwner) public virtual onlyOwnerOrAdmin {
        owner = newOwner;
        emit OwnerUpdated(msg.sender, newOwner);
    }

    /**
     * @notice Adds `newAdmin` as an amdin of the contract
     * @dev Can only be called by the current owner or an admin
     * @param newAdmin A new admin of the contract
     */
    function addAdmin(address newAdmin) public virtual onlyOwnerOrAdmin {
        admins[newAdmin] = true;
        emit AdminAdded(address(0), newAdmin);
    }

    /**
     * @notice Removes `prevAdmin` as an amdin of the contract
     * @dev Can only be called by the current owner or an admin
     * @param prevAdmin The admin to remove
     */
    function removeAdmin(address prevAdmin) public virtual onlyOwnerOrAdmin {
        admins[prevAdmin] = false;
        emit AdminRemoved(address(0), prevAdmin);
    }
}

File 12 of 21 : FountCardCheck.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "openzeppelin/token/ERC1155/IERC1155.sol";

/**
 * @author Sam King (samkingstudio.eth) for Fount Gallery
 * @title  Fount Gallery Card Check
 * @notice Utility functions to check ownership of a Fount Gallery Patron Card NFT
 */
contract FountCardCheck {
    /// @dev Address of the Fount Gallery Patron Card contract
    IERC1155 internal _fountCard;

    /// @dev Does not own a Fount Gallery Patron Card
    error NotFountCardHolder();

    /**
     * @dev Does not own enough Fount Gallery Patron Cards
     * @param required The minimum amount of cards that need to be owned
     * @param owned The actualy amount of cards owned
     */
    error DoesNotHoldEnoughFountCards(uint256 required, uint256 owned);

    /**
     * @dev Init with the Fount Gallery Patron Card contract address
     * @param fountCard The Fount Gallery Patron Card contract address
     */
    constructor(address fountCard) {
        _fountCard = IERC1155(fountCard);
    }

    /**
     * @dev Modifier that only allows the caller to do something if they hold
     * a Fount Gallery Patron Card
     */
    modifier onlyWhenFountCardHolder() {
        if (_getFountCardBalance(msg.sender) < 1) revert NotFountCardHolder();
        _;
    }

    /**
     * @dev Modifier that only allows the caller to do something if they hold
     * at least a specific amount Fount Gallery Patron Cards
     * @param minAmount The minimum amount of cards that need to be owned
     */
    modifier onlyWhenHoldingMinFountCards(uint256 minAmount) {
        uint256 balance = _getFountCardBalance(msg.sender);
        if (minAmount > balance) revert DoesNotHoldEnoughFountCards(minAmount, balance);
        _;
    }

    /**
     * @dev Get the number of Fount Gallery Patron Cards an address owns
     * @param owner The owner address to query
     * @return balance The balance of the owner
     */
    function _getFountCardBalance(address owner) internal view returns (uint256 balance) {
        balance = _fountCard.balanceOf(owner, 1);
    }

    /**
     * @dev Check if an address holds at least one Fount Gallery Patron Card
     * @param owner The owner address to query
     * @return isHolder If the owner holds at least one card
     */
    function _isFountCardHolder(address owner) internal view returns (bool isHolder) {
        isHolder = _getFountCardBalance(owner) > 0;
    }
}

File 13 of 21 : SwappableMetadata.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

/**
 * @author Sam King (samkingstudio.eth) for Fount Gallery
 * @title  Swappable metadata module
 * @notice Allows the use of a separate and swappable metadata contract
 */
abstract contract SwappableMetadata {
    /* ------------------------------------------------------------------------
                                   S T O R A G E
    ------------------------------------------------------------------------ */

    /// @notice Address of metadata contract
    address public metadata;

    /// @notice Flag for whether the metadata address can be updated or not
    bool public isMetadataLocked;

    /* ------------------------------------------------------------------------
                                    E R R O R S
    ------------------------------------------------------------------------ */

    error MetadataLocked();

    /* ------------------------------------------------------------------------
                                    E V E N T S
    ------------------------------------------------------------------------ */

    /**
     * @dev When the metadata contract has been set
     * @param metadataContract The new metadata contract address
     */
    event MetadataContractSet(address indexed metadataContract);

    /**
     * @dev When the metadata contract has been locked and is no longer swappable
     * @param metadataContract The final locked metadata contract address
     */
    event MetadataContractLocked(address indexed metadataContract);

    /* ------------------------------------------------------------------------
                                      I N I T
    ------------------------------------------------------------------------ */

    /**
     * @param metadata_ The address of the initial metadata contract
     */
    constructor(address metadata_) {
        metadata = metadata_;
        emit MetadataContractSet(metadata_);
    }

    /* ------------------------------------------------------------------------
                                     A D M I N
    ------------------------------------------------------------------------ */

    /**
     * @notice Sets the metadata address
     * @param metadata_ The new address of the metadata contract
     */
    function _setMetadataAddress(address metadata_) internal {
        if (isMetadataLocked) revert MetadataLocked();
        metadata = metadata_;
        emit MetadataContractSet(metadata_);
    }

    /**
     * @notice Sets the metadata address
     * @param metadata The new address of the metadata contract
     */
    function setMetadataAddress(address metadata) public virtual;

    /**
     * @dev Locks the metadata address preventing further updates
     */
    function _lockMetadata() internal {
        isMetadataLocked = true;
        emit MetadataContractLocked(metadata);
    }
}

File 14 of 21 : Royalties.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "openzeppelin/interfaces/IERC2981.sol";

/**
 * @author Sam King (samkingstudio.eth) for Fount Gallery
 * @title  Royalty payments
 * @notice Support for the royalty standard (ERC-2981)
 */
abstract contract Royalties is IERC2981 {
    /* ------------------------------------------------------------------------
                                   S T O R A G E
    ------------------------------------------------------------------------ */

    /// @dev Store information about token royalties
    struct RoyaltyInfo {
        address receiver;
        uint96 amount;
    }

    /// @dev The current royalty information
    RoyaltyInfo internal _royaltyInfo;

    /// @dev Interface id for the royalty information standard
    /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
    bytes4 internal constant ROYALTY_INTERFACE_ID = 0x2a55205a;

    /* ------------------------------------------------------------------------
                                    E R R O R S
    ------------------------------------------------------------------------ */

    error MoreThanOneHundredPercentRoyalty();

    /* ------------------------------------------------------------------------
                                    E V E N T S
    ------------------------------------------------------------------------ */

    event RoyaltyInfoSet(address indexed receiver, uint256 indexed amount);
    event RoyaltyInfoUpdated(address indexed receiver, uint256 indexed amount);

    /* ------------------------------------------------------------------------
                                      I N I T
    ------------------------------------------------------------------------ */

    /**
     * @param royaltiesReceiver The receiver of royalty payments
     * @param royaltiesAmount The royalty percentage with two decimals (10,000 = 100%)
     */
    constructor(address royaltiesReceiver, uint256 royaltiesAmount) {
        _royaltyInfo = RoyaltyInfo(royaltiesReceiver, uint96(royaltiesAmount));
        emit RoyaltyInfoSet(royaltiesReceiver, royaltiesAmount);
    }

    /* ------------------------------------------------------------------------
                                  E R C 2 9 8 1
    ------------------------------------------------------------------------ */

    /// @notice EIP-2981 royalty standard for on-chain royalties
    function royaltyInfo(uint256, uint256 salePrice)
        public
        view
        virtual
        returns (address receiver, uint256 royaltyAmount)
    {
        receiver = _royaltyInfo.receiver;
        royaltyAmount = (salePrice * _royaltyInfo.amount) / 100_00;
    }

    /* ------------------------------------------------------------------------
                                     A D M I N
    ------------------------------------------------------------------------ */

    /**
     * @dev Internal function to set the royalty information
     * @param receiver The receiver of royalty payments
     * @param amount The royalty percentage with two decimals (10,000 = 100%)
     */
    function _setRoyaltyInfo(address receiver, uint256 amount) internal {
        if (amount > 100_00) revert MoreThanOneHundredPercentRoyalty();
        _royaltyInfo = RoyaltyInfo(receiver, uint24(amount));
        emit RoyaltyInfoUpdated(receiver, amount);
    }
}

File 15 of 21 : Withdraw.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.15;

import "openzeppelin/token/ERC20/IERC20.sol";
import "openzeppelin/token/ERC721/IERC721.sol";
import "openzeppelin/token/ERC1155/IERC1155.sol";

/**
 * @author Sam King (samkingstudio.eth) for Fount Gallery
 * @title  Withdraw ETH and tokens module
 * @notice Allows the withdrawal of ETH, ERC20, ERC721, an ERC1155 tokens
 */
abstract contract Withdraw {
    /* ------------------------------------------------------------------------
                                    E R R O R S
    ------------------------------------------------------------------------ */

    error CannotWithdrawToZeroAddress();
    error WithdrawFailed();
    error BalanceTooLow();
    error ZeroBalance();

    /* ------------------------------------------------------------------------
                                  W I T H D R A W
    ------------------------------------------------------------------------ */

    function _withdrawETH(address to) internal {
        // Prevent withdrawing to the zero address
        if (to == address(0)) revert CannotWithdrawToZeroAddress();

        // Check there is eth to withdraw
        uint256 balance = address(this).balance;
        if (balance == 0) revert ZeroBalance();

        // Transfer funds
        (bool success, ) = payable(to).call{value: balance}("");
        if (!success) revert WithdrawFailed();
    }

    function _withdrawToken(address tokenAddress, address to) internal {
        // Prevent withdrawing to the zero address
        if (to == address(0)) revert CannotWithdrawToZeroAddress();

        // Check there are tokens to withdraw
        uint256 balance = IERC20(tokenAddress).balanceOf(address(this));
        if (balance == 0) revert ZeroBalance();

        // Transfer tokens
        bool success = IERC20(tokenAddress).transfer(to, balance);
        if (!success) revert WithdrawFailed();
    }

    function _withdrawERC721Token(
        address tokenAddress,
        uint256 id,
        address to
    ) internal {
        // Prevent withdrawing to the zero address
        if (to == address(0)) revert CannotWithdrawToZeroAddress();

        // Check the NFT is in this contract
        address owner = IERC721(tokenAddress).ownerOf(id);
        if (owner != address(this)) revert ZeroBalance();

        // Transfer NFT
        IERC721(tokenAddress).transferFrom(address(this), to, id);
    }

    function _withdrawERC1155Token(
        address tokenAddress,
        uint256 id,
        uint256 amount,
        address to
    ) internal {
        // Prevent withdrawing to the zero address
        if (to == address(0)) revert CannotWithdrawToZeroAddress();

        // Check the tokens are owned by this contract, and there's at least `amount`
        uint256 balance = IERC1155(tokenAddress).balanceOf(address(this), id);
        if (balance == 0) revert ZeroBalance();
        if (amount > balance) revert BalanceTooLow();

        // Transfer tokens
        IERC1155(tokenAddress).safeTransferFrom(address(this), to, id, amount, "");
    }
}

File 16 of 21 : ERC1155.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    event URI(string value, uint256 indexed id);

    /*//////////////////////////////////////////////////////////////
                             ERC1155 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => mapping(uint256 => uint256)) public balanceOf;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                             METADATA LOGIC
    //////////////////////////////////////////////////////////////*/

    function uri(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                              ERC1155 LOGIC
    //////////////////////////////////////////////////////////////*/

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public virtual {
        require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

        balanceOf[from][id] -= amount;
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                    ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual {
        require(ids.length == amounts.length, "LENGTH_MISMATCH");

        require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");

        // Storing these outside the loop saves ~15 gas per iteration.
        uint256 id;
        uint256 amount;

        for (uint256 i = 0; i < ids.length; ) {
            id = ids[i];
            amount = amounts[i];

            balanceOf[from][id] -= amount;
            balanceOf[to][id] += amount;

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                    ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
        public
        view
        virtual
        returns (uint256[] memory balances)
    {
        require(owners.length == ids.length, "LENGTH_MISMATCH");

        balances = new uint256[](owners.length);

        // Unchecked because the only math done is incrementing
        // the array index counter which cannot possibly overflow.
        unchecked {
            for (uint256 i = 0; i < owners.length; ++i) {
                balances[i] = balanceOf[owners[i]][ids[i]];
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
            interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                    ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchMint(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[to][ids[i]] += amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, address(0), to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                    ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchBurn(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[from][ids[i]] -= amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                ++i;
            }
        }

        emit TransferBatch(msg.sender, from, address(0), ids, amounts);
    }

    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        balanceOf[from][id] -= amount;

        emit TransferSingle(msg.sender, from, address(0), id, amount);
    }
}

/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155TokenReceiver {
    function onERC1155Received(
        address,
        address,
        uint256,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(
        address,
        address,
        uint256[] calldata,
        uint256[] calldata,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
    }
}

File 17 of 21 : ERC1155Base.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

import "solmate/tokens/ERC1155.sol";
import "fount-contracts/auth/Auth.sol";
import "fount-contracts/community/FountCardCheck.sol";
import "fount-contracts/extensions/SwappableMetadata.sol";
import "fount-contracts/utils/Royalties.sol";
import "fount-contracts/utils/Withdraw.sol";
import "closedsea/OperatorFilterer.sol";
import "openzeppelin/utils/cryptography/ECDSA.sol";
import "openzeppelin/utils/cryptography/EIP712.sol";
import "openzeppelin/token/ERC20/IERC20.sol";
import "./interfaces/IMetadata.sol";
import "./interfaces/IMorningsPayments.sol";
import "./interfaces/IWETH.sol";

/**
 * @author Fount Gallery
 * @title  ERC1155Base
 * @notice Base contract for Mornings Open Editions to inherit from
 *
 * Features:
 *   - EIP-712 signature minting and verification
 *   - On-chain checking of Fount Gallery Patron cards for minting
 *   - Swappable metadata contract
 *   - On-chain royalties standard (EIP-2981)
 *   - Support for OpenSea's Operator Filterer to allow royalties
 */
abstract contract ERC1155Base is
    ERC1155,
    Auth,
    FountCardCheck,
    SwappableMetadata,
    Royalties,
    Withdraw,
    EIP712,
    OperatorFilterer
{
    /* ------------------------------------------------------------------------
       S T O R A G E
    ------------------------------------------------------------------------ */

    /// @notice Gutty Kreum
    address public artist = 0x95D89b7069D3e401EfE987a94e4cC4C64Af746Fb;

    /// @notice Contract information
    string public contractURI;

    /// @notice Contract name
    string public name = "Mornings";

    /// @notice Contract symbol
    string public symbol = "GKAM";

    /// @notice EIP-712 signing domain
    string public constant SIGNING_DOMAIN = "MorningsOpenEditions";

    /// @notice EIP-712 signature version
    string public constant SIGNATURE_VERSION = "1";

    /// @notice EIP-712 signed data type hash for minting with an off-chain signature
    bytes32 public constant MINT_SIGNATURE_TYPEHASH =
        keccak256(
            "MintSignatureData(uint256 id,uint256 amount_guttys,uint256 amount_founts,address to,uint256 nonce)"
        );

    /// @dev EIP-712 signed data struct for minting with an off-chain signature
    struct MintSignatureData {
        uint256 id;
        uint256 amount_guttys;
        uint256 amount_founts;
        address to;
        uint256 nonce;
        bytes signature;
    }

    /// @notice Approved signer public addresses
    mapping(address => bool) public approvedSigners;

    /// @notice Nonce management to avoid signature replay attacks
    mapping(address => uint256) public nonces;

    /// @notice If operator filtering is applied
    bool public operatorFilteringEnabled;

    /// @notice Wrapped ETH contract address for safe ETH transfer fallbacks
    address public weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @notice Address where proceeds should be sent
    address public payments;

    /* ------------------------------------------------------------------------
       E R R O R S
    ------------------------------------------------------------------------ */

    error CannotSetPaymentAddressToZero();

    /* ------------------------------------------------------------------------
       E V E N T S
    ------------------------------------------------------------------------ */

    event Init();

    /* ------------------------------------------------------------------------
       I N I T
    ------------------------------------------------------------------------ */

    /**
     * @param owner_ The owner of the contract
     * @param admin_ The admin of the contract
     * @param payments_ The admin of the contract
     * @param royaltiesAmount_ The royalty percentage with two decimals (10,000 = 100%)
     * @param metadata_ The initial metadata contract address
     * @param fountCard_ The address of the Fount Gallery Patron Card
     */
    constructor(
        address owner_,
        address admin_,
        address payments_,
        uint256 royaltiesAmount_,
        address metadata_,
        address fountCard_
    )
        ERC1155()
        Auth(owner_, admin_)
        FountCardCheck(fountCard_)
        SwappableMetadata(metadata_)
        Royalties(payments_, royaltiesAmount_)
        EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION)
    {
        payments = payments_;
        _registerForOperatorFiltering();
        operatorFilteringEnabled = true;
        emit Init();
    }

    /* ------------------------------------------------------------------------
       A R T I S T   M I N T I N G
    ------------------------------------------------------------------------ */

    function _mintToArtistFirst(address to, uint256 id, uint256 amount) internal {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), artist, id, amount);
        emit TransferSingle(msg.sender, artist, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, artist, id, amount, "") ==
                    ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /* ------------------------------------------------------------------------
       S I G N A T U R E   V E R I F I C A T I O N
    ------------------------------------------------------------------------ */

    /**
     * @notice Internal function to verify an EIP-712 minting signature
     * @param id The token id
     * @param to The account that has approval to mint
     * @param signature The EIP-712 signature
     * @return bool If the signature is verified or not
     */
    function _verifyMintSignature(
        uint256 id,
        uint256 amount_guttys,
        uint256 amount_founts,
        address to,
        bytes calldata signature
    ) internal returns (bool) {
        MintSignatureData memory data = MintSignatureData({
            id: id,
            amount_guttys: amount_guttys,
            amount_founts: amount_founts,
            to: to,
            nonce: nonces[to],
            signature: signature
        });

        // Hash the data for verification
        bytes32 digest = _hashTypedDataV4(
            keccak256(
                abi.encode(
                    MINT_SIGNATURE_TYPEHASH,
                    data.id,
                    data.amount_guttys,
                    data.amount_founts,
                    data.to,
                    nonces[data.to]++
                )
            )
        );

        // Verifiy signature is ok
        address addr = ECDSA.recover(digest, data.signature);
        return approvedSigners[addr] && addr != address(0);
    }

    /* ------------------------------------------------------------------------
       A D M I N
    ------------------------------------------------------------------------ */

    /** SIGNERS ------------------------------------------------------------ */

    /**
     * @notice Admin function to set an EIP-712 signer address
     * @param signer The address of the new signer
     * @param approved If the signer is approved
     */
    function setSigner(address signer, bool approved) external onlyOwnerOrAdmin {
        approvedSigners[signer] = approved;
    }

    /** METADATA ----------------------------------------------------------- */

    /**
     * @notice Admin function to set the metadata contract address
     * @param metadata The new metadata contract address
     */
    function setMetadataAddress(address metadata) public override onlyOwnerOrAdmin {
        _setMetadataAddress(metadata);
    }

    /**
     * @notice Admin function to set the contract URI for marketplaces
     * @param contractURI_ The new contract URI
     */
    function setContractURI(string memory contractURI_) external onlyOwnerOrAdmin {
        contractURI = contractURI_;
    }

    /** ROYALTIES ---------------------------------------------------------- */

    /**
     * @notice Admin function to set the royalty information
     * @param receiver The receiver of royalty payments
     * @param amount The royalty percentage with two decimals (10,000 = 100%)
     */
    function setRoyaltyInfo(address receiver, uint256 amount) external onlyOwnerOrAdmin {
        _setRoyaltyInfo(receiver, amount);
    }

    /**
     * @notice Admin function to set whether OpenSea's Operator Filtering should be enabled
     * @param enabled If the operator filtering should be enabled
     */
    function setOperatorFilteringEnabled(bool enabled) external onlyOwnerOrAdmin {
        operatorFilteringEnabled = enabled;
    }

    function registerForOperatorFiltering(
        address subscriptionOrRegistrantToCopy,
        bool subscribe
    ) external onlyOwnerOrAdmin {
        _registerForOperatorFiltering(subscriptionOrRegistrantToCopy, subscribe);
    }

    /** PAYMENTS ----------------------------------------------------------- */

    /**
     * @notice Admin function to set the payment address for withdrawing funds
     * @param paymentAddress The new address where payments should be sent upon withdrawal
     */
    function setPaymentAddress(address paymentAddress) external onlyOwnerOrAdmin {
        if (paymentAddress == address(0)) revert CannotSetPaymentAddressToZero();
        payments = paymentAddress;
    }

    /* ------------------------------------------------------------------------
       R O T A L T I E S
    ------------------------------------------------------------------------ */

    /**
     * @notice Add interface for on-chain royalty standard
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view override(ERC1155, IERC165) returns (bool) {
        return interfaceId == ROYALTY_INTERFACE_ID || super.supportsInterface(interfaceId);
    }

    /**
     * @notice Repeats the OpenSea Operator Filtering registration
     */
    function repeatRegistration() public {
        _registerForOperatorFiltering();
    }

    /**
     * @notice Override ERC-1155 `setApprovalForAll` to support OpenSea Operator Filtering
     */
    function setApprovalForAll(
        address operator,
        bool approved
    ) public override onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }

    /**
     * @notice Override ERC-1155 `safeTransferFrom` to support OpenSea Operator Filtering
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) public override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @notice Override ERC-1155 `safeTransferFrom` to support OpenSea Operator Filtering
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) public virtual override onlyAllowedOperator(from) {
        super.safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Overrde `OperatorFilterer._operatorFilteringEnabled` to return whether
     * the operator filtering is enabled in this contract.
     */
    function _operatorFilteringEnabled() internal view virtual override returns (bool) {
        return operatorFilteringEnabled;
    }

    /* ------------------------------------------------------------------------
       S A F E   T R A N S F E R S
    ------------------------------------------------------------------------ */

    /**
     * @notice Safely transfer ETH by wrapping as WETH if the ETH transfer fails
     * @param to The address to transfer ETH/WETH to
     * @param amount The amount of ETH/WETH to transfer
     */
    function _transferETHWithFallback(address to, uint256 amount) internal {
        if (!_transferETH(to, amount)) {
            IWETH(weth).deposit{value: amount}();
            IERC20(weth).transfer(to, amount);
        }
    }

    /**
     * @notice Transfer ETH and return the success status.
     * @param to The address to transfer ETH to
     * @param amount The amount of ETH to transfer
     */
    function _transferETH(address to, uint256 amount) internal returns (bool) {
        (bool success, ) = payable(to).call{value: amount}(new bytes(0));
        return success;
    }

    /* ------------------------------------------------------------------------
       E R C 1 1 5 5
    ------------------------------------------------------------------------ */

    /**
     * @notice Returns the token metadata
     * @return id The token id to get metadata for
     */
    function uri(uint256 id) public view override returns (string memory) {
        return IMetadata(metadata).tokenURI(id);
    }

    /**
     * @notice Burn a token. You can only burn tokens you own.
     * @param id The token id to burn
     * @param amount The amount to burn
     */
    function burn(uint256 id, uint256 amount) external {
        require(balanceOf[msg.sender][id] >= amount, "CANNOT_BURN");
        _burn(msg.sender, id, amount);
    }

    /* ------------------------------------------------------------------------
       W I T H D R A W
    ------------------------------------------------------------------------ */

    /**
     * @notice Admin function to withdraw ETH from this contract
     * @dev Withdraws to the `payments` address.
     *
     * Reverts if:
     *  - there are active auctions
     *  - the payments address is set to zero
     *
     */
    function withdrawETH() public onlyOwnerOrAdmin {
        // Send the eth to the payments address
        _withdrawETH(payments);
    }

    /**
     * @notice Admin function to withdraw ETH from this contract and release from payments contract
     * @dev Withdraws to the `payments` address, then calls `releaseAllETH` as a splitter.
     *
     * Reverts if:
     *  - there are active auctions
     *  - the payments address is set to zero
     *
     */
    function withdrawAndReleaseAllETH() public onlyOwnerOrAdmin {
        // Send the eth to the payments address
        _withdrawETH(payments);
        // And then release all the ETH to the payees
        IMorningsPayments(payments).releaseAllETH();
    }

    /**
     * @notice Admin function to withdraw ERC-20 tokens from this contract
     * @dev Withdraws to the `payments` address.
     *
     * Reverts if:
     *  - the payments address is set to zero
     *
     */
    function withdrawTokens(address tokenAddress) public onlyOwnerOrAdmin {
        // Send the tokens to the payments address
        _withdrawToken(tokenAddress, payments);
    }

    /**
     * @notice Admin function to withdraw ERC-20 tokens from this contract
     * @param to The address to send the ERC-20 tokens to
     */
    function withdrawTokens(address tokenAddress, address to) public onlyOwnerOrAdmin {
        _withdrawToken(tokenAddress, to);
    }
}

File 18 of 21 : MorningsOpenEditions.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

import "./ERC1155Base.sol";

/**
 * @author Fount Gallery
 * @title  Mornings Open Editions by Gutty Kreum
 * @notice Mornings is a collection of digital memories exploring morning ambience by pixel artist, Gutty Kreum.
 *         A limited release in collaboration with Fount Gallery, Mornings drops on June 22, 2023.
 *
 * Features:
 *   - Open edition NFTs
 *   - ERC-1155 lazy minting
 *   - Flexible minting conditions with EIP-712 signatures or on-chain Fount Card checks
 *   - Swappable metadata contract
 *   - On-chain royalties standard (EIP-2981)
 *   - Support for OpenSea's Operator Filterer to allow royalties
 */
contract MorningsOpenEditions is ERC1155Base {
    /* ------------------------------------------------------------------------
       S T O R A G E
    ------------------------------------------------------------------------ */

    /// @dev Stores information about a given token
    struct TokenData {
        uint128 price;
        uint32 startTime;
        uint32 endTime;
        uint256 gutty_reserve_collected;
        uint256 fount_reserve_collected;
        uint16 perAddressAllowance;
        bool fountExclusive;
        bool requiresSig;
    }

    /// @dev Mapping of token id to token data
    mapping(uint256 => TokenData) internal _idToTokenData;

    /// @dev Check if the artist has minted the batch of 25 prior to launch
    bool public _artistBatchMinted = false;

    /// @notice The amount of tokens reserved for Fount Gallery Patrons
    uint256 public constant FOUNT_PATRON_RESERVE = 100;

    /// @notice The amount of tokens reserved for Gutty Kreum artwork holders
    uint256 public constant GUTTY_KREUM_RESERVE = 225;

    /* ------------------------------------------------------------------------
       M O D I F I E R S
    ------------------------------------------------------------------------ */

    /**
     * @dev Reverts if the caller is not the artist
     */
    modifier onlyArtist() {
        require(msg.sender == artist, "Only the artist can call this function");
        _;
    }

    /* ------------------------------------------------------------------------
       E R R O R S
    ------------------------------------------------------------------------ */

    /** TOKEN DATA ---------------------------------------------------------- */
    error TokenDataDoesNotExist();
    error TokenDataAlreadyExists();
    error CannotSetStartTimeToZero();
    error CannotSetEndTimeToThePast();

    /** SALE CONDITIONS ---------------------------------------------------- */
    error RequiresFountCard();
    error RequiresSignature();
    error InvalidSignature();
    error SoldOut();
    error BatchAlreadyMinted();

    /** PURCHASING --------------------------------------------------------- */
    error NotForSale();
    error IncorrectPaymentAmount();
    error AmountExceedsMaxWalletMint();
    error AmountExceedsWalletAllowance();

    /** EDITIONS ----------------------------------------------------------- */
    error OpenEditionEnded();
    error OpenEditionNotStartedYet();

    /* ------------------------------------------------------------------------
       E V E N T S
    ------------------------------------------------------------------------ */

    event TokenDataAdded(uint256 indexed id, TokenData tokenData);
    event TokenDataSaleTimesUpdated(uint256 indexed id, TokenData tokenData);
    event TokenDataSalePriceUpdated(uint256 indexed id, TokenData tokenData);
    event TokenDataSaleConditionsUpdated(uint256 indexed id, TokenData tokenData);

    event CollectedOpenEdition(uint256 indexed id);

    /* ------------------------------------------------------------------------
       I N I T
    ------------------------------------------------------------------------ */

    /**
     * @param owner_ The owner of the contract
     * @param admin_ The admin of the contract
     * @param payments_ The address where payments should be sent
     * @param royaltiesAmount_ The royalty percentage with two decimals (10,000 = 100%)
     * @param metadata_ The initial metadata contract address
     * @param fountCard_ The address of the Fount Gallery Patron Card
     */
    constructor(
        address owner_,
        address admin_,
        address payments_,
        uint256 royaltiesAmount_,
        address metadata_,
        address fountCard_
    ) ERC1155Base(owner_, admin_, payments_, royaltiesAmount_, metadata_, fountCard_) {}

    /* ------------------------------------------------------------------------
       O P E N   E D I T I O N S
    ------------------------------------------------------------------------ */

    /**
     * @notice Mints a batch of 25 editions to the artist's wallet
     *
     * Reverts if:
     * - the batch has already been minted
     */
    function mintArtistBatch() external onlyArtist {
        if (_artistBatchMinted) revert BatchAlreadyMinted();

        TokenData memory tokenData = _idToTokenData[3];
        tokenData.gutty_reserve_collected += 25;
        _idToTokenData[3] = tokenData;

        _artistBatchMinted = true;
        _mintToArtistFirst(artist, 3, 25);
        emit CollectedOpenEdition(3);
    }

    /**
     * @notice Mints a number of editions from an open edition NFT
     * @dev Calls internal `_collectEdition` for logic.
     *
     * Reverts if:
     *  - the edition requires an off-chain signature
     *  - see `_collectEdition` for other conditions
     *
     * @param id The id of the edition
     * @param amount_guttys The amount of editions to mint from the Gutty Kreum reserve
     * @param amount_founts The amount of editions to mint from the Fount Gallery Patron Card reserve
     * @param to The address to mint the token to
     */
    function collectEdition(
        uint256 id,
        uint256 amount_guttys,
        uint256 amount_founts,
        address to
    ) external payable {
        TokenData memory tokenData = _idToTokenData[id];
        if (tokenData.requiresSig) revert RequiresSignature();
        _collectEdition(id, amount_guttys, amount_founts, to, tokenData);
    }

    /**
     * @notice Mints a number of editions from an open edition NFT with an off-chain signature
     * @dev Calls internal `_collectEdition` for logic.
     *
     * Reverts if:
     *  - the edition requires an off-chain signature and the signature is invalid
     *  - see `_collectEdition` for other conditions
     *
     * @param id The id of the edition
     * @param amount_guttys The amount of editions to mint from the Gutty Kreum reserve
     * @param amount_founts The amount of editions to mint from the Fount Gallery Patron Card reserve
     * @param to The address to mint the token to
     * @param signature The off-chain signature which permits a mint
     */
    function collectEdition(
        uint256 id,
        uint256 amount_guttys,
        uint256 amount_founts,
        address to,
        bytes calldata signature
    ) external payable {
        TokenData memory tokenData = _idToTokenData[id];
        if (
            tokenData.requiresSig &&
            !_verifyMintSignature(id, amount_guttys, amount_founts, to, signature)
        ) {
            revert InvalidSignature();
        }
        _collectEdition(id, amount_guttys, amount_founts, to, tokenData);
    }

    /**
     * @notice Internal function to mint some editions with some conditions
     * @dev Allows minting to a different address from msg.sender.
     *
     * Reverts if:
     *  - the edition has not started
     *  - the edition has ended
     *  - msg.value does not equal the required amount
     *  - the edition requires a Fount Card, but `to` does not hold one
     *
     * @param id The token id of the edition
     * @param amount_guttys The amount of editions to mint from the Gutty Kreum reserve
     * @param amount_founts The amount of editions to mint from the Fount Gallery Patron Card reserve
     * @param to The address to mint the token to
     * @param tokenData Information about the token
     */
    function _collectEdition(
        uint256 id,
        uint256 amount_guttys,
        uint256 amount_founts,
        address to,
        TokenData memory tokenData
    ) internal {
        uint256 trueGuttysToMintAmount;
        uint256 trueFountsToMintAmount;

        // Check to see if the edition is mintable and the price is correct
        if (tokenData.startTime > block.timestamp) revert OpenEditionNotStartedYet();
        if (tokenData.endTime > 0 && block.timestamp > tokenData.endTime) revert OpenEditionEnded();
        if (msg.value > 0) revert IncorrectPaymentAmount();

        // Check if it's a Fount Gallery exclusive
        if (tokenData.fountExclusive && !_isFountCardHolder(to)) revert RequiresFountCard();

        // Check to see if the mint amounts exceed the reserves
        if (
            GUTTY_KREUM_RESERVE <= tokenData.gutty_reserve_collected &&
            FOUNT_PATRON_RESERVE <= tokenData.fount_reserve_collected
        ) revert SoldOut();

        // If the amount of tokens to mint will exceed the Fount Patron Reserve, only mint the remaining amount
        // eg. 98/100 tokens minted, 5 tokens requested, only 2 tokens will be minted
        if (amount_founts > FOUNT_PATRON_RESERVE - tokenData.fount_reserve_collected) {
            trueFountsToMintAmount = FOUNT_PATRON_RESERVE - tokenData.fount_reserve_collected;
        } else {
            trueFountsToMintAmount = amount_founts;
        }

        // If the amount of tokens to mint will exceed the Gutty Kreum artwork holder Reserve, only mint the remaining amount
        // eg. 223/225 tokens minted, 5 tokens requested, only 2 tokens will be minted
        if (amount_guttys > GUTTY_KREUM_RESERVE - tokenData.gutty_reserve_collected) {
            trueGuttysToMintAmount = GUTTY_KREUM_RESERVE - tokenData.gutty_reserve_collected;
        } else {
            trueGuttysToMintAmount = amount_guttys;
        }

        // Add the new mint to the token data
        unchecked {
            tokenData.gutty_reserve_collected += trueGuttysToMintAmount;
            tokenData.fount_reserve_collected += trueFountsToMintAmount;
        }
        _idToTokenData[id] = tokenData;

        // Calculate the total amount of tokens to mint
        uint256 mintAmount = uint256(trueGuttysToMintAmount) + uint256(trueFountsToMintAmount);

        // Mint the NFT to the `to` address
        _mintToArtistFirst(to, id, mintAmount);
        emit CollectedOpenEdition(id);
    }

    /* ------------------------------------------------------------------------
       A D M I N
    ------------------------------------------------------------------------ */

    /** ADD TOKEN DATA ----------------------------------------------------- */

    /**
     * @notice Admin function to make a token available for sale
     * @dev As soon as the token data is registered, the NFT will be available to collect.
     *
     * Reverts if:
     *  - `startTime` is zero (used to check if a token can be sold or not)
     *  - `endTime` is in the past
     *  - the token data already exists (to update token data, use the other admin
     *    functions to set price and sale conditions)
     *
     * @param id The token id
     * @param price The sale price, if any
     * @param startTime The start time of the sale
     * @param endTime The end time of the sale, if any
     * @param mintPerAddress The max amount that can be minted for a wallet, if any
     * @param fountExclusive If the sale requires a Fount Gallery Patron card
     * @param requiresSig If the sale requires an off-chain signature
     */
    function addTokenForSale(
        uint256 id,
        uint128 price,
        uint32 startTime,
        uint32 endTime,
        uint16 mintPerAddress,
        bool fountExclusive,
        bool requiresSig
    ) external onlyOwnerOrAdmin {
        // Check that start time is valid. This value is used to check if the token data
        // exists. Setting to zero will effectively "delete" the token data for other functions.
        if (startTime == 0) revert CannotSetStartTimeToZero();

        // Check the end time is not in the past
        if (endTime > 0 && block.timestamp > endTime) revert CannotSetEndTimeToThePast();

        TokenData memory tokenData = _idToTokenData[id];

        // Check the token data is empty before adding
        if (tokenData.startTime != 0) revert TokenDataAlreadyExists();

        // Set the new token data
        tokenData.price = price;
        tokenData.startTime = startTime;
        tokenData.endTime = endTime;
        tokenData.perAddressAllowance = mintPerAddress;
        tokenData.fountExclusive = fountExclusive;
        tokenData.requiresSig = requiresSig;
        _idToTokenData[id] = tokenData;
        emit TokenDataAdded(id, tokenData);
    }

    /** SET SALE PRICE ----------------------------------------------------- */

    /**
     * @notice Admin function to update the sale price for a token
     * @dev Sets the start and end time values for a token. Setting `endTime` to zero
     * effectively keeps the edition open forever.
     *
     * Reverts if:
     *  - `startTime` is zero (used to check if a token can be sold or not)
     *  - `endTime` is in the past
     *  - the token data does not exist, must be added with `addTokenForSale` first
     *
     * @param id The token id
     * @param startTime The new start time of the sale
     * @param endTime The new end time of the sale
     */
    function setTokenSaleTimes(
        uint256 id,
        uint32 startTime,
        uint32 endTime
    ) external onlyOwnerOrAdmin {
        // Check that start time is not zero. This value is used to check if the token data
        // exists. Setting to zero will effectively "delete" the token data for other functions.
        if (startTime == 0) revert CannotSetStartTimeToZero();

        // Check the end time is not in the past
        if (endTime > 0 && block.timestamp > endTime) revert CannotSetEndTimeToThePast();

        TokenData memory tokenData = _idToTokenData[id];

        // Check the token data already exists.
        // If not, it should be created with `addTokenForSale` first.
        if (tokenData.startTime == 0) revert TokenDataDoesNotExist();

        // Set the new sale price
        tokenData.startTime = startTime;
        tokenData.endTime = endTime;
        _idToTokenData[id] = tokenData;
        emit TokenDataSaleTimesUpdated(id, tokenData);
    }

    /** SET SALE TIMES ----------------------------------------------------- */

    /**
     * @notice Admin function to update the sale price for a token
     * @dev Reverts if the token data does not exist. Must be added with `addTokenForSale` first.
     * @param id The token id
     * @param price The new sale price
     */
    function setTokenSalePrice(uint256 id, uint128 price) external onlyOwnerOrAdmin {
        TokenData memory tokenData = _idToTokenData[id];

        // Check the token data already exists.
        // If not, it should be created with `addTokenForSale` first.
        if (tokenData.startTime == 0) revert TokenDataDoesNotExist();

        // Set the new sale price
        tokenData.price = price;
        _idToTokenData[id] = tokenData;
        emit TokenDataSalePriceUpdated(id, tokenData);
    }

    /** SET SALE CONDITIONS ------------------------------------------------ */

    /**
     * @notice Admin function to update the sale conditions for a token
     * @dev Reverts if the token data does not exist. Must be added with `addTokenForSale` first.
     * @param id The token id
     * @param mintPerAddress The max amount that can be minted for a wallet, if any
     * @param fountExclusive If the sale requires a Fount Gallery Patron card
     * @param requiresSig If the sale requires an off-chain signature
     */
    function setTokenSaleConditions(
        uint256 id,
        uint16 mintPerAddress,
        bool fountExclusive,
        bool requiresSig
    ) external onlyOwnerOrAdmin {
        TokenData memory tokenData = _idToTokenData[id];

        // Check the token data already exists.
        // If not, it should be created with `addTokenForSale` first.
        if (tokenData.startTime == 0) revert TokenDataDoesNotExist();

        tokenData.perAddressAllowance = mintPerAddress;
        tokenData.fountExclusive = fountExclusive;
        tokenData.requiresSig = requiresSig;
        _idToTokenData[id] = tokenData;

        emit TokenDataSaleConditionsUpdated(id, tokenData);
    }

    /* ------------------------------------------------------------------------
                                   G E T T E R S
    ------------------------------------------------------------------------ */

    function tokenPrice(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].price;
    }

    function tokenStartTime(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].startTime;
    }

    function tokenEndTime(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].endTime;
    }

    function tokenGuttyReserveCollectedCount(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].gutty_reserve_collected;
    }

    function tokenFountReserveCollectedCount(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].fount_reserve_collected;
    }

    function tokenAllowancePerAddress(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].perAddressAllowance;
    }

    function tokenRemainingAllowanceForAddress(
        uint256 id,
        address account
    ) external view returns (uint256) {
        TokenData memory tokenData = _idToTokenData[id];
        uint256 currentBalance = balanceOf[account][id];
        uint256 remainingAllowance = currentBalance > tokenData.perAddressAllowance
            ? 0
            : tokenData.perAddressAllowance - currentBalance;
        return remainingAllowance;
    }

    function tokenIsFountExclusive(uint256 id) external view returns (bool) {
        return _idToTokenData[id].fountExclusive;
    }

    function tokenRequiresOffChainSignatureToMint(uint256 id) external view returns (bool) {
        return _idToTokenData[id].requiresSig;
    }
}

File 19 of 21 : IMetadata.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

interface IMetadata {
    function tokenURI(uint256 id) external view returns (string memory);
}

File 20 of 21 : IMorningsPayments.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

interface IMorningsPayments {
    function releaseAllETH() external;

    function releaseAllToken(address tokenAddress) external;
}

File 21 of 21 : IWETH.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 wad) external;

    function transfer(address to, uint256 value) external returns (bool);
}

Settings
{
  "remappings": [
    "closedsea/=packages/contracts/lib/closedsea/src/",
    "ds-test/=packages/contracts/lib/ds-test/src/",
    "erc4626-tests/=packages/contracts/lib/closedsea/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "erc721a-upgradeable/=packages/contracts/lib/closedsea/lib/erc721a-upgradeable/contracts/",
    "erc721a/=packages/contracts/lib/closedsea/lib/erc721a/contracts/",
    "ethier/=packages/contracts/lib/ethier/",
    "forge-std/=packages/contracts/lib/forge-std/src/",
    "fount-contracts/=packages/contracts/lib/fount-contracts/src/",
    "openzeppelin-contracts-upgradeable/=packages/contracts/lib/closedsea/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=packages/contracts/lib/openzeppelin-contracts/",
    "openzeppelin/=packages/contracts/lib/fount-contracts/lib/openzeppelin-contracts/contracts/",
    "operator-filter-registry/=packages/contracts/lib/closedsea/lib/operator-filter-registry/",
    "solmate/=packages/contracts/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"payments_","type":"address"},{"internalType":"uint256","name":"royaltiesAmount_","type":"uint256"},{"internalType":"address","name":"metadata_","type":"address"},{"internalType":"address","name":"fountCard_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountExceedsMaxWalletMint","type":"error"},{"inputs":[],"name":"AmountExceedsWalletAllowance","type":"error"},{"inputs":[],"name":"BalanceTooLow","type":"error"},{"inputs":[],"name":"BatchAlreadyMinted","type":"error"},{"inputs":[],"name":"CannotSetEndTimeToThePast","type":"error"},{"inputs":[],"name":"CannotSetPaymentAddressToZero","type":"error"},{"inputs":[],"name":"CannotSetStartTimeToZero","type":"error"},{"inputs":[],"name":"CannotWithdrawToZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"owned","type":"uint256"}],"name":"DoesNotHoldEnoughFountCards","type":"error"},{"inputs":[],"name":"IncorrectPaymentAmount","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"MetadataLocked","type":"error"},{"inputs":[],"name":"MoreThanOneHundredPercentRoyalty","type":"error"},{"inputs":[],"name":"NotForSale","type":"error"},{"inputs":[],"name":"NotFountCardHolder","type":"error"},{"inputs":[],"name":"OpenEditionEnded","type":"error"},{"inputs":[],"name":"OpenEditionNotStartedYet","type":"error"},{"inputs":[],"name":"RequiresFountCard","type":"error"},{"inputs":[],"name":"RequiresSignature","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"TokenDataAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDataDoesNotExist","type":"error"},{"inputs":[],"name":"WithdrawFailed","type":"error"},{"inputs":[],"name":"ZeroBalance","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"prevAdmin","type":"address"}],"name":"AdminRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CollectedOpenEdition","type":"event"},{"anonymous":false,"inputs":[],"name":"Init","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"metadataContract","type":"address"}],"name":"MetadataContractLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"metadataContract","type":"address"}],"name":"MetadataContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RoyaltyInfoSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RoyaltyInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"gutty_reserve_collected","type":"uint256"},{"internalType":"uint256","name":"fount_reserve_collected","type":"uint256"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct MorningsOpenEditions.TokenData","name":"tokenData","type":"tuple"}],"name":"TokenDataAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"gutty_reserve_collected","type":"uint256"},{"internalType":"uint256","name":"fount_reserve_collected","type":"uint256"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct MorningsOpenEditions.TokenData","name":"tokenData","type":"tuple"}],"name":"TokenDataSaleConditionsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"gutty_reserve_collected","type":"uint256"},{"internalType":"uint256","name":"fount_reserve_collected","type":"uint256"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct MorningsOpenEditions.TokenData","name":"tokenData","type":"tuple"}],"name":"TokenDataSalePriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"gutty_reserve_collected","type":"uint256"},{"internalType":"uint256","name":"fount_reserve_collected","type":"uint256"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct MorningsOpenEditions.TokenData","name":"tokenData","type":"tuple"}],"name":"TokenDataSaleTimesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"FOUNT_PATRON_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUTTY_KREUM_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINT_SIGNATURE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNATURE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNING_DOMAIN","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_artistBatchMinted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint16","name":"mintPerAddress","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"name":"addTokenForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedSigners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"artist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount_guttys","type":"uint256"},{"internalType":"uint256","name":"amount_founts","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"collectEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount_guttys","type":"uint256"},{"internalType":"uint256","name":"amount_founts","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"collectEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMetadataLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadata","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintArtistBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorFilteringEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payments","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"subscriptionOrRegistrantToCopy","type":"address"},{"internalType":"bool","name":"subscribe","type":"bool"}],"name":"registerForOperatorFiltering","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prevAdmin","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repeatRegistration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"contractURI_","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"metadata","type":"address"}],"name":"setMetadataAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setOperatorFilteringEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"paymentAddress","type":"address"}],"name":"setPaymentAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint16","name":"mintPerAddress","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"name":"setTokenSaleConditions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint128","name":"price","type":"uint128"}],"name":"setTokenSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"}],"name":"setTokenSaleTimes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenAllowancePerAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenFountReserveCollectedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenGuttyReserveCollectedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenIsFountExclusive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"tokenRemainingAllowanceForAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenRequiresOffChainSignatureToMint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAndReleaseAllETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]

600780546001600160a01b0319167395d89b7069d3e401efe987a94e4cc4c64af746fb1790556101806040526008610140908152674d6f726e696e677360c01b61016052600990620000529082620004eb565b50604080518082019091526004815263474b414d60e01b6020820152600a906200007d9082620004eb565b50600d8054610100600160a81b03191674c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2001790556010805460ff19169055348015620000bd57600080fd5b5060405162004bdb38038062004bdb833981016040819052620000e091620005d4565b8585858585856040518060400160405280601481526020017f4d6f726e696e67734f70656e45646974696f6e73000000000000000000000000815250604051806040016040528060018152602001603160f81b815250858585858b8b81600260006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031660006001600160a01b03167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a36001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a35050600480546001600160a01b039283166001600160a01b0319918216179091556005805492841692909116821790556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a2506040805180820182526001600160a01b0384168082526001600160601b0384166020909201829052600160a01b909102811760065590518291907f984cbbb47b413608120ad6b444ea0004fe19b6f88a5c0992e612b97fd3cb631e90600090a35050815160208084019190912082518383012060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81880181905281830187905260608201869052608082019490945230818401528151808203909301835260c00190528051940193909320919290916080523060c052610120525050600e80546001600160a01b0319166001600160a01b03881617905550620003619050620003a9565b600d805460ff191660011790556040517f57a86f7d14ccde89e22870afe839e3011216827daa9b24e18629f0a1e9d6cc1490600090a15050505050505050505050506200064c565b620003ca733cc6cdda760b79bafa08df41ecfa224f810dceb66001620003cc565b565b6001600160a01b0390911690637d3e3dbe81620003fc5782620003f55750634420e486620003fc565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16200043c578060005160e01c036200043c57600080fd5b5060006024525050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200047157607f821691505b6020821081036200049257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004e657600081815260208120601f850160051c81016020861015620004c15750805b601f850160051c820191505b81811015620004e257828155600101620004cd565b5050505b505050565b81516001600160401b0381111562000507576200050762000446565b6200051f816200051884546200045c565b8462000498565b602080601f8311600181146200055757600084156200053e5750858301515b600019600386901b1c1916600185901b178555620004e2565b600085815260208120601f198616915b82811015620005885788860151825594840194600190910190840162000567565b5085821015620005a75787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b0381168114620005cf57600080fd5b919050565b60008060008060008060c08789031215620005ee57600080fd5b620005f987620005b7565b95506200060960208801620005b7565b94506200061960408801620005b7565b9350606087015192506200063060808801620005b7565b91506200064060a08801620005b7565b90509295509295509295565b60805160a05160c05160e051610100516101205161453f6200069c600039600061361701526000613666015260006136410152600061359a015260006135c4015260006135ee015261453f6000f3fe6080604052600436106103955760003560e01c8063881ced95116101dc578063c0fd735b11610102578063e2e784d5116100a0578063ecd8dbf71161006f578063ecd8dbf714610bc8578063f242432a14610be8578063fb796e6c14610c08578063fd6724fc14610c2257600080fd5b8063e2e784d514610b18578063e3faad9414610b38578063e8a3d48514610b78578063e985e9c514610b8d57600080fd5b8063de7ff469116100dc578063de7ff46914610aa9578063df27092014610ac9578063e086e5ec14610ae3578063e17b25af14610af857600080fd5b8063c0fd735b14610a3d578063d4ddce8a14610a52578063d7e45cd714610a8857600080fd5b8063a41572961161017a578063b05fc5cc11610149578063b05fc5cc146109d5578063b390c0ab146109e8578063b7c0b8e814610a08578063c01c3c9c14610a2857600080fd5b8063a415729614610934578063a522ad2514610961578063a6d23e1014610981578063af4fddfa146109a157600080fd5b80638da5cb5b116101b65780638da5cb5b146108bf578063938e3d7b146108df57806395d89b41146108ff578063a22cb4651461091457600080fd5b8063881ced951461083557806389d020dc1461086f5780638a8755121461088f57600080fd5b806343bc1612116102c157806358a478ed1161025f578063704802751161022e57806370480275146107b35780637c1a8343146107d35780637ecebe00146107f35780637f20256a1461082057600080fd5b806358a478ed146107145780635e1c0746146107445780635e1e1004146107595780636b2a9d251461077957600080fd5b806349df728c1161029b57806349df728c146106825780634d820b4f146106a25780634e1273f4146106d2578063582e8ae5146106ff57600080fd5b806343bc16121461060e578063453722411461062e57806346d8efad1461066257600080fd5b80631785f53c1161033957806331cb61051161030857806331cb610514610561578063392f37e9146105815780633fc8cef3146105b9578063429b62e5146105de57600080fd5b80631785f53c146104a957806326645a2c146104c95780632a55205a146105025780632eb2c2d61461054157600080fd5b80630651efa3116103755780630651efa31461043457806306fdde03146104475780630e89341c1461046957806313af40351461048957600080fd5b8062029eb81461039a578062fdd58e146103bc57806301ffc9a714610404575b600080fd5b3480156103a657600080fd5b506103ba6103b5366004613957565b610c5c565b005b3480156103c857600080fd5b506103f16103d73660046139f3565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b34801561041057600080fd5b5061042461041f366004613a33565b610f84565b60405190151581526020016103fb565b6103ba610442366004613a57565b610faf565b34801561045357600080fd5b5061045c611075565b6040516103fb9190613aba565b34801561047557600080fd5b5061045c610484366004613aed565b611103565b34801561049557600080fd5b506103ba6104a4366004613b06565b611175565b3480156104b557600080fd5b506103ba6104c4366004613b06565b611205565b3480156104d557600080fd5b506104246104e4366004613aed565b6000908152600f602052604090206003015462010000900460ff1690565b34801561050e57600080fd5b5061052261051d366004613b21565b611293565b604080516001600160a01b0390931683526020830191909152016103fb565b34801561054d57600080fd5b506103ba61055c366004613bca565b6112da565b34801561056d57600080fd5b506103ba61057c366004613c85565b61131a565b34801561058d57600080fd5b506005546105a1906001600160a01b031681565b6040516001600160a01b0390911681526020016103fb565b3480156105c557600080fd5b50600d546105a19061010090046001600160a01b031681565b3480156105ea57600080fd5b506104246105f9366004613b06565b60036020526000908152604090205460ff1681565b34801561061a57600080fd5b506007546105a1906001600160a01b031681565b34801561063a57600080fd5b506103f1610649366004613aed565b6000908152600f602052604090206003015461ffff1690565b34801561066e57600080fd5b506103ba61067d366004613c85565b611389565b34801561068e57600080fd5b506103ba61069d366004613b06565b6113db565b3480156106ae57600080fd5b506103f16106bd366004613aed565b6000908152600f602052604090206002015490565b3480156106de57600080fd5b506106f26106ed366004613cbc565b611439565b6040516103fb9190613d28565b34801561070b57600080fd5b506103f160e181565b34801561072057600080fd5b506103f161072f366004613aed565b6000908152600f602052604090206001015490565b34801561075057600080fd5b506103ba61156e565b34801561076557600080fd5b506103ba610774366004613b06565b611578565b34801561078557600080fd5b50610424610794366004613aed565b6000908152600f60205260409020600301546301000000900460ff1690565b3480156107bf57600080fd5b506103ba6107ce366004613b06565b611605565b3480156107df57600080fd5b506103ba6107ee366004613d6c565b611696565b3480156107ff57600080fd5b506103f161080e366004613b06565b600c6020526000908152604090205481565b34801561082c57600080fd5b506103f1606481565b34801561084157600080fd5b506103f1610850366004613aed565b6000908152600f6020526040902054600160801b900463ffffffff1690565b34801561087b57600080fd5b506103ba61088a366004613d8f565b61188e565b34801561089b57600080fd5b506104246108aa366004613b06565b600b6020526000908152604090205460ff1681565b3480156108cb57600080fd5b506002546105a1906001600160a01b031681565b3480156108eb57600080fd5b506103ba6108fa366004613e4f565b611a97565b34801561090b57600080fd5b5061045c611ae7565b34801561092057600080fd5b506103ba61092f366004613c85565b611af4565b34801561094057600080fd5b5061045c604051806040016040528060018152602001603160f81b81525081565b34801561096d57600080fd5b506103ba61097c366004613ecf565b611b18565b34801561098d57600080fd5b50600e546105a1906001600160a01b031681565b3480156109ad57600080fd5b506103f17f3ebe2a8026435bce72f492f4f1687396bda15f10d2b8fe0db69d6dbaf7564a2b81565b6103ba6109e3366004613ef9565b611b66565b3480156109f457600080fd5b506103ba610a03366004613b21565b611c47565b348015610a1457600080fd5b506103ba610a23366004613f6a565b611ca8565b348015610a3457600080fd5b506103ba611cff565b348015610a4957600080fd5b506103ba61202f565b348015610a5e57600080fd5b506103f1610a6d366004613aed565b6000908152600f60205260409020546001600160801b031690565b348015610a9457600080fd5b5060055461042490600160a01b900460ff1681565b348015610ab557600080fd5b506103f1610ac4366004613f87565b6120f2565b348015610ad557600080fd5b506010546104249060ff1681565b348015610aef57600080fd5b506103ba6121d2565b348015610b0457600080fd5b506103ba610b13366004613b06565b61222b565b348015610b2457600080fd5b506103ba610b333660046139f3565b612278565b348015610b4457600080fd5b5061045c604051806040016040528060148152602001734d6f726e696e67734f70656e45646974696f6e7360601b81525081565b348015610b8457600080fd5b5061045c6122c6565b348015610b9957600080fd5b50610424610ba8366004613ecf565b600160209081526000928352604080842090915290825290205460ff1681565b348015610bd457600080fd5b506103ba610be3366004613faa565b6122d3565b348015610bf457600080fd5b506103ba610c03366004613fe6565b61252f565b348015610c1457600080fd5b50600d546104249060ff1681565b348015610c2e57600080fd5b506103f1610c3d366004613aed565b6000908152600f6020526040902054600160a01b900463ffffffff1690565b6002546001600160a01b0316331480610c8457503360009081526003602052604090205460ff165b610ca95760405162461bcd60e51b8152600401610ca090614040565b60405180910390fd5b8463ffffffff16600003610cd0576040516361bc7fb160e11b815260040160405180910390fd5b60008463ffffffff16118015610ceb57508363ffffffff1642115b15610d095760405163312728dd60e11b815260040160405180910390fd5b6000878152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b909104169381019390935260018101546060840152600281015460808401526003015461ffff811660a084015260ff6201000082048116151560c0850152630100000090910416151560e083015215610db7576040516320705a1b60e11b815260040160405180910390fd5b8681600001906001600160801b031690816001600160801b03168152505085816020019063ffffffff16908163ffffffff168152505084816040019063ffffffff16908163ffffffff1681525050838160a0019061ffff16908161ffff1681525050828160c0019015159081151581525050818160e001901515908115158152505080600f60008a815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff160217905550606082015181600101556080820151816002015560a08201518160030160006101000a81548161ffff021916908361ffff16021790555060c08201518160030160026101000a81548160ff02191690831515021790555060e08201518160030160036101000a81548160ff021916908315150217905550905050877f14eb4bf6c7d72fc73e72c7352fc7607a0ac11969cadce90af77c0540a7b0c33082604051610f729190614066565b60405180910390a25050505050505050565b60006001600160e01b0319821663152a902d60e11b1480610fa95750610fa982612562565b92915050565b6000848152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b900490921692820192909252600182015460608201526002820154608082015260039091015461ffff811660a083015260ff6201000082048116151560c084015263010000009091041615801560e083015261106157604051630426ff7760e01b815260040160405180910390fd5b61106e85858585856125b0565b5050505050565b60098054611082906140ec565b80601f01602080910402602001604051908101604052809291908181526020018280546110ae906140ec565b80156110fb5780601f106110d0576101008083540402835291602001916110fb565b820191906000526020600020905b8154815290600101906020018083116110de57829003601f168201915b505050505081565b60055460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa15801561114d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fa99190810190614126565b6002546001600160a01b031633148061119d57503360009081526003602052604090205460ff165b6111b95760405162461bcd60e51b8152600401610ca090614040565b600280546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6002546001600160a01b031633148061122d57503360009081526003602052604090205460ff165b6112495760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b038116600081815260036020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b03811690600090612710906112c790600160a01b90046bffffffffffffffffffffffff16856141b3565b6112d191906141ca565b90509250929050565b876001600160a01b03811633146112ff57600d5460ff16156112ff576112ff33612829565b61130f898989898989898961286d565b505050505050505050565b6002546001600160a01b031633148061134257503360009081526003602052604090205460ff165b61135e5760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b03919091166000908152600b60205260409020805460ff1916911515919091179055565b6002546001600160a01b03163314806113b157503360009081526003602052604090205460ff165b6113cd5760405162461bcd60e51b8152600401610ca090614040565b6113d78282612b10565b5050565b6002546001600160a01b031633148061140357503360009081526003602052604090205460ff165b61141f5760405162461bcd60e51b8152600401610ca090614040565b600e546114369082906001600160a01b0316612b85565b50565b606083821461147c5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ca0565b8367ffffffffffffffff81111561149557611495613de0565b6040519080825280602002602001820160405280156114be578160200160208202803683370190505b50905060005b84811015611565576000808787848181106114e1576114e16141ec565b90506020020160208101906114f69190613b06565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858481811061152a5761152a6141ec565b90506020020135815260200190815260200160002054828281518110611552576115526141ec565b60209081029190910101526001016114c4565b50949350505050565b611576612cd1565b565b6002546001600160a01b03163314806115a057503360009081526003602052604090205460ff165b6115bc5760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b0381166115e357604051631f4c499760e01b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031633148061162d57503360009081526003602052604090205460ff165b6116495760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b6002546001600160a01b03163314806116be57503360009081526003602052604090205460ff165b6116da5760405162461bcd60e51b8152600401610ca090614040565b6000828152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103611788576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b0380831682526000848152600f602090815260409182902084518154928601518487015163ffffffff908116600160a01b0263ffffffff60a01b1991909216600160801b026001600160a01b031990951692909616919091179290921793909316178255606083015160018301556080830151600283015560a08301516003909201805460c085015160e0860151151563010000000263ff00000019911515620100000262ffffff1990931661ffff909616959095179190911716929092179091555183907f75c878cf35971786285583083fa747eac0e90af627ab5be381b17c8ddb38973690611881908490614066565b60405180910390a2505050565b6002546001600160a01b03163314806118b657503360009081526003602052604090205460ff165b6118d25760405162461bcd60e51b8152600401610ca090614040565b6000848152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103611980576040516347c0cce560e01b815260040160405180910390fd5b61ffff80851660a0830190815284151560c0840190815284151560e085019081526000898152600f60209081526040918290208751815492890151848a015163ffffffff908116600160a01b0263ffffffff60a01b1991909216600160801b026001600160a01b03199095166001600160801b03909316929092179390931716919091178155606087015160018201556080870151600282015593516003909401805493519251151563010000000263ff00000019931515620100000262ffffff19909516959096169490941792909217169290921790555185907fb132ee833b779c5596c27a38e7d120b7069d74aef3357175003558fa5314ca5d90611a88908490614066565b60405180910390a25050505050565b6002546001600160a01b0316331480611abf57503360009081526003602052604090205460ff165b611adb5760405162461bcd60e51b8152600401610ca090614040565b60086113d78282614248565b600a8054611082906140ec565b81600d5460ff1615611b0957611b0981612829565b611b138383612cf0565b505050565b6002546001600160a01b0316331480611b4057503360009081526003602052604090205460ff165b611b5c5760405162461bcd60e51b8152600401610ca090614040565b6113d78282612b85565b6000868152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b900490921692820192909252600182015460608201526002820154608082015260039091015461ffff811660a083015260ff6201000082048116151560c084015263010000009091041615801560e0830181905290611c135750611c11878787878787612d5c565b155b15611c3157604051638baa579f60e01b815260040160405180910390fd5b611c3e87878787856125b0565b50505050505050565b33600090815260208181526040808320858452909152902054811115611c9d5760405162461bcd60e51b815260206004820152600b60248201526a21a0a72727aa2fa12aa92760a91b6044820152606401610ca0565b6113d7338383612ef8565b6002546001600160a01b0316331480611cd057503360009081526003602052604090205460ff165b611cec5760405162461bcd60e51b8152600401610ca090614040565b600d805460ff1916911515919091179055565b6007546001600160a01b03163314611d685760405162461bcd60e51b815260206004820152602660248201527f4f6e6c7920746865206172746973742063616e2063616c6c20746869732066756044820152653731ba34b7b760d11b6064820152608401610ca0565b60105460ff1615611d8c57604051633c85668760e21b815260040160405180910390fd5b6003600052600f602090815260408051610100810182527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc8296828546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b9004909216908201527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682954606082018181527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682a5460808401527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682b5461ffff811660a085015260ff6201000082048116151560c0860152630100000090910416151560e0840152601991611e9f908390614308565b90525060036000819052600f602090815282517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682880549285015160408601516001600160801b039093166001600160a01b031990941693909317600160801b63ffffffff948516021763ffffffff60a01b1916600160a01b939092169290920217905560608201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc82968295560808201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682a5560a08201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682b805460c085015160e086015161ffff90941662ffffff199092169190911762010000911515919091021763ff00000019166301000000921515929092029190911790556010805460ff19166001179055600754612000916001600160a01b03909116906019612f6a565b6040516003907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a250565b6002546001600160a01b031633148061205757503360009081526003602052604090205460ff165b6120735760405162461bcd60e51b8152600401610ca090614040565b600e54612088906001600160a01b03166130f1565b600e60009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120d857600080fd5b505af11580156120ec573d6000803e3d6000fd5b50505050565b6000828152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b8204811683870152600160a01b9091041681840152600182015460608201526002820154608082015260039091015461ffff80821660a0840190815260ff6201000084048116151560c08601526301000000909304909216151560e08401526001600160a01b0387168652858552838620888752909452918420549151909284911682116121c557818360a0015161ffff166121c0919061431b565b6121c8565b60005b9695505050505050565b6002546001600160a01b03163314806121fa57503360009081526003602052604090205460ff165b6122165760405162461bcd60e51b8152600401610ca090614040565b600e54611576906001600160a01b03166130f1565b6002546001600160a01b031633148061225357503360009081526003602052604090205460ff165b61226f5760405162461bcd60e51b8152600401610ca090614040565b611436816131af565b6002546001600160a01b03163314806122a057503360009081526003602052604090205460ff165b6122bc5760405162461bcd60e51b8152600401610ca090614040565b6113d78282613224565b60088054611082906140ec565b6002546001600160a01b03163314806122fb57503360009081526003602052604090205460ff165b6123175760405162461bcd60e51b8152600401610ca090614040565b8163ffffffff1660000361233e576040516361bc7fb160e11b815260040160405180910390fd5b60008163ffffffff1611801561235957508063ffffffff1642115b156123775760405163312728dd60e11b815260040160405180910390fd5b6000838152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103612425576040516347c0cce560e01b815260040160405180910390fd5b63ffffffff808416602080840191825284831660408086019182526000898152600f9093529182902085518154945192518616600160a01b0263ffffffff60a01b1993909616600160801b026001600160a01b03199095166001600160801b03909116179390931716929092178155606083015160018201556080830151600282015560a08301516003909101805460c085015160e0860151151563010000000263ff00000019911515620100000262ffffff1990931661ffff9095169490941791909117169190911790555184907f4928d82a7d532bdf3025387660ebf504492c6a5eeb09af6d819dfc8fde01581590612521908490614066565b60405180910390a250505050565b856001600160a01b038116331461255457600d5460ff16156125545761255433612829565b611c3e8787878787876132a7565b60006301ffc9a760e01b6001600160e01b0319831614806125935750636cdb3d1360e11b6001600160e01b03198316145b80610fa95750506001600160e01b0319166303a24d0760e21b1490565b60008042836020015163ffffffff1611156125dd576040516254d81f60e41b815260040160405180910390fd5b6000836040015163ffffffff161180156126005750826040015163ffffffff1642115b1561261e576040516330aee1db60e21b815260040160405180910390fd5b341561263d57604051636992e1ff60e01b815260040160405180910390fd5b8260c00151801561265457506126528461348f565b155b1561267257604051633664886760e11b815260040160405180910390fd5b826060015160e11115801561268c57508260800151606411155b156126aa576040516352df9fe560e01b815260040160405180910390fd5b60808301516126ba90606461431b565b8511156126d85760808301516126d190606461431b565b90506126db565b50835b60608301516126eb9060e161431b565b8611156127095760608301516127029060e161431b565b915061270d565b8591505b60608301805183018152608084018051830181526000898152600f6020908152604080832088518154938a0151928a015163ffffffff908116600160a01b0263ffffffff60a01b1991909416600160801b026001600160a01b03199095166001600160801b03909216919091179390931792909216178155925160018401559051600283015560a08501516003909201805460c087015160e0880151151563010000000263ff00000019911515620100000262ffffff1990931661ffff909616959095179190911716929092179091556127e78284614308565b90506127f4858983612f6a565b60405188907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a25050505050505050565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa612865573d6000803e3d6000fd5b6000603a5250565b8483146128ae5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ca0565b336001600160a01b03891614806128e857506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b6129255760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ca0565b60008060005b878110156129e057888882818110612945576129456141ec565b905060200201359250868682818110612960576129606141ec565b6001600160a01b038e166000908152602081815260408083208984528252822080549390910294909401359550859392509061299d90849061431b565b90915550506001600160a01b038a16600090815260208181526040808320868452909152812080548492906129d3908490614308565b909155505060010161292b565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b604051612a349493929190614360565b60405180910390a46001600160a01b0389163b15612adb5760405163bc197c8160e01b808252906001600160a01b038b169063bc197c8190612a889033908f908e908e908e908e908e908e906004016143bb565b6020604051808303816000875af1158015612aa7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acb919061441f565b6001600160e01b03191614612ae8565b6001600160a01b03891615155b612b045760405162461bcd60e51b8152600401610ca09061443c565b50505050505050505050565b6001600160a01b0390911690637d3e3dbe81612b3d5782612b365750634420e486612b3d565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af1612b7b578060005160e01c03612b7b57600080fd5b5060006024525050565b6001600160a01b038116612bac5760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612bf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c179190614466565b905080600003612c3a5760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af1158015612c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb1919061447f565b9050806120ec57604051631d42c86760e21b815260040160405180910390fd5b611576733cc6cdda760b79bafa08df41ecfa224f810dceb66001612b10565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6000806040518060c00160405280898152602001888152602001878152602001866001600160a01b03168152602001600c6000886001600160a01b03166001600160a01b0316815260200190815260200160002054815260200185858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050825160208085015160408087015160608801516001600160a01b0381168752600c90945290852080549798509496612ea596507f3ebe2a8026435bce72f492f4f1687396bda15f10d2b8fe0db69d6dbaf7564a2b959293919288612e518361449c565b90915550604080516020810197909752860194909452606085019290925260808401526001600160a01b031660a083015260c082015260e001604051602081830303815290604052805190602001206134a2565b90506000612eb7828460a001516134f0565b6001600160a01b0381166000908152600b602052604090205490915060ff168015612eea57506001600160a01b03811615155b9a9950505050505050505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612f2990849061431b565b909155505060408051838152602081018390526000916001600160a01b038616913391600080516020614513833981519152910160405180910390a4505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612f9b908490614308565b909155505060075460408051848152602081018490526001600160a01b03909216916000913391600080516020614513833981519152910160405180910390a460075460408051848152602081018490526001600160a01b038681169316913391600080516020614513833981519152910160405180910390a46001600160a01b0383163b156130c85760075460405163f23a6e6160e01b8082523360048301526001600160a01b039283166024830152604482018590526064820184905260a06084830152600060a48301529185169063f23a6e619060c4016020604051808303816000875af1158015613094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b8919061441f565b6001600160e01b031916146130d5565b6001600160a01b03831615155b611b135760405162461bcd60e51b8152600401610ca09061443c565b6001600160a01b0381166131185760405163172fe2d160e01b815260040160405180910390fd5b47600081900361313b5760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613188576040519150601f19603f3d011682016040523d82523d6000602084013e61318d565b606091505b5050905080611b1357604051631d42c86760e21b815260040160405180910390fd5b600554600160a01b900460ff16156131da576040516313ef243160e11b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115613247576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b909102811760065590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b336001600160a01b03871614806132e157506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b61331e5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ca0565b6001600160a01b0386166000908152602081815260408083208784529091528120805485929061334f90849061431b565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290613385908490614308565b909155505060408051858152602081018590526001600160a01b0380881692908916913391600080516020614513833981519152910160405180910390a46001600160a01b0385163b1561345e5760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e619061340b9033908b908a908a908a908a906004016144b5565b6020604051808303816000875af115801561342a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344e919061441f565b6001600160e01b0319161461346b565b6001600160a01b03851615155b6134875760405162461bcd60e51b8152600401610ca09061443c565b505050505050565b60008061349b83613514565b1192915050565b6000610fa96134af61358d565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006134ff85856136b4565b9150915061350c816136f9565b509392505050565b60048054604051627eeac760e11b81526001600160a01b0384811693820193909352600160248201526000929091169062fdd58e90604401602060405180830381865afa158015613569573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa99190614466565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480156135e657507f000000000000000000000000000000000000000000000000000000000000000046145b1561361057507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60008082516041036136ea5760208301516040840151606085015160001a6136de87828585613843565b945094505050506136f2565b506000905060025b9250929050565b600081600481111561370d5761370d6144fc565b036137155750565b6001816004811115613729576137296144fc565b036137765760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ca0565b600281600481111561378a5761378a6144fc565b036137d75760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ca0565b60038160048111156137eb576137eb6144fc565b036114365760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610ca0565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561387a57506000905060036138fe565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156138ce573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166138f7576000600192509250506138fe565b9150600090505b94509492505050565b80356001600160801b038116811461391e57600080fd5b919050565b803563ffffffff8116811461391e57600080fd5b803561ffff8116811461391e57600080fd5b801515811461143657600080fd5b600080600080600080600060e0888a03121561397257600080fd5b8735965061398260208901613907565b955061399060408901613923565b945061399e60608901613923565b93506139ac60808901613937565b925060a08801356139bc81613949565b915060c08801356139cc81613949565b8091505092959891949750929550565b80356001600160a01b038116811461391e57600080fd5b60008060408385031215613a0657600080fd5b613a0f836139dc565b946020939093013593505050565b6001600160e01b03198116811461143657600080fd5b600060208284031215613a4557600080fd5b8135613a5081613a1d565b9392505050565b60008060008060808587031215613a6d57600080fd5b843593506020850135925060408501359150613a8b606086016139dc565b905092959194509250565b60005b83811015613ab1578181015183820152602001613a99565b50506000910152565b6020815260008251806020840152613ad9816040850160208701613a96565b601f01601f19169190910160400192915050565b600060208284031215613aff57600080fd5b5035919050565b600060208284031215613b1857600080fd5b613a50826139dc565b60008060408385031215613b3457600080fd5b50508035926020909101359150565b60008083601f840112613b5557600080fd5b50813567ffffffffffffffff811115613b6d57600080fd5b6020830191508360208260051b85010111156136f257600080fd5b60008083601f840112613b9a57600080fd5b50813567ffffffffffffffff811115613bb257600080fd5b6020830191508360208285010111156136f257600080fd5b60008060008060008060008060a0898b031215613be657600080fd5b613bef896139dc565b9750613bfd60208a016139dc565b9650604089013567ffffffffffffffff80821115613c1a57600080fd5b613c268c838d01613b43565b909850965060608b0135915080821115613c3f57600080fd5b613c4b8c838d01613b43565b909650945060808b0135915080821115613c6457600080fd5b50613c718b828c01613b88565b999c989b5096995094979396929594505050565b60008060408385031215613c9857600080fd5b613ca1836139dc565b91506020830135613cb181613949565b809150509250929050565b60008060008060408587031215613cd257600080fd5b843567ffffffffffffffff80821115613cea57600080fd5b613cf688838901613b43565b90965094506020870135915080821115613d0f57600080fd5b50613d1c87828801613b43565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015613d6057835183529284019291840191600101613d44565b50909695505050505050565b60008060408385031215613d7f57600080fd5b823591506112d160208401613907565b60008060008060808587031215613da557600080fd5b84359350613db560208601613937565b92506040850135613dc581613949565b91506060850135613dd581613949565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613e1f57613e1f613de0565b604052919050565b600067ffffffffffffffff821115613e4157613e41613de0565b50601f01601f191660200190565b600060208284031215613e6157600080fd5b813567ffffffffffffffff811115613e7857600080fd5b8201601f81018413613e8957600080fd5b8035613e9c613e9782613e27565b613df6565b818152856020838501011115613eb157600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613ee257600080fd5b613eeb836139dc565b91506112d1602084016139dc565b60008060008060008060a08789031215613f1257600080fd5b863595506020870135945060408701359350613f30606088016139dc565b9250608087013567ffffffffffffffff811115613f4c57600080fd5b613f5889828a01613b88565b979a9699509497509295939492505050565b600060208284031215613f7c57600080fd5b8135613a5081613949565b60008060408385031215613f9a57600080fd5b823591506112d1602084016139dc565b600080600060608486031215613fbf57600080fd5b83359250613fcf60208501613923565b9150613fdd60408501613923565b90509250925092565b60008060008060008060a08789031215613fff57600080fd5b614008876139dc565b9550614016602088016139dc565b94506040870135935060608701359250608087013567ffffffffffffffff811115613f4c57600080fd5b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6000610100820190506001600160801b038351168252602083015163ffffffff80821660208501528060408601511660408501525050606083015160608301526080830151608083015261ffff60a08401511660a083015260c08301516140d160c084018215159052565b5060e08301516140e560e084018215159052565b5092915050565b600181811c9082168061410057607f821691505b60208210810361412057634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561413857600080fd5b815167ffffffffffffffff81111561414f57600080fd5b8201601f8101841361416057600080fd5b805161416e613e9782613e27565b81815285602083850101111561418357600080fd5b614194826020830160208601613a96565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610fa957610fa961419d565b6000826141e757634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b601f821115611b1357600081815260208120601f850160051c810160208610156142295750805b601f850160051c820191505b8181101561348757828155600101614235565b815167ffffffffffffffff81111561426257614262613de0565b6142768161427084546140ec565b84614202565b602080601f8311600181146142ab57600084156142935750858301515b600019600386901b1c1916600185901b178555613487565b600085815260208120601f198616915b828110156142da578886015182559484019460019091019084016142bb565b50858210156142f85787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80820180821115610fa957610fa961419d565b81810381811115610fa957610fa961419d565b81835260006001600160fb1b0383111561434757600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061437460408301868861432e565b828103602084015261438781858761432e565b979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a0604082018190526000906143e8908301888a61432e565b82810360608401526143fb81878961432e565b90508281036080840152614410818587614392565b9b9a5050505050505050505050565b60006020828403121561443157600080fd5b8151613a5081613a1d565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60006020828403121561447857600080fd5b5051919050565b60006020828403121561449157600080fd5b8151613a5081613949565b6000600182016144ae576144ae61419d565b5060010190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a0608082018190526000906144f09083018486614392565b98975050505050505050565b634e487b7160e01b600052602160045260246000fdfec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62a164736f6c6343000811000a0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085056ddc1b6e64e9afb6e662b503b1b5c3cdecad00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000069442276c71df2de463b7b3d170f427a8dd26e0a00000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

Deployed Bytecode

0x6080604052600436106103955760003560e01c8063881ced95116101dc578063c0fd735b11610102578063e2e784d5116100a0578063ecd8dbf71161006f578063ecd8dbf714610bc8578063f242432a14610be8578063fb796e6c14610c08578063fd6724fc14610c2257600080fd5b8063e2e784d514610b18578063e3faad9414610b38578063e8a3d48514610b78578063e985e9c514610b8d57600080fd5b8063de7ff469116100dc578063de7ff46914610aa9578063df27092014610ac9578063e086e5ec14610ae3578063e17b25af14610af857600080fd5b8063c0fd735b14610a3d578063d4ddce8a14610a52578063d7e45cd714610a8857600080fd5b8063a41572961161017a578063b05fc5cc11610149578063b05fc5cc146109d5578063b390c0ab146109e8578063b7c0b8e814610a08578063c01c3c9c14610a2857600080fd5b8063a415729614610934578063a522ad2514610961578063a6d23e1014610981578063af4fddfa146109a157600080fd5b80638da5cb5b116101b65780638da5cb5b146108bf578063938e3d7b146108df57806395d89b41146108ff578063a22cb4651461091457600080fd5b8063881ced951461083557806389d020dc1461086f5780638a8755121461088f57600080fd5b806343bc1612116102c157806358a478ed1161025f578063704802751161022e57806370480275146107b35780637c1a8343146107d35780637ecebe00146107f35780637f20256a1461082057600080fd5b806358a478ed146107145780635e1c0746146107445780635e1e1004146107595780636b2a9d251461077957600080fd5b806349df728c1161029b57806349df728c146106825780634d820b4f146106a25780634e1273f4146106d2578063582e8ae5146106ff57600080fd5b806343bc16121461060e578063453722411461062e57806346d8efad1461066257600080fd5b80631785f53c1161033957806331cb61051161030857806331cb610514610561578063392f37e9146105815780633fc8cef3146105b9578063429b62e5146105de57600080fd5b80631785f53c146104a957806326645a2c146104c95780632a55205a146105025780632eb2c2d61461054157600080fd5b80630651efa3116103755780630651efa31461043457806306fdde03146104475780630e89341c1461046957806313af40351461048957600080fd5b8062029eb81461039a578062fdd58e146103bc57806301ffc9a714610404575b600080fd5b3480156103a657600080fd5b506103ba6103b5366004613957565b610c5c565b005b3480156103c857600080fd5b506103f16103d73660046139f3565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b34801561041057600080fd5b5061042461041f366004613a33565b610f84565b60405190151581526020016103fb565b6103ba610442366004613a57565b610faf565b34801561045357600080fd5b5061045c611075565b6040516103fb9190613aba565b34801561047557600080fd5b5061045c610484366004613aed565b611103565b34801561049557600080fd5b506103ba6104a4366004613b06565b611175565b3480156104b557600080fd5b506103ba6104c4366004613b06565b611205565b3480156104d557600080fd5b506104246104e4366004613aed565b6000908152600f602052604090206003015462010000900460ff1690565b34801561050e57600080fd5b5061052261051d366004613b21565b611293565b604080516001600160a01b0390931683526020830191909152016103fb565b34801561054d57600080fd5b506103ba61055c366004613bca565b6112da565b34801561056d57600080fd5b506103ba61057c366004613c85565b61131a565b34801561058d57600080fd5b506005546105a1906001600160a01b031681565b6040516001600160a01b0390911681526020016103fb565b3480156105c557600080fd5b50600d546105a19061010090046001600160a01b031681565b3480156105ea57600080fd5b506104246105f9366004613b06565b60036020526000908152604090205460ff1681565b34801561061a57600080fd5b506007546105a1906001600160a01b031681565b34801561063a57600080fd5b506103f1610649366004613aed565b6000908152600f602052604090206003015461ffff1690565b34801561066e57600080fd5b506103ba61067d366004613c85565b611389565b34801561068e57600080fd5b506103ba61069d366004613b06565b6113db565b3480156106ae57600080fd5b506103f16106bd366004613aed565b6000908152600f602052604090206002015490565b3480156106de57600080fd5b506106f26106ed366004613cbc565b611439565b6040516103fb9190613d28565b34801561070b57600080fd5b506103f160e181565b34801561072057600080fd5b506103f161072f366004613aed565b6000908152600f602052604090206001015490565b34801561075057600080fd5b506103ba61156e565b34801561076557600080fd5b506103ba610774366004613b06565b611578565b34801561078557600080fd5b50610424610794366004613aed565b6000908152600f60205260409020600301546301000000900460ff1690565b3480156107bf57600080fd5b506103ba6107ce366004613b06565b611605565b3480156107df57600080fd5b506103ba6107ee366004613d6c565b611696565b3480156107ff57600080fd5b506103f161080e366004613b06565b600c6020526000908152604090205481565b34801561082c57600080fd5b506103f1606481565b34801561084157600080fd5b506103f1610850366004613aed565b6000908152600f6020526040902054600160801b900463ffffffff1690565b34801561087b57600080fd5b506103ba61088a366004613d8f565b61188e565b34801561089b57600080fd5b506104246108aa366004613b06565b600b6020526000908152604090205460ff1681565b3480156108cb57600080fd5b506002546105a1906001600160a01b031681565b3480156108eb57600080fd5b506103ba6108fa366004613e4f565b611a97565b34801561090b57600080fd5b5061045c611ae7565b34801561092057600080fd5b506103ba61092f366004613c85565b611af4565b34801561094057600080fd5b5061045c604051806040016040528060018152602001603160f81b81525081565b34801561096d57600080fd5b506103ba61097c366004613ecf565b611b18565b34801561098d57600080fd5b50600e546105a1906001600160a01b031681565b3480156109ad57600080fd5b506103f17f3ebe2a8026435bce72f492f4f1687396bda15f10d2b8fe0db69d6dbaf7564a2b81565b6103ba6109e3366004613ef9565b611b66565b3480156109f457600080fd5b506103ba610a03366004613b21565b611c47565b348015610a1457600080fd5b506103ba610a23366004613f6a565b611ca8565b348015610a3457600080fd5b506103ba611cff565b348015610a4957600080fd5b506103ba61202f565b348015610a5e57600080fd5b506103f1610a6d366004613aed565b6000908152600f60205260409020546001600160801b031690565b348015610a9457600080fd5b5060055461042490600160a01b900460ff1681565b348015610ab557600080fd5b506103f1610ac4366004613f87565b6120f2565b348015610ad557600080fd5b506010546104249060ff1681565b348015610aef57600080fd5b506103ba6121d2565b348015610b0457600080fd5b506103ba610b13366004613b06565b61222b565b348015610b2457600080fd5b506103ba610b333660046139f3565b612278565b348015610b4457600080fd5b5061045c604051806040016040528060148152602001734d6f726e696e67734f70656e45646974696f6e7360601b81525081565b348015610b8457600080fd5b5061045c6122c6565b348015610b9957600080fd5b50610424610ba8366004613ecf565b600160209081526000928352604080842090915290825290205460ff1681565b348015610bd457600080fd5b506103ba610be3366004613faa565b6122d3565b348015610bf457600080fd5b506103ba610c03366004613fe6565b61252f565b348015610c1457600080fd5b50600d546104249060ff1681565b348015610c2e57600080fd5b506103f1610c3d366004613aed565b6000908152600f6020526040902054600160a01b900463ffffffff1690565b6002546001600160a01b0316331480610c8457503360009081526003602052604090205460ff165b610ca95760405162461bcd60e51b8152600401610ca090614040565b60405180910390fd5b8463ffffffff16600003610cd0576040516361bc7fb160e11b815260040160405180910390fd5b60008463ffffffff16118015610ceb57508363ffffffff1642115b15610d095760405163312728dd60e11b815260040160405180910390fd5b6000878152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b909104169381019390935260018101546060840152600281015460808401526003015461ffff811660a084015260ff6201000082048116151560c0850152630100000090910416151560e083015215610db7576040516320705a1b60e11b815260040160405180910390fd5b8681600001906001600160801b031690816001600160801b03168152505085816020019063ffffffff16908163ffffffff168152505084816040019063ffffffff16908163ffffffff1681525050838160a0019061ffff16908161ffff1681525050828160c0019015159081151581525050818160e001901515908115158152505080600f60008a815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff160217905550606082015181600101556080820151816002015560a08201518160030160006101000a81548161ffff021916908361ffff16021790555060c08201518160030160026101000a81548160ff02191690831515021790555060e08201518160030160036101000a81548160ff021916908315150217905550905050877f14eb4bf6c7d72fc73e72c7352fc7607a0ac11969cadce90af77c0540a7b0c33082604051610f729190614066565b60405180910390a25050505050505050565b60006001600160e01b0319821663152a902d60e11b1480610fa95750610fa982612562565b92915050565b6000848152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b900490921692820192909252600182015460608201526002820154608082015260039091015461ffff811660a083015260ff6201000082048116151560c084015263010000009091041615801560e083015261106157604051630426ff7760e01b815260040160405180910390fd5b61106e85858585856125b0565b5050505050565b60098054611082906140ec565b80601f01602080910402602001604051908101604052809291908181526020018280546110ae906140ec565b80156110fb5780601f106110d0576101008083540402835291602001916110fb565b820191906000526020600020905b8154815290600101906020018083116110de57829003601f168201915b505050505081565b60055460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa15801561114d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fa99190810190614126565b6002546001600160a01b031633148061119d57503360009081526003602052604090205460ff165b6111b95760405162461bcd60e51b8152600401610ca090614040565b600280546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6002546001600160a01b031633148061122d57503360009081526003602052604090205460ff165b6112495760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b038116600081815260036020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b03811690600090612710906112c790600160a01b90046bffffffffffffffffffffffff16856141b3565b6112d191906141ca565b90509250929050565b876001600160a01b03811633146112ff57600d5460ff16156112ff576112ff33612829565b61130f898989898989898961286d565b505050505050505050565b6002546001600160a01b031633148061134257503360009081526003602052604090205460ff165b61135e5760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b03919091166000908152600b60205260409020805460ff1916911515919091179055565b6002546001600160a01b03163314806113b157503360009081526003602052604090205460ff165b6113cd5760405162461bcd60e51b8152600401610ca090614040565b6113d78282612b10565b5050565b6002546001600160a01b031633148061140357503360009081526003602052604090205460ff165b61141f5760405162461bcd60e51b8152600401610ca090614040565b600e546114369082906001600160a01b0316612b85565b50565b606083821461147c5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ca0565b8367ffffffffffffffff81111561149557611495613de0565b6040519080825280602002602001820160405280156114be578160200160208202803683370190505b50905060005b84811015611565576000808787848181106114e1576114e16141ec565b90506020020160208101906114f69190613b06565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858481811061152a5761152a6141ec565b90506020020135815260200190815260200160002054828281518110611552576115526141ec565b60209081029190910101526001016114c4565b50949350505050565b611576612cd1565b565b6002546001600160a01b03163314806115a057503360009081526003602052604090205460ff165b6115bc5760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b0381166115e357604051631f4c499760e01b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031633148061162d57503360009081526003602052604090205460ff165b6116495760405162461bcd60e51b8152600401610ca090614040565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b6002546001600160a01b03163314806116be57503360009081526003602052604090205460ff165b6116da5760405162461bcd60e51b8152600401610ca090614040565b6000828152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103611788576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b0380831682526000848152600f602090815260409182902084518154928601518487015163ffffffff908116600160a01b0263ffffffff60a01b1991909216600160801b026001600160a01b031990951692909616919091179290921793909316178255606083015160018301556080830151600283015560a08301516003909201805460c085015160e0860151151563010000000263ff00000019911515620100000262ffffff1990931661ffff909616959095179190911716929092179091555183907f75c878cf35971786285583083fa747eac0e90af627ab5be381b17c8ddb38973690611881908490614066565b60405180910390a2505050565b6002546001600160a01b03163314806118b657503360009081526003602052604090205460ff165b6118d25760405162461bcd60e51b8152600401610ca090614040565b6000848152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103611980576040516347c0cce560e01b815260040160405180910390fd5b61ffff80851660a0830190815284151560c0840190815284151560e085019081526000898152600f60209081526040918290208751815492890151848a015163ffffffff908116600160a01b0263ffffffff60a01b1991909216600160801b026001600160a01b03199095166001600160801b03909316929092179390931716919091178155606087015160018201556080870151600282015593516003909401805493519251151563010000000263ff00000019931515620100000262ffffff19909516959096169490941792909217169290921790555185907fb132ee833b779c5596c27a38e7d120b7069d74aef3357175003558fa5314ca5d90611a88908490614066565b60405180910390a25050505050565b6002546001600160a01b0316331480611abf57503360009081526003602052604090205460ff165b611adb5760405162461bcd60e51b8152600401610ca090614040565b60086113d78282614248565b600a8054611082906140ec565b81600d5460ff1615611b0957611b0981612829565b611b138383612cf0565b505050565b6002546001600160a01b0316331480611b4057503360009081526003602052604090205460ff165b611b5c5760405162461bcd60e51b8152600401610ca090614040565b6113d78282612b85565b6000868152600f602090815260409182902082516101008101845281546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b900490921692820192909252600182015460608201526002820154608082015260039091015461ffff811660a083015260ff6201000082048116151560c084015263010000009091041615801560e0830181905290611c135750611c11878787878787612d5c565b155b15611c3157604051638baa579f60e01b815260040160405180910390fd5b611c3e87878787856125b0565b50505050505050565b33600090815260208181526040808320858452909152902054811115611c9d5760405162461bcd60e51b815260206004820152600b60248201526a21a0a72727aa2fa12aa92760a91b6044820152606401610ca0565b6113d7338383612ef8565b6002546001600160a01b0316331480611cd057503360009081526003602052604090205460ff165b611cec5760405162461bcd60e51b8152600401610ca090614040565b600d805460ff1916911515919091179055565b6007546001600160a01b03163314611d685760405162461bcd60e51b815260206004820152602660248201527f4f6e6c7920746865206172746973742063616e2063616c6c20746869732066756044820152653731ba34b7b760d11b6064820152608401610ca0565b60105460ff1615611d8c57604051633c85668760e21b815260040160405180910390fd5b6003600052600f602090815260408051610100810182527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc8296828546001600160801b038116825263ffffffff600160801b8204811694830194909452600160a01b9004909216908201527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682954606082018181527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682a5460808401527f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682b5461ffff811660a085015260ff6201000082048116151560c0860152630100000090910416151560e0840152601991611e9f908390614308565b90525060036000819052600f602090815282517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682880549285015160408601516001600160801b039093166001600160a01b031990941693909317600160801b63ffffffff948516021763ffffffff60a01b1916600160a01b939092169290920217905560608201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc82968295560808201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682a5560a08201517f45f76dafbbad695564362934e24d72eedc57f9fc1a65f39bca62176cc829682b805460c085015160e086015161ffff90941662ffffff199092169190911762010000911515919091021763ff00000019166301000000921515929092029190911790556010805460ff19166001179055600754612000916001600160a01b03909116906019612f6a565b6040516003907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a250565b6002546001600160a01b031633148061205757503360009081526003602052604090205460ff165b6120735760405162461bcd60e51b8152600401610ca090614040565b600e54612088906001600160a01b03166130f1565b600e60009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120d857600080fd5b505af11580156120ec573d6000803e3d6000fd5b50505050565b6000828152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b8204811683870152600160a01b9091041681840152600182015460608201526002820154608082015260039091015461ffff80821660a0840190815260ff6201000084048116151560c08601526301000000909304909216151560e08401526001600160a01b0387168652858552838620888752909452918420549151909284911682116121c557818360a0015161ffff166121c0919061431b565b6121c8565b60005b9695505050505050565b6002546001600160a01b03163314806121fa57503360009081526003602052604090205460ff165b6122165760405162461bcd60e51b8152600401610ca090614040565b600e54611576906001600160a01b03166130f1565b6002546001600160a01b031633148061225357503360009081526003602052604090205460ff165b61226f5760405162461bcd60e51b8152600401610ca090614040565b611436816131af565b6002546001600160a01b03163314806122a057503360009081526003602052604090205460ff165b6122bc5760405162461bcd60e51b8152600401610ca090614040565b6113d78282613224565b60088054611082906140ec565b6002546001600160a01b03163314806122fb57503360009081526003602052604090205460ff165b6123175760405162461bcd60e51b8152600401610ca090614040565b8163ffffffff1660000361233e576040516361bc7fb160e11b815260040160405180910390fd5b60008163ffffffff1611801561235957508063ffffffff1642115b156123775760405163312728dd60e11b815260040160405180910390fd5b6000838152600f6020908152604080832081516101008101835281546001600160801b038116825263ffffffff600160801b82048116958301869052600160a01b909104169281019290925260018101546060830152600281015460808301526003015461ffff811660a083015260ff6201000082048116151560c0840152630100000090910416151560e08201529103612425576040516347c0cce560e01b815260040160405180910390fd5b63ffffffff808416602080840191825284831660408086019182526000898152600f9093529182902085518154945192518616600160a01b0263ffffffff60a01b1993909616600160801b026001600160a01b03199095166001600160801b03909116179390931716929092178155606083015160018201556080830151600282015560a08301516003909101805460c085015160e0860151151563010000000263ff00000019911515620100000262ffffff1990931661ffff9095169490941791909117169190911790555184907f4928d82a7d532bdf3025387660ebf504492c6a5eeb09af6d819dfc8fde01581590612521908490614066565b60405180910390a250505050565b856001600160a01b038116331461255457600d5460ff16156125545761255433612829565b611c3e8787878787876132a7565b60006301ffc9a760e01b6001600160e01b0319831614806125935750636cdb3d1360e11b6001600160e01b03198316145b80610fa95750506001600160e01b0319166303a24d0760e21b1490565b60008042836020015163ffffffff1611156125dd576040516254d81f60e41b815260040160405180910390fd5b6000836040015163ffffffff161180156126005750826040015163ffffffff1642115b1561261e576040516330aee1db60e21b815260040160405180910390fd5b341561263d57604051636992e1ff60e01b815260040160405180910390fd5b8260c00151801561265457506126528461348f565b155b1561267257604051633664886760e11b815260040160405180910390fd5b826060015160e11115801561268c57508260800151606411155b156126aa576040516352df9fe560e01b815260040160405180910390fd5b60808301516126ba90606461431b565b8511156126d85760808301516126d190606461431b565b90506126db565b50835b60608301516126eb9060e161431b565b8611156127095760608301516127029060e161431b565b915061270d565b8591505b60608301805183018152608084018051830181526000898152600f6020908152604080832088518154938a0151928a015163ffffffff908116600160a01b0263ffffffff60a01b1991909416600160801b026001600160a01b03199095166001600160801b03909216919091179390931792909216178155925160018401559051600283015560a08501516003909201805460c087015160e0880151151563010000000263ff00000019911515620100000262ffffff1990931661ffff909616959095179190911716929092179091556127e78284614308565b90506127f4858983612f6a565b60405188907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a25050505050505050565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa612865573d6000803e3d6000fd5b6000603a5250565b8483146128ae5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610ca0565b336001600160a01b03891614806128e857506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b6129255760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ca0565b60008060005b878110156129e057888882818110612945576129456141ec565b905060200201359250868682818110612960576129606141ec565b6001600160a01b038e166000908152602081815260408083208984528252822080549390910294909401359550859392509061299d90849061431b565b90915550506001600160a01b038a16600090815260208181526040808320868452909152812080548492906129d3908490614308565b909155505060010161292b565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b604051612a349493929190614360565b60405180910390a46001600160a01b0389163b15612adb5760405163bc197c8160e01b808252906001600160a01b038b169063bc197c8190612a889033908f908e908e908e908e908e908e906004016143bb565b6020604051808303816000875af1158015612aa7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612acb919061441f565b6001600160e01b03191614612ae8565b6001600160a01b03891615155b612b045760405162461bcd60e51b8152600401610ca09061443c565b50505050505050505050565b6001600160a01b0390911690637d3e3dbe81612b3d5782612b365750634420e486612b3d565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af1612b7b578060005160e01c03612b7b57600080fd5b5060006024525050565b6001600160a01b038116612bac5760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612bf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c179190614466565b905080600003612c3a5760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af1158015612c8d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cb1919061447f565b9050806120ec57604051631d42c86760e21b815260040160405180910390fd5b611576733cc6cdda760b79bafa08df41ecfa224f810dceb66001612b10565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6000806040518060c00160405280898152602001888152602001878152602001866001600160a01b03168152602001600c6000886001600160a01b03166001600160a01b0316815260200190815260200160002054815260200185858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050825160208085015160408087015160608801516001600160a01b0381168752600c90945290852080549798509496612ea596507f3ebe2a8026435bce72f492f4f1687396bda15f10d2b8fe0db69d6dbaf7564a2b959293919288612e518361449c565b90915550604080516020810197909752860194909452606085019290925260808401526001600160a01b031660a083015260c082015260e001604051602081830303815290604052805190602001206134a2565b90506000612eb7828460a001516134f0565b6001600160a01b0381166000908152600b602052604090205490915060ff168015612eea57506001600160a01b03811615155b9a9950505050505050505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612f2990849061431b565b909155505060408051838152602081018390526000916001600160a01b038616913391600080516020614513833981519152910160405180910390a4505050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612f9b908490614308565b909155505060075460408051848152602081018490526001600160a01b03909216916000913391600080516020614513833981519152910160405180910390a460075460408051848152602081018490526001600160a01b038681169316913391600080516020614513833981519152910160405180910390a46001600160a01b0383163b156130c85760075460405163f23a6e6160e01b8082523360048301526001600160a01b039283166024830152604482018590526064820184905260a06084830152600060a48301529185169063f23a6e619060c4016020604051808303816000875af1158015613094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b8919061441f565b6001600160e01b031916146130d5565b6001600160a01b03831615155b611b135760405162461bcd60e51b8152600401610ca09061443c565b6001600160a01b0381166131185760405163172fe2d160e01b815260040160405180910390fd5b47600081900361313b5760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613188576040519150601f19603f3d011682016040523d82523d6000602084013e61318d565b606091505b5050905080611b1357604051631d42c86760e21b815260040160405180910390fd5b600554600160a01b900460ff16156131da576040516313ef243160e11b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115613247576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b909102811760065590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b336001600160a01b03871614806132e157506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b61331e5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ca0565b6001600160a01b0386166000908152602081815260408083208784529091528120805485929061334f90849061431b565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290613385908490614308565b909155505060408051858152602081018590526001600160a01b0380881692908916913391600080516020614513833981519152910160405180910390a46001600160a01b0385163b1561345e5760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e619061340b9033908b908a908a908a908a906004016144b5565b6020604051808303816000875af115801561342a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344e919061441f565b6001600160e01b0319161461346b565b6001600160a01b03851615155b6134875760405162461bcd60e51b8152600401610ca09061443c565b505050505050565b60008061349b83613514565b1192915050565b6000610fa96134af61358d565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006134ff85856136b4565b9150915061350c816136f9565b509392505050565b60048054604051627eeac760e11b81526001600160a01b0384811693820193909352600160248201526000929091169062fdd58e90604401602060405180830381865afa158015613569573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa99190614466565b6000306001600160a01b037f000000000000000000000000663e218f49edffdb838131f1f2fda255f593206d161480156135e657507f000000000000000000000000000000000000000000000000000000000000000146145b1561361057507f7801042e2ef91426e891f70220f66ffcd199bd3b77bae53e1bcd2d4fb9053b6190565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527fad862c941698014fb2bfd67682e111f44f4d73d146cbeddc6f77eb4e40f02bff828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60008082516041036136ea5760208301516040840151606085015160001a6136de87828585613843565b945094505050506136f2565b506000905060025b9250929050565b600081600481111561370d5761370d6144fc565b036137155750565b6001816004811115613729576137296144fc565b036137765760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610ca0565b600281600481111561378a5761378a6144fc565b036137d75760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610ca0565b60038160048111156137eb576137eb6144fc565b036114365760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610ca0565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561387a57506000905060036138fe565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156138ce573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166138f7576000600192509250506138fe565b9150600090505b94509492505050565b80356001600160801b038116811461391e57600080fd5b919050565b803563ffffffff8116811461391e57600080fd5b803561ffff8116811461391e57600080fd5b801515811461143657600080fd5b600080600080600080600060e0888a03121561397257600080fd5b8735965061398260208901613907565b955061399060408901613923565b945061399e60608901613923565b93506139ac60808901613937565b925060a08801356139bc81613949565b915060c08801356139cc81613949565b8091505092959891949750929550565b80356001600160a01b038116811461391e57600080fd5b60008060408385031215613a0657600080fd5b613a0f836139dc565b946020939093013593505050565b6001600160e01b03198116811461143657600080fd5b600060208284031215613a4557600080fd5b8135613a5081613a1d565b9392505050565b60008060008060808587031215613a6d57600080fd5b843593506020850135925060408501359150613a8b606086016139dc565b905092959194509250565b60005b83811015613ab1578181015183820152602001613a99565b50506000910152565b6020815260008251806020840152613ad9816040850160208701613a96565b601f01601f19169190910160400192915050565b600060208284031215613aff57600080fd5b5035919050565b600060208284031215613b1857600080fd5b613a50826139dc565b60008060408385031215613b3457600080fd5b50508035926020909101359150565b60008083601f840112613b5557600080fd5b50813567ffffffffffffffff811115613b6d57600080fd5b6020830191508360208260051b85010111156136f257600080fd5b60008083601f840112613b9a57600080fd5b50813567ffffffffffffffff811115613bb257600080fd5b6020830191508360208285010111156136f257600080fd5b60008060008060008060008060a0898b031215613be657600080fd5b613bef896139dc565b9750613bfd60208a016139dc565b9650604089013567ffffffffffffffff80821115613c1a57600080fd5b613c268c838d01613b43565b909850965060608b0135915080821115613c3f57600080fd5b613c4b8c838d01613b43565b909650945060808b0135915080821115613c6457600080fd5b50613c718b828c01613b88565b999c989b5096995094979396929594505050565b60008060408385031215613c9857600080fd5b613ca1836139dc565b91506020830135613cb181613949565b809150509250929050565b60008060008060408587031215613cd257600080fd5b843567ffffffffffffffff80821115613cea57600080fd5b613cf688838901613b43565b90965094506020870135915080821115613d0f57600080fd5b50613d1c87828801613b43565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015613d6057835183529284019291840191600101613d44565b50909695505050505050565b60008060408385031215613d7f57600080fd5b823591506112d160208401613907565b60008060008060808587031215613da557600080fd5b84359350613db560208601613937565b92506040850135613dc581613949565b91506060850135613dd581613949565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613e1f57613e1f613de0565b604052919050565b600067ffffffffffffffff821115613e4157613e41613de0565b50601f01601f191660200190565b600060208284031215613e6157600080fd5b813567ffffffffffffffff811115613e7857600080fd5b8201601f81018413613e8957600080fd5b8035613e9c613e9782613e27565b613df6565b818152856020838501011115613eb157600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613ee257600080fd5b613eeb836139dc565b91506112d1602084016139dc565b60008060008060008060a08789031215613f1257600080fd5b863595506020870135945060408701359350613f30606088016139dc565b9250608087013567ffffffffffffffff811115613f4c57600080fd5b613f5889828a01613b88565b979a9699509497509295939492505050565b600060208284031215613f7c57600080fd5b8135613a5081613949565b60008060408385031215613f9a57600080fd5b823591506112d1602084016139dc565b600080600060608486031215613fbf57600080fd5b83359250613fcf60208501613923565b9150613fdd60408501613923565b90509250925092565b60008060008060008060a08789031215613fff57600080fd5b614008876139dc565b9550614016602088016139dc565b94506040870135935060608701359250608087013567ffffffffffffffff811115613f4c57600080fd5b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6000610100820190506001600160801b038351168252602083015163ffffffff80821660208501528060408601511660408501525050606083015160608301526080830151608083015261ffff60a08401511660a083015260c08301516140d160c084018215159052565b5060e08301516140e560e084018215159052565b5092915050565b600181811c9082168061410057607f821691505b60208210810361412057634e487b7160e01b600052602260045260246000fd5b50919050565b60006020828403121561413857600080fd5b815167ffffffffffffffff81111561414f57600080fd5b8201601f8101841361416057600080fd5b805161416e613e9782613e27565b81815285602083850101111561418357600080fd5b614194826020830160208601613a96565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610fa957610fa961419d565b6000826141e757634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b601f821115611b1357600081815260208120601f850160051c810160208610156142295750805b601f850160051c820191505b8181101561348757828155600101614235565b815167ffffffffffffffff81111561426257614262613de0565b6142768161427084546140ec565b84614202565b602080601f8311600181146142ab57600084156142935750858301515b600019600386901b1c1916600185901b178555613487565b600085815260208120601f198616915b828110156142da578886015182559484019460019091019084016142bb565b50858210156142f85787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80820180821115610fa957610fa961419d565b81810381811115610fa957610fa961419d565b81835260006001600160fb1b0383111561434757600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061437460408301868861432e565b828103602084015261438781858761432e565b979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a0604082018190526000906143e8908301888a61432e565b82810360608401526143fb81878961432e565b90508281036080840152614410818587614392565b9b9a5050505050505050505050565b60006020828403121561443157600080fd5b8151613a5081613a1d565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60006020828403121561447857600080fd5b5051919050565b60006020828403121561449157600080fd5b8151613a5081613949565b6000600182016144ae576144ae61419d565b5060010190565b6001600160a01b03878116825286166020820152604081018590526060810184905260a0608082018190526000906144f09083018486614392565b98975050505050505050565b634e487b7160e01b600052602160045260246000fdfec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62a164736f6c6343000811000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085056ddc1b6e64e9afb6e662b503b1b5c3cdecad00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000069442276c71df2de463b7b3d170f427a8dd26e0a00000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

-----Decoded View---------------
Arg [0] : owner_ (address): 0x3B1Bd4C99c059ED58155240FD01D6fC86A430D4D
Arg [1] : admin_ (address): 0x6306D0cDFADD6095A313e8484275b6cC7036166C
Arg [2] : payments_ (address): 0x85056DdC1B6e64e9AfB6E662B503b1B5C3CDEcad
Arg [3] : royaltiesAmount_ (uint256): 750
Arg [4] : metadata_ (address): 0x69442276C71DF2de463b7B3d170F427a8dD26E0a
Arg [5] : fountCard_ (address): 0x16F444F2d9E696834C1c9b536Dc3896E1B545213

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d
Arg [1] : 0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c
Arg [2] : 00000000000000000000000085056ddc1b6e64e9afb6e662b503b1b5c3cdecad
Arg [3] : 00000000000000000000000000000000000000000000000000000000000002ee
Arg [4] : 00000000000000000000000069442276c71df2de463b7b3d170f427a8dd26e0a
Arg [5] : 00000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213


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.