ETH Price: $3,432.02 (-1.38%)
Gas: 7 Gwei

Contract

0x2F4C0c83ef2C39d269c3F4Fa12C5Bd04BF16bDDd
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...177499002023-07-22 16:36:11361 days ago1690043771IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0012498620.46334586
Set Approval For...170631812023-04-17 1:11:23458 days ago1681693883IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0015221724.92175897
Set Approval For...170234252023-04-11 7:37:59463 days ago1681198679IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0012526620.50934212
Set Approval For...169854892023-04-05 22:24:47469 days ago1680733487IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0019760732.35336509
Set Approval For...169661182023-04-03 4:23:23471 days ago1680495803IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0010463117.1308371
Set Approval For...169638332023-04-02 20:41:47472 days ago1680468107IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0010629617.40333034
Safe Transfer Fr...169547752023-04-01 14:05:47473 days ago1680357947IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0012583422.39444232
Set Approval For...169420902023-03-30 19:19:11475 days ago1680203951IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0019215231.46011528
Set Approval For...169420772023-03-30 19:16:35475 days ago1680203795IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0017767929.09051802
Set Approval For...169384032023-03-30 6:52:59475 days ago1680159179IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0016434126.90675218
Set Approval For...166241592023-02-14 2:57:47519 days ago1676343467IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0009939716.27378459
Set Approval For...166078232023-02-11 20:11:23522 days ago1676146283IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0016206326.53392078
Collect Edition165996722023-02-10 16:52:47523 days ago1676047967IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0028465431.16738325
Set Token Sale T...165919392023-02-09 14:57:59524 days ago1675954679IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0014441642.8661382
Set Token Sale T...165919392023-02-09 14:57:59524 days ago1675954679IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0014441642.8661382
Set Approval For...165491862023-02-03 15:35:23530 days ago1675438523IN
0x2F4C0c83...4BF16bDDd
0 ETH0.002083534.11212346
Set Approval For...164984632023-01-27 13:31:11537 days ago1674826271IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0010347116.94079838
Set Approval For...163955552023-01-13 4:41:47551 days ago1673584907IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0009893316.19786246
Collect Edition163915142023-01-12 15:07:23552 days ago1673536043IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0009071523.40754711
Collect Edition163915112023-01-12 15:06:47552 days ago1673536007IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0020090221.99718022
Set Approval For...163785742023-01-10 19:43:23554 days ago1673379803IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0013408321.95291187
Set Token Sale T...163703642023-01-09 16:13:23555 days ago1673280803IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0017516151.99217618
Set Token Sale T...163703642023-01-09 16:13:23555 days ago1673280803IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0017516151.99217618
Set Approval For...163669882023-01-09 4:55:35555 days ago1673240135IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0010451717.11214226
Set Approval For...163433722023-01-05 21:48:47559 days ago1672955327IN
0x2F4C0c83...4BF16bDDd
0 ETH0.0013846622.67038595
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

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 : 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 2 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 3 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 4 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 5 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 6 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 7 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 8 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 9 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 10 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 11 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 12 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 13 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 14 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 15 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 16 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 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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.