ETH Price: $3,426.81 (-1.53%)
Gas: 6 Gwei

Token

Drivers Open Editions by Everfresh (DRIVERS)
 

Overview

Max Total Supply

102 DRIVERS

Holders

83

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

0xd480C4bEC2CBbd09BE7f365bB23A713Ec0048D22
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:
DriversOpenEditions

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 20 : 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 20 : 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 3 of 20 : 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 4 of 20 : 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 5 of 20 : 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 6 of 20 : 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 7 of 20 : 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 8 of 20 : 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 9 of 20 : 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 10 of 20 : 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: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * 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 11 of 20 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_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) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_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 12 of 20 : 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 13 of 20 : 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 14 of 20 : 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 15 of 20 : 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 16 of 20 : DriversOpenEditions.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

/**

  ##########      ##########      #####   #####    #####   ############   ##########        ##########
  ############    ############    #####   #####    #####   ############   ############     ############
  #####   #####   #####  ######   #####   #####    #####   ############   #####  ######   ######  ######
  #####   #####   #####   #####   #####   #####    #####   #####          #####   #####   ######  ######
  #####   #####   #####   #####   #####    ####    ####    #####          #####   #####   #######
  #####   #####   #####  #####    #####    ####    ####    ##########     #####  #####     ##########
  #####   #####   ###########     #####    ####    ####    ##########     ###########       ###########
  #####   #####   ############    #####    ####    ####    #####          ############           #######
  #####   #####   #####   #####   #####     ####  ####     #####          #####   #####   ######  ######
  #####   #####   #####   #####   #####     ##########     ############   #####   #####   ######  ######
  ############    #####   #####   #####      ########      ############   #####   #####    ############
  ##########      #####   #####   #####        ####        ############   #####   #####     ##########

  By Everfresh

*/

import "./ERC1155Base.sol";

/**
 * @author Fount Gallery
 * @title  Drivers Open Editions by Everfresh
 * @notice Drivers is celebrated motion artist Everfresh's first Fount Gallery release. Driven by
 * the rhythm of skate culture and dance, the Drivers collection delivers an immersive world of
 * form and flow.
 *
 * 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 DriversOpenEditions is ERC1155Base {
    /* ------------------------------------------------------------------------
       S T O R A G E
    ------------------------------------------------------------------------ */

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

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

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

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

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

    /** 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 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 The amount to mint
     * @param to The address to mint the token to
     */
    function collectEdition(
        uint256 id,
        uint256 amount,
        address to
    ) external payable {
        TokenData memory tokenData = _idToTokenData[id];
        if (tokenData.requiresSig) revert RequiresSignature();
        _collectEdition(id, amount, 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 The amount to mint
     * @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,
        address to,
        bytes calldata signature
    ) external payable {
        TokenData memory tokenData = _idToTokenData[id];
        if (tokenData.requiresSig && !_verifyMintSignature(id, amount, to, signature)) {
            revert InvalidSignature();
        }
        _collectEdition(id, amount, 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 The amount of editions to mint
     * @param to The address to mint the token to
     * @param tokenData Information about the token
     */
    function _collectEdition(
        uint256 id,
        uint256 amount,
        address to,
        TokenData memory tokenData
    ) internal {
        uint256 mintAmount = amount;

        // 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 (tokenData.price > 0 && tokenData.price * amount != msg.value) {
            revert IncorrectPaymentAmount();
        }

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

        // Check if there's a cap on mints per wallet
        if (tokenData.perAddressAllowance > 0) {
            // Check the amount doesn't exceed the per wallet allowance to mint
            if (amount > tokenData.perAddressAllowance) revert AmountExceedsMaxWalletMint();

            // Get the accounts remaining balance for this edition
            uint256 currentBalance = balanceOf[to][id];
            uint256 remainingAllowance = currentBalance >= tokenData.perAddressAllowance
                ? 0
                : tokenData.perAddressAllowance - currentBalance;

            // Set the mint amount based on the remaining allowance of `to`
            if (amount > remainingAllowance) {
                mintAmount = remainingAllowance;
            }

            // If there's no allowed tokens to mint, then revert
            if (mintAmount == 0) revert AmountExceedsWalletAllowance();

            // If the request amount was over the actual mint amount, refund any ETH to the msg.sender
            if (tokenData.price > 0 && amount > mintAmount) {
                _transferETHWithFallback(msg.sender, (amount - mintAmount) * tokenData.price);
            }
        }

        // Add the new mint to the token data
        unchecked {
            tokenData.collected += uint32(mintAmount);
        }
        _idToTokenData[id] = tokenData;

        // 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 tokenCollectedCount(uint256 id) external view returns (uint256) {
        return _idToTokenData[id].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 17 of 20 : 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/IDriversPayments.sol";
import "./interfaces/IWETH.sol";

/**
 * @author Fount Gallery
 * @title  ERC1155Base
 * @notice Base contract for Drivers 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 everfresh.eth
    address public everfresh = 0xBb3444a06E9928dDA9a739CdAb3E0c5cf6890099;

    /// @notice Contract information
    string public contractURI;

    /// @notice Contract name
    string public name = "Drivers Open Editions by Everfresh";

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

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

    /// @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,address to,uint256 nonce)");

    /// @dev EIP-712 signed data struct for minting with an off-chain signature
    struct MintSignatureData {
        uint256 id;
        uint256 amount;
        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), everfresh, id, amount);
        emit TransferSingle(msg.sender, everfresh, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(
                    msg.sender,
                    everfresh,
                    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,
        address to,
        bytes calldata signature
    ) internal returns (bool) {
        MintSignatureData memory data = MintSignatureData({
            id: id,
            amount: amount,
            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,
                    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
        IDriversPayments(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 20 : IDriversPayments.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

interface IDriversPayments {
    function releaseAllETH() external;

    function releaseAllToken(address tokenAddress) external;
}

File 19 of 20 : 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 20 : 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/fount-contracts/lib/ethier/",
    "forge-std/=packages/contracts/lib/forge-std/src/",
    "fount-contracts/=packages/contracts/lib/fount-contracts/src/",
    "fount-drivers/=packages/contracts/src/",
    "openzeppelin-contracts-upgradeable/=packages/contracts/lib/closedsea/lib/openzeppelin-contracts-upgradeable/contracts/",
    "openzeppelin-contracts/=packages/contracts/lib/openzeppelin-contracts/",
    "openzeppelin/=packages/contracts/lib/openzeppelin-contracts/contracts/",
    "operator-filter-registry/=packages/contracts/lib/closedsea/lib/operator-filter-registry/src/",
    "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":"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":"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":"uint32","name":"collected","type":"uint32"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct DriversOpenEditions.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":"uint32","name":"collected","type":"uint32"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct DriversOpenEditions.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":"uint32","name":"collected","type":"uint32"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct DriversOpenEditions.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":"uint32","name":"collected","type":"uint32"},{"internalType":"uint16","name":"perAddressAllowance","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"indexed":false,"internalType":"struct DriversOpenEditions.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":"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":[{"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":[{"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","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"collectEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"collectEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"everfresh","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"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":"tokenCollectedCount","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":"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"}]

600780546001600160a01b03191673bb3444a06e9928dda9a739cdab3e0c5cf68900991790556101a0604052602261014081815290620049ff610160396009906200004b9082620004dd565b506040805180820190915260078152664452495645525360c81b6020820152600a90620000799082620004dd565b50600d8054610100600160a81b03191674c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200179055348015620000af57600080fd5b5060405162004a2138038062004a21833981016040819052620000d291620005c6565b8585858585856040518060400160405280601381526020017f447269766572734f70656e45646974696f6e7300000000000000000000000000815250604051806040016040528060018152602001603160f81b815250858585858b8b81600260006101000a8154816001600160a01b0302191690836001600160a01b03160217905550816001600160a01b031660006001600160a01b03167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a36001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a35050600480546001600160a01b039283166001600160a01b0319918216179091556005805492841692909116821790556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a2506040805180820182526001600160a01b0384168082526001600160601b0384166020909201829052600160a01b909102811760065590518291907f984cbbb47b413608120ad6b444ea0004fe19b6f88a5c0992e612b97fd3cb631e90600090a35050815160208084019190912082518383012060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81880181905281830187905260608201869052608082019490945230818401528151808203909301835260c00190528051940193909320919290916080523060c052610120525050600e80546001600160a01b0319166001600160a01b038816179055506200035390506200039b565b600d805460ff191660011790556040517f57a86f7d14ccde89e22870afe839e3011216827daa9b24e18629f0a1e9d6cc1490600090a15050505050505050505050506200063e565b620003bc733cc6cdda760b79bafa08df41ecfa224f810dceb66001620003be565b565b6001600160a01b0390911690637d3e3dbe81620003ee5782620003e75750634420e486620003ee565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16200042e578060005160e01c036200042e57600080fd5b5060006024525050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200046357607f821691505b6020821081036200048457634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004d857600081815260208120601f850160051c81016020861015620004b35750805b601f850160051c820191505b81811015620004d457828155600101620004bf565b5050505b505050565b81516001600160401b03811115620004f957620004f962000438565b62000511816200050a84546200044e565b846200048a565b602080601f831160018114620005495760008415620005305750858301515b600019600386901b1c1916600185901b178555620004d4565b600085815260208120601f198616915b828110156200057a5788860151825594840194600190910190840162000559565b5085821015620005995787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b0381168114620005c157600080fd5b919050565b60008060008060008060c08789031215620005e057600080fd5b620005eb87620005a9565b9550620005fb60208801620005a9565b94506200060b60408801620005a9565b9350606087015192506200062260808801620005a9565b91506200063260a08801620005a9565b90509295509295509295565b60805160a05160c05160e05161010051610120516143716200068e6000396000613354015260006133a30152600061337e015260006132d7015260006133010152600061332b01526143716000f3fe60806040526004361061034e5760003560e01c80638a875512116101c6578063d7e45cd7116100f7578063e8a3d48511610095578063ef6ea27a1161006f578063ef6ea27a14610ae6578063f242432a14610b20578063fb796e6c14610b40578063fd6724fc14610b5a57600080fd5b8063e8a3d48514610a76578063e985e9c514610a8b578063ecd8dbf714610ac657600080fd5b8063e086e5ec116100d1578063e086e5ec146109e2578063e17b25af146109f7578063e2e784d514610a17578063e3faad9414610a3757600080fd5b8063d7e45cd714610981578063de7ff469146109a2578063e07b1afb146109c257600080fd5b8063a6d23e1011610164578063b7c0b8e81161013e578063b7c0b8e814610903578063b8e94ab314610923578063c0fd735b14610936578063d4ddce8a1461094b57600080fd5b8063a6d23e101461088f578063af4fddfa146108af578063b390c0ab146108e357600080fd5b806395d89b41116101a057806395d89b411461080d578063a22cb46514610822578063a415729614610842578063a522ad251461086f57600080fd5b80638a8755121461079d5780638da5cb5b146107cd578063938e3d7b146107ed57600080fd5b8063429b62e5116102a05780635e1e10041161023e5780637c1a8343116102185780637c1a8343146106f65780637ecebe0014610716578063881ced951461074357806389d020dc1461077d57600080fd5b80635e1e10041461067f5780636b2a9d251461069f57806370480275146106d657600080fd5b806347a9341e1161027a57806347a9341e1461060a57806349df728c1461061d5780634e1273f41461063d5780635e1c07461461066a57600080fd5b8063429b62e51461058257806345372241146105b257806346d8efad146105ea57600080fd5b80631785f53c1161030d5780632eb2c2d6116102e75780632eb2c2d6146104e557806331cb610514610505578063392f37e9146105255780633fc8cef31461055d57600080fd5b80631785f53c1461044f57806326645a2c1461046f5780632a55205a146104a657600080fd5b8062029eb814610353578062fdd58e1461037557806301ffc9a7146103bd57806306fdde03146103ed5780630e89341c1461040f57806313af40351461042f575b600080fd5b34801561035f57600080fd5b5061037361036e366004613784565b610b94565b005b34801561038157600080fd5b506103aa610390366004613820565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b3480156103c957600080fd5b506103dd6103d8366004613860565b610ece565b60405190151581526020016103b4565b3480156103f957600080fd5b50610402610ef9565b6040516103b491906138a8565b34801561041b57600080fd5b5061040261042a3660046138db565b610f87565b34801561043b57600080fd5b5061037361044a3660046138f4565b610ff9565b34801561045b57600080fd5b5061037361046a3660046138f4565b611089565b34801561047b57600080fd5b506103dd61048a3660046138db565b6000908152600f6020526040902054600160f01b900460ff1690565b3480156104b257600080fd5b506104c66104c136600461390f565b611117565b604080516001600160a01b0390931683526020830191909152016103b4565b3480156104f157600080fd5b506103736105003660046139b8565b61115e565b34801561051157600080fd5b50610373610520366004613a73565b61119e565b34801561053157600080fd5b50600554610545906001600160a01b031681565b6040516001600160a01b0390911681526020016103b4565b34801561056957600080fd5b50600d546105459061010090046001600160a01b031681565b34801561058e57600080fd5b506103dd61059d3660046138f4565b60036020526000908152604090205460ff1681565b3480156105be57600080fd5b506103aa6105cd3660046138db565b6000908152600f6020526040902054600160e01b900461ffff1690565b3480156105f657600080fd5b50610373610605366004613a73565b61120d565b610373610618366004613aaa565b61125f565b34801561062957600080fd5b506103736106383660046138f4565b611339565b34801561064957600080fd5b5061065d610658366004613b12565b611397565b6040516103b49190613b7e565b34801561067657600080fd5b506103736114cc565b34801561068b57600080fd5b5061037361069a3660046138f4565b6114d6565b3480156106ab57600080fd5b506103dd6106ba3660046138db565b6000908152600f6020526040902054600160f81b900460ff1690565b3480156106e257600080fd5b506103736106f13660046138f4565b611563565b34801561070257600080fd5b50610373610711366004613bc2565b6115f4565b34801561072257600080fd5b506103aa6107313660046138f4565b600c6020526000908152604090205481565b34801561074f57600080fd5b506103aa61075e3660046138db565b6000908152600f6020526040902054600160801b900463ffffffff1690565b34801561078957600080fd5b50610373610798366004613be5565b611806565b3480156107a957600080fd5b506103dd6107b83660046138f4565b600b6020526000908152604090205460ff1681565b3480156107d957600080fd5b50600254610545906001600160a01b031681565b3480156107f957600080fd5b50610373610808366004613ca5565b611a25565b34801561081957600080fd5b50610402611a75565b34801561082e57600080fd5b5061037361083d366004613a73565b611a82565b34801561084e57600080fd5b50610402604051806040016040528060018152602001603160f81b81525081565b34801561087b57600080fd5b5061037361088a366004613d25565b611aa6565b34801561089b57600080fd5b50600e54610545906001600160a01b031681565b3480156108bb57600080fd5b506103aa7fe37c1ccae98d27199c22415b5eeafcff88faf573ce46a133cfc68db0c918d56581565b3480156108ef57600080fd5b506103736108fe36600461390f565b611af4565b34801561090f57600080fd5b5061037361091e366004613d4f565b611b55565b610373610931366004613d6c565b611bac565b34801561094257600080fd5b50610373611c6c565b34801561095757600080fd5b506103aa6109663660046138db565b6000908152600f60205260409020546001600160801b031690565b34801561098d57600080fd5b506005546103dd90600160a01b900460ff1681565b3480156109ae57600080fd5b506103aa6109bd366004613da1565b611d29565b3480156109ce57600080fd5b50600754610545906001600160a01b031681565b3480156109ee57600080fd5b50610373611e02565b348015610a0357600080fd5b50610373610a123660046138f4565b611e5b565b348015610a2357600080fd5b50610373610a32366004613820565b611ea8565b348015610a4357600080fd5b5061040260405180604001604052806013815260200172447269766572734f70656e45646974696f6e7360681b81525081565b348015610a8257600080fd5b50610402611ef6565b348015610a9757600080fd5b506103dd610aa6366004613d25565b600160209081526000928352604080842090915290825290205460ff1681565b348015610ad257600080fd5b50610373610ae1366004613dc4565b611f03565b348015610af257600080fd5b506103aa610b013660046138db565b6000908152600f6020526040902054600160c01b900463ffffffff1690565b348015610b2c57600080fd5b50610373610b3b366004613df7565b61217d565b348015610b4c57600080fd5b50600d546103dd9060ff1681565b348015610b6657600080fd5b506103aa610b753660046138db565b6000908152600f6020526040902054600160a01b900463ffffffff1690565b6002546001600160a01b0316331480610bbc57503360009081526003602052604090205460ff165b610be15760405162461bcd60e51b8152600401610bd890613e6f565b60405180910390fd5b8463ffffffff16600003610c08576040516361bc7fb160e11b815260040160405180910390fd5b60008463ffffffff16118015610c2357508363ffffffff1642115b15610c415760405163312728dd60e11b815260040160405180910390fd5b6000878152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b82048116938301849052600160a01b8204811694830194909452600160c01b8104909316606082015261ffff600160e01b840416608082015260ff600160f01b84048116151560a0830152600160f81b909304909216151560c083015215610cee576040516320705a1b60e11b815260040160405180910390fd5b8681600001906001600160801b031690816001600160801b03168152505085816020019063ffffffff16908163ffffffff168152505084816040019063ffffffff16908163ffffffff168152505083816080019061ffff16908161ffff1681525050828160a0019015159081151581525050818160c001901515908115158152505080600f60008a815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548161ffff021916908361ffff16021790555060a082015181600001601e6101000a81548160ff02191690831515021790555060c082015181600001601f6101000a81548160ff021916908315150217905550905050877fcbbe66244ef9bdffe7f2771b55a9ef388ac4d13d901ba070b3b61b96ed7c1aa882604051610ebc9190613e95565b60405180910390a25050505050505050565b60006001600160e01b0319821663152a902d60e11b1480610ef35750610ef3826121b9565b92915050565b60098054610f0690613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3290613f02565b8015610f7f5780601f10610f5457610100808354040283529160200191610f7f565b820191906000526020600020905b815481529060010190602001808311610f6257829003601f168201915b505050505081565b60055460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610fd1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ef39190810190613f3c565b6002546001600160a01b031633148061102157503360009081526003602052604090205460ff165b61103d5760405162461bcd60e51b8152600401610bd890613e6f565b600280546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6002546001600160a01b03163314806110b157503360009081526003602052604090205460ff165b6110cd5760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b038116600081815260036020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b038116906000906127109061114b90600160a01b90046bffffffffffffffffffffffff1685613fc9565b6111559190613fe0565b90509250929050565b876001600160a01b038116331461118357600d5460ff16156111835761118333612207565b611193898989898989898961224b565b505050505050505050565b6002546001600160a01b03163314806111c657503360009081526003602052604090205460ff165b6111e25760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b03919091166000908152600b60205260409020805460ff1916911515919091179055565b6002546001600160a01b031633148061123557503360009081526003602052604090205460ff165b6112515760405162461bcd60e51b8152600401610bd890613e6f565b61125b82826124ee565b5050565b6000858152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b8204811693830193909352600160a01b8104831693820193909352600160c01b8304909116606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b90920490911615801560c083018190529061130757506113058686868686612563565b155b1561132557604051638baa579f60e01b815260040160405180910390fd5b611331868686846126d2565b505050505050565b6002546001600160a01b031633148061136157503360009081526003602052604090205460ff165b61137d5760405162461bcd60e51b8152600401610bd890613e6f565b600e546113949082906001600160a01b03166129ea565b50565b60608382146113da5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610bd8565b8367ffffffffffffffff8111156113f3576113f3613c36565b60405190808252806020026020018201604052801561141c578160200160208202803683370190505b50905060005b848110156114c35760008087878481811061143f5761143f614002565b905060200201602081019061145491906138f4565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858481811061148857611488614002565b905060200201358152602001908152602001600020548282815181106114b0576114b0614002565b6020908102919091010152600101611422565b50949350505050565b6114d4612b36565b565b6002546001600160a01b03163314806114fe57503360009081526003602052604090205460ff165b61151a5760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b03811661154157604051631f4c499760e01b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031633148061158b57503360009081526003602052604090205460ff165b6115a75760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b6002546001600160a01b031633148061161c57503360009081526003602052604090205460ff165b6116385760405162461bcd60e51b8152600401610bd890613e6f565b6000828152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c082015291036116e5576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b0382811682526000848152600f60209081526040918290208451815492860151848701516060880151608089015160a08a015160c08b0151959099166001600160a01b031990971696909617600160801b63ffffffff948516021767ffffffffffffffff60a01b1916600160a01b9284169290920263ffffffff60c01b191691909117600160c01b92909116919091021762ffffff60e01b1916600160e01b61ffff9094169390930260ff60f01b191692909217600160f01b94151594909402939093176001600160f81b0316600160f81b91151591909102179091555183907f44e4819dc1ed2a187bca4e8978c8bbf1a42c34bb4697c9f02db89d87d007614b906117f9908490613e95565b60405180910390a2505050565b6002546001600160a01b031633148061182e57503360009081526003602052604090205460ff165b61184a5760405162461bcd60e51b8152600401610bd890613e6f565b6000848152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c082015291036118f7576040516347c0cce560e01b815260040160405180910390fd5b61ffff8085166080830190815284151560a0840190815284151560c085019081526000898152600f60209081526040918290208751815492890151848a015160608b01519851975196511515600160f81b026001600160f81b03971515600160f01b0260ff60f01b1999909b16600160e01b029890981662ffffff60e01b1963ffffffff9a8b16600160c01b0263ffffffff60c01b19938c16600160a01b029390931667ffffffffffffffff60a01b199b909416600160801b026001600160a01b03199097166001600160801b039095169490941795909517989098161796909617959095161794909417161790555185907f63ad5f4d7f7728e5b8f9a8e757982827e6df61fa74911e98cb44748a0f9b057890611a16908490613e95565b60405180910390a25050505050565b6002546001600160a01b0316331480611a4d57503360009081526003602052604090205460ff165b611a695760405162461bcd60e51b8152600401610bd890613e6f565b600861125b828261405e565b600a8054610f0690613f02565b81600d5460ff1615611a9757611a9781612207565b611aa18383612b55565b505050565b6002546001600160a01b0316331480611ace57503360009081526003602052604090205460ff165b611aea5760405162461bcd60e51b8152600401610bd890613e6f565b61125b82826129ea565b33600090815260208181526040808320858452909152902054811115611b4a5760405162461bcd60e51b815260206004820152600b60248201526a21a0a72727aa2fa12aa92760a91b6044820152606401610bd8565b61125b338383612bc1565b6002546001600160a01b0316331480611b7d57503360009081526003602052604090205460ff165b611b995760405162461bcd60e51b8152600401610bd890613e6f565b600d805460ff1916911515919091179055565b6000838152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b8204811693830193909352600160a01b8104831693820193909352600160c01b8304909116606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b90920490911615801560c0830152611c5a57604051630426ff7760e01b815260040160405180910390fd5b611c66848484846126d2565b50505050565b6002546001600160a01b0316331480611c9457503360009081526003602052604090205460ff165b611cb05760405162461bcd60e51b8152600401610bd890613e6f565b600e54611cc5906001600160a01b0316612c33565b600e60009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611d1557600080fd5b505af1158015611c66573d6000803e3d6000fd5b6000828152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b8204811683860152600160a01b8204811683850152600160c01b820416606083015261ffff600160e01b820481166080840190815260ff600160f01b84048116151560a0860152600160f81b909304909216151560c08401526001600160a01b038716865285855283862088875290945291842054915190928491168211611df55781836080015161ffff16611df0919061411e565b611df8565b60005b9695505050505050565b6002546001600160a01b0316331480611e2a57503360009081526003602052604090205460ff165b611e465760405162461bcd60e51b8152600401610bd890613e6f565b600e546114d4906001600160a01b0316612c33565b6002546001600160a01b0316331480611e8357503360009081526003602052604090205460ff165b611e9f5760405162461bcd60e51b8152600401610bd890613e6f565b61139481612cf1565b6002546001600160a01b0316331480611ed057503360009081526003602052604090205460ff165b611eec5760405162461bcd60e51b8152600401610bd890613e6f565b61125b8282612d66565b60088054610f0690613f02565b6002546001600160a01b0316331480611f2b57503360009081526003602052604090205460ff165b611f475760405162461bcd60e51b8152600401610bd890613e6f565b8163ffffffff16600003611f6e576040516361bc7fb160e11b815260040160405180910390fd5b60008163ffffffff16118015611f8957508063ffffffff1642115b15611fa75760405163312728dd60e11b815260040160405180910390fd5b6000838152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c08201529103612054576040516347c0cce560e01b815260040160405180910390fd5b63ffffffff808416602080840191825284831660408086019182526000898152600f9093529182902085518154945192516060880151608089015160a08a015160c08b01511515600160f81b026001600160f81b03911515600160f01b0260ff60f01b1961ffff909416600160e01b029390931662ffffff60e01b19948c16600160c01b0263ffffffff60c01b19968d16600160a01b029690961667ffffffffffffffff60a01b1999909c16600160801b026001600160a01b0319909b166001600160801b03909716969096179990991796909616989098179190911716179490941716919091179091555184907fe7decc699896feefecbb9be5418a0bc1c84d880973ee5ecf2f92deb0f0f7f75e9061216f908490613e95565b60405180910390a250505050565b856001600160a01b03811633146121a257600d5460ff16156121a2576121a233612207565b6121b0878787878787612de9565b50505050505050565b60006301ffc9a760e01b6001600160e01b0319831614806121ea5750636cdb3d1360e11b6001600160e01b03198316145b80610ef35750506001600160e01b0319166303a24d0760e21b1490565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa612243573d6000803e3d6000fd5b6000603a5250565b84831461228c5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610bd8565b336001600160a01b03891614806122c657506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b6123035760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610bd8565b60008060005b878110156123be5788888281811061232357612323614002565b90506020020135925086868281811061233e5761233e614002565b6001600160a01b038e166000908152602081815260408083208984528252822080549390910294909401359550859392509061237b90849061411e565b90915550506001600160a01b038a16600090815260208181526040808320868452909152812080548492906123b1908490614131565b9091555050600101612309565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b6040516124129493929190614176565b60405180910390a46001600160a01b0389163b156124b95760405163bc197c8160e01b808252906001600160a01b038b169063bc197c81906124669033908f908e908e908e908e908e908e906004016141d1565b6020604051808303816000875af1158015612485573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a99190614235565b6001600160e01b031916146124c6565b6001600160a01b03891615155b6124e25760405162461bcd60e51b8152600401610bd890614252565b50505050505050505050565b6001600160a01b0390911690637d3e3dbe8161251b57826125145750634420e48661251b565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af1612559578060005160e01c0361255957600080fd5b5060006024525050565b6040805160a08101825286815260208082018790526001600160a01b0386168284018190526000908152600c82528381205460608401528351601f8601839004830281018301909452848452928392916080830191908790879081908401838280828437600092018290525093909452505082516020808501516040808701516001600160a01b0381168652600c90935284208054969750939561268095507fe37c1ccae98d27199c22415b5eeafcff88faf573ce46a133cfc68db0c918d56594919291876126318361427c565b9091555060408051602081019690965285019390935260608401919091526001600160a01b0316608083015260a082015260c00160405160208183030381529060405280519060200120612fc9565b90506000612692828460800151613017565b6001600160a01b0381166000908152600b602052604090205490915060ff1680156126c557506001600160a01b03811615155b9998505050505050505050565b600083905042826020015163ffffffff161115612701576040516254d81f60e41b815260040160405180910390fd5b6000826040015163ffffffff161180156127245750816040015163ffffffff1642115b15612742576040516330aee1db60e21b815260040160405180910390fd5b81516001600160801b03161580159061277157508151349061276e9086906001600160801b0316613fc9565b14155b1561278f57604051636992e1ff60e01b815260040160405180910390fd5b8160a0015180156127a657506127a48361303b565b155b156127c457604051633664886760e11b815260040160405180910390fd5b608082015161ffff16156128c457816080015161ffff168411156127fb57604051632d00877b60e11b815260040160405180910390fd5b6001600160a01b038316600090815260208181526040808320888452909152812054608084015190919061ffff168210156128495781846080015161ffff16612844919061411e565b61284c565b60005b90508086111561285a578092505b8260000361287a5760405162726eb760e11b815260040160405180910390fd5b83516001600160801b03161580159061289257508286115b156128c15783516128c19033906001600160801b03166128b2868a61411e565b6128bc9190613fc9565b61304e565b50505b60608201805163ffffffff908301811682526000878152600f60209081526040918290208651815492880151938801519551608089015160a08a015160c08b01511515600160f81b026001600160f81b03911515600160f01b0260ff60f01b1961ffff909416600160e01b029390931662ffffff60e01b19948a16600160c01b0263ffffffff60c01b199b8b16600160a01b029b909b1667ffffffffffffffff60a01b1999909a16600160801b026001600160a01b03199098166001600160801b039096169590951796909617969096169690961796909617959095169490941792909217161790556129b8838683613143565b60405185907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a25050505050565b6001600160a01b038116612a115760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7c9190614295565b905080600003612a9f5760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af1158015612af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b1691906142ae565b905080611c6657604051631d42c86760e21b815260040160405180910390fd5b6114d4733cc6cdda760b79bafa08df41ecfa224f810dceb660016124ee565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612bf290849061411e565b909155505060408051838152602081018390526000916001600160a01b038616913391600080516020614345833981519152910160405180910390a4505050565b6001600160a01b038116612c5a5760405163172fe2d160e01b815260040160405180910390fd5b476000819003612c7d5760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612cca576040519150601f19603f3d011682016040523d82523d6000602084013e612ccf565b606091505b5050905080611aa157604051631d42c86760e21b815260040160405180910390fd5b600554600160a01b900460ff1615612d1c576040516313ef243160e11b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115612d89576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b909102811760065590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b336001600160a01b0387161480612e2357506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b612e605760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610bd8565b6001600160a01b03861660009081526020818152604080832087845290915281208054859290612e9190849061411e565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290612ec7908490614131565b909155505060408051858152602081018590526001600160a01b0380881692908916913391600080516020614345833981519152910160405180910390a46001600160a01b0385163b15612fa05760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e6190612f4d9033908b908a908a908a908a906004016142cb565b6020604051808303816000875af1158015612f6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f909190614235565b6001600160e01b03191614612fad565b6001600160a01b03851615155b6113315760405162461bcd60e51b8152600401610bd890614252565b6000610ef3612fd66132ca565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061302685856133f1565b9150915061303381613436565b509392505050565b60008061304783613580565b1192915050565b61305882826135f9565b61125b57600d60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130ac57600080fd5b505af11580156130c0573d6000803e3d6000fd5b5050600d5460405163a9059cbb60e01b81526001600160a01b03878116600483015260248201879052610100909204909116935063a9059cbb925060440190506020604051808303816000875af115801561311f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa191906142ae565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290613174908490614131565b909155505060075460408051848152602081018490526001600160a01b03909216916000913391600080516020614345833981519152910160405180910390a460075460408051848152602081018490526001600160a01b038681169316913391600080516020614345833981519152910160405180910390a46001600160a01b0383163b156132a15760075460405163f23a6e6160e01b8082523360048301526001600160a01b039283166024830152604482018590526064820184905260a06084830152600060a48301529185169063f23a6e619060c4016020604051808303816000875af115801561326d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132919190614235565b6001600160e01b031916146132ae565b6001600160a01b03831615155b611aa15760405162461bcd60e51b8152600401610bd890614252565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614801561332357507f000000000000000000000000000000000000000000000000000000000000000046145b1561334d57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60008082516041036134275760208301516040840151606085015160001a61341b87828585613670565b9450945050505061342f565b506000905060025b9250929050565b600081600481111561344a5761344a614312565b036134525750565b600181600481111561346657613466614312565b036134b35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610bd8565b60028160048111156134c7576134c7614312565b036135145760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610bd8565b600381600481111561352857613528614312565b036113945760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610bd8565b60048054604051627eeac760e11b81526001600160a01b0384811693820193909352600160248201526000929091169062fdd58e90604401602060405180830381865afa1580156135d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef39190614295565b60408051600080825260208201928390529182916001600160a01b03861691859161362391614328565b60006040518083038185875af1925050503d8060008114613660576040519150601f19603f3d011682016040523d82523d6000602084013e613665565b606091505b509095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156136a7575060009050600361372b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156136fb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166137245760006001925092505061372b565b9150600090505b94509492505050565b80356001600160801b038116811461374b57600080fd5b919050565b803563ffffffff8116811461374b57600080fd5b803561ffff8116811461374b57600080fd5b801515811461139457600080fd5b600080600080600080600060e0888a03121561379f57600080fd5b873596506137af60208901613734565b95506137bd60408901613750565b94506137cb60608901613750565b93506137d960808901613764565b925060a08801356137e981613776565b915060c08801356137f981613776565b8091505092959891949750929550565b80356001600160a01b038116811461374b57600080fd5b6000806040838503121561383357600080fd5b61383c83613809565b946020939093013593505050565b6001600160e01b03198116811461139457600080fd5b60006020828403121561387257600080fd5b813561387d8161384a565b9392505050565b60005b8381101561389f578181015183820152602001613887565b50506000910152565b60208152600082518060208401526138c7816040850160208701613884565b601f01601f19169190910160400192915050565b6000602082840312156138ed57600080fd5b5035919050565b60006020828403121561390657600080fd5b61387d82613809565b6000806040838503121561392257600080fd5b50508035926020909101359150565b60008083601f84011261394357600080fd5b50813567ffffffffffffffff81111561395b57600080fd5b6020830191508360208260051b850101111561342f57600080fd5b60008083601f84011261398857600080fd5b50813567ffffffffffffffff8111156139a057600080fd5b60208301915083602082850101111561342f57600080fd5b60008060008060008060008060a0898b0312156139d457600080fd5b6139dd89613809565b97506139eb60208a01613809565b9650604089013567ffffffffffffffff80821115613a0857600080fd5b613a148c838d01613931565b909850965060608b0135915080821115613a2d57600080fd5b613a398c838d01613931565b909650945060808b0135915080821115613a5257600080fd5b50613a5f8b828c01613976565b999c989b5096995094979396929594505050565b60008060408385031215613a8657600080fd5b613a8f83613809565b91506020830135613a9f81613776565b809150509250929050565b600080600080600060808688031215613ac257600080fd5b8535945060208601359350613ad960408701613809565b9250606086013567ffffffffffffffff811115613af557600080fd5b613b0188828901613976565b969995985093965092949392505050565b60008060008060408587031215613b2857600080fd5b843567ffffffffffffffff80821115613b4057600080fd5b613b4c88838901613931565b90965094506020870135915080821115613b6557600080fd5b50613b7287828801613931565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015613bb657835183529284019291840191600101613b9a565b50909695505050505050565b60008060408385031215613bd557600080fd5b8235915061115560208401613734565b60008060008060808587031215613bfb57600080fd5b84359350613c0b60208601613764565b92506040850135613c1b81613776565b91506060850135613c2b81613776565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c7557613c75613c36565b604052919050565b600067ffffffffffffffff821115613c9757613c97613c36565b50601f01601f191660200190565b600060208284031215613cb757600080fd5b813567ffffffffffffffff811115613cce57600080fd5b8201601f81018413613cdf57600080fd5b8035613cf2613ced82613c7d565b613c4c565b818152856020838501011115613d0757600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613d3857600080fd5b613d4183613809565b915061115560208401613809565b600060208284031215613d6157600080fd5b813561387d81613776565b600080600060608486031215613d8157600080fd5b8335925060208401359150613d9860408501613809565b90509250925092565b60008060408385031215613db457600080fd5b8235915061115560208401613809565b600080600060608486031215613dd957600080fd5b83359250613de960208501613750565b9150613d9860408501613750565b60008060008060008060a08789031215613e1057600080fd5b613e1987613809565b9550613e2760208801613809565b94506040870135935060608701359250608087013567ffffffffffffffff811115613e5157600080fd5b613e5d89828a01613976565b979a9699509497509295939492505050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060e0820190506001600160801b038351168252602083015163ffffffff8082166020850152806040860151166040850152806060860151166060850152505061ffff608084015116608083015260a0830151151560a083015260c0830151151560c083015292915050565b600181811c90821680613f1657607f821691505b602082108103613f3657634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215613f4e57600080fd5b815167ffffffffffffffff811115613f6557600080fd5b8201601f81018413613f7657600080fd5b8051613f84613ced82613c7d565b818152856020838501011115613f9957600080fd5b613faa826020830160208601613884565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ef357610ef3613fb3565b600082613ffd57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b601f821115611aa157600081815260208120601f850160051c8101602086101561403f5750805b601f850160051c820191505b818110156113315782815560010161404b565b815167ffffffffffffffff81111561407857614078613c36565b61408c816140868454613f02565b84614018565b602080601f8311600181146140c157600084156140a95750858301515b600019600386901b1c1916600185901b178555611331565b600085815260208120601f198616915b828110156140f0578886015182559484019460019091019084016140d1565b508582101561410e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610ef357610ef3613fb3565b80820180821115610ef357610ef3613fb3565b81835260006001600160fb1b0383111561415d57600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061418a604083018688614144565b828103602084015261419d818587614144565b979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a0604082018190526000906141fe908301888a614144565b8281036060840152614211818789614144565b905082810360808401526142268185876141a8565b9b9a5050505050505050505050565b60006020828403121561424757600080fd5b815161387d8161384a565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60006001820161428e5761428e613fb3565b5060010190565b6000602082840312156142a757600080fd5b5051919050565b6000602082840312156142c057600080fd5b815161387d81613776565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905260009061430690830184866141a8565b98975050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000825161433a818460208701613884565b919091019291505056fec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62a164736f6c6343000811000a44726976657273204f70656e2045646974696f6e73206279204576657266726573680000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf00000000000000000000000000000000000000000000000000000000000002ee0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e300000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

Deployed Bytecode

0x60806040526004361061034e5760003560e01c80638a875512116101c6578063d7e45cd7116100f7578063e8a3d48511610095578063ef6ea27a1161006f578063ef6ea27a14610ae6578063f242432a14610b20578063fb796e6c14610b40578063fd6724fc14610b5a57600080fd5b8063e8a3d48514610a76578063e985e9c514610a8b578063ecd8dbf714610ac657600080fd5b8063e086e5ec116100d1578063e086e5ec146109e2578063e17b25af146109f7578063e2e784d514610a17578063e3faad9414610a3757600080fd5b8063d7e45cd714610981578063de7ff469146109a2578063e07b1afb146109c257600080fd5b8063a6d23e1011610164578063b7c0b8e81161013e578063b7c0b8e814610903578063b8e94ab314610923578063c0fd735b14610936578063d4ddce8a1461094b57600080fd5b8063a6d23e101461088f578063af4fddfa146108af578063b390c0ab146108e357600080fd5b806395d89b41116101a057806395d89b411461080d578063a22cb46514610822578063a415729614610842578063a522ad251461086f57600080fd5b80638a8755121461079d5780638da5cb5b146107cd578063938e3d7b146107ed57600080fd5b8063429b62e5116102a05780635e1e10041161023e5780637c1a8343116102185780637c1a8343146106f65780637ecebe0014610716578063881ced951461074357806389d020dc1461077d57600080fd5b80635e1e10041461067f5780636b2a9d251461069f57806370480275146106d657600080fd5b806347a9341e1161027a57806347a9341e1461060a57806349df728c1461061d5780634e1273f41461063d5780635e1c07461461066a57600080fd5b8063429b62e51461058257806345372241146105b257806346d8efad146105ea57600080fd5b80631785f53c1161030d5780632eb2c2d6116102e75780632eb2c2d6146104e557806331cb610514610505578063392f37e9146105255780633fc8cef31461055d57600080fd5b80631785f53c1461044f57806326645a2c1461046f5780632a55205a146104a657600080fd5b8062029eb814610353578062fdd58e1461037557806301ffc9a7146103bd57806306fdde03146103ed5780630e89341c1461040f57806313af40351461042f575b600080fd5b34801561035f57600080fd5b5061037361036e366004613784565b610b94565b005b34801561038157600080fd5b506103aa610390366004613820565b600060208181529281526040808220909352908152205481565b6040519081526020015b60405180910390f35b3480156103c957600080fd5b506103dd6103d8366004613860565b610ece565b60405190151581526020016103b4565b3480156103f957600080fd5b50610402610ef9565b6040516103b491906138a8565b34801561041b57600080fd5b5061040261042a3660046138db565b610f87565b34801561043b57600080fd5b5061037361044a3660046138f4565b610ff9565b34801561045b57600080fd5b5061037361046a3660046138f4565b611089565b34801561047b57600080fd5b506103dd61048a3660046138db565b6000908152600f6020526040902054600160f01b900460ff1690565b3480156104b257600080fd5b506104c66104c136600461390f565b611117565b604080516001600160a01b0390931683526020830191909152016103b4565b3480156104f157600080fd5b506103736105003660046139b8565b61115e565b34801561051157600080fd5b50610373610520366004613a73565b61119e565b34801561053157600080fd5b50600554610545906001600160a01b031681565b6040516001600160a01b0390911681526020016103b4565b34801561056957600080fd5b50600d546105459061010090046001600160a01b031681565b34801561058e57600080fd5b506103dd61059d3660046138f4565b60036020526000908152604090205460ff1681565b3480156105be57600080fd5b506103aa6105cd3660046138db565b6000908152600f6020526040902054600160e01b900461ffff1690565b3480156105f657600080fd5b50610373610605366004613a73565b61120d565b610373610618366004613aaa565b61125f565b34801561062957600080fd5b506103736106383660046138f4565b611339565b34801561064957600080fd5b5061065d610658366004613b12565b611397565b6040516103b49190613b7e565b34801561067657600080fd5b506103736114cc565b34801561068b57600080fd5b5061037361069a3660046138f4565b6114d6565b3480156106ab57600080fd5b506103dd6106ba3660046138db565b6000908152600f6020526040902054600160f81b900460ff1690565b3480156106e257600080fd5b506103736106f13660046138f4565b611563565b34801561070257600080fd5b50610373610711366004613bc2565b6115f4565b34801561072257600080fd5b506103aa6107313660046138f4565b600c6020526000908152604090205481565b34801561074f57600080fd5b506103aa61075e3660046138db565b6000908152600f6020526040902054600160801b900463ffffffff1690565b34801561078957600080fd5b50610373610798366004613be5565b611806565b3480156107a957600080fd5b506103dd6107b83660046138f4565b600b6020526000908152604090205460ff1681565b3480156107d957600080fd5b50600254610545906001600160a01b031681565b3480156107f957600080fd5b50610373610808366004613ca5565b611a25565b34801561081957600080fd5b50610402611a75565b34801561082e57600080fd5b5061037361083d366004613a73565b611a82565b34801561084e57600080fd5b50610402604051806040016040528060018152602001603160f81b81525081565b34801561087b57600080fd5b5061037361088a366004613d25565b611aa6565b34801561089b57600080fd5b50600e54610545906001600160a01b031681565b3480156108bb57600080fd5b506103aa7fe37c1ccae98d27199c22415b5eeafcff88faf573ce46a133cfc68db0c918d56581565b3480156108ef57600080fd5b506103736108fe36600461390f565b611af4565b34801561090f57600080fd5b5061037361091e366004613d4f565b611b55565b610373610931366004613d6c565b611bac565b34801561094257600080fd5b50610373611c6c565b34801561095757600080fd5b506103aa6109663660046138db565b6000908152600f60205260409020546001600160801b031690565b34801561098d57600080fd5b506005546103dd90600160a01b900460ff1681565b3480156109ae57600080fd5b506103aa6109bd366004613da1565b611d29565b3480156109ce57600080fd5b50600754610545906001600160a01b031681565b3480156109ee57600080fd5b50610373611e02565b348015610a0357600080fd5b50610373610a123660046138f4565b611e5b565b348015610a2357600080fd5b50610373610a32366004613820565b611ea8565b348015610a4357600080fd5b5061040260405180604001604052806013815260200172447269766572734f70656e45646974696f6e7360681b81525081565b348015610a8257600080fd5b50610402611ef6565b348015610a9757600080fd5b506103dd610aa6366004613d25565b600160209081526000928352604080842090915290825290205460ff1681565b348015610ad257600080fd5b50610373610ae1366004613dc4565b611f03565b348015610af257600080fd5b506103aa610b013660046138db565b6000908152600f6020526040902054600160c01b900463ffffffff1690565b348015610b2c57600080fd5b50610373610b3b366004613df7565b61217d565b348015610b4c57600080fd5b50600d546103dd9060ff1681565b348015610b6657600080fd5b506103aa610b753660046138db565b6000908152600f6020526040902054600160a01b900463ffffffff1690565b6002546001600160a01b0316331480610bbc57503360009081526003602052604090205460ff165b610be15760405162461bcd60e51b8152600401610bd890613e6f565b60405180910390fd5b8463ffffffff16600003610c08576040516361bc7fb160e11b815260040160405180910390fd5b60008463ffffffff16118015610c2357508363ffffffff1642115b15610c415760405163312728dd60e11b815260040160405180910390fd5b6000878152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b82048116938301849052600160a01b8204811694830194909452600160c01b8104909316606082015261ffff600160e01b840416608082015260ff600160f01b84048116151560a0830152600160f81b909304909216151560c083015215610cee576040516320705a1b60e11b815260040160405180910390fd5b8681600001906001600160801b031690816001600160801b03168152505085816020019063ffffffff16908163ffffffff168152505084816040019063ffffffff16908163ffffffff168152505083816080019061ffff16908161ffff1681525050828160a0019015159081151581525050818160c001901515908115158152505080600f60008a815260200190815260200160002060008201518160000160006101000a8154816001600160801b0302191690836001600160801b0316021790555060208201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160186101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001601c6101000a81548161ffff021916908361ffff16021790555060a082015181600001601e6101000a81548160ff02191690831515021790555060c082015181600001601f6101000a81548160ff021916908315150217905550905050877fcbbe66244ef9bdffe7f2771b55a9ef388ac4d13d901ba070b3b61b96ed7c1aa882604051610ebc9190613e95565b60405180910390a25050505050505050565b60006001600160e01b0319821663152a902d60e11b1480610ef35750610ef3826121b9565b92915050565b60098054610f0690613f02565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3290613f02565b8015610f7f5780601f10610f5457610100808354040283529160200191610f7f565b820191906000526020600020905b815481529060010190602001808311610f6257829003601f168201915b505050505081565b60055460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610fd1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ef39190810190613f3c565b6002546001600160a01b031633148061102157503360009081526003602052604090205460ff165b61103d5760405162461bcd60e51b8152600401610bd890613e6f565b600280546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b6002546001600160a01b03163314806110b157503360009081526003602052604090205460ff165b6110cd5760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b038116600081815260036020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b038116906000906127109061114b90600160a01b90046bffffffffffffffffffffffff1685613fc9565b6111559190613fe0565b90509250929050565b876001600160a01b038116331461118357600d5460ff16156111835761118333612207565b611193898989898989898961224b565b505050505050505050565b6002546001600160a01b03163314806111c657503360009081526003602052604090205460ff165b6111e25760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b03919091166000908152600b60205260409020805460ff1916911515919091179055565b6002546001600160a01b031633148061123557503360009081526003602052604090205460ff165b6112515760405162461bcd60e51b8152600401610bd890613e6f565b61125b82826124ee565b5050565b6000858152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b8204811693830193909352600160a01b8104831693820193909352600160c01b8304909116606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b90920490911615801560c083018190529061130757506113058686868686612563565b155b1561132557604051638baa579f60e01b815260040160405180910390fd5b611331868686846126d2565b505050505050565b6002546001600160a01b031633148061136157503360009081526003602052604090205460ff165b61137d5760405162461bcd60e51b8152600401610bd890613e6f565b600e546113949082906001600160a01b03166129ea565b50565b60608382146113da5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610bd8565b8367ffffffffffffffff8111156113f3576113f3613c36565b60405190808252806020026020018201604052801561141c578160200160208202803683370190505b50905060005b848110156114c35760008087878481811061143f5761143f614002565b905060200201602081019061145491906138f4565b6001600160a01b03166001600160a01b03168152602001908152602001600020600085858481811061148857611488614002565b905060200201358152602001908152602001600020548282815181106114b0576114b0614002565b6020908102919091010152600101611422565b50949350505050565b6114d4612b36565b565b6002546001600160a01b03163314806114fe57503360009081526003602052604090205460ff165b61151a5760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b03811661154157604051631f4c499760e01b815260040160405180910390fd5b600e80546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031633148061158b57503360009081526003602052604090205460ff165b6115a75760405162461bcd60e51b8152600401610bd890613e6f565b6001600160a01b038116600081815260036020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b6002546001600160a01b031633148061161c57503360009081526003602052604090205460ff165b6116385760405162461bcd60e51b8152600401610bd890613e6f565b6000828152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c082015291036116e5576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b0382811682526000848152600f60209081526040918290208451815492860151848701516060880151608089015160a08a015160c08b0151959099166001600160a01b031990971696909617600160801b63ffffffff948516021767ffffffffffffffff60a01b1916600160a01b9284169290920263ffffffff60c01b191691909117600160c01b92909116919091021762ffffff60e01b1916600160e01b61ffff9094169390930260ff60f01b191692909217600160f01b94151594909402939093176001600160f81b0316600160f81b91151591909102179091555183907f44e4819dc1ed2a187bca4e8978c8bbf1a42c34bb4697c9f02db89d87d007614b906117f9908490613e95565b60405180910390a2505050565b6002546001600160a01b031633148061182e57503360009081526003602052604090205460ff165b61184a5760405162461bcd60e51b8152600401610bd890613e6f565b6000848152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c082015291036118f7576040516347c0cce560e01b815260040160405180910390fd5b61ffff8085166080830190815284151560a0840190815284151560c085019081526000898152600f60209081526040918290208751815492890151848a015160608b01519851975196511515600160f81b026001600160f81b03971515600160f01b0260ff60f01b1999909b16600160e01b029890981662ffffff60e01b1963ffffffff9a8b16600160c01b0263ffffffff60c01b19938c16600160a01b029390931667ffffffffffffffff60a01b199b909416600160801b026001600160a01b03199097166001600160801b039095169490941795909517989098161796909617959095161794909417161790555185907f63ad5f4d7f7728e5b8f9a8e757982827e6df61fa74911e98cb44748a0f9b057890611a16908490613e95565b60405180910390a25050505050565b6002546001600160a01b0316331480611a4d57503360009081526003602052604090205460ff165b611a695760405162461bcd60e51b8152600401610bd890613e6f565b600861125b828261405e565b600a8054610f0690613f02565b81600d5460ff1615611a9757611a9781612207565b611aa18383612b55565b505050565b6002546001600160a01b0316331480611ace57503360009081526003602052604090205460ff165b611aea5760405162461bcd60e51b8152600401610bd890613e6f565b61125b82826129ea565b33600090815260208181526040808320858452909152902054811115611b4a5760405162461bcd60e51b815260206004820152600b60248201526a21a0a72727aa2fa12aa92760a91b6044820152606401610bd8565b61125b338383612bc1565b6002546001600160a01b0316331480611b7d57503360009081526003602052604090205460ff165b611b995760405162461bcd60e51b8152600401610bd890613e6f565b600d805460ff1916911515919091179055565b6000838152600f6020908152604091829020825160e08101845290546001600160801b038116825263ffffffff600160801b8204811693830193909352600160a01b8104831693820193909352600160c01b8304909116606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b90920490911615801560c0830152611c5a57604051630426ff7760e01b815260040160405180910390fd5b611c66848484846126d2565b50505050565b6002546001600160a01b0316331480611c9457503360009081526003602052604090205460ff165b611cb05760405162461bcd60e51b8152600401610bd890613e6f565b600e54611cc5906001600160a01b0316612c33565b600e60009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611d1557600080fd5b505af1158015611c66573d6000803e3d6000fd5b6000828152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b8204811683860152600160a01b8204811683850152600160c01b820416606083015261ffff600160e01b820481166080840190815260ff600160f01b84048116151560a0860152600160f81b909304909216151560c08401526001600160a01b038716865285855283862088875290945291842054915190928491168211611df55781836080015161ffff16611df0919061411e565b611df8565b60005b9695505050505050565b6002546001600160a01b0316331480611e2a57503360009081526003602052604090205460ff165b611e465760405162461bcd60e51b8152600401610bd890613e6f565b600e546114d4906001600160a01b0316612c33565b6002546001600160a01b0316331480611e8357503360009081526003602052604090205460ff165b611e9f5760405162461bcd60e51b8152600401610bd890613e6f565b61139481612cf1565b6002546001600160a01b0316331480611ed057503360009081526003602052604090205460ff165b611eec5760405162461bcd60e51b8152600401610bd890613e6f565b61125b8282612d66565b60088054610f0690613f02565b6002546001600160a01b0316331480611f2b57503360009081526003602052604090205460ff165b611f475760405162461bcd60e51b8152600401610bd890613e6f565b8163ffffffff16600003611f6e576040516361bc7fb160e11b815260040160405180910390fd5b60008163ffffffff16118015611f8957508063ffffffff1642115b15611fa75760405163312728dd60e11b815260040160405180910390fd5b6000838152600f60209081526040808320815160e08101835290546001600160801b038116825263ffffffff600160801b82048116948301859052600160a01b8204811693830193909352600160c01b8104909216606082015261ffff600160e01b830416608082015260ff600160f01b83048116151560a0830152600160f81b909204909116151560c08201529103612054576040516347c0cce560e01b815260040160405180910390fd5b63ffffffff808416602080840191825284831660408086019182526000898152600f9093529182902085518154945192516060880151608089015160a08a015160c08b01511515600160f81b026001600160f81b03911515600160f01b0260ff60f01b1961ffff909416600160e01b029390931662ffffff60e01b19948c16600160c01b0263ffffffff60c01b19968d16600160a01b029690961667ffffffffffffffff60a01b1999909c16600160801b026001600160a01b0319909b166001600160801b03909716969096179990991796909616989098179190911716179490941716919091179091555184907fe7decc699896feefecbb9be5418a0bc1c84d880973ee5ecf2f92deb0f0f7f75e9061216f908490613e95565b60405180910390a250505050565b856001600160a01b03811633146121a257600d5460ff16156121a2576121a233612207565b6121b0878787878787612de9565b50505050505050565b60006301ffc9a760e01b6001600160e01b0319831614806121ea5750636cdb3d1360e11b6001600160e01b03198316145b80610ef35750506001600160e01b0319166303a24d0760e21b1490565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa612243573d6000803e3d6000fd5b6000603a5250565b84831461228c5760405162461bcd60e51b815260206004820152600f60248201526e0988a9c8ea890be9a92a69a82a8869608b1b6044820152606401610bd8565b336001600160a01b03891614806122c657506001600160a01b038816600090815260016020908152604080832033845290915290205460ff165b6123035760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610bd8565b60008060005b878110156123be5788888281811061232357612323614002565b90506020020135925086868281811061233e5761233e614002565b6001600160a01b038e166000908152602081815260408083208984528252822080549390910294909401359550859392509061237b90849061411e565b90915550506001600160a01b038a16600090815260208181526040808320868452909152812080548492906123b1908490614131565b9091555050600101612309565b50886001600160a01b03168a6001600160a01b0316336001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8b8b8b8b6040516124129493929190614176565b60405180910390a46001600160a01b0389163b156124b95760405163bc197c8160e01b808252906001600160a01b038b169063bc197c81906124669033908f908e908e908e908e908e908e906004016141d1565b6020604051808303816000875af1158015612485573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a99190614235565b6001600160e01b031916146124c6565b6001600160a01b03891615155b6124e25760405162461bcd60e51b8152600401610bd890614252565b50505050505050505050565b6001600160a01b0390911690637d3e3dbe8161251b57826125145750634420e48661251b565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af1612559578060005160e01c0361255957600080fd5b5060006024525050565b6040805160a08101825286815260208082018790526001600160a01b0386168284018190526000908152600c82528381205460608401528351601f8601839004830281018301909452848452928392916080830191908790879081908401838280828437600092018290525093909452505082516020808501516040808701516001600160a01b0381168652600c90935284208054969750939561268095507fe37c1ccae98d27199c22415b5eeafcff88faf573ce46a133cfc68db0c918d56594919291876126318361427c565b9091555060408051602081019690965285019390935260608401919091526001600160a01b0316608083015260a082015260c00160405160208183030381529060405280519060200120612fc9565b90506000612692828460800151613017565b6001600160a01b0381166000908152600b602052604090205490915060ff1680156126c557506001600160a01b03811615155b9998505050505050505050565b600083905042826020015163ffffffff161115612701576040516254d81f60e41b815260040160405180910390fd5b6000826040015163ffffffff161180156127245750816040015163ffffffff1642115b15612742576040516330aee1db60e21b815260040160405180910390fd5b81516001600160801b03161580159061277157508151349061276e9086906001600160801b0316613fc9565b14155b1561278f57604051636992e1ff60e01b815260040160405180910390fd5b8160a0015180156127a657506127a48361303b565b155b156127c457604051633664886760e11b815260040160405180910390fd5b608082015161ffff16156128c457816080015161ffff168411156127fb57604051632d00877b60e11b815260040160405180910390fd5b6001600160a01b038316600090815260208181526040808320888452909152812054608084015190919061ffff168210156128495781846080015161ffff16612844919061411e565b61284c565b60005b90508086111561285a578092505b8260000361287a5760405162726eb760e11b815260040160405180910390fd5b83516001600160801b03161580159061289257508286115b156128c15783516128c19033906001600160801b03166128b2868a61411e565b6128bc9190613fc9565b61304e565b50505b60608201805163ffffffff908301811682526000878152600f60209081526040918290208651815492880151938801519551608089015160a08a015160c08b01511515600160f81b026001600160f81b03911515600160f01b0260ff60f01b1961ffff909416600160e01b029390931662ffffff60e01b19948a16600160c01b0263ffffffff60c01b199b8b16600160a01b029b909b1667ffffffffffffffff60a01b1999909a16600160801b026001600160a01b03199098166001600160801b039096169590951796909617969096169690961796909617959095169490941792909217161790556129b8838683613143565b60405185907f97740a2d1e4e75b5dea30b31b96c67193bed444129f7f62010953c83c9b03dcd90600090a25050505050565b6001600160a01b038116612a115760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612a58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7c9190614295565b905080600003612a9f5760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af1158015612af2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b1691906142ae565b905080611c6657604051631d42c86760e21b815260040160405180910390fd5b6114d4733cc6cdda760b79bafa08df41ecfa224f810dceb660016124ee565b3360008181526001602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290612bf290849061411e565b909155505060408051838152602081018390526000916001600160a01b038616913391600080516020614345833981519152910160405180910390a4505050565b6001600160a01b038116612c5a5760405163172fe2d160e01b815260040160405180910390fd5b476000819003612c7d5760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612cca576040519150601f19603f3d011682016040523d82523d6000602084013e612ccf565b606091505b5050905080611aa157604051631d42c86760e21b815260040160405180910390fd5b600554600160a01b900460ff1615612d1c576040516313ef243160e11b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115612d89576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b909102811760065590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b336001600160a01b0387161480612e2357506001600160a01b038616600090815260016020908152604080832033845290915290205460ff165b612e605760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610bd8565b6001600160a01b03861660009081526020818152604080832087845290915281208054859290612e9190849061411e565b90915550506001600160a01b03851660009081526020818152604080832087845290915281208054859290612ec7908490614131565b909155505060408051858152602081018590526001600160a01b0380881692908916913391600080516020614345833981519152910160405180910390a46001600160a01b0385163b15612fa05760405163f23a6e6160e01b808252906001600160a01b0387169063f23a6e6190612f4d9033908b908a908a908a908a906004016142cb565b6020604051808303816000875af1158015612f6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f909190614235565b6001600160e01b03191614612fad565b6001600160a01b03851615155b6113315760405162461bcd60e51b8152600401610bd890614252565b6000610ef3612fd66132ca565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b600080600061302685856133f1565b9150915061303381613436565b509392505050565b60008061304783613580565b1192915050565b61305882826135f9565b61125b57600d60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156130ac57600080fd5b505af11580156130c0573d6000803e3d6000fd5b5050600d5460405163a9059cbb60e01b81526001600160a01b03878116600483015260248201879052610100909204909116935063a9059cbb925060440190506020604051808303816000875af115801561311f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa191906142ae565b6001600160a01b03831660009081526020818152604080832085845290915281208054839290613174908490614131565b909155505060075460408051848152602081018490526001600160a01b03909216916000913391600080516020614345833981519152910160405180910390a460075460408051848152602081018490526001600160a01b038681169316913391600080516020614345833981519152910160405180910390a46001600160a01b0383163b156132a15760075460405163f23a6e6160e01b8082523360048301526001600160a01b039283166024830152604482018590526064820184905260a06084830152600060a48301529185169063f23a6e619060c4016020604051808303816000875af115801561326d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132919190614235565b6001600160e01b031916146132ae565b6001600160a01b03831615155b611aa15760405162461bcd60e51b8152600401610bd890614252565b6000306001600160a01b037f0000000000000000000000002f4c0c83ef2c39d269c3f4fa12c5bd04bf16bddd1614801561332357507f000000000000000000000000000000000000000000000000000000000000000146145b1561334d57507f92bfdd905040fb90672083edca76000e631b640026e4cc1cc5bc15a8bc9c69a990565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f7edc74ecdd8a6af46cbe45aa86005f8ad014ffa05c89cc8963f530c9d96ba5f5828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b60008082516041036134275760208301516040840151606085015160001a61341b87828585613670565b9450945050505061342f565b506000905060025b9250929050565b600081600481111561344a5761344a614312565b036134525750565b600181600481111561346657613466614312565b036134b35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610bd8565b60028160048111156134c7576134c7614312565b036135145760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610bd8565b600381600481111561352857613528614312565b036113945760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610bd8565b60048054604051627eeac760e11b81526001600160a01b0384811693820193909352600160248201526000929091169062fdd58e90604401602060405180830381865afa1580156135d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef39190614295565b60408051600080825260208201928390529182916001600160a01b03861691859161362391614328565b60006040518083038185875af1925050503d8060008114613660576040519150601f19603f3d011682016040523d82523d6000602084013e613665565b606091505b509095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156136a7575060009050600361372b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156136fb573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166137245760006001925092505061372b565b9150600090505b94509492505050565b80356001600160801b038116811461374b57600080fd5b919050565b803563ffffffff8116811461374b57600080fd5b803561ffff8116811461374b57600080fd5b801515811461139457600080fd5b600080600080600080600060e0888a03121561379f57600080fd5b873596506137af60208901613734565b95506137bd60408901613750565b94506137cb60608901613750565b93506137d960808901613764565b925060a08801356137e981613776565b915060c08801356137f981613776565b8091505092959891949750929550565b80356001600160a01b038116811461374b57600080fd5b6000806040838503121561383357600080fd5b61383c83613809565b946020939093013593505050565b6001600160e01b03198116811461139457600080fd5b60006020828403121561387257600080fd5b813561387d8161384a565b9392505050565b60005b8381101561389f578181015183820152602001613887565b50506000910152565b60208152600082518060208401526138c7816040850160208701613884565b601f01601f19169190910160400192915050565b6000602082840312156138ed57600080fd5b5035919050565b60006020828403121561390657600080fd5b61387d82613809565b6000806040838503121561392257600080fd5b50508035926020909101359150565b60008083601f84011261394357600080fd5b50813567ffffffffffffffff81111561395b57600080fd5b6020830191508360208260051b850101111561342f57600080fd5b60008083601f84011261398857600080fd5b50813567ffffffffffffffff8111156139a057600080fd5b60208301915083602082850101111561342f57600080fd5b60008060008060008060008060a0898b0312156139d457600080fd5b6139dd89613809565b97506139eb60208a01613809565b9650604089013567ffffffffffffffff80821115613a0857600080fd5b613a148c838d01613931565b909850965060608b0135915080821115613a2d57600080fd5b613a398c838d01613931565b909650945060808b0135915080821115613a5257600080fd5b50613a5f8b828c01613976565b999c989b5096995094979396929594505050565b60008060408385031215613a8657600080fd5b613a8f83613809565b91506020830135613a9f81613776565b809150509250929050565b600080600080600060808688031215613ac257600080fd5b8535945060208601359350613ad960408701613809565b9250606086013567ffffffffffffffff811115613af557600080fd5b613b0188828901613976565b969995985093965092949392505050565b60008060008060408587031215613b2857600080fd5b843567ffffffffffffffff80821115613b4057600080fd5b613b4c88838901613931565b90965094506020870135915080821115613b6557600080fd5b50613b7287828801613931565b95989497509550505050565b6020808252825182820181905260009190848201906040850190845b81811015613bb657835183529284019291840191600101613b9a565b50909695505050505050565b60008060408385031215613bd557600080fd5b8235915061115560208401613734565b60008060008060808587031215613bfb57600080fd5b84359350613c0b60208601613764565b92506040850135613c1b81613776565b91506060850135613c2b81613776565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c7557613c75613c36565b604052919050565b600067ffffffffffffffff821115613c9757613c97613c36565b50601f01601f191660200190565b600060208284031215613cb757600080fd5b813567ffffffffffffffff811115613cce57600080fd5b8201601f81018413613cdf57600080fd5b8035613cf2613ced82613c7d565b613c4c565b818152856020838501011115613d0757600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613d3857600080fd5b613d4183613809565b915061115560208401613809565b600060208284031215613d6157600080fd5b813561387d81613776565b600080600060608486031215613d8157600080fd5b8335925060208401359150613d9860408501613809565b90509250925092565b60008060408385031215613db457600080fd5b8235915061115560208401613809565b600080600060608486031215613dd957600080fd5b83359250613de960208501613750565b9150613d9860408501613750565b60008060008060008060a08789031215613e1057600080fd5b613e1987613809565b9550613e2760208801613809565b94506040870135935060608701359250608087013567ffffffffffffffff811115613e5157600080fd5b613e5d89828a01613976565b979a9699509497509295939492505050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060e0820190506001600160801b038351168252602083015163ffffffff8082166020850152806040860151166040850152806060860151166060850152505061ffff608084015116608083015260a0830151151560a083015260c0830151151560c083015292915050565b600181811c90821680613f1657607f821691505b602082108103613f3657634e487b7160e01b600052602260045260246000fd5b50919050565b600060208284031215613f4e57600080fd5b815167ffffffffffffffff811115613f6557600080fd5b8201601f81018413613f7657600080fd5b8051613f84613ced82613c7d565b818152856020838501011115613f9957600080fd5b613faa826020830160208601613884565b95945050505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610ef357610ef3613fb3565b600082613ffd57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b601f821115611aa157600081815260208120601f850160051c8101602086101561403f5750805b601f850160051c820191505b818110156113315782815560010161404b565b815167ffffffffffffffff81111561407857614078613c36565b61408c816140868454613f02565b84614018565b602080601f8311600181146140c157600084156140a95750858301515b600019600386901b1c1916600185901b178555611331565b600085815260208120601f198616915b828110156140f0578886015182559484019460019091019084016140d1565b508582101561410e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b81810381811115610ef357610ef3613fb3565b80820180821115610ef357610ef3613fb3565b81835260006001600160fb1b0383111561415d57600080fd5b8260051b80836020870137939093016020019392505050565b60408152600061418a604083018688614144565b828103602084015261419d818587614144565b979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b0389811682528816602082015260a0604082018190526000906141fe908301888a614144565b8281036060840152614211818789614144565b905082810360808401526142268185876141a8565b9b9a5050505050505050505050565b60006020828403121561424757600080fd5b815161387d8161384a565b60208082526010908201526f155394d0519157d49150d2541251539560821b604082015260600190565b60006001820161428e5761428e613fb3565b5060010190565b6000602082840312156142a757600080fd5b5051919050565b6000602082840312156142c057600080fd5b815161387d81613776565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905260009061430690830184866141a8565b98975050505050505050565b634e487b7160e01b600052602160045260246000fd5b6000825161433a818460208701613884565b919091019291505056fec3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62a164736f6c6343000811000a

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

0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf00000000000000000000000000000000000000000000000000000000000002ee0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e300000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

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

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d
Arg [1] : 0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c
Arg [2] : 00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf
Arg [3] : 00000000000000000000000000000000000000000000000000000000000002ee
Arg [4] : 0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e3
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.