ETH Price: $3,387.71 (+1.63%)

Token

Drivers Limited Editions by Everfresh (DRIVERS)
 

Overview

Max Total Supply

0 DRIVERS

Holders

19

Total Transfers

-

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
DriversLimitedEditions

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 20 : DriversLimitedEditions.sol
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.17;

/**

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

  By Everfresh

*/

import "./ERC721Base.sol";
import "fount-contracts/utils/Withdraw.sol";
import "./interfaces/IDriversPayments.sol";

/**
 * @author Fount Gallery
 * @title  Drivers Limited 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:
 *   - Mixed 1/1 and limited edition NFTs
 *   - Auctions with "Buy it now" for 1/1 NFTs
 *   - Flexible collecting 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 DriversLimitedEditions is ERC721Base, Withdraw {
    /* ------------------------------------------------------------------------
       S T O R A G E
    ------------------------------------------------------------------------ */

    /// @dev Cap for edition sizes. Also used to generate token ids for editions.
    uint256 internal constant MAX_EDITION_SIZE = 1000;

    /// @dev Stores information about a sale for a given token
    struct TokenData {
        uint128 price;
        uint16 editionSize;
        uint16 collected;
        bool fountExclusive;
        bool requiresSig;
        bool freeToCollect;
    }

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

    /// @dev General auction config
    uint256 public auctionTimeBuffer = 5 minutes;
    uint256 public auctionIncPercentage = 10;

    /// @dev Auction config for a specific token auction
    struct AuctionData {
        uint32 duration;
        uint32 startTime;
        uint32 firstBidTime;
        address highestBidder;
        uint128 highestBid;
        uint128 reservePrice;
    }

    /// @dev Mapping of base token id to auction data
    mapping(uint256 => AuctionData) public auctions;

    /// @dev Counter to keep track of active auctions. Prevents withdrawals unless zero.
    uint256 public activeAuctions;

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

    /// @dev Toggle to allow collecting
    bool internal _isSaleLive;

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

    /**
     * @dev Makes sure that the sale is live before proceeding
     */
    modifier onlyWhenSaleIsLive() {
        if (!_isSaleLive) revert SaleNotLive();
        _;
    }

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

    /** TOKEN DATA ---------------------------------------------------------- */
    error TokenDataDoesNotExist();
    error TokenDataAlreadyExists();
    error InvalidBaseId();
    error CannotSetEditionSizeToZero();

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

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

    /** ONE OF ONES -------------------------------------------------------- */
    error NotOneOfOne();

    /** AUCTIONS ----------------------------------------------------------- */
    error AuctionDoesNotExist();
    error AuctionNotStarted();
    error AuctionAlreadyExists();
    error AuctionAlreadyStarted();
    error AuctionReserveNotMet(uint256 reserve, uint256 sent);
    error AuctionMinimumBidNotMet(uint256 minBid, uint256 sent);
    error AuctionNotEnded();
    error AuctionEnded();
    error AuctionAlreadySettled();
    error AlreadySold();
    error CannotSetAuctionDurationToZero();
    error CannotSetAuctionStartTimeToZero();
    error CannotSetAuctionReservePriceToZero();
    error CannotWithdrawWithActiveAuctions();

    /** EDITIONS ----------------------------------------------------------- */
    error NotEdition();
    error EditionSoldOut();
    error EditionSizeLessThanCurrentlySold();
    error EditionSizeExceedsMaxValue();

    /** PAYMENTS ----------------------------------------------------------- */
    error CannotSetPaymentAddressToZero();

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

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

    event AuctionCreated(uint256 indexed id, AuctionData auction);
    event AuctionBid(uint256 indexed id, AuctionData auction);
    event AuctionSettled(uint256 indexed id, AuctionData auction);
    event AuctionSoldEarly(uint256 indexed id, AuctionData auction);
    event AuctionCancelled(uint256 indexed id);

    event AuctionDurationUpdated(uint256 indexed id, uint256 indexed duration);
    event AuctionStartTimeUpdated(uint256 indexed id, uint256 indexed startTime);
    event AuctionReservePriceUpdated(uint256 indexed id, uint256 indexed reservePrice);

    event CollectedOneOfOne(uint256 indexed id);
    event CollectedEdition(
        uint256 indexed baseId,
        uint256 indexed editionNumber,
        uint256 indexed tokenId
    );

    /* ------------------------------------------------------------------------
       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_
    ) ERC721Base(owner_, admin_, payments_, royaltiesAmount_, metadata_, fountCard_) {
        payments = payments_;
    }

    /* ------------------------------------------------------------------------
       O N E   O F   O N E S
    ------------------------------------------------------------------------ */

    /** BUY NOW ------------------------------------------------------------ */

    /**
     * @notice Collects a 1/1 NFT that's available for sale
     * @dev Calls internal `_collectOneOfOne` for additional logic and minting.
     *
     * Reverts if:
     *  - the sale requires an off-chain signature
     *  - see `_collectOneOfOne` for other conditions
     *
     * @param baseId The base id of the token to collect
     * @param to The address to collect the token to
     */
    function collectOneOfOne(uint256 baseId, address to) external payable onlyWhenSaleIsLive {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig) revert RequiresSignature();
        _collectOneOfOne(baseId, to, tokenData);
    }

    /**
     * @notice Collects a 1/1 NFT that's available for sale using an off-chain signature
     * @dev Calls internal `_collectOneOfOne` for additional logic and minting.
     *
     * Reverts if:
     *  - the signature provided is not valid
     *  - see `_collectOneOfOne` for other conditions
     *
     * @param baseId The base id of the token to collect
     * @param to The address to collect the token to
     * @param signature The off-chain signature that permits a mint
     */
    function collectOneOfOne(
        uint256 baseId,
        address to,
        bytes calldata signature
    ) external payable onlyWhenSaleIsLive {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig && !_verifyMintSignature(baseId, to, signature)) {
            revert InvalidSignature();
        }
        _collectOneOfOne(baseId, to, tokenData);
    }

    /**
     * @notice Internal logic for minting 1/1 NFTs
     * @dev Handles collecting a 1/1 when there's also an active auction e.g. "Buy it now"
     *
     * Reverts if:
     *  - the token is not a 1/1
     *  - msg.value does not equal the required amount
     *  - the token requires a Fount Card, but `to` does not hold one
     *  - the token has already been minted
     *
     * @param baseId The base id of the token to collect
     * @param to The address to collect the token to
     * @param tokenData Information about the token
     */
    function _collectOneOfOne(
        uint256 baseId,
        address to,
        TokenData memory tokenData
    ) internal {
        if (tokenData.editionSize != 1) revert NotOneOfOne();
        if (!tokenData.freeToCollect && tokenData.price == 0) revert NotForSale();
        if (tokenData.price != msg.value) revert IncorrectPaymentAmount();
        if (tokenData.fountExclusive && !_isFountCardHolder(to)) revert RequiresFountCard();

        // If there is an auction for this token and it has bids,
        // then refund the highest bidder, and end the auction early.
        AuctionData memory auction = auctions[baseId];
        if (auction.firstBidTime > 0) {
            // End the auction by setting the duration to "end" at the current block timestamp.
            // This will prevent new bids on the auction since it will revert with `AuctionEnded`.
            auction.duration = uint32(block.timestamp - auction.firstBidTime);
            auctions[baseId] = auction;

            // Refund the highest bidder
            _transferETHWithFallback(auction.highestBidder, auction.highestBid);

            // Decrease the active auctions count
            unchecked {
                --activeAuctions;
            }

            emit AuctionSoldEarly(baseId, auction);
        }

        // Record the mint in the token data
        unchecked {
            ++tokenData.collected;
        }
        _baseIdToTokenData[baseId] = tokenData;

        // Transfer the NFT from Everfresh to the `to` address
        _transferFromArtist(to, baseId);
        emit CollectedOneOfOne(baseId);
    }

    /** AUCTION BIDS ------------------------------------------------------- */

    /**
     * @notice Places a bid for a token
     * @dev Calls internal `_placeBid` function for logic.
     *
     * Reverts if:
     *   - the token requires an off-chain signature
     *   - see `_placeBid` for other conditions
     *
     * @param baseId The base id of the token to register a bid for
     */
    function placeBid(uint256 baseId) external payable onlyWhenSaleIsLive {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig) revert RequiresSignature();
        _placeBid(baseId, tokenData);
    }

    /**
     * @notice Places a bid for a token with an off-chain signature
     * @dev Calls internal `_placeBid` function for logic.
     *
     * Reverts if:
     *   - the token requires an off-chain signature and the signature is invalid
     *   - see `_placeBid` for other conditions
     *
     * @param baseId The base id of the token to register a bid for
     * @param signature The off-chain signature that permits a mint
     */
    function placeBid(uint256 baseId, bytes calldata signature)
        external
        payable
        onlyWhenSaleIsLive
    {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig && !_verifyMintSignature(baseId, msg.sender, signature)) {
            revert InvalidSignature();
        }
        _placeBid(baseId, tokenData);
    }

    /**
     * @notice Internal function to place a bid for a token
     * @dev Takes the amount of ETH sent as the bid. If the bid is the new highest bid,
     * then the previous highest bidder is refunded (in WETH if the refund fails with ETH).
     * If a bid is placed within the auction time buffer then the buffer is added to the
     * time remaining on the auction e.g. extends by 5 minutes.
     *
     * Reverts if:
     *   - the token requires a Fount Card, but msg.sender does not hold one
     *   - the auction has not yet started
     *   - the auction has ended
     *   - the auction reserve bid has not been met if it's the first bid
     *   - the bid does not meet the minimum (increment percentage of current highest bid)
     *
     * @param baseId The base id of the token to register a bid for
     * @param tokenData Information about the token
     */
    function _placeBid(uint256 baseId, TokenData memory tokenData) internal {
        // Check msg.sender qualifies to bid
        if (tokenData.fountExclusive && !_isFountCardHolder(msg.sender)) revert RequiresFountCard();

        // Load the auction
        AuctionData memory auction = auctions[baseId];

        // Check auction is ready to accept bids
        if (auction.startTime == 0 || auction.startTime > block.timestamp) {
            revert AuctionNotStarted();
        }

        // If first bid, start the auction
        if (auction.firstBidTime == 0) {
            // Check the first bid meets the reserve
            if (auction.reservePrice > msg.value) {
                revert AuctionReserveNotMet(auction.reservePrice, msg.value);
            }

            // Save the bid time
            auction.firstBidTime = uint32(block.timestamp);
        } else {
            // Check it hasn't ended
            if (block.timestamp > (auction.firstBidTime + auction.duration)) revert AuctionEnded();

            // Check the value sent meets the minimum price increase
            uint256 highestBid = auction.highestBid;
            uint256 minBid;
            unchecked {
                minBid = highestBid + ((highestBid * auctionIncPercentage) / 100);
            }
            if (minBid > msg.value) revert AuctionMinimumBidNotMet(minBid, msg.value);

            // Refund the previous highest bid
            _transferETHWithFallback(auction.highestBidder, highestBid);
        }

        // Save the new highest bid and bidder
        auction.highestBid = uint96(msg.value);
        auction.highestBidder = msg.sender;

        // Calculate the time remaining
        uint256 timeRemaining;
        unchecked {
            timeRemaining = auction.firstBidTime + auction.duration - block.timestamp;
        }

        // If bid is placed within the time buffer of the auction ending, increase the duration
        if (timeRemaining < auctionTimeBuffer) {
            unchecked {
                auction.duration += uint32(auctionTimeBuffer - timeRemaining);
            }
        }

        // Save the new auction data
        auctions[baseId] = auction;

        // Emit event
        emit AuctionBid(baseId, auction);
    }

    /** AUCTION SETTLEMENT ------------------------------------------------- */

    /**
     * @notice Allows the winner to settle the auction which mints of their new NFT
     * @dev Mints the NFT to the highest bidder (winner) only once the auction is over.
     * Can be called by anyone so Fount Gallery can pay the gas if needed.
     *
     * Reverts if:
     *   - the auction hasn't started yet
     *   - the auction is not over
     *   - the token has already been sold via `collectOneOfOne`
     *
     * @param baseId The base id of token to settle the auction for
     */
    function settleAuction(uint256 baseId) external {
        AuctionData memory auction = auctions[baseId];

        // Check auction has started
        if (auction.firstBidTime == 0) revert AuctionNotStarted();

        // Check auction has ended
        if (auction.firstBidTime + auction.duration > block.timestamp) revert AuctionNotEnded();

        // Transfer the NFT to the highest bidder
        if (_ownerOf[baseId] != everfresh) revert AlreadySold();
        _transferFromArtist(auction.highestBidder, baseId);
        emit CollectedOneOfOne(baseId);

        // Decrease the active auctions count
        unchecked {
            --activeAuctions;
        }

        // Emit event
        emit AuctionSettled(baseId, auction);
    }

    /* ------------------------------------------------------------------------
       L I M I T E D   E D I T I O N S
    ------------------------------------------------------------------------ */

    /**
     * @notice Mints the next edition of a limited edition NFT
     * @dev Calls internal `_collectEdition` for logic.
     *
     * Reverts if:
     *  - the edition requires an off-chain signature
     *  - see `_collectEdition` for other conditions
     *
     * @param baseId The base NFT id of the edition
     * @param to The address to mint the token to
     */
    function collectEdition(uint256 baseId, address to) external payable onlyWhenSaleIsLive {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig) revert RequiresSignature();
        _collectEdition(baseId, to, tokenData);
    }

    /**
     * @notice Mints the next edition of a limited 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 baseId The base NFT id of the edition
     * @param to The address to mint the token to
     * @param signature The off-chain signature which permits a mint
     */
    function collectEdition(
        uint256 baseId,
        address to,
        bytes calldata signature
    ) external payable onlyWhenSaleIsLive {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.requiresSig && !_verifyMintSignature(baseId, to, signature)) {
            revert InvalidSignature();
        }
        _collectEdition(baseId, to, tokenData);
    }

    /**
     * @notice Internal function to collect the next edition with some conditions
     * @dev Allows collecting to a different address from msg.sender.
     *
     * Reverts if:
     *  - the token is not an edition
     *  - the edition is sold out
     *  - msg.value does not equal the required amount
     *  - the edition requires a Fount Card, but `to` does not hold one
     *
     * @param baseId The base NFT id of the edition
     * @param to The address to collect the token to
     * @param tokenData Information about the token
     */
    function _collectEdition(
        uint256 baseId,
        address to,
        TokenData memory tokenData
    ) internal {
        // Check to see if the next edition is collectable and the price is correct
        if (tokenData.editionSize < 2) revert NotEdition();
        if (tokenData.collected + 1 > tokenData.editionSize) revert EditionSoldOut();
        if (!tokenData.freeToCollect && tokenData.price == 0) revert NotForSale();
        if (tokenData.price != msg.value) revert IncorrectPaymentAmount();

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

        // Get the next edition number and token id
        uint256 editionNumber = tokenData.collected + 1;
        uint256 tokenId = _getEditionTokenId(baseId, editionNumber);

        // Add the new mint to the token data
        unchecked {
            ++tokenData.collected;
        }
        _baseIdToTokenData[baseId] = tokenData;

        // Transfer the NFT from Everfresh to the `to` address
        _transferFromArtist(to, tokenId);
        emit CollectedEdition(baseId, editionNumber, tokenId);
    }

    /** UTILS -------------------------------------------------------------- */

    /**
     * @notice Internal function to get the token id for an edition
     * @param baseId The base NFT id of the edition
     * @param editionNumber The edition number to make the token id for
     * @return tokenId The token id for the edition
     */
    function _getEditionTokenId(uint256 baseId, uint256 editionNumber)
        internal
        pure
        returns (uint256)
    {
        return baseId * MAX_EDITION_SIZE + editionNumber;
    }

    /**
     * @notice Get the token id for a specific edition number
     * @param baseId The base NFT id of the edition
     * @param editionNumber The edition number to make the token id for
     * @return tokenId The token id for the edition
     */
    function getEditionTokenId(uint256 baseId, uint256 editionNumber)
        external
        pure
        returns (uint256)
    {
        return _getEditionTokenId(baseId, editionNumber);
    }

    /**
     * @notice Get the edition number from a token id
     * @dev Returns `0` if it's not an edition
     * @param tokenId The token id for the edition
     * @return editionNumber The edition number e.g. 2 of 10
     */
    function getEditionNumberFromTokenId(uint256 tokenId) external pure returns (uint256) {
        if (tokenId >= MAX_EDITION_SIZE) return 0;
        return tokenId % MAX_EDITION_SIZE;
    }

    /**
     * @notice Get the base NFT id from a token id
     * @dev Returns the token id argument if it's not an edition
     * @param tokenId The token id for the edition
     * @return baseId The base NFT id e.g. 2 from "2004"
     */
    function getEditionBaseIdFromTokenId(uint256 tokenId) external pure returns (uint256) {
        if (tokenId >= MAX_EDITION_SIZE) return tokenId;
        return tokenId / MAX_EDITION_SIZE;
    }

    /* ------------------------------------------------------------------------
       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 provided
     * a price has been set. This prevents auctions without a "buy it now" price from being
     * purchased for free unintentionally.
     *
     * If a free mint is intended, set `price` to zero and `freeMint` to true.
     *
     * Reverts if:
     *  - the edition size exeeds the max allowed value (`MAX_EDITION_SIZE`)
     *  - the token data already exists (to update token data, use the other admin
     *    functions to set price and sale conditions)
     *
     * @param baseId The base NFT id
     * @param price The sale price (buy it now for auctions)
     * @param editionSize The size of the edition. Set to 1 for one of one NFTs.
     * @param fountExclusive If the sale requires a Fount Gallery Patron card
     * @param requiresSig If the sale requires an off-chain signature
     * @param freeMint If the sale requires an off-chain signature
     */
    function addTokenForSale(
        uint256 baseId,
        uint128 price,
        uint16 editionSize,
        bool fountExclusive,
        bool requiresSig,
        bool freeMint
    ) external onlyOwnerOrAdmin {
        // Check the baseId is valid
        if (baseId > type(uint256).max / MAX_EDITION_SIZE) revert InvalidBaseId();

        // Check a valid edition size has been used
        if (editionSize == 0) revert CannotSetEditionSizeToZero();

        // Check the edition size does not exceed the max
        if (editionSize > MAX_EDITION_SIZE - 1) revert EditionSizeExceedsMaxValue();

        TokenData memory tokenData = _baseIdToTokenData[baseId];

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

        // Set the new token data
        tokenData.price = price;
        tokenData.editionSize = editionSize;
        tokenData.fountExclusive = fountExclusive;
        tokenData.requiresSig = requiresSig;
        tokenData.freeToCollect = freeMint;
        _baseIdToTokenData[baseId] = tokenData;
        emit TokenDataAdded(baseId, tokenData);

        // Mint to Everfresh
        if (editionSize == 1) {
            _mint(everfresh, baseId);
        } else {
            for (uint256 i = 0; i < editionSize; i++) {
                _mint(everfresh, _getEditionTokenId(baseId, i + 1));
            }
        }
    }

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

    /**
     * @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 baseId The base NFT id
     * @param price The new sale price
     * @param freeMint If the NFT can be minted for free
     */
    function setTokenSalePrice(
        uint256 baseId,
        uint128 price,
        bool freeMint
    ) external onlyOwnerOrAdmin {
        TokenData memory tokenData = _baseIdToTokenData[baseId];

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

        // Set the new sale price
        tokenData.price = price;
        tokenData.freeToCollect = freeMint;
        _baseIdToTokenData[baseId] = tokenData;
        emit TokenDataSalePriceUpdated(baseId, 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 baseId The base NFT id
     * @param fountExclusive If the sale requires a Fount Gallery Patron card
     * @param requiresSig If the sale requires an off-chain signature
     */
    function setTokenSaleConditions(
        uint256 baseId,
        bool fountExclusive,
        bool requiresSig
    ) external onlyOwnerOrAdmin {
        TokenData memory tokenData = _baseIdToTokenData[baseId];

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

        tokenData.fountExclusive = fountExclusive;
        tokenData.requiresSig = requiresSig;
        _baseIdToTokenData[baseId] = tokenData;
        emit TokenDataSaleConditionsUpdated(baseId, tokenData);
    }

    /** AUCTION CREATION --------------------------------------------------- */

    /**
     * @notice Admin function to create an auction for a 1/1
     * @dev Can only create auctions for 1/1 NFTs, not editions.
     *
     * Reverts if:
     *  - the token is not a 1/1
     *  - the auction already exists
     *
     * @param baseId The base NFT id
     */
    function createAuction(
        uint256 baseId,
        uint32 duration,
        uint32 startTime,
        uint128 reservePrice
    ) external onlyOwnerOrAdmin {
        if (duration == 0) revert CannotSetAuctionDurationToZero();
        if (startTime == 0) revert CannotSetAuctionStartTimeToZero();

        // Check if the token data exists and it's a 1/1
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        if (tokenData.editionSize != 1) revert NotOneOfOne();

        // Load the auction data
        AuctionData memory auction = auctions[baseId];

        // Check there's no auction already
        if (auction.startTime > 0) revert AuctionAlreadyExists();

        // Create the auction data
        auction.duration = duration;
        auction.startTime = startTime;
        auction.reservePrice = reservePrice;
        auctions[baseId] = auction;

        // Increment active auctions counter
        unchecked {
            ++activeAuctions;
        }

        // Emit created event
        emit AuctionCreated(baseId, auction);
    }

    /** AUCTION CANCELLATION ----------------------------------------------- */

    /**
     * @notice Admin function to cancel an auction
     * @dev Calls internal `_cancelAuction` for logic.
     * @param baseId The base NFT id
     */
    function cancelAuction(uint256 baseId) external onlyOwnerOrAdmin {
        AuctionData memory auction = auctions[baseId];
        _cancelAuction(baseId, auction);
    }

    /**
     * @notice Internal function for cancelling an auction
     * @dev Cancels the auction by refunding the highest bid and deleting the data
     *
     * Reverts if:
     *  - the auctions has ended (in case it hasn't been settled yet)
     *
     * @param baseId The base NFT id
     * @param auction The auction data to determine conditions and refunds
     */
    function _cancelAuction(uint256 baseId, AuctionData memory auction) internal {
        if (auction.firstBidTime > 0) {
            // Prevent cancelling if the auction has ended in case it hasn't been settled yet
            if (block.timestamp > (auction.firstBidTime + auction.duration)) revert AuctionEnded();
            // Refund the highest bidder
            _transferETHWithFallback(auction.highestBidder, auction.highestBid);
        }

        // Delete the auction data and reduce the active auction count
        delete auctions[baseId];
        unchecked {
            --activeAuctions;
        }

        emit AuctionCancelled(baseId);
    }

    /** AUCTION DURATION --------------------------------------------------- */

    /**
     * @notice Admin function to set the duration of a specific auction
     * @dev Emits an `AuctionDurationUpdated` event if successful
     *
     * Reverts if:
     *  - `duration` is zero
     *  - the auction does not exist
     *  - the auction already has bids
     *
     * @param baseId The base NFT id
     * @param duration The new auction duration
     */
    function setAuctionDuration(uint256 baseId, uint32 duration) external onlyOwnerOrAdmin {
        if (duration == 0) revert CannotSetAuctionDurationToZero();

        AuctionData memory auction = auctions[baseId];
        if (auction.startTime == 0) revert AuctionDoesNotExist();
        if (auction.firstBidTime > 0) revert AuctionAlreadyStarted();

        auction.duration = duration;
        auctions[baseId] = auction;
        emit AuctionDurationUpdated(baseId, duration);
    }

    /** AUCTION START TIME ------------------------------------------------- */

    /**
     * @notice Admin function to set the start time of a specific auction
     * @dev Emits an `AuctionStartTimeUpdated` event if successful
     *
     * Reverts if:
     *  - `startTime` is zero
     *  - the auction does not exist
     *  - the auction already has bids
     *
     * @param baseId The base NFT id
     * @param startTime The new auction start time
     */
    function setAuctionStartTime(uint256 baseId, uint32 startTime) external onlyOwnerOrAdmin {
        if (startTime == 0) revert CannotSetAuctionStartTimeToZero();

        AuctionData memory auction = auctions[baseId];
        if (auction.startTime == 0) revert AuctionDoesNotExist();
        if (auction.firstBidTime > 0) revert AuctionAlreadyStarted();

        auction.startTime = startTime;
        auctions[baseId] = auction;
        emit AuctionStartTimeUpdated(baseId, startTime);
    }

    /** AUCTION RESERVE PRICE ---------------------------------------------- */

    /**
     * @notice Admin function to set the reserve price of a specific auction
     * @dev Emits an `AuctionReservePriceUpdated` event if successful
     *
     * Reverts if:
     *  - `reservePrice` is zero
     *  - the auction does not exist
     *  - the auction already has bids
     *
     * @param baseId The base NFT id
     * @param reservePrice The new auction start time
     */
    function setAuctionReservePrice(uint256 baseId, uint128 reservePrice)
        external
        onlyOwnerOrAdmin
    {
        if (reservePrice == 0) revert CannotSetAuctionReservePriceToZero();

        AuctionData memory auction = auctions[baseId];
        if (auction.startTime == 0) revert AuctionDoesNotExist();
        if (auction.firstBidTime > 0) revert AuctionAlreadyStarted();

        auction.reservePrice = reservePrice;
        auctions[baseId] = auction;
        emit AuctionReservePriceUpdated(baseId, reservePrice);
    }

    /** TAKE SALE LIVE ----------------------------------------------------- */

    /**
     * @notice Admin function to set the sale live state
     * @dev If set to false, then collecting will be paused.
     * @param isLive Whether the sale is live or not
     */
    function setSaleLiveState(bool isLive) external onlyOwnerOrAdmin {
        _isSaleLive = isLive;
    }

    /** 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;
    }

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

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

    function tokenIsOneOfOne(uint256 baseId) external view returns (bool) {
        return _baseIdToTokenData[baseId].editionSize == 1;
    }

    function tokenIsEdition(uint256 baseId) external view returns (bool) {
        return _baseIdToTokenData[baseId].editionSize > 1;
    }

    function tokenEditionSize(uint256 baseId) external view returns (uint256) {
        return _baseIdToTokenData[baseId].editionSize;
    }

    function tokenCollectedCount(uint256 baseId) external view returns (uint256) {
        return _baseIdToTokenData[baseId].collected;
    }

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

    function tokenRequiresOffChainSignatureToCollect(uint256 baseId) external view returns (bool) {
        return _baseIdToTokenData[baseId].requiresSig;
    }

    function tokenIsFreeToCollect(uint256 baseId) external view returns (bool) {
        TokenData memory tokenData = _baseIdToTokenData[baseId];
        return tokenData.price == 0 && tokenData.freeToCollect;
    }

    function auctionHasStarted(uint256 baseId) external view returns (bool) {
        return auctions[baseId].firstBidTime > 0;
    }

    function auctionStartTime(uint256 baseId) external view returns (uint256) {
        return auctions[baseId].startTime;
    }

    function auctionHasEnded(uint256 baseId) external view returns (bool) {
        AuctionData memory auction = auctions[baseId];
        bool hasStarted = auctions[baseId].firstBidTime > 0;
        return hasStarted && block.timestamp >= auction.firstBidTime + auction.duration;
    }

    function auctionEndTime(uint256 baseId) external view returns (uint256) {
        AuctionData memory auction = auctions[baseId];
        bool hasStarted = auctions[baseId].firstBidTime > 0;
        return hasStarted ? auction.startTime + auction.duration : 0;
    }

    function auctionDuration(uint256 baseId) external view returns (uint256) {
        return auctions[baseId].duration;
    }

    function auctionFirstBidTime(uint256 baseId) external view returns (uint256) {
        return auctions[baseId].firstBidTime;
    }

    function auctionHighestBidder(uint256 baseId) external view returns (address) {
        return auctions[baseId].highestBidder;
    }

    function auctionHighestBid(uint256 baseId) external view returns (uint256) {
        return auctions[baseId].highestBid;
    }

    function auctionReservePrice(uint256 baseId) external view returns (uint256) {
        return auctions[baseId].reservePrice;
    }

    /* ------------------------------------------------------------------------
       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 {
        // Check there are no active auctions
        if (activeAuctions > 0) revert CannotWithdrawWithActiveAuctions();
        // 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 {
        // Check there are no active auctions
        if (activeAuctions > 0) revert CannotWithdrawWithActiveAuctions();
        // 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 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 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

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

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

    string public name;

    string public symbol;

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

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

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

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

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

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

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

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

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

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

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

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

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

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

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

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

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

import "solmate/tokens/ERC721.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 "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/IWETH.sol";

/**
 * @author Fount Gallery
 * @title  ERC721Base
 * @notice Base contract for Drivers Limited 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
 *   - Safe transferring of ETH with WETH fallback
 */
abstract contract ERC721Base is
    ERC721,
    Auth,
    FountCardCheck,
    SwappableMetadata,
    Royalties,
    EIP712,
    OperatorFilterer
{
    /* ------------------------------------------------------------------------
       S T O R A G E
    ------------------------------------------------------------------------ */

    /// @notice everfresh.eth
    address public everfresh = 0xBb3444a06E9928dDA9a739CdAb3E0c5cf6890099;

    /// @notice Contract information
    string public contractURI;

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

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

    /// @dev EIP-712 signed data struct for minting with an off-chain signature
    struct MintSignatureData {
        uint256 id;
        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;

    /* ------------------------------------------------------------------------
       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 royaltiesReceiver_ The address where royalties 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 royaltiesReceiver_,
        uint256 royaltiesAmount_,
        address metadata_,
        address fountCard_
    )
        ERC721("Drivers Limited Editions by Everfresh", "DRIVERS")
        Auth(owner_, admin_)
        FountCardCheck(fountCard_)
        SwappableMetadata(metadata_)
        Royalties(royaltiesReceiver_, royaltiesAmount_)
        EIP712(SIGNING_DOMAIN, SIGNATURE_VERSION)
    {
        _registerForOperatorFiltering();
        operatorFilteringEnabled = true;
        emit Init();
    }

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

    function _transferFromArtist(address to, uint256 id) internal {
        require(everfresh == _ownerOf[id], "WRONG_FROM");
        require(to != address(0), "INVALID_RECIPIENT");

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[everfresh]--;
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;
        delete getApproved[id];

        emit Transfer(everfresh, to, id);
    }

    /* ------------------------------------------------------------------------
       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 base NFT 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,
        address to,
        bytes calldata signature
    ) internal returns (bool) {
        MintSignatureData memory data = MintSignatureData({
            id: id,
            to: to,
            nonce: nonces[to],
            signature: signature
        });

        // Hash the data for verification
        bytes32 digest = _hashTypedDataV4(
            keccak256(abi.encode(MINT_SIGNATURE_TYPEHASH, data.id, 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);
    }

    /* ------------------------------------------------------------------------
       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;
    }

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

    /**
     * @notice Add interface for on-chain royalty standard
     */
    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, 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-721 `setApprovalForAll` to support OpenSea Operator Filtering
     */
    function setApprovalForAll(address operator, bool approved)
        public
        override
        onlyAllowedOperatorApproval(operator)
    {
        super.setApprovalForAll(operator, approved);
    }

    /**
     * @notice Override ERC-721 `approve` to support OpenSea Operator Filtering
     */
    function approve(address operator, uint256 id)
        public
        override
        onlyAllowedOperatorApproval(operator)
    {
        super.approve(operator, id);
    }

    /**
     * @notice Override ERC-721 `transferFrom` to support OpenSea Operator Filtering
     */
    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public override onlyAllowedOperator(from) {
        super.transferFrom(from, to, id);
    }

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

    /**
     * @notice Override ERC-721 `safeTransferFrom` to support OpenSea Operator Filtering
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, id, 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;
    }

    /* ------------------------------------------------------------------------
       E R C 7 2 1
    ------------------------------------------------------------------------ */

    /**
     * @notice Returns the token metadata
     * @return id The token id to get metadata for
     */
    function tokenURI(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
     */
    function burn(uint256 id) external {
        require(ownerOf(id) == msg.sender, "NOT_OWNER");
        _burn(id);
    }
}

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":"AlreadySold","type":"error"},{"inputs":[],"name":"AuctionAlreadyExists","type":"error"},{"inputs":[],"name":"AuctionAlreadySettled","type":"error"},{"inputs":[],"name":"AuctionAlreadyStarted","type":"error"},{"inputs":[],"name":"AuctionDoesNotExist","type":"error"},{"inputs":[],"name":"AuctionEnded","type":"error"},{"inputs":[{"internalType":"uint256","name":"minBid","type":"uint256"},{"internalType":"uint256","name":"sent","type":"uint256"}],"name":"AuctionMinimumBidNotMet","type":"error"},{"inputs":[],"name":"AuctionNotEnded","type":"error"},{"inputs":[],"name":"AuctionNotStarted","type":"error"},{"inputs":[{"internalType":"uint256","name":"reserve","type":"uint256"},{"internalType":"uint256","name":"sent","type":"uint256"}],"name":"AuctionReserveNotMet","type":"error"},{"inputs":[],"name":"BalanceTooLow","type":"error"},{"inputs":[],"name":"CannotSetAuctionDurationToZero","type":"error"},{"inputs":[],"name":"CannotSetAuctionReservePriceToZero","type":"error"},{"inputs":[],"name":"CannotSetAuctionStartTimeToZero","type":"error"},{"inputs":[],"name":"CannotSetEditionSizeToZero","type":"error"},{"inputs":[],"name":"CannotSetPaymentAddressToZero","type":"error"},{"inputs":[],"name":"CannotWithdrawToZeroAddress","type":"error"},{"inputs":[],"name":"CannotWithdrawWithActiveAuctions","type":"error"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"},{"internalType":"uint256","name":"owned","type":"uint256"}],"name":"DoesNotHoldEnoughFountCards","type":"error"},{"inputs":[],"name":"EditionSizeExceedsMaxValue","type":"error"},{"inputs":[],"name":"EditionSizeLessThanCurrentlySold","type":"error"},{"inputs":[],"name":"EditionSoldOut","type":"error"},{"inputs":[],"name":"IncorrectPaymentAmount","type":"error"},{"inputs":[],"name":"InvalidBaseId","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"MetadataLocked","type":"error"},{"inputs":[],"name":"MoreThanOneHundredPercentRoyalty","type":"error"},{"inputs":[],"name":"NotEdition","type":"error"},{"inputs":[],"name":"NotForSale","type":"error"},{"inputs":[],"name":"NotFountCardHolder","type":"error"},{"inputs":[],"name":"NotOneOfOne","type":"error"},{"inputs":[],"name":"RequiresFountCard","type":"error"},{"inputs":[],"name":"RequiresSignature","type":"error"},{"inputs":[],"name":"SaleNotLive","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":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"firstBidTime","type":"uint32"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"uint128","name":"highestBid","type":"uint128"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"indexed":false,"internalType":"struct DriversLimitedEditions.AuctionData","name":"auction","type":"tuple"}],"name":"AuctionBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"AuctionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"firstBidTime","type":"uint32"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"uint128","name":"highestBid","type":"uint128"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"indexed":false,"internalType":"struct DriversLimitedEditions.AuctionData","name":"auction","type":"tuple"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"AuctionDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"reservePrice","type":"uint256"}],"name":"AuctionReservePriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"firstBidTime","type":"uint32"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"uint128","name":"highestBid","type":"uint128"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"indexed":false,"internalType":"struct DriversLimitedEditions.AuctionData","name":"auction","type":"tuple"}],"name":"AuctionSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"firstBidTime","type":"uint32"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"uint128","name":"highestBid","type":"uint128"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"indexed":false,"internalType":"struct DriversLimitedEditions.AuctionData","name":"auction","type":"tuple"}],"name":"AuctionSoldEarly","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"AuctionStartTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"baseId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"editionNumber","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"CollectedEdition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"CollectedOneOfOne","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":"uint16","name":"editionSize","type":"uint16"},{"internalType":"uint16","name":"collected","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"},{"internalType":"bool","name":"freeToCollect","type":"bool"}],"indexed":false,"internalType":"struct DriversLimitedEditions.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":"uint16","name":"editionSize","type":"uint16"},{"internalType":"uint16","name":"collected","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"},{"internalType":"bool","name":"freeToCollect","type":"bool"}],"indexed":false,"internalType":"struct DriversLimitedEditions.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":"uint16","name":"editionSize","type":"uint16"},{"internalType":"uint16","name":"collected","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"},{"internalType":"bool","name":"freeToCollect","type":"bool"}],"indexed":false,"internalType":"struct DriversLimitedEditions.TokenData","name":"tokenData","type":"tuple"}],"name":"TokenDataSalePriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MINT_SIGNATURE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNATURE_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SIGNING_DOMAIN","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeAuctions","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"uint16","name":"editionSize","type":"uint16"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"},{"internalType":"bool","name":"freeMint","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":"operator","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedSigners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionFirstBidTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionHasEnded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionHasStarted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionHighestBid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionHighestBidder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionIncPercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionReservePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"auctionStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionTimeBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"auctions","outputs":[{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"firstBidTime","type":"uint32"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"uint128","name":"highestBid","type":"uint128"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"cancelAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","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":"baseId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"collectEdition","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"collectOneOfOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"collectOneOfOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint32","name":"duration","type":"uint32"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"name":"createAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"everfresh","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getEditionBaseIdFromTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getEditionNumberFromTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint256","name":"editionNumber","type":"uint256"}],"name":"getEditionTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"payments","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"placeBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"placeBid","outputs":[],"stateMutability":"payable","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":"id","type":"uint256"}],"name":"safeTransferFrom","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":"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":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint32","name":"duration","type":"uint32"}],"name":"setAuctionDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint128","name":"reservePrice","type":"uint128"}],"name":"setAuctionReservePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"}],"name":"setAuctionStartTime","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":"bool","name":"isLive","type":"bool"}],"name":"setSaleLiveState","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":"baseId","type":"uint256"},{"internalType":"bool","name":"fountExclusive","type":"bool"},{"internalType":"bool","name":"requiresSig","type":"bool"}],"name":"setTokenSaleConditions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"},{"internalType":"uint128","name":"price","type":"uint128"},{"internalType":"bool","name":"freeMint","type":"bool"}],"name":"setTokenSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"settleAuction","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":"baseId","type":"uint256"}],"name":"tokenCollectedCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenEditionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenIsEdition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenIsFountExclusive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenIsFreeToCollect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenIsOneOfOne","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"baseId","type":"uint256"}],"name":"tokenRequiresOffChainSignatureToCollect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","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"}]

610140604052600b80546001600160a01b03191673bb3444a06e9928dda9a739cdab3e0c5cf6890099179055600f805474c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200610100600160a81b031990911617905561012c601155600a6012553480156200006d57600080fd5b506040516200624f3803806200624f833981016040819052620000909162000451565b8585858585856040518060400160405280601681526020017f447269766572734c696d6974656445646974696f6e7300000000000000000000815250604051806040016040528060018152602001603160f81b815250858585858b8b6040518060600160405280602581526020016200622a602591396040805180820190915260078152664452495645525360c81b602082015260006200013283826200056e565b5060016200014182826200056e565b5050600680546001600160a01b0319166001600160a01b0385169081179091556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a36001600160a01b038116600081815260076020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a35050600880546001600160a01b039283166001600160a01b0319918216179091556009805492841692909116821790556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a2506040805180820182526001600160a01b0384168082526001600160601b0384166020909201829052600160a01b9091028117600a5590518291907f984cbbb47b413608120ad6b444ea0004fe19b6f88a5c0992e612b97fd3cb631e90600090a35050815160209283012081519183019190912060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818301969096526060810194909452608080850193909352308483018190528151808603909301835260c094850190915281519190950120905291909152610120526200032e62000397565b600f805460ff191660011790556040517f57a86f7d14ccde89e22870afe839e3011216827daa9b24e18629f0a1e9d6cc1490600090a15050601580546001600160a01b0319166001600160a01b039990991698909817909755506200063a975050505050505050565b620003b8733cc6cdda760b79bafa08df41ecfa224f810dceb66001620003ba565b565b6001600160a01b0390911690637d3e3dbe81620003ea5782620003e35750634420e486620003ea565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16200042a578060005160e01c036200042a57600080fd5b5060006024525050565b80516001600160a01b03811681146200044c57600080fd5b919050565b60008060008060008060c087890312156200046b57600080fd5b620004768762000434565b9550620004866020880162000434565b9450620004966040880162000434565b935060608701519250620004ad6080880162000434565b9150620004bd60a0880162000434565b90509295509295509295565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620004f457607f821691505b6020821081036200051557634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200056957600081815260208120601f850160051c81016020861015620005445750805b601f850160051c820191505b81811015620005655782815560010162000550565b5050505b505050565b81516001600160401b038111156200058a576200058a620004c9565b620005a2816200059b8454620004df565b846200051b565b602080601f831160018114620005da5760008415620005c15750858301515b600019600386901b1c1916600185901b17855562000565565b600085815260208120601f198616915b828110156200060b57888601518255948401946001909101908401620005ea565b50858210156200062a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516101005161012051615ba06200068a6000396000614d2101526000614d7001526000614d4b01526000614ca401526000614cce01526000614cf80152615ba06000f3fe60806040526004361061049f5760003560e01c8063864bc0a011610260578063b9c2443d11610144578063d7e45cd7116100c1578063e3faad9411610085578063e3faad9414611067578063e8a3d485146110a9578063e985e9c5146110be578063ef6ea27a146110f9578063f9e3c46f14611131578063fb796e6c1461117157600080fd5b8063d7e45cd714610fd1578063e07b1afb14610ff2578063e086e5ec14611012578063e17b25af14611027578063e2e784d51461104757600080fd5b8063c87b56dd11610108578063c87b56dd14610f0e578063cb93752814610f2e578063d2e4b90514610f4e578063d46e7ae114610f88578063d4ddce8a14610f9b57600080fd5b8063b9c2443d14610e28578063bdaaf19414610e48578063bf40defb14610e81578063bfe29d5714610ebd578063c0fd735b14610ef957600080fd5b8063a2df15e2116101dd578063a6d23e10116101a1578063a6d23e1014610d61578063aa05234114610d81578063abadb36514610da1578063af4fddfa14610db4578063b7c0b8e814610de8578063b88d4fde14610e0857600080fd5b8063a2df15e214610ca1578063a415729614610cb7578063a43b87a214610ce4578063a522ad2514610d21578063a5aef37d14610d4157600080fd5b806395d89b411161022457806395d89b4114610c0657806396b5a75514610c1b5780639886973114610c3b5780639979ef4514610c6e578063a22cb46514610c8157600080fd5b8063864bc0a014610b6d5780638a87551214610b805780638da5cb5b14610bb0578063923d8dfa14610bd0578063938e3d7b14610be657600080fd5b8063392f37e9116103875780635e1c074611610304578063695747c2116102c8578063695747c214610a88578063702f9bbe14610aa85780637048027514610ae057806370a0823114610b00578063777de70414610b205780637ecebe0014610b4057600080fd5b80635e1c0746146109e95780635e1e1004146109fe578063633511bb14610a1e5780636352211e14610a5557806365a1e83314610a7557600080fd5b80634588d1c71161034b5780634588d1c7146108ac57806346d8efad146108cc57806349df728c146108ec5780635090d0c61461090c578063571a26a01461092257600080fd5b8063392f37e9146107f75780633fc8cef31461081757806342842e0e1461083c57806342966c681461085c578063429b62e51461087c57600080fd5b80631551b7c11161042057806326645a2c116103e457806326645a2c146106cc5780632a55205a146107035780632e9936111461074257806331cb61051461076257806331ccd4bc1461078257806333465c5f146107bd57600080fd5b80631551b7c1146106395780631785f53c1461065957806319ffb5831461067957806320f3f8451461069957806323b872dd146106ac57600080fd5b80630a87c3cf116104675780630a87c3cf146105995780630e9e835c146105b957806311a774fd146105d957806313af4035146105f957806314dfc68e1461061957600080fd5b806301ffc9a7146104a457806306d715fa146104d957806306fdde0314610507578063081812fc14610529578063095ea7b314610577575b600080fd5b3480156104b057600080fd5b506104c46104bf366004615112565b61118b565b60405190151581526020015b60405180910390f35b3480156104e557600080fd5b506104f96104f436600461512f565b6111b6565b6040519081526020016104d0565b34801561051357600080fd5b5061051c6111d1565b6040516104d0919061516c565b34801561053557600080fd5b5061055f61054436600461512f565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016104d0565b34801561058357600080fd5b506105976105923660046151b6565b61125f565b005b3480156105a557600080fd5b506105976105b4366004615205565b611283565b3480156105c557600080fd5b506104c46105d436600461512f565b611467565b3480156105e557600080fd5b506105976105f4366004615245565b611515565b34801561060557600080fd5b5061059761061436600461526c565b6116df565b34801561062557600080fd5b506104f961063436600461512f565b61176f565b34801561064557600080fd5b50610597610654366004615287565b61178e565b34801561066557600080fd5b5061059761067436600461526c565b6117f0565b34801561068557600080fd5b506105976106943660046152a4565b61187e565b6105976106a7366004615308565b611a8a565b3480156106b857600080fd5b506105976106c7366004615361565b611b7a565b3480156106d857600080fd5b506104c46106e736600461512f565b600090815260106020526040902054600160a01b900460ff1690565b34801561070f57600080fd5b5061072361071e36600461539d565b611bb0565b604080516001600160a01b0390931683526020830191909152016104d0565b34801561074e57600080fd5b5061059761075d36600461512f565b611bf2565b34801561076e57600080fd5b5061059761077d3660046153bf565b611d84565b34801561078e57600080fd5b506104c461079d36600461512f565b600090815260106020526040902054600160801b900461ffff1660011490565b3480156107c957600080fd5b506104f96107d836600461512f565b600090815260136020526040902054600160201b900463ffffffff1690565b34801561080357600080fd5b5060095461055f906001600160a01b031681565b34801561082357600080fd5b50600f5461055f9061010090046001600160a01b031681565b34801561084857600080fd5b50610597610857366004615361565b611df3565b34801561086857600080fd5b5061059761087736600461512f565b611e23565b34801561088857600080fd5b506104c461089736600461526c565b60076020526000908152604090205460ff1681565b3480156108b857600080fd5b506105976108c73660046153f6565b611e7b565b3480156108d857600080fd5b506105976108e73660046153bf565b61216a565b3480156108f857600080fd5b5061059761090736600461526c565b6121bc565b34801561091857600080fd5b506104f960145481565b34801561092e57600080fd5b5061099a61093d36600461512f565b6013602052600090815260409020805460019091015463ffffffff80831692600160201b8104821692600160401b820490921691600160601b9091046001600160a01b0316906001600160801b0380821691600160801b90041686565b6040805163ffffffff9788168152958716602087015293909516928401929092526001600160a01b031660608301526001600160801b03908116608083015290911660a082015260c0016104d0565b3480156109f557600080fd5b50610597612217565b348015610a0a57600080fd5b50610597610a1936600461526c565b612221565b348015610a2a57600080fd5b506104c4610a3936600461512f565b600090815260106020526040902054600160a81b900460ff1690565b348015610a6157600080fd5b5061055f610a7036600461512f565b6122ae565b610597610a83366004615474565b612305565b348015610a9457600080fd5b506104f9610aa336600461539d565b6123d6565b348015610ab457600080fd5b506104f9610ac336600461512f565b600090815260106020526040902054600160801b900461ffff1690565b348015610aec57600080fd5b50610597610afb36600461526c565b6123e9565b348015610b0c57600080fd5b506104f9610b1b36600461526c565b61247a565b348015610b2c57600080fd5b506104f9610b3b36600461512f565b6124dd565b348015610b4c57600080fd5b506104f9610b5b36600461526c565b600e6020526000908152604090205481565b610597610b7b366004615497565b61258a565b348015610b8c57600080fd5b506104c4610b9b36600461526c565b600d6020526000908152604090205460ff1681565b348015610bbc57600080fd5b5060065461055f906001600160a01b031681565b348015610bdc57600080fd5b506104f960125481565b348015610bf257600080fd5b50610597610c0136600461554f565b612672565b348015610c1257600080fd5b5061051c6126c2565b348015610c2757600080fd5b50610597610c3636600461512f565b6126cf565b348015610c4757600080fd5b506104f9610c5636600461512f565b60009081526013602052604090205463ffffffff1690565b610597610c7c36600461512f565b61279c565b348015610c8d57600080fd5b50610597610c9c3660046153bf565b61286c565b348015610cad57600080fd5b506104f960115481565b348015610cc357600080fd5b5061051c604051806040016040528060018152602001603160f81b81525081565b348015610cf057600080fd5b5061055f610cff36600461512f565b600090815260136020526040902054600160601b90046001600160a01b031690565b348015610d2d57600080fd5b50610597610d3c3660046155ce565b61288b565b348015610d4d57600080fd5b50610597610d5c36600461560c565b6128d9565b348015610d6d57600080fd5b5060155461055f906001600160a01b031681565b348015610d8d57600080fd5b506104c4610d9c36600461512f565b612ba8565b610597610daf366004615308565b612c3b565b348015610dc057600080fd5b506104f97f9a1ad8626c8e414784b966be6c93b2550ea90ccdf34423b1e4aca0c3b942ada581565b348015610df457600080fd5b50610597610e03366004615287565b612d24565b348015610e1457600080fd5b50610597610e23366004615659565b612d7b565b348015610e3457600080fd5b50610597610e433660046156c7565b612db5565b348015610e5457600080fd5b506104f9610e6336600461512f565b6000908152601360205260409020600101546001600160801b031690565b348015610e8d57600080fd5b506104c4610e9c36600461512f565b6000908152601060205260409020546001600160801b90910461ffff161190565b348015610ec957600080fd5b506104c4610ed836600461512f565b600090815260136020526040902054600160401b900463ffffffff16151590565b348015610f0557600080fd5b50610597612fc3565b348015610f1a57600080fd5b5061051c610f2936600461512f565b6130a1565b348015610f3a57600080fd5b50610597610f493660046156c7565b613113565b348015610f5a57600080fd5b506104f9610f6936600461512f565b600090815260136020526040902054600160401b900463ffffffff1690565b610597610f96366004615474565b613320565b348015610fa757600080fd5b506104f9610fb636600461512f565b6000908152601060205260409020546001600160801b031690565b348015610fdd57600080fd5b506009546104c490600160a01b900460ff1681565b348015610ffe57600080fd5b50600b5461055f906001600160a01b031681565b34801561101e57600080fd5b506105976133f1565b34801561103357600080fd5b5061059761104236600461526c565b61346b565b34801561105357600080fd5b506105976110623660046151b6565b6134b8565b34801561107357600080fd5b5061051c60405180604001604052806016815260200175447269766572734c696d6974656445646974696f6e7360501b81525081565b3480156110b557600080fd5b5061051c613506565b3480156110ca57600080fd5b506104c46110d93660046155ce565b600560209081526000928352604080842090915290825290205460ff1681565b34801561110557600080fd5b506104f961111436600461512f565b600090815260106020526040902054600160901b900461ffff1690565b34801561113d57600080fd5b506104f961114c36600461512f565b600090815260136020526040902060010154600160801b90046001600160801b031690565b34801561117d57600080fd5b50600f546104c49060ff1681565b60006001600160e01b0319821663152a902d60e11b14806111b057506111b082613513565b92915050565b60006103e882106111c5575090565b6111b06103e883615716565b600080546111de9061572a565b80601f016020809104026020016040519081016040528092919081815260200182805461120a9061572a565b80156112575780601f1061122c57610100808354040283529160200191611257565b820191906000526020600020905b81548152906001019060200180831161123a57829003601f168201915b505050505081565b81600f5460ff16156112745761127481613561565b61127e83836135a5565b505050565b6006546001600160a01b03163314806112ab57503360009081526007602052604090205460ff165b6112d05760405162461bcd60e51b81526004016112c790615764565b60405180910390fd5b6000838152601060209081526040808320815160c08101835290546001600160801b038116825261ffff600160801b82048116948301859052600160901b8204169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a0820152910361136b576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b03808416825282151560a08301908152600086815260106020908152604091829020855181549287015184880151606089015160808a015197511515600160b01b0260ff60b01b19981515600160a81b029890981661ffff60a81b19911515600160a01b0260ff60a01b1961ffff948516600160901b021662ffffff60901b1994909516600160801b026001600160901b031990981695909a1694909417959095171617959095179190911693909317919091179091555184907fc190e68218b7249bd1d46cf62b59253a4b51eed2bfb8924a7a56661fb9a473489061145990849061578a565b60405180910390a250505050565b6000818152601360208181526040808420815160c081018352815463ffffffff8082168352600160201b8204811683870152600160401b820416938201849052600160601b90046001600160a01b031660608201526001909101546001600160801b038082166080840152600160801b9091041660a08201528585529290915215801590819061150d57508151604083015161150391906157e7565b63ffffffff164210155b949350505050565b6006546001600160a01b031633148061153d57503360009081526007602052604090205460ff165b6115595760405162461bcd60e51b81526004016112c790615764565b6000838152601060209081526040808320815160c08101835290546001600160801b038116825261ffff600160801b82048116948301859052600160901b8204169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a082015291036115f4576040516347c0cce560e01b815260040160405180910390fd5b82151560608201908152821515608083019081526000868152601060209081526040918290208551815492870151848801519651955160a08901511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19971515600160a01b0260ff60a01b1961ffff9a8b16600160901b021662ffffff60901b199a909416600160801b026001600160901b03199097166001600160801b03909516949094179590951797909716171793909316179290921790555184907fea454d1e05d501c547b57c90d87e01eaef34d99308681d143ec564111cf7763a9061145990849061578a565b6006546001600160a01b031633148061170757503360009081526007602052604090205460ff165b6117235760405162461bcd60e51b81526004016112c790615764565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b60006103e8821061178257506000919050565b6111b06103e88361580b565b6006546001600160a01b03163314806117b657503360009081526007602052604090205460ff165b6117d25760405162461bcd60e51b81526004016112c790615764565b60158054911515600160a01b0260ff60a01b19909216919091179055565b6006546001600160a01b031633148061181857503360009081526007602052604090205460ff165b6118345760405162461bcd60e51b81526004016112c790615764565b6001600160a01b038116600081815260076020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b03163314806118a657503360009081526007602052604090205460ff165b6118c25760405162461bcd60e51b81526004016112c790615764565b806001600160801b03166000036118ec57604051633646340760e21b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a082015291036119865760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff16156119af5760405163628e388360e01b815260040160405180910390fd5b6001600160801b0380831660a0830181815260008681526013602090815260408083208751815493890151838a015160608b01516001600160a01b0316600160601b026001600160601b0363ffffffff928316600160401b02166001600160401b03938316600160201b0267ffffffffffffffff199098169290941691909117959095171617929092178255608087015193518616600160801b0293909516929092176001909201919091559151909185917fd44c1f367e4b7835166bd3805433cc6133391fa6e0099d7303ec10205c9efcb89190a3505050565b601554600160a01b900460ff16611ab457604051637e19eeed60e11b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a0840152611b4a5750611b4885858585613687565b155b15611b6857604051638baa579f60e01b815260040160405180910390fd5b611b738585836137e0565b5050505050565b826001600160a01b0381163314611b9f57600f5460ff1615611b9f57611b9f33613561565b611baa848484613b33565b50505050565b600a546001600160a01b0381169060009061271090611bdf90600160a01b90046001600160601b03168561581f565b611be99190615716565b90509250929050565b6000818152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b8204811695830195909552600160401b8104909416928101839052600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a0830152909103611c8f576040516301dff5d560e71b815260040160405180910390fd5b805160408201514291611ca1916157e7565b63ffffffff161115611cc657604051636463738960e01b815260040160405180910390fd5b600b546000838152600260205260409020546001600160a01b03908116911614611d0357604051631b42fb7f60e31b815260040160405180910390fd5b611d11816060015183613cc4565b60405182907f7bb9aafce2f4a89681d211146eaa6c59ec03a137171363e78aa243d7d0bf36d890600090a26014805460001901905560405182907f2be75b1f4f563cd2d2d28f28e51ddcb63c202fa685d6202078fa5376c8269d3490611d78908490615836565b60405180910390a25050565b6006546001600160a01b0316331480611dac57503360009081526007602052604090205460ff165b611dc85760405162461bcd60e51b81526004016112c790615764565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b826001600160a01b0381163314611e1857600f5460ff1615611e1857611e1833613561565b611baa848484613dca565b33611e2d826122ae565b6001600160a01b031614611e6f5760405162461bcd60e51b81526020600482015260096024820152682727aa2fa7aba722a960b91b60448201526064016112c7565b611e7881613ebd565b50565b6006546001600160a01b0316331480611ea357503360009081526007602052604090205460ff165b611ebf5760405162461bcd60e51b81526004016112c790615764565b611ecd6103e8600019615716565b861115611eed57604051630a779b1560e21b815260040160405180910390fd5b8361ffff16600003611f1257604051634d74210f60e11b815260040160405180910390fd5b611f1f60016103e861589a565b8461ffff161115611f43576040516317ee9bc760e21b815260040160405180910390fd5b600086815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b82048116938301849052600160901b8204169382019390935260ff600160a01b8404811615156060830152600160a81b8404811615156080830152600160b01b909304909216151560a083015215611fde576040516320705a1b60e11b815260040160405180910390fd5b6001600160801b03808716825261ffff8087166020808501918252871515606086019081528715156080870190815287151560a0880190815260008e81526010909452604093849020885181549651868b01519551945193511515600160b01b0260ff60b01b19941515600160a81b029490941661ffff60a81b19951515600160a01b0260ff60a01b19978b16600160901b029790971662ffffff60901b1992909a16600160801b026001600160901b031990991692909a16919091179690961795909516959095179190911716939093179190911790555187907f2f4457ef75a9f3a9d9845f891558d05d38ead4a1df33f2d5a3c14bfe653fba8c906120e690849061578a565b60405180910390a28461ffff1660010361211557600b54612110906001600160a01b031688613f78565b612161565b60005b8561ffff1681101561215f57600b5461214d906001600160a01b03166121488a6121438560016158ad565b61404d565b613f78565b80612157816158c0565b915050612118565b505b50505050505050565b6006546001600160a01b031633148061219257503360009081526007602052604090205460ff165b6121ae5760405162461bcd60e51b81526004016112c790615764565b6121b88282614066565b5050565b6006546001600160a01b03163314806121e457503360009081526007602052604090205460ff165b6122005760405162461bcd60e51b81526004016112c790615764565b601554611e789082906001600160a01b03166140db565b61221f614227565b565b6006546001600160a01b031633148061224957503360009081526007602052604090205460ff165b6122655760405162461bcd60e51b81526004016112c790615764565b6001600160a01b03811661228c57604051631f4c499760e01b815260040160405180910390fd5b601580546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600260205260409020546001600160a01b0316806123005760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016112c7565b919050565b601554600160a01b900460ff1661232f57604051637e19eeed60e11b815260040160405180910390fd5b600082815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a08301526123cb57604051630426ff7760e01b815260040160405180910390fd5b61127e8383836137e0565b60006123e2838361404d565b9392505050565b6006546001600160a01b031633148061241157503360009081526007602052604090205460ff165b61242d5760405162461bcd60e51b81526004016112c790615764565b6001600160a01b038116600081815260076020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b60006001600160a01b0382166124c15760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b60448201526064016112c7565b506001600160a01b031660009081526003602052604090205490565b6000818152601360208181526040808420815160c081018352815463ffffffff8082168352600160201b8204811683870152600160401b820416938201849052600160601b90046001600160a01b031660608201526001909101546001600160801b038082166080840152600160801b9091041660a08201528585529290915215158061256b57600061257c565b8151602083015161257c91906157e7565b63ffffffff16949350505050565b601554600160a01b900460ff166125b457604051637e19eeed60e11b815260040160405180910390fd5b600083815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a084015261264a575061264884338585613687565b155b1561266857604051638baa579f60e01b815260040160405180910390fd5b611baa8482614246565b6006546001600160a01b031633148061269a57503360009081526007602052604090205460ff165b6126b65760405162461bcd60e51b81526004016112c790615764565b600c6121b8828261591f565b600180546111de9061572a565b6006546001600160a01b03163314806126f757503360009081526007602052604090205460ff165b6127135760405162461bcd60e51b81526004016112c790615764565b600081815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b8204811694830194909452600160401b810490931693810193909352600160601b9091046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201526121b88282614546565b601554600160a01b900460ff166127c657604051637e19eeed60e11b815260040160405180910390fd5b600081815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a083015261286257604051630426ff7760e01b815260040160405180910390fd5b6121b88282614246565b81600f5460ff16156128815761288181613561565b61127e83836145f4565b6006546001600160a01b03163314806128b357503360009081526007602052604090205460ff165b6128cf5760405162461bcd60e51b81526004016112c790615764565b6121b882826140db565b6006546001600160a01b031633148061290157503360009081526007602052604090205460ff165b61291d5760405162461bcd60e51b81526004016112c790615764565b8263ffffffff16600003612944576040516335f7aa5b60e11b815260040160405180910390fd5b8163ffffffff1660000361296b57604051634b6e1bd360e01b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b82048116938301849052600160901b8204169382019390935260ff600160a01b8404811615156060830152600160a81b8404811615156080830152600160b01b909304909216151560a0830152600114612a0857604051630eea117d60e31b815260040160405180910390fd5b600085815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b82048116948301859052600160401b82041694820194909452600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a083015215612aa157604051628b039960e31b815260040160405180910390fd5b63ffffffff808616825284811660208084019182526001600160801b0380871660a0860190815260008b815260139093526040928390208651815495518589015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199099169390991692909217969096179590951695909517939093178455608085015192518116600160801b02921691909117600192830155601480549092019091555186907f67e0934daec5a59c2ce373b1d94d8160057ae0a6cfa7a01ccdfc12d63f5ae7fb90612b98908490615836565b60405180910390a2505050505050565b6000818152601060209081526040808320815160c08101835290546001600160801b03811680835261ffff600160801b8304811695840195909552600160901b82049094169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a0820152901580156123e2575060a0015192915050565b601554600160a01b900460ff16612c6557604051637e19eeed60e11b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a0840152612cfb5750612cf985858585613687565b155b15612d1957604051638baa579f60e01b815260040160405180910390fd5b611b73858583614660565b6006546001600160a01b0316331480612d4c57503360009081526007602052604090205460ff165b612d685760405162461bcd60e51b81526004016112c790615764565b600f805460ff1916911515919091179055565b846001600160a01b0381163314612da057600f5460ff1615612da057612da033613561565b612dad8686868686614886565b505050505050565b6006546001600160a01b0316331480612ddd57503360009081526007602052604090205460ff165b612df95760405162461bcd60e51b81526004016112c790615764565b8063ffffffff16600003612e2057604051634b6e1bd360e01b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201529103612eba5760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff1615612ee35760405163628e388360e01b815260040160405180910390fd5b63ffffffff80831660208084018281526000878152601390925260408083208651815493518389015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199097169390991692909217949094179390931695909517919091178455608085015160a08601516001600160801b03908116600160801b029116176001909401939093559151909185917f7076391b57145201e1b1e818500795c44fda2ae9af4dc5f2ea3d36a5539eb7779190a3505050565b6006546001600160a01b0316331480612feb57503360009081526007602052604090205460ff165b6130075760405162461bcd60e51b81526004016112c790615764565b6014541561302857604051630745ab4760e51b815260040160405180910390fd5b60155461303d906001600160a01b0316614967565b601560009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561308d57600080fd5b505af1158015611baa573d6000803e3d6000fd5b60095460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa1580156130eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b091908101906159de565b6006546001600160a01b031633148061313b57503360009081526007602052604090205460ff165b6131575760405162461bcd60e51b81526004016112c790615764565b8063ffffffff1660000361317e576040516335f7aa5b60e11b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a082015291036132185760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff16156132415760405163628e388360e01b815260040160405180910390fd5b63ffffffff808316808352600085815260136020908152604080832086518154938801518389015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199097169390991692909217949094179390931695909517919091178455608085015160a08601516001600160801b03908116600160801b029116176001909401939093559151909185917f9702db1e67fa6b64b8288101859f3b327a978f15d66e12ad769e5bbf30814d289190a3505050565b601554600160a01b900460ff1661334a57604051637e19eeed60e11b815260040160405180910390fd5b600082815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a08301526133e657604051630426ff7760e01b815260040160405180910390fd5b61127e838383614660565b6006546001600160a01b031633148061341957503360009081526007602052604090205460ff165b6134355760405162461bcd60e51b81526004016112c790615764565b6014541561345657604051630745ab4760e51b815260040160405180910390fd5b60155461221f906001600160a01b0316614967565b6006546001600160a01b031633148061349357503360009081526007602052604090205460ff165b6134af5760405162461bcd60e51b81526004016112c790615764565b611e7881614a25565b6006546001600160a01b03163314806134e057503360009081526007602052604090205460ff165b6134fc5760405162461bcd60e51b81526004016112c790615764565b6121b88282614a9a565b600c80546111de9061572a565b60006301ffc9a760e01b6001600160e01b03198316148061354457506380ac58cd60e01b6001600160e01b03198316145b806111b05750506001600160e01b031916635b5e139f60e01b1490565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa61359d573d6000803e3d6000fd5b6000603a5250565b6000818152600260205260409020546001600160a01b0316338114806135ee57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b61362b5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016112c7565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080516080810182528581526001600160a01b03851660208083018290526000918252600e815283822054838501528351601f860182900482028101820190945284845290928392916060830191908790879081908401838280828437600092018290525093909452505082516020808501516001600160a01b0381168452600e909152604083208054959650929461378f94507f9a1ad8626c8e414784b966be6c93b2550ea90ccdf34423b1e4aca0c3b942ada59386613748836158c0565b909155506040805160208101959095528401929092526001600160a01b03166060830152608082015260a00160405160208183030381529060405280519060200120614b1d565b905060006137a1828460600151614b6b565b6001600160a01b0381166000908152600d602052604090205490915060ff1680156137d457506001600160a01b03811615155b98975050505050505050565b806020015161ffff1660011461380957604051630eea117d60e31b815260040160405180910390fd5b8060a00151158015613823575080516001600160801b0316155b1561384157604051631d99ddbf60e01b815260040160405180910390fd5b80516001600160801b0316341461386b57604051636992e1ff60e01b815260040160405180910390fd5b80606001518015613882575061388082614b8f565b155b156138a057604051633664886760e11b815260040160405180910390fd5b600083815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b8204811694830194909452600160401b8104909316938101849052600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201529015613a375760408101516139399063ffffffff164261589a565b63ffffffff908116825260008581526013602090815260409182902084518154928601519386015160608701516001600160a01b038116600160601b026001600160601b03928816600160401b02929092166001600160401b03968816600160201b0267ffffffffffffffff199096169390971692909217939093179390931693909317178255608083015160a08401516001600160801b03908116600160801b0291169081176001909301929092556139f291614ba2565b6014805460001901905560405184907f4215ff61a9831416ed985d067257b9f8802a061f560876a779ebc5f3c6189fe890613a2e908490615836565b60405180910390a25b6040808301805161ffff600190910181168252600087815260106020908152939020855181549487015193516060880151608089015160a08a01511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19921515600160a01b0260ff60a01b19948816600160901b029490941662ffffff60901b1998909716600160801b026001600160901b03199099166001600160801b0390951694909417979097179590951693909317929092179290921617919091179055613b028385613cc4565b60405184907f7bb9aafce2f4a89681d211146eaa6c59ec03a137171363e78aa243d7d0bf36d890600090a250505050565b6000818152600260205260409020546001600160a01b03848116911614613b895760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016112c7565b6001600160a01b038216613baf5760405162461bcd60e51b81526004016112c790615a54565b336001600160a01b0384161480613be957506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80613c0a57506000818152600460205260409020546001600160a01b031633145b613c475760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016112c7565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b0319908116831790915560049092528483208054909216909155925184939291600080516020615b7483398151915291a4505050565b600081815260026020526040902054600b546001600160a01b03908116911614613d1d5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016112c7565b6001600160a01b038216613d435760405162461bcd60e51b81526004016112c790615a54565b600b80546001600160a01b0390811660009081526003602090815260408083208054600019019055868416808452818420805460010190558684526002835281842080546001600160a01b031990811683179091556004909352818420805490931690925593549351859491939190911691600080516020615b7483398151915291a45050565b613dd5838383611b7a565b6001600160a01b0382163b1580613e7e5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015613e4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e729190615a7f565b6001600160e01b031916145b61127e5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016112c7565b6000818152600260205260409020546001600160a01b031680613f0f5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016112c7565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b03199081169091556004909252808320805490921690915551849290600080516020615b74833981519152908390a45050565b6001600160a01b038216613f9e5760405162461bcd60e51b81526004016112c790615a54565b6000818152600260205260409020546001600160a01b031615613ff45760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b60448201526064016112c7565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020615b74833981519152908290a45050565b60008161405c6103e88561581f565b6123e291906158ad565b6001600160a01b0390911690637d3e3dbe81614093578261408c5750634420e486614093565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16140d1578060005160e01c036140d157600080fd5b5060006024525050565b6001600160a01b0381166141025760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015614149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061416d9190615a9c565b9050806000036141905760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af11580156141e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142079190615ab5565b905080611baa57604051631d42c86760e21b815260040160405180910390fd5b61221f733cc6cdda760b79bafa08df41ecfa224f810dceb66001614066565b8060600151801561425d575061425b33614b8f565b155b1561427b57604051633664886760e11b815260040160405180910390fd5b600082815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b82048116948301859052600160401b82041694820194909452600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a0830152158061430c575042816020015163ffffffff16115b1561432a576040516301dff5d560e71b815260040160405180910390fd5b806040015163ffffffff1660000361439257348160a001516001600160801b031611156143815760a0810151604051635cf8b88960e11b81526001600160801b0390911660048201523460248201526044016112c7565b63ffffffff42166040820152614431565b805160408201516143a391906157e7565b63ffffffff164211156143c95760405163283a4a6160e21b815260040160405180910390fd5b600081608001516001600160801b03169050600060646012548302816143f1576143f16156ea565b0482019050348111156144205760405163bc1510d560e01b8152600481018290523460248201526044016112c7565b61442e836060015183614ba2565b50505b346001600160601b0316608082015233606082015280516040820151601154429190920163ffffffff16039081101561447757601154825163ffffffff91839003011682525b60008481526013602090815260409182902084518154928601518487015160608801516001600160a01b0316600160601b026001600160601b0363ffffffff928316600160401b02166001600160401b03938316600160201b0267ffffffffffffffff199097169290941691909117949094171617919091178155608084015160a08501516001600160801b03908116600160801b029116176001909101555184907f90e14ed1433e5f6856e46c6068401974e908b3ef4a8ecd5401cbd68d8b4c2a1f90611459908590615836565b604081015163ffffffff16156145a8578051604082015161456791906157e7565b63ffffffff1642111561458d5760405163283a4a6160e21b815260040160405180910390fd5b6145a8816060015182608001516001600160801b0316614ba2565b600082815260136020526040808220828155600101829055601480546000190190555183917f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df91a25050565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6002816020015161ffff16101561468a57604051630556890560e01b815260040160405180910390fd5b806020015161ffff16816040015160016146a49190615ad2565b61ffff1611156146c75760405163a8fda6c160e01b815260040160405180910390fd5b8060a001511580156146e1575080516001600160801b0316155b156146ff57604051631d99ddbf60e01b815260040160405180910390fd5b80516001600160801b0316341461472957604051636992e1ff60e01b815260040160405180910390fd5b80606001518015614740575061473e82614b8f565b155b1561475e57604051633664886760e11b815260040160405180910390fd5b6000816040015160016147719190615ad2565b61ffff1690506000614783858361404d565b6040808501805161ffff6001909101811682526000898152601060209081529390208751815494890151935160608a015160808b015160a08c01511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19921515600160a01b0260ff60a01b19948816600160901b029490941662ffffff60901b1998909716600160801b026001600160901b03199099166001600160801b039095169490941797909717959095169390931792909217929092161791909117905590506148508482613cc4565b8082867fdf5fda6ef84c661a9a8c7217395c3d91bc7e519453e81fcbfa1f0f2d19a8d5be60405160405180910390a45050505050565b614891858585611b7a565b6001600160a01b0384163b15806149285750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906148d99033908a90899089908990600401615aed565b6020604051808303816000875af11580156148f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061491c9190615a7f565b6001600160e01b031916145b611b735760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016112c7565b6001600160a01b03811661498e5760405163172fe2d160e01b815260040160405180910390fd5b4760008190036149b15760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146149fe576040519150601f19603f3d011682016040523d82523d6000602084013e614a03565b606091505b505090508061127e57604051631d42c86760e21b815260040160405180910390fd5b600954600160a01b900460ff1615614a50576040516313ef243160e11b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115614abd576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b9091028117600a5590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b60006111b0614b2a614c97565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000614b7a8585614dbe565b91509150614b8781614e03565b509392505050565b600080614b9b83614f4d565b1192915050565b614bac8282614fc1565b6121b857600f60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015614c0057600080fd5b505af1158015614c14573d6000803e3d6000fd5b5050600f5460405163a9059cbb60e01b81526001600160a01b03878116600483015260248201879052610100909204909116935063a9059cbb925060440190506020604051808303816000875af1158015614c73573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127e9190615ab5565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015614cf057507f000000000000000000000000000000000000000000000000000000000000000046145b15614d1a57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000808251604103614df45760208301516040840151606085015160001a614de887828585615038565b94509450505050614dfc565b506000905060025b9250929050565b6000816004811115614e1757614e17615b41565b03614e1f5750565b6001816004811115614e3357614e33615b41565b03614e805760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016112c7565b6002816004811115614e9457614e94615b41565b03614ee15760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016112c7565b6003816004811115614ef557614ef5615b41565b03611e785760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016112c7565b600854604051627eeac760e11b81526001600160a01b03838116600483015260016024830152600092169062fdd58e90604401602060405180830381865afa158015614f9d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b09190615a9c565b60408051600080825260208201928390529182916001600160a01b038616918591614feb91615b57565b60006040518083038185875af1925050503d8060008114615028576040519150601f19603f3d011682016040523d82523d6000602084013e61502d565b606091505b509095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561506f57506000905060036150f3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156150c3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166150ec576000600192509250506150f3565b9150600090505b94509492505050565b6001600160e01b031981168114611e7857600080fd5b60006020828403121561512457600080fd5b81356123e2816150fc565b60006020828403121561514157600080fd5b5035919050565b60005b8381101561516357818101518382015260200161514b565b50506000910152565b602081526000825180602084015261518b816040850160208701615148565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461230057600080fd5b600080604083850312156151c957600080fd5b6151d28361519f565b946020939093013593505050565b80356001600160801b038116811461230057600080fd5b8015158114611e7857600080fd5b60008060006060848603121561521a57600080fd5b8335925061522a602085016151e0565b9150604084013561523a816151f7565b809150509250925092565b60008060006060848603121561525a57600080fd5b83359250602084013561522a816151f7565b60006020828403121561527e57600080fd5b6123e28261519f565b60006020828403121561529957600080fd5b81356123e2816151f7565b600080604083850312156152b757600080fd5b82359150611be9602084016151e0565b60008083601f8401126152d957600080fd5b5081356001600160401b038111156152f057600080fd5b602083019150836020828501011115614dfc57600080fd5b6000806000806060858703121561531e57600080fd5b8435935061532e6020860161519f565b925060408501356001600160401b0381111561534957600080fd5b615355878288016152c7565b95989497509550505050565b60008060006060848603121561537657600080fd5b61537f8461519f565b925061538d6020850161519f565b9150604084013590509250925092565b600080604083850312156153b057600080fd5b50508035926020909101359150565b600080604083850312156153d257600080fd5b6153db8361519f565b915060208301356153eb816151f7565b809150509250929050565b60008060008060008060c0878903121561540f57600080fd5b8635955061541f602088016151e0565b9450604087013561ffff8116811461543657600080fd5b93506060870135615446816151f7565b92506080870135615456816151f7565b915060a0870135615466816151f7565b809150509295509295509295565b6000806040838503121561548757600080fd5b82359150611be96020840161519f565b6000806000604084860312156154ac57600080fd5b8335925060208401356001600160401b038111156154c957600080fd5b6154d5868287016152c7565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615520576155206154e2565b604052919050565b60006001600160401b03821115615541576155416154e2565b50601f01601f191660200190565b60006020828403121561556157600080fd5b81356001600160401b0381111561557757600080fd5b8201601f8101841361558857600080fd5b803561559b61559682615528565b6154f8565b8181528560208385010111156155b057600080fd5b81602084016020830137600091810160200191909152949350505050565b600080604083850312156155e157600080fd5b6155ea8361519f565b9150611be96020840161519f565b803563ffffffff8116811461230057600080fd5b6000806000806080858703121561562257600080fd5b84359350615632602086016155f8565b9250615640604086016155f8565b915061564e606086016151e0565b905092959194509250565b60008060008060006080868803121561567157600080fd5b61567a8661519f565b94506156886020870161519f565b93506040860135925060608601356001600160401b038111156156aa57600080fd5b6156b6888289016152c7565b969995985093965092949392505050565b600080604083850312156156da57600080fd5b82359150611be9602084016155f8565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082615725576157256156ea565b500490565b600181811c9082168061573e57607f821691505b60208210810361575e57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060c0820190506001600160801b038351168252602083015161ffff8082166020850152806040860151166040850152505060608301511515606083015260808301511515608083015260a0830151151560a083015292915050565b63ffffffff81811683821601908082111561580457615804615700565b5092915050565b60008261581a5761581a6156ea565b500690565b80820281158282048414176111b0576111b0615700565b815163ffffffff9081168252602080840151821690830152604080840151909116908201526060808301516001600160a01b0316908201526080808301516001600160801b039081169183019190915260a092830151169181019190915260c00190565b818103818111156111b0576111b0615700565b808201808211156111b0576111b0615700565b6000600182016158d2576158d2615700565b5060010190565b601f82111561127e57600081815260208120601f850160051c810160208610156159005750805b601f850160051c820191505b81811015612dad5782815560010161590c565b81516001600160401b03811115615938576159386154e2565b61594c81615946845461572a565b846158d9565b602080601f83116001811461598157600084156159695750858301515b600019600386901b1c1916600185901b178555612dad565b600085815260208120601f198616915b828110156159b057888601518255948401946001909101908401615991565b50858210156159ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156159f057600080fd5b81516001600160401b03811115615a0657600080fd5b8201601f81018413615a1757600080fd5b8051615a2561559682615528565b818152856020838501011115615a3a57600080fd5b615a4b826020830160208601615148565b95945050505050565b6020808252601190820152701253959053125117d49150d25412515395607a1b604082015260600190565b600060208284031215615a9157600080fd5b81516123e2816150fc565b600060208284031215615aae57600080fd5b5051919050565b600060208284031215615ac757600080fd5b81516123e2816151f7565b61ffff81811683821601908082111561580457615804615700565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b634e487b7160e01b600052602160045260246000fd5b60008251615b69818460208701615148565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c6343000811000a44726976657273204c696d697465642045646974696f6e73206279204576657266726573680000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf00000000000000000000000000000000000000000000000000000000000002ee0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e300000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

Deployed Bytecode

0x60806040526004361061049f5760003560e01c8063864bc0a011610260578063b9c2443d11610144578063d7e45cd7116100c1578063e3faad9411610085578063e3faad9414611067578063e8a3d485146110a9578063e985e9c5146110be578063ef6ea27a146110f9578063f9e3c46f14611131578063fb796e6c1461117157600080fd5b8063d7e45cd714610fd1578063e07b1afb14610ff2578063e086e5ec14611012578063e17b25af14611027578063e2e784d51461104757600080fd5b8063c87b56dd11610108578063c87b56dd14610f0e578063cb93752814610f2e578063d2e4b90514610f4e578063d46e7ae114610f88578063d4ddce8a14610f9b57600080fd5b8063b9c2443d14610e28578063bdaaf19414610e48578063bf40defb14610e81578063bfe29d5714610ebd578063c0fd735b14610ef957600080fd5b8063a2df15e2116101dd578063a6d23e10116101a1578063a6d23e1014610d61578063aa05234114610d81578063abadb36514610da1578063af4fddfa14610db4578063b7c0b8e814610de8578063b88d4fde14610e0857600080fd5b8063a2df15e214610ca1578063a415729614610cb7578063a43b87a214610ce4578063a522ad2514610d21578063a5aef37d14610d4157600080fd5b806395d89b411161022457806395d89b4114610c0657806396b5a75514610c1b5780639886973114610c3b5780639979ef4514610c6e578063a22cb46514610c8157600080fd5b8063864bc0a014610b6d5780638a87551214610b805780638da5cb5b14610bb0578063923d8dfa14610bd0578063938e3d7b14610be657600080fd5b8063392f37e9116103875780635e1c074611610304578063695747c2116102c8578063695747c214610a88578063702f9bbe14610aa85780637048027514610ae057806370a0823114610b00578063777de70414610b205780637ecebe0014610b4057600080fd5b80635e1c0746146109e95780635e1e1004146109fe578063633511bb14610a1e5780636352211e14610a5557806365a1e83314610a7557600080fd5b80634588d1c71161034b5780634588d1c7146108ac57806346d8efad146108cc57806349df728c146108ec5780635090d0c61461090c578063571a26a01461092257600080fd5b8063392f37e9146107f75780633fc8cef31461081757806342842e0e1461083c57806342966c681461085c578063429b62e51461087c57600080fd5b80631551b7c11161042057806326645a2c116103e457806326645a2c146106cc5780632a55205a146107035780632e9936111461074257806331cb61051461076257806331ccd4bc1461078257806333465c5f146107bd57600080fd5b80631551b7c1146106395780631785f53c1461065957806319ffb5831461067957806320f3f8451461069957806323b872dd146106ac57600080fd5b80630a87c3cf116104675780630a87c3cf146105995780630e9e835c146105b957806311a774fd146105d957806313af4035146105f957806314dfc68e1461061957600080fd5b806301ffc9a7146104a457806306d715fa146104d957806306fdde0314610507578063081812fc14610529578063095ea7b314610577575b600080fd5b3480156104b057600080fd5b506104c46104bf366004615112565b61118b565b60405190151581526020015b60405180910390f35b3480156104e557600080fd5b506104f96104f436600461512f565b6111b6565b6040519081526020016104d0565b34801561051357600080fd5b5061051c6111d1565b6040516104d0919061516c565b34801561053557600080fd5b5061055f61054436600461512f565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016104d0565b34801561058357600080fd5b506105976105923660046151b6565b61125f565b005b3480156105a557600080fd5b506105976105b4366004615205565b611283565b3480156105c557600080fd5b506104c46105d436600461512f565b611467565b3480156105e557600080fd5b506105976105f4366004615245565b611515565b34801561060557600080fd5b5061059761061436600461526c565b6116df565b34801561062557600080fd5b506104f961063436600461512f565b61176f565b34801561064557600080fd5b50610597610654366004615287565b61178e565b34801561066557600080fd5b5061059761067436600461526c565b6117f0565b34801561068557600080fd5b506105976106943660046152a4565b61187e565b6105976106a7366004615308565b611a8a565b3480156106b857600080fd5b506105976106c7366004615361565b611b7a565b3480156106d857600080fd5b506104c46106e736600461512f565b600090815260106020526040902054600160a01b900460ff1690565b34801561070f57600080fd5b5061072361071e36600461539d565b611bb0565b604080516001600160a01b0390931683526020830191909152016104d0565b34801561074e57600080fd5b5061059761075d36600461512f565b611bf2565b34801561076e57600080fd5b5061059761077d3660046153bf565b611d84565b34801561078e57600080fd5b506104c461079d36600461512f565b600090815260106020526040902054600160801b900461ffff1660011490565b3480156107c957600080fd5b506104f96107d836600461512f565b600090815260136020526040902054600160201b900463ffffffff1690565b34801561080357600080fd5b5060095461055f906001600160a01b031681565b34801561082357600080fd5b50600f5461055f9061010090046001600160a01b031681565b34801561084857600080fd5b50610597610857366004615361565b611df3565b34801561086857600080fd5b5061059761087736600461512f565b611e23565b34801561088857600080fd5b506104c461089736600461526c565b60076020526000908152604090205460ff1681565b3480156108b857600080fd5b506105976108c73660046153f6565b611e7b565b3480156108d857600080fd5b506105976108e73660046153bf565b61216a565b3480156108f857600080fd5b5061059761090736600461526c565b6121bc565b34801561091857600080fd5b506104f960145481565b34801561092e57600080fd5b5061099a61093d36600461512f565b6013602052600090815260409020805460019091015463ffffffff80831692600160201b8104821692600160401b820490921691600160601b9091046001600160a01b0316906001600160801b0380821691600160801b90041686565b6040805163ffffffff9788168152958716602087015293909516928401929092526001600160a01b031660608301526001600160801b03908116608083015290911660a082015260c0016104d0565b3480156109f557600080fd5b50610597612217565b348015610a0a57600080fd5b50610597610a1936600461526c565b612221565b348015610a2a57600080fd5b506104c4610a3936600461512f565b600090815260106020526040902054600160a81b900460ff1690565b348015610a6157600080fd5b5061055f610a7036600461512f565b6122ae565b610597610a83366004615474565b612305565b348015610a9457600080fd5b506104f9610aa336600461539d565b6123d6565b348015610ab457600080fd5b506104f9610ac336600461512f565b600090815260106020526040902054600160801b900461ffff1690565b348015610aec57600080fd5b50610597610afb36600461526c565b6123e9565b348015610b0c57600080fd5b506104f9610b1b36600461526c565b61247a565b348015610b2c57600080fd5b506104f9610b3b36600461512f565b6124dd565b348015610b4c57600080fd5b506104f9610b5b36600461526c565b600e6020526000908152604090205481565b610597610b7b366004615497565b61258a565b348015610b8c57600080fd5b506104c4610b9b36600461526c565b600d6020526000908152604090205460ff1681565b348015610bbc57600080fd5b5060065461055f906001600160a01b031681565b348015610bdc57600080fd5b506104f960125481565b348015610bf257600080fd5b50610597610c0136600461554f565b612672565b348015610c1257600080fd5b5061051c6126c2565b348015610c2757600080fd5b50610597610c3636600461512f565b6126cf565b348015610c4757600080fd5b506104f9610c5636600461512f565b60009081526013602052604090205463ffffffff1690565b610597610c7c36600461512f565b61279c565b348015610c8d57600080fd5b50610597610c9c3660046153bf565b61286c565b348015610cad57600080fd5b506104f960115481565b348015610cc357600080fd5b5061051c604051806040016040528060018152602001603160f81b81525081565b348015610cf057600080fd5b5061055f610cff36600461512f565b600090815260136020526040902054600160601b90046001600160a01b031690565b348015610d2d57600080fd5b50610597610d3c3660046155ce565b61288b565b348015610d4d57600080fd5b50610597610d5c36600461560c565b6128d9565b348015610d6d57600080fd5b5060155461055f906001600160a01b031681565b348015610d8d57600080fd5b506104c4610d9c36600461512f565b612ba8565b610597610daf366004615308565b612c3b565b348015610dc057600080fd5b506104f97f9a1ad8626c8e414784b966be6c93b2550ea90ccdf34423b1e4aca0c3b942ada581565b348015610df457600080fd5b50610597610e03366004615287565b612d24565b348015610e1457600080fd5b50610597610e23366004615659565b612d7b565b348015610e3457600080fd5b50610597610e433660046156c7565b612db5565b348015610e5457600080fd5b506104f9610e6336600461512f565b6000908152601360205260409020600101546001600160801b031690565b348015610e8d57600080fd5b506104c4610e9c36600461512f565b6000908152601060205260409020546001600160801b90910461ffff161190565b348015610ec957600080fd5b506104c4610ed836600461512f565b600090815260136020526040902054600160401b900463ffffffff16151590565b348015610f0557600080fd5b50610597612fc3565b348015610f1a57600080fd5b5061051c610f2936600461512f565b6130a1565b348015610f3a57600080fd5b50610597610f493660046156c7565b613113565b348015610f5a57600080fd5b506104f9610f6936600461512f565b600090815260136020526040902054600160401b900463ffffffff1690565b610597610f96366004615474565b613320565b348015610fa757600080fd5b506104f9610fb636600461512f565b6000908152601060205260409020546001600160801b031690565b348015610fdd57600080fd5b506009546104c490600160a01b900460ff1681565b348015610ffe57600080fd5b50600b5461055f906001600160a01b031681565b34801561101e57600080fd5b506105976133f1565b34801561103357600080fd5b5061059761104236600461526c565b61346b565b34801561105357600080fd5b506105976110623660046151b6565b6134b8565b34801561107357600080fd5b5061051c60405180604001604052806016815260200175447269766572734c696d6974656445646974696f6e7360501b81525081565b3480156110b557600080fd5b5061051c613506565b3480156110ca57600080fd5b506104c46110d93660046155ce565b600560209081526000928352604080842090915290825290205460ff1681565b34801561110557600080fd5b506104f961111436600461512f565b600090815260106020526040902054600160901b900461ffff1690565b34801561113d57600080fd5b506104f961114c36600461512f565b600090815260136020526040902060010154600160801b90046001600160801b031690565b34801561117d57600080fd5b50600f546104c49060ff1681565b60006001600160e01b0319821663152a902d60e11b14806111b057506111b082613513565b92915050565b60006103e882106111c5575090565b6111b06103e883615716565b600080546111de9061572a565b80601f016020809104026020016040519081016040528092919081815260200182805461120a9061572a565b80156112575780601f1061122c57610100808354040283529160200191611257565b820191906000526020600020905b81548152906001019060200180831161123a57829003601f168201915b505050505081565b81600f5460ff16156112745761127481613561565b61127e83836135a5565b505050565b6006546001600160a01b03163314806112ab57503360009081526007602052604090205460ff165b6112d05760405162461bcd60e51b81526004016112c790615764565b60405180910390fd5b6000838152601060209081526040808320815160c08101835290546001600160801b038116825261ffff600160801b82048116948301859052600160901b8204169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a0820152910361136b576040516347c0cce560e01b815260040160405180910390fd5b6001600160801b03808416825282151560a08301908152600086815260106020908152604091829020855181549287015184880151606089015160808a015197511515600160b01b0260ff60b01b19981515600160a81b029890981661ffff60a81b19911515600160a01b0260ff60a01b1961ffff948516600160901b021662ffffff60901b1994909516600160801b026001600160901b031990981695909a1694909417959095171617959095179190911693909317919091179091555184907fc190e68218b7249bd1d46cf62b59253a4b51eed2bfb8924a7a56661fb9a473489061145990849061578a565b60405180910390a250505050565b6000818152601360208181526040808420815160c081018352815463ffffffff8082168352600160201b8204811683870152600160401b820416938201849052600160601b90046001600160a01b031660608201526001909101546001600160801b038082166080840152600160801b9091041660a08201528585529290915215801590819061150d57508151604083015161150391906157e7565b63ffffffff164210155b949350505050565b6006546001600160a01b031633148061153d57503360009081526007602052604090205460ff165b6115595760405162461bcd60e51b81526004016112c790615764565b6000838152601060209081526040808320815160c08101835290546001600160801b038116825261ffff600160801b82048116948301859052600160901b8204169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a082015291036115f4576040516347c0cce560e01b815260040160405180910390fd5b82151560608201908152821515608083019081526000868152601060209081526040918290208551815492870151848801519651955160a08901511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19971515600160a01b0260ff60a01b1961ffff9a8b16600160901b021662ffffff60901b199a909416600160801b026001600160901b03199097166001600160801b03909516949094179590951797909716171793909316179290921790555184907fea454d1e05d501c547b57c90d87e01eaef34d99308681d143ec564111cf7763a9061145990849061578a565b6006546001600160a01b031633148061170757503360009081526007602052604090205460ff165b6117235760405162461bcd60e51b81526004016112c790615764565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b60006103e8821061178257506000919050565b6111b06103e88361580b565b6006546001600160a01b03163314806117b657503360009081526007602052604090205460ff165b6117d25760405162461bcd60e51b81526004016112c790615764565b60158054911515600160a01b0260ff60a01b19909216919091179055565b6006546001600160a01b031633148061181857503360009081526007602052604090205460ff165b6118345760405162461bcd60e51b81526004016112c790615764565b6001600160a01b038116600081815260076020526040808220805460ff19169055517fdb9d5d31320daf5bc7181d565b6da4d12e30f0f4d5aa324a992426c14a1d19ce908290a350565b6006546001600160a01b03163314806118a657503360009081526007602052604090205460ff165b6118c25760405162461bcd60e51b81526004016112c790615764565b806001600160801b03166000036118ec57604051633646340760e21b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a082015291036119865760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff16156119af5760405163628e388360e01b815260040160405180910390fd5b6001600160801b0380831660a0830181815260008681526013602090815260408083208751815493890151838a015160608b01516001600160a01b0316600160601b026001600160601b0363ffffffff928316600160401b02166001600160401b03938316600160201b0267ffffffffffffffff199098169290941691909117959095171617929092178255608087015193518616600160801b0293909516929092176001909201919091559151909185917fd44c1f367e4b7835166bd3805433cc6133391fa6e0099d7303ec10205c9efcb89190a3505050565b601554600160a01b900460ff16611ab457604051637e19eeed60e11b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a0840152611b4a5750611b4885858585613687565b155b15611b6857604051638baa579f60e01b815260040160405180910390fd5b611b738585836137e0565b5050505050565b826001600160a01b0381163314611b9f57600f5460ff1615611b9f57611b9f33613561565b611baa848484613b33565b50505050565b600a546001600160a01b0381169060009061271090611bdf90600160a01b90046001600160601b03168561581f565b611be99190615716565b90509250929050565b6000818152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b8204811695830195909552600160401b8104909416928101839052600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a0830152909103611c8f576040516301dff5d560e71b815260040160405180910390fd5b805160408201514291611ca1916157e7565b63ffffffff161115611cc657604051636463738960e01b815260040160405180910390fd5b600b546000838152600260205260409020546001600160a01b03908116911614611d0357604051631b42fb7f60e31b815260040160405180910390fd5b611d11816060015183613cc4565b60405182907f7bb9aafce2f4a89681d211146eaa6c59ec03a137171363e78aa243d7d0bf36d890600090a26014805460001901905560405182907f2be75b1f4f563cd2d2d28f28e51ddcb63c202fa685d6202078fa5376c8269d3490611d78908490615836565b60405180910390a25050565b6006546001600160a01b0316331480611dac57503360009081526007602052604090205460ff165b611dc85760405162461bcd60e51b81526004016112c790615764565b6001600160a01b03919091166000908152600d60205260409020805460ff1916911515919091179055565b826001600160a01b0381163314611e1857600f5460ff1615611e1857611e1833613561565b611baa848484613dca565b33611e2d826122ae565b6001600160a01b031614611e6f5760405162461bcd60e51b81526020600482015260096024820152682727aa2fa7aba722a960b91b60448201526064016112c7565b611e7881613ebd565b50565b6006546001600160a01b0316331480611ea357503360009081526007602052604090205460ff165b611ebf5760405162461bcd60e51b81526004016112c790615764565b611ecd6103e8600019615716565b861115611eed57604051630a779b1560e21b815260040160405180910390fd5b8361ffff16600003611f1257604051634d74210f60e11b815260040160405180910390fd5b611f1f60016103e861589a565b8461ffff161115611f43576040516317ee9bc760e21b815260040160405180910390fd5b600086815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b82048116938301849052600160901b8204169382019390935260ff600160a01b8404811615156060830152600160a81b8404811615156080830152600160b01b909304909216151560a083015215611fde576040516320705a1b60e11b815260040160405180910390fd5b6001600160801b03808716825261ffff8087166020808501918252871515606086019081528715156080870190815287151560a0880190815260008e81526010909452604093849020885181549651868b01519551945193511515600160b01b0260ff60b01b19941515600160a81b029490941661ffff60a81b19951515600160a01b0260ff60a01b19978b16600160901b029790971662ffffff60901b1992909a16600160801b026001600160901b031990991692909a16919091179690961795909516959095179190911716939093179190911790555187907f2f4457ef75a9f3a9d9845f891558d05d38ead4a1df33f2d5a3c14bfe653fba8c906120e690849061578a565b60405180910390a28461ffff1660010361211557600b54612110906001600160a01b031688613f78565b612161565b60005b8561ffff1681101561215f57600b5461214d906001600160a01b03166121488a6121438560016158ad565b61404d565b613f78565b80612157816158c0565b915050612118565b505b50505050505050565b6006546001600160a01b031633148061219257503360009081526007602052604090205460ff165b6121ae5760405162461bcd60e51b81526004016112c790615764565b6121b88282614066565b5050565b6006546001600160a01b03163314806121e457503360009081526007602052604090205460ff165b6122005760405162461bcd60e51b81526004016112c790615764565b601554611e789082906001600160a01b03166140db565b61221f614227565b565b6006546001600160a01b031633148061224957503360009081526007602052604090205460ff165b6122655760405162461bcd60e51b81526004016112c790615764565b6001600160a01b03811661228c57604051631f4c499760e01b815260040160405180910390fd5b601580546001600160a01b0319166001600160a01b0392909216919091179055565b6000818152600260205260409020546001600160a01b0316806123005760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016112c7565b919050565b601554600160a01b900460ff1661232f57604051637e19eeed60e11b815260040160405180910390fd5b600082815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a08301526123cb57604051630426ff7760e01b815260040160405180910390fd5b61127e8383836137e0565b60006123e2838361404d565b9392505050565b6006546001600160a01b031633148061241157503360009081526007602052604090205460ff165b61242d5760405162461bcd60e51b81526004016112c790615764565b6001600160a01b038116600081815260076020526040808220805460ff19166001179055517fbf3f493c772c8c283fd124432c2d0f539ab343faa04258fe88e52912d36b102b908290a350565b60006001600160a01b0382166124c15760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b60448201526064016112c7565b506001600160a01b031660009081526003602052604090205490565b6000818152601360208181526040808420815160c081018352815463ffffffff8082168352600160201b8204811683870152600160401b820416938201849052600160601b90046001600160a01b031660608201526001909101546001600160801b038082166080840152600160801b9091041660a08201528585529290915215158061256b57600061257c565b8151602083015161257c91906157e7565b63ffffffff16949350505050565b601554600160a01b900460ff166125b457604051637e19eeed60e11b815260040160405180910390fd5b600083815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a084015261264a575061264884338585613687565b155b1561266857604051638baa579f60e01b815260040160405180910390fd5b611baa8482614246565b6006546001600160a01b031633148061269a57503360009081526007602052604090205460ff165b6126b65760405162461bcd60e51b81526004016112c790615764565b600c6121b8828261591f565b600180546111de9061572a565b6006546001600160a01b03163314806126f757503360009081526007602052604090205460ff165b6127135760405162461bcd60e51b81526004016112c790615764565b600081815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b8204811694830194909452600160401b810490931693810193909352600160601b9091046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201526121b88282614546565b601554600160a01b900460ff166127c657604051637e19eeed60e11b815260040160405180910390fd5b600081815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a083015261286257604051630426ff7760e01b815260040160405180910390fd5b6121b88282614246565b81600f5460ff16156128815761288181613561565b61127e83836145f4565b6006546001600160a01b03163314806128b357503360009081526007602052604090205460ff165b6128cf5760405162461bcd60e51b81526004016112c790615764565b6121b882826140db565b6006546001600160a01b031633148061290157503360009081526007602052604090205460ff165b61291d5760405162461bcd60e51b81526004016112c790615764565b8263ffffffff16600003612944576040516335f7aa5b60e11b815260040160405180910390fd5b8163ffffffff1660000361296b57604051634b6e1bd360e01b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b82048116938301849052600160901b8204169382019390935260ff600160a01b8404811615156060830152600160a81b8404811615156080830152600160b01b909304909216151560a0830152600114612a0857604051630eea117d60e31b815260040160405180910390fd5b600085815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b82048116948301859052600160401b82041694820194909452600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a083015215612aa157604051628b039960e31b815260040160405180910390fd5b63ffffffff808616825284811660208084019182526001600160801b0380871660a0860190815260008b815260139093526040928390208651815495518589015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199099169390991692909217969096179590951695909517939093178455608085015192518116600160801b02921691909117600192830155601480549092019091555186907f67e0934daec5a59c2ce373b1d94d8160057ae0a6cfa7a01ccdfc12d63f5ae7fb90612b98908490615836565b60405180910390a2505050505050565b6000818152601060209081526040808320815160c08101835290546001600160801b03811680835261ffff600160801b8304811695840195909552600160901b82049094169282019290925260ff600160a01b8304811615156060830152600160a81b8304811615156080830152600160b01b909204909116151560a0820152901580156123e2575060a0015192915050565b601554600160a01b900460ff16612c6557604051637e19eeed60e11b815260040160405180910390fd5b600084815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b8204811615801560808501819052600160b01b909304909116151560a0840152612cfb5750612cf985858585613687565b155b15612d1957604051638baa579f60e01b815260040160405180910390fd5b611b73858583614660565b6006546001600160a01b0316331480612d4c57503360009081526007602052604090205460ff165b612d685760405162461bcd60e51b81526004016112c790615764565b600f805460ff1916911515919091179055565b846001600160a01b0381163314612da057600f5460ff1615612da057612da033613561565b612dad8686868686614886565b505050505050565b6006546001600160a01b0316331480612ddd57503360009081526007602052604090205460ff165b612df95760405162461bcd60e51b81526004016112c790615764565b8063ffffffff16600003612e2057604051634b6e1bd360e01b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201529103612eba5760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff1615612ee35760405163628e388360e01b815260040160405180910390fd5b63ffffffff80831660208084018281526000878152601390925260408083208651815493518389015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199097169390991692909217949094179390931695909517919091178455608085015160a08601516001600160801b03908116600160801b029116176001909401939093559151909185917f7076391b57145201e1b1e818500795c44fda2ae9af4dc5f2ea3d36a5539eb7779190a3505050565b6006546001600160a01b0316331480612feb57503360009081526007602052604090205460ff165b6130075760405162461bcd60e51b81526004016112c790615764565b6014541561302857604051630745ab4760e51b815260040160405180910390fd5b60155461303d906001600160a01b0316614967565b601560009054906101000a90046001600160a01b03166001600160a01b031663465105f06040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561308d57600080fd5b505af1158015611baa573d6000803e3d6000fd5b60095460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa1580156130eb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111b091908101906159de565b6006546001600160a01b031633148061313b57503360009081526007602052604090205460ff165b6131575760405162461bcd60e51b81526004016112c790615764565b8063ffffffff1660000361317e576040516335f7aa5b60e11b815260040160405180910390fd5b6000828152601360209081526040808320815160c081018352815463ffffffff8082168352600160201b82048116958301869052600160401b82041693820193909352600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a082015291036132185760405163e6759c6760e01b815260040160405180910390fd5b604081015163ffffffff16156132415760405163628e388360e01b815260040160405180910390fd5b63ffffffff808316808352600085815260136020908152604080832086518154938801518389015160608a01516001600160a01b0316600160601b026001600160601b03918a16600160401b02919091166001600160401b03928a16600160201b0267ffffffffffffffff199097169390991692909217949094179390931695909517919091178455608085015160a08601516001600160801b03908116600160801b029116176001909401939093559151909185917f9702db1e67fa6b64b8288101859f3b327a978f15d66e12ad769e5bbf30814d289190a3505050565b601554600160a01b900460ff1661334a57604051637e19eeed60e11b815260040160405180910390fd5b600082815260106020908152604091829020825160c08101845290546001600160801b038116825261ffff600160801b8204811693830193909352600160901b81049092169281019290925260ff600160a01b8204811615156060840152600160a81b820481161580156080850152600160b01b90920416151560a08301526133e657604051630426ff7760e01b815260040160405180910390fd5b61127e838383614660565b6006546001600160a01b031633148061341957503360009081526007602052604090205460ff165b6134355760405162461bcd60e51b81526004016112c790615764565b6014541561345657604051630745ab4760e51b815260040160405180910390fd5b60155461221f906001600160a01b0316614967565b6006546001600160a01b031633148061349357503360009081526007602052604090205460ff165b6134af5760405162461bcd60e51b81526004016112c790615764565b611e7881614a25565b6006546001600160a01b03163314806134e057503360009081526007602052604090205460ff165b6134fc5760405162461bcd60e51b81526004016112c790615764565b6121b88282614a9a565b600c80546111de9061572a565b60006301ffc9a760e01b6001600160e01b03198316148061354457506380ac58cd60e01b6001600160e01b03198316145b806111b05750506001600160e01b031916635b5e139f60e01b1490565b69c617113400112233445560005230601a5280603a52600080604460166daaeb6d7670e522a718067333cd4e5afa61359d573d6000803e3d6000fd5b6000603a5250565b6000818152600260205260409020546001600160a01b0316338114806135ee57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b61362b5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016112c7565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b604080516080810182528581526001600160a01b03851660208083018290526000918252600e815283822054838501528351601f860182900482028101820190945284845290928392916060830191908790879081908401838280828437600092018290525093909452505082516020808501516001600160a01b0381168452600e909152604083208054959650929461378f94507f9a1ad8626c8e414784b966be6c93b2550ea90ccdf34423b1e4aca0c3b942ada59386613748836158c0565b909155506040805160208101959095528401929092526001600160a01b03166060830152608082015260a00160405160208183030381529060405280519060200120614b1d565b905060006137a1828460600151614b6b565b6001600160a01b0381166000908152600d602052604090205490915060ff1680156137d457506001600160a01b03811615155b98975050505050505050565b806020015161ffff1660011461380957604051630eea117d60e31b815260040160405180910390fd5b8060a00151158015613823575080516001600160801b0316155b1561384157604051631d99ddbf60e01b815260040160405180910390fd5b80516001600160801b0316341461386b57604051636992e1ff60e01b815260040160405180910390fd5b80606001518015613882575061388082614b8f565b155b156138a057604051633664886760e11b815260040160405180910390fd5b600083815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b8204811694830194909452600160401b8104909316938101849052600160601b9092046001600160a01b03166060830152600101546001600160801b038082166080840152600160801b9091041660a08201529015613a375760408101516139399063ffffffff164261589a565b63ffffffff908116825260008581526013602090815260409182902084518154928601519386015160608701516001600160a01b038116600160601b026001600160601b03928816600160401b02929092166001600160401b03968816600160201b0267ffffffffffffffff199096169390971692909217939093179390931693909317178255608083015160a08401516001600160801b03908116600160801b0291169081176001909301929092556139f291614ba2565b6014805460001901905560405184907f4215ff61a9831416ed985d067257b9f8802a061f560876a779ebc5f3c6189fe890613a2e908490615836565b60405180910390a25b6040808301805161ffff600190910181168252600087815260106020908152939020855181549487015193516060880151608089015160a08a01511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19921515600160a01b0260ff60a01b19948816600160901b029490941662ffffff60901b1998909716600160801b026001600160901b03199099166001600160801b0390951694909417979097179590951693909317929092179290921617919091179055613b028385613cc4565b60405184907f7bb9aafce2f4a89681d211146eaa6c59ec03a137171363e78aa243d7d0bf36d890600090a250505050565b6000818152600260205260409020546001600160a01b03848116911614613b895760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016112c7565b6001600160a01b038216613baf5760405162461bcd60e51b81526004016112c790615a54565b336001600160a01b0384161480613be957506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80613c0a57506000818152600460205260409020546001600160a01b031633145b613c475760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064016112c7565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b0319908116831790915560049092528483208054909216909155925184939291600080516020615b7483398151915291a4505050565b600081815260026020526040902054600b546001600160a01b03908116911614613d1d5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b60448201526064016112c7565b6001600160a01b038216613d435760405162461bcd60e51b81526004016112c790615a54565b600b80546001600160a01b0390811660009081526003602090815260408083208054600019019055868416808452818420805460010190558684526002835281842080546001600160a01b031990811683179091556004909352818420805490931690925593549351859491939190911691600080516020615b7483398151915291a45050565b613dd5838383611b7a565b6001600160a01b0382163b1580613e7e5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015613e4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e729190615a7f565b6001600160e01b031916145b61127e5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016112c7565b6000818152600260205260409020546001600160a01b031680613f0f5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b60448201526064016112c7565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b03199081169091556004909252808320805490921690915551849290600080516020615b74833981519152908390a45050565b6001600160a01b038216613f9e5760405162461bcd60e51b81526004016112c790615a54565b6000818152600260205260409020546001600160a01b031615613ff45760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b60448201526064016112c7565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020615b74833981519152908290a45050565b60008161405c6103e88561581f565b6123e291906158ad565b6001600160a01b0390911690637d3e3dbe81614093578261408c5750634420e486614093565b5063a0af29035b8060e01b60005230600452826024526004600060446000806daaeb6d7670e522a718067333cd4e5af16140d1578060005160e01c036140d157600080fd5b5060006024525050565b6001600160a01b0381166141025760405163172fe2d160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015614149573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061416d9190615a9c565b9050806000036141905760405163334ab3f560e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af11580156141e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142079190615ab5565b905080611baa57604051631d42c86760e21b815260040160405180910390fd5b61221f733cc6cdda760b79bafa08df41ecfa224f810dceb66001614066565b8060600151801561425d575061425b33614b8f565b155b1561427b57604051633664886760e11b815260040160405180910390fd5b600082815260136020908152604091829020825160c081018452815463ffffffff8082168352600160201b82048116948301859052600160401b82041694820194909452600160601b9093046001600160a01b03166060840152600101546001600160801b038082166080850152600160801b9091041660a0830152158061430c575042816020015163ffffffff16115b1561432a576040516301dff5d560e71b815260040160405180910390fd5b806040015163ffffffff1660000361439257348160a001516001600160801b031611156143815760a0810151604051635cf8b88960e11b81526001600160801b0390911660048201523460248201526044016112c7565b63ffffffff42166040820152614431565b805160408201516143a391906157e7565b63ffffffff164211156143c95760405163283a4a6160e21b815260040160405180910390fd5b600081608001516001600160801b03169050600060646012548302816143f1576143f16156ea565b0482019050348111156144205760405163bc1510d560e01b8152600481018290523460248201526044016112c7565b61442e836060015183614ba2565b50505b346001600160601b0316608082015233606082015280516040820151601154429190920163ffffffff16039081101561447757601154825163ffffffff91839003011682525b60008481526013602090815260409182902084518154928601518487015160608801516001600160a01b0316600160601b026001600160601b0363ffffffff928316600160401b02166001600160401b03938316600160201b0267ffffffffffffffff199097169290941691909117949094171617919091178155608084015160a08501516001600160801b03908116600160801b029116176001909101555184907f90e14ed1433e5f6856e46c6068401974e908b3ef4a8ecd5401cbd68d8b4c2a1f90611459908590615836565b604081015163ffffffff16156145a8578051604082015161456791906157e7565b63ffffffff1642111561458d5760405163283a4a6160e21b815260040160405180910390fd5b6145a8816060015182608001516001600160801b0316614ba2565b600082815260136020526040808220828155600101829055601480546000190190555183917f2809c7e17bf978fbc7194c0a694b638c4215e9140cacc6c38ca36010b45697df91a25050565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6002816020015161ffff16101561468a57604051630556890560e01b815260040160405180910390fd5b806020015161ffff16816040015160016146a49190615ad2565b61ffff1611156146c75760405163a8fda6c160e01b815260040160405180910390fd5b8060a001511580156146e1575080516001600160801b0316155b156146ff57604051631d99ddbf60e01b815260040160405180910390fd5b80516001600160801b0316341461472957604051636992e1ff60e01b815260040160405180910390fd5b80606001518015614740575061473e82614b8f565b155b1561475e57604051633664886760e11b815260040160405180910390fd5b6000816040015160016147719190615ad2565b61ffff1690506000614783858361404d565b6040808501805161ffff6001909101811682526000898152601060209081529390208751815494890151935160608a015160808b015160a08c01511515600160b01b0260ff60b01b19911515600160a81b029190911661ffff60a81b19921515600160a01b0260ff60a01b19948816600160901b029490941662ffffff60901b1998909716600160801b026001600160901b03199099166001600160801b039095169490941797909717959095169390931792909217929092161791909117905590506148508482613cc4565b8082867fdf5fda6ef84c661a9a8c7217395c3d91bc7e519453e81fcbfa1f0f2d19a8d5be60405160405180910390a45050505050565b614891858585611b7a565b6001600160a01b0384163b15806149285750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906148d99033908a90899089908990600401615aed565b6020604051808303816000875af11580156148f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061491c9190615a7f565b6001600160e01b031916145b611b735760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b60448201526064016112c7565b6001600160a01b03811661498e5760405163172fe2d160e01b815260040160405180910390fd5b4760008190036149b15760405163334ab3f560e11b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146149fe576040519150601f19603f3d011682016040523d82523d6000602084013e614a03565b606091505b505090508061127e57604051631d42c86760e21b815260040160405180910390fd5b600954600160a01b900460ff1615614a50576040516313ef243160e11b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0383169081179091556040517f0713c9f4b0c5db294e61505e6819f6ad0cccf782df1a544939dc55d13fe7fc1c90600090a250565b612710811115614abd576040516303c799a760e61b815260040160405180910390fd5b6040805180820182526001600160a01b03841680825262ffffff84166020909201829052600160a01b9091028117600a5590518291907ff21fccf4d64d86d532c4e4eb86c007b6ad57a460c27d724188625e755ec6cf6d90600090a35050565b60006111b0614b2a614c97565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000806000614b7a8585614dbe565b91509150614b8781614e03565b509392505050565b600080614b9b83614f4d565b1192915050565b614bac8282614fc1565b6121b857600f60019054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015614c0057600080fd5b505af1158015614c14573d6000803e3d6000fd5b5050600f5460405163a9059cbb60e01b81526001600160a01b03878116600483015260248201879052610100909204909116935063a9059cbb925060440190506020604051808303816000875af1158015614c73573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127e9190615ab5565b6000306001600160a01b037f0000000000000000000000002a13ca75851eb518375d6e9cf7d1441bcf4a825816148015614cf057507f000000000000000000000000000000000000000000000000000000000000000146145b15614d1a57507fbb9355a78ff71cb72ba2edbfa1ca21c88d4f8c731533c97c4a677ac5d39ba21b90565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527fb30aa96379938f3d26fa51ee56f3b18dc754d9a68044dec5e47c2a85e3cb898d828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6000808251604103614df45760208301516040840151606085015160001a614de887828585615038565b94509450505050614dfc565b506000905060025b9250929050565b6000816004811115614e1757614e17615b41565b03614e1f5750565b6001816004811115614e3357614e33615b41565b03614e805760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016112c7565b6002816004811115614e9457614e94615b41565b03614ee15760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016112c7565b6003816004811115614ef557614ef5615b41565b03611e785760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b60648201526084016112c7565b600854604051627eeac760e11b81526001600160a01b03838116600483015260016024830152600092169062fdd58e90604401602060405180830381865afa158015614f9d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111b09190615a9c565b60408051600080825260208201928390529182916001600160a01b038616918591614feb91615b57565b60006040518083038185875af1925050503d8060008114615028576040519150601f19603f3d011682016040523d82523d6000602084013e61502d565b606091505b509095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561506f57506000905060036150f3565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156150c3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166150ec576000600192509250506150f3565b9150600090505b94509492505050565b6001600160e01b031981168114611e7857600080fd5b60006020828403121561512457600080fd5b81356123e2816150fc565b60006020828403121561514157600080fd5b5035919050565b60005b8381101561516357818101518382015260200161514b565b50506000910152565b602081526000825180602084015261518b816040850160208701615148565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461230057600080fd5b600080604083850312156151c957600080fd5b6151d28361519f565b946020939093013593505050565b80356001600160801b038116811461230057600080fd5b8015158114611e7857600080fd5b60008060006060848603121561521a57600080fd5b8335925061522a602085016151e0565b9150604084013561523a816151f7565b809150509250925092565b60008060006060848603121561525a57600080fd5b83359250602084013561522a816151f7565b60006020828403121561527e57600080fd5b6123e28261519f565b60006020828403121561529957600080fd5b81356123e2816151f7565b600080604083850312156152b757600080fd5b82359150611be9602084016151e0565b60008083601f8401126152d957600080fd5b5081356001600160401b038111156152f057600080fd5b602083019150836020828501011115614dfc57600080fd5b6000806000806060858703121561531e57600080fd5b8435935061532e6020860161519f565b925060408501356001600160401b0381111561534957600080fd5b615355878288016152c7565b95989497509550505050565b60008060006060848603121561537657600080fd5b61537f8461519f565b925061538d6020850161519f565b9150604084013590509250925092565b600080604083850312156153b057600080fd5b50508035926020909101359150565b600080604083850312156153d257600080fd5b6153db8361519f565b915060208301356153eb816151f7565b809150509250929050565b60008060008060008060c0878903121561540f57600080fd5b8635955061541f602088016151e0565b9450604087013561ffff8116811461543657600080fd5b93506060870135615446816151f7565b92506080870135615456816151f7565b915060a0870135615466816151f7565b809150509295509295509295565b6000806040838503121561548757600080fd5b82359150611be96020840161519f565b6000806000604084860312156154ac57600080fd5b8335925060208401356001600160401b038111156154c957600080fd5b6154d5868287016152c7565b9497909650939450505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715615520576155206154e2565b604052919050565b60006001600160401b03821115615541576155416154e2565b50601f01601f191660200190565b60006020828403121561556157600080fd5b81356001600160401b0381111561557757600080fd5b8201601f8101841361558857600080fd5b803561559b61559682615528565b6154f8565b8181528560208385010111156155b057600080fd5b81602084016020830137600091810160200191909152949350505050565b600080604083850312156155e157600080fd5b6155ea8361519f565b9150611be96020840161519f565b803563ffffffff8116811461230057600080fd5b6000806000806080858703121561562257600080fd5b84359350615632602086016155f8565b9250615640604086016155f8565b915061564e606086016151e0565b905092959194509250565b60008060008060006080868803121561567157600080fd5b61567a8661519f565b94506156886020870161519f565b93506040860135925060608601356001600160401b038111156156aa57600080fd5b6156b6888289016152c7565b969995985093965092949392505050565b600080604083850312156156da57600080fd5b82359150611be9602084016155f8565b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082615725576157256156ea565b500490565b600181811c9082168061573e57607f821691505b60208210810361575e57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600060c0820190506001600160801b038351168252602083015161ffff8082166020850152806040860151166040850152505060608301511515606083015260808301511515608083015260a0830151151560a083015292915050565b63ffffffff81811683821601908082111561580457615804615700565b5092915050565b60008261581a5761581a6156ea565b500690565b80820281158282048414176111b0576111b0615700565b815163ffffffff9081168252602080840151821690830152604080840151909116908201526060808301516001600160a01b0316908201526080808301516001600160801b039081169183019190915260a092830151169181019190915260c00190565b818103818111156111b0576111b0615700565b808201808211156111b0576111b0615700565b6000600182016158d2576158d2615700565b5060010190565b601f82111561127e57600081815260208120601f850160051c810160208610156159005750805b601f850160051c820191505b81811015612dad5782815560010161590c565b81516001600160401b03811115615938576159386154e2565b61594c81615946845461572a565b846158d9565b602080601f83116001811461598157600084156159695750858301515b600019600386901b1c1916600185901b178555612dad565b600085815260208120601f198616915b828110156159b057888601518255948401946001909101908401615991565b50858210156159ce5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156159f057600080fd5b81516001600160401b03811115615a0657600080fd5b8201601f81018413615a1757600080fd5b8051615a2561559682615528565b818152856020838501011115615a3a57600080fd5b615a4b826020830160208601615148565b95945050505050565b6020808252601190820152701253959053125117d49150d25412515395607a1b604082015260600190565b600060208284031215615a9157600080fd5b81516123e2816150fc565b600060208284031215615aae57600080fd5b5051919050565b600060208284031215615ac757600080fd5b81516123e2816151f7565b61ffff81811683821601908082111561580457615804615700565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b634e487b7160e01b600052602160045260246000fd5b60008251615b69818460208701615148565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa164736f6c6343000811000a

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

0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf00000000000000000000000000000000000000000000000000000000000002ee0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e300000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213

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

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000003b1bd4c99c059ed58155240fd01d6fc86a430d4d
Arg [1] : 0000000000000000000000006306d0cdfadd6095a313e8484275b6cc7036166c
Arg [2] : 00000000000000000000000085991f5f68b0f3678baae5848dea092c582df0cf
Arg [3] : 00000000000000000000000000000000000000000000000000000000000002ee
Arg [4] : 0000000000000000000000008d12974b9003112ecb9f58d60095cc03bef8f0e3
Arg [5] : 00000000000000000000000016f444f2d9e696834c1c9b536dc3896e1b545213


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.