ETH Price: $2,059.89 (+7.37%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw193472182024-03-02 11:35:11725 days ago1709379311IN
0xeE8d11Ba...128A48197
0 ETH0.0014366345.80816358
Rescue183684372023-10-17 6:54:59862 days ago1697525699IN
0xeE8d11Ba...128A48197
0 ETH0.000518456.1001276
Rescue183684172023-10-17 6:50:59862 days ago1697525459IN
0xeE8d11Ba...128A48197
0 ETH0.000470686.63732712
Rescue183684092023-10-17 6:49:23862 days ago1697525363IN
0xeE8d11Ba...128A48197
0 ETH0.000774046.83090574
Rescue183683632023-10-17 6:39:47862 days ago1697524787IN
0xeE8d11Ba...128A48197
0 ETH0.000416025.69462378
Rescue183683502023-10-17 6:37:11862 days ago1697524631IN
0xeE8d11Ba...128A48197
0 ETH0.000293035.71054271
Rescue183683452023-10-17 6:36:11862 days ago1697524571IN
0xeE8d11Ba...128A48197
0 ETH0.000230544.95630528
Rescue183683342023-10-17 6:33:59862 days ago1697524439IN
0xeE8d11Ba...128A48197
0 ETH0.000723615.37382416
Rescue183683172023-10-17 6:30:35862 days ago1697524235IN
0xeE8d11Ba...128A48197
0 ETH0.000445045.90600985
Rescue183683062023-10-17 6:28:23862 days ago1697524103IN
0xeE8d11Ba...128A48197
0 ETH0.000933795.12164286
Rescue183339112023-10-12 11:02:59867 days ago1697108579IN
0xeE8d11Ba...128A48197
0 ETH0.000801675.84503172
Rescue183338772023-10-12 10:55:59867 days ago1697108159IN
0xeE8d11Ba...128A48197
0 ETH0.000320475.95737691
Rescue183338612023-10-12 10:52:47867 days ago1697107967IN
0xeE8d11Ba...128A48197
0 ETH0.000816445.95274204
Rescue183232012023-10-10 23:02:11869 days ago1696978931IN
0xeE8d11Ba...128A48197
0 ETH0.000380937.42347557
Withdraw Seller ...178624532023-08-07 10:26:47933 days ago1691404007IN
0xeE8d11Ba...128A48197
0 ETH0.0007307317.57134736
List And Sell Pr...177305032023-07-19 23:26:47952 days ago1689809207IN
0xeE8d11Ba...128A48197
0 ETH0.0076248216.01211404
List And Sell Pr...177303612023-07-19 22:57:59952 days ago1689807479IN
0xeE8d11Ba...128A48197
0 ETH0.0070201317.3580092
List And Sell Pr...177303442023-07-19 22:54:35952 days ago1689807275IN
0xeE8d11Ba...128A48197
0 ETH0.0069596116.7807593
List And Sell Pr...177303392023-07-19 22:53:35952 days ago1689807215IN
0xeE8d11Ba...128A48197
0 ETH0.00772518.19286864
List And Sell Pr...177303112023-07-19 22:47:59952 days ago1689806879IN
0xeE8d11Ba...128A48197
0 ETH0.006407815.84395075
List And Sell Pr...177302722023-07-19 22:40:11952 days ago1689806411IN
0xeE8d11Ba...128A48197
0 ETH0.0069227116.30296426
List And Sell Pr...177302672023-07-19 22:39:11952 days ago1689806351IN
0xeE8d11Ba...128A48197
0 ETH0.0066134616.35296535
List And Sell Pr...177302602023-07-19 22:37:47952 days ago1689806267IN
0xeE8d11Ba...128A48197
0 ETH0.0069337316.32937814
List And Sell Pr...177301942023-07-19 22:24:23952 days ago1689805463IN
0xeE8d11Ba...128A48197
0 ETH0.0072923218.03103918
List And Sell Pr...177301722023-07-19 22:19:59952 days ago1689805199IN
0xeE8d11Ba...128A48197
0 ETH0.0076651418.95343488
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer193472182024-03-02 11:35:11725 days ago1709379311
0xeE8d11Ba...128A48197
0.12242 ETH
Deposit177024352023-07-16 0:54:23956 days ago1689468863
0xeE8d11Ba...128A48197
0.888 ETH
Transfer177024352023-07-16 0:54:23956 days ago1689468863
0xeE8d11Ba...128A48197
0.072 ETH
Transfer177024352023-07-16 0:54:23956 days ago1689468863
0xeE8d11Ba...128A48197
0.04 ETH
Deposit177023972023-07-16 0:46:35956 days ago1689468395
0xeE8d11Ba...128A48197
0.3108 ETH
Transfer177023972023-07-16 0:46:35956 days ago1689468395
0xeE8d11Ba...128A48197
0.0252 ETH
Transfer177023972023-07-16 0:46:35956 days ago1689468395
0xeE8d11Ba...128A48197
0.014 ETH
Deposit175035582023-06-18 2:00:23983 days ago1687053623
0xeE8d11Ba...128A48197
0.7992 ETH
Transfer175035582023-06-18 2:00:23983 days ago1687053623
0xeE8d11Ba...128A48197
0.0648 ETH
Transfer175035582023-06-18 2:00:23983 days ago1687053623
0xeE8d11Ba...128A48197
0.036 ETH
Deposit174936322023-06-16 16:38:11985 days ago1686933491
0xeE8d11Ba...128A48197
1.776 ETH
Transfer174936322023-06-16 16:38:11985 days ago1686933491
0xeE8d11Ba...128A48197
0.144 ETH
Transfer174936322023-06-16 16:38:11985 days ago1686933491
0xeE8d11Ba...128A48197
0.08 ETH
Deposit173308712023-05-24 18:36:591008 days ago1684953419
0xeE8d11Ba...128A48197
0.059496 ETH
Transfer173308712023-05-24 18:36:591008 days ago1684953419
0xeE8d11Ba...128A48197
0.004824 ETH
Transfer173308712023-05-24 18:36:591008 days ago1684953419
0xeE8d11Ba...128A48197
0.00268 ETH
Deposit173178442023-05-22 22:36:471010 days ago1684795007
0xeE8d11Ba...128A48197
0.06216 ETH
Transfer173178442023-05-22 22:36:471010 days ago1684795007
0xeE8d11Ba...128A48197
0.00504 ETH
Transfer173178442023-05-22 22:36:471010 days ago1684795007
0xeE8d11Ba...128A48197
0.0028 ETH
Deposit171056352023-04-23 1:05:471040 days ago1682211947
0xeE8d11Ba...128A48197
0.0444 ETH
Transfer171056352023-04-23 1:05:471040 days ago1682211947
0xeE8d11Ba...128A48197
0.0036 ETH
Transfer171056352023-04-23 1:05:471040 days ago1682211947
0xeE8d11Ba...128A48197
0.002 ETH
Deposit171004992023-04-22 7:48:471040 days ago1682149727
0xeE8d11Ba...128A48197
0.00444 ETH
Transfer171004992023-04-22 7:48:471040 days ago1682149727
0xeE8d11Ba...128A48197
0.00036 ETH
Transfer171004992023-04-22 7:48:471040 days ago1682149727
0xeE8d11Ba...128A48197
0.0002 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CentMarketplaceV1

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 400 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./CentBaseTimedAuctionBETA.sol";


/// @title CentMarketplaceV1.
/// @author @Dadogg80 - Viken Blockchain Solutions.

/// @notice This is the marketplace smartcontract with all the global variables, custom errors, events, 
///         and modifiers derived from the Centaurify TimedAuction and Storage smart contracts.     


contract CentMarketplaceV1 is CentBaseTimedAuctionBETA {
    using Counters for Counters.Counter;
    using ERC165Checker for address;
    
    Counters.Counter private _itemsIndex;
    Counters.Counter private _itemsSold;

    Counters.Counter private _orderIds;
    Counters.Counter private _ordersSold;

    /// @notice The constructor will set the serviceWallet address and deploy a escrow contract.
    /// @dev Will emit the event { EscrowDeployed }.
    constructor(address payable _serviceWallet, address _operator) {
        require(_serviceWallet != address(0));

        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(OPERATOR_ROLE, _operator);
        _setupRole(ADMIN_ROLE, _msgSender());
        _setupRole(ITEM_CREATOR_ROLE, _operator);

        serviceFee = 200;
        serviceWallet = _serviceWallet;
        escrow = new Escrow();

        emit EscrowDeployed(escrow, address(this));
    }

    /// @notice Creates an new MarketItem on the marketplace.
    /// @dev ATTENTION this function require approvals from `nftContract` to transfer tokenId
    /// @param nftContract Contract address of the nft to add to marketplace. 
    /// @param tokenId The tokenId the token to add on the marketplace.
    /// @param seller The address of the seller of this nft.
    /// @return itemId Will return the bytes32 marketItemId.
    function createMarketItem(address nftContract, uint256 tokenId, address payable seller) 
        public
        onlyRole(ITEM_CREATOR_ROLE)
        returns (bytes32 itemId) 
    {
        //if (seller != IERC721(nftContract).ownerOf(tokenId)) revert NotTokenOwner();
        return _createMarketItem(nftContract, tokenId, seller);
    }

    /// @notice Creates an new MarketOrder of a marketItem.
    /// @param itemId Id of the marketItem to create a market order. 
    /// @param priceInWei The sales price of this order.
    /// @return orderId Will return the bytes32 orderId. 
    function createMarketOrder(bytes32 itemId, uint256 priceInWei) 
        public
        nonReentrant
        isAuthorized(itemId)
        isNotActive(itemId)
        returns (bytes32)
    {
        MarketItem storage _item = itemsMapping[itemId];
        uint256 _priceInWei = priceInWei;
        
        if (_priceInWei <= 0) revert LowValue(_priceInWei);

        _orderIds.increment();
        bytes32 _orderId = bytes32(_orderIds.current());
        
        if (ordersMapping[_orderId].isOrder) revert ActiveOrder(_orderId);

        ordersMapping[_orderId] = MarketOrder(
            _orderId,
            _item.itemId,
            _priceInWei,
            true,
            false
        );

        _item.status = Status(1);
        _item.active = true;

        arrayOfOrderIds.push(_orderId);

        emit MarketOrderCreated(
            _orderId,
            _item.itemId,
            _priceInWei,
            true
        );

        return _orderId;
    }

    /// @notice Method used to purchase a marketOrder.
    /// @param one Requires the param to be bool true.
    /// @param orderId The id of the MarketOrder to purchase.
    function executeOrder(bool one, bytes32 orderId) 
        external 
        payable 
        isActiveOrder(orderId) nonReentrant 
        costs(one, orderId) 
    {
        _executeOrder(one, orderId, _msgSender());
    }

    /// @notice Method used to remove an order from listing on our marketplace.
    /// @dev Restricted to the {seller/tokenOwner} or the marketplace {owner} account.
    /// @dev Will emit the event { MarketOrderRemoved }.
    /// @param orderId The orderId to cancel.
    function cancelOrder(bytes32 orderId) 
        external 
        isActiveOrder(orderId)
        isAuthorized(ordersMapping[orderId].itemId)
    {
        bytes32 _orderId = orderId;
        bytes32 _itemId = ordersMapping[_orderId].itemId;
        MarketItem storage _item = itemsMapping[_itemId];

        ordersMapping[_orderId].isOrder = false;
        ordersMapping[_orderId].sold = false;

        _item.status = Status(0);
        _item.active = false;
        
        _orderRemove(_orderId);
        emit MarketOrderRemoved(_orderId, _msgSender());
    }

    /// @notice Method used to remove an item from our marketplace.
    /// @param itemId The itemId to remove.
    /// @dev Restricted to the {seller/tokenOwner} or the marketplace {owner} account.
    /// @dev Will emit the event { MarketItemRemoved }.
    function removeItem(bytes32 itemId) external isAuthorized(itemId) isNotActive(itemId) {
        _itemRemove(itemId);
        emit MarketItemRemoved(itemId, _msgSender());
    }

    /// @notice Get the market item.
    /// @param itemId The itemId to query .
    /// @return marketItem Returns the MarketItem struct.
    function getMarketItem(bytes32 itemId) external view returns (MarketItem memory) {
        return itemsMapping[itemId];
    }

    /// @notice Get the information regarding a specific orderId.
    /// @param orderId The orderId to query.
    /// @return marketOrder Returns the MarketOrder struct.
    function getMarketOrder(bytes32 orderId) external view returns (MarketOrder memory) {
        return ordersMapping[orderId];
    }

       /// @notice Internal method to fetch all the marketItems.
    /// @return activeMarketItems Returns an bytes32 array of all active marketItemIds.
    function fetchMarketItems() external view returns (bytes32[] memory){
        return activeMarketItems;
    }

    /// @notice Method used to fetch all the marketOrders.
    /// @return marketOrder Returns an array of all the active marketOrders structs.
    function fetchMarketOrders() external view returns (MarketOrder[] memory) {
        uint orderCount = _orderIds.current();
        uint unsoldOrderCount = _orderIds.current() - _ordersSold.current();
        uint currentIndex = 0;

        MarketOrder[] memory _orders = new MarketOrder[](unsoldOrderCount);
        for (uint i = 0; i < orderCount; i++) {
            bytes32 currentId = bytes32(i + 1);
            MarketOrder storage currentOrder = ordersMapping[currentId];
            if (currentOrder.isOrder) {
                _orders[currentIndex] = currentOrder;
                currentIndex += 1;
            }
            if (currentIndex == unsoldOrderCount) break;
        }
        return _orders;
    }

/// --------------------------------- PRIVATE METHODS ---------------------------------

    /// @notice Private method to remove/delete an MarketItem from the marketplace.
    /// @param itemId The id of the order to remove.
    function _itemRemove(bytes32 itemId) private {
        MarketItem memory _item = itemsMapping[itemId];
        if (_item.active) revert IsActive(itemId, itemsMapping[itemId].status);
        
        delete itemsMapping[itemId];

        IERC721(_item.nftContract).safeTransferFrom(
            address(this), 
            _item.tokenOwner, 
            _item.tokenId
        );
        
    }
    
    /// @notice Private method to remove/delete an MarketOrder from the marketplace.
    /// @param orderId The id of the order to remove.
    function _orderRemove(bytes32 orderId) private {
        if (ordersMapping[orderId].isOrder) revert ActiveOrder(orderId);
        delete ordersMapping[orderId];
    }

    /// @notice Private helper method used to purchase a marketOrder.
    /// @param one Requires the param to be bool true.
    /// @param orderId The id of the MarketOrder to purchase.
    /// @param buyer The address of the buyer
    function _executeOrder(bool one, bytes32 orderId, address buyer) private {
        if (one != true) revert ErrorMessage("Requires bool value: true");
        MarketOrder storage _order = ordersMapping[orderId];
        if (!_order.isOrder) revert NoListing(_order.orderId);
 
        _order.isOrder = false;
        _order.sold = true;       
        _ordersSold.increment();

        MarketItem storage _item = itemsMapping[_order.itemId];
        _item.status = Status(0);
        _item.active = false;

        (, uint256 _toSellerAmount, uint256 _totalFeeAmount) = _calculateFees(_order.priceInWei);

        _orderRemove(_order.orderId);
        
        (bool success) = IERC165(_item.nftContract).supportsInterface(_INTERFACE_ID_ERC2981);
        
        if (!success) {
            (bool _success,) = serviceWallet.call{value: _totalFeeAmount}("");
            if (!_success) revert FailedTransaction("Fees");
            _sendPaymentToEscrow(_item.tokenOwner, _toSellerAmount);
            emit TransferServiceFee(serviceWallet, _totalFeeAmount);
        
        } else {
            _transferRoyaltiesAndServiceFee(_item, _totalFeeAmount, _toSellerAmount);
        }

        IERC721(_item.nftContract).safeTransferFrom(address(this), buyer, _item.tokenId);
    
        emit MarketOrderSold(orderId, _item.tokenId, _order.priceInWei, _item.nftContract, _item.escrow, _item.tokenOwner, _msgSender());
    }

    /// @notice Restricted method used to create a new market item
    /// @dev Restricted to internal view.
    function _createMarketItem(address nftContract, uint256 tokenId, address payable seller) 
        internal
        returns (bytes32 itemId) 
    {
        if (seller != IERC721(nftContract).ownerOf(tokenId)) revert NotTokenOwner();
        uint256 _index = _itemsIndex.current();
        uint256 _salt = block.timestamp;
        bytes32 _itemId = keccak256(abi.encodePacked(_msgSender(), nftContract, tokenId, _salt));
        
        itemsMapping[_itemId] = MarketItem(
            _itemId,
            _index,
            payable(seller),
            address(this),
            escrow,
            nftContract,
            tokenId,
            Status(0),
            false
        );

        activeMarketItems.push(_itemId);
        _itemsIndex.increment();

        emit MarketItemCreated(_itemId, _index, seller);

        IERC721(nftContract).safeTransferFrom(seller, address(this), tokenId);
        
        return _itemId;
    }
/// --------------------------------- ADMIN METHODS ---------------------------------

    /// @notice Restricted method used to withdraw the funds from the marketplace.
    /// @dev Restricted to Admin Role.
    function withdraw() external onlyRole(ADMIN_ROLE) {
        (bool success,) = payable(_msgSender()).call{value: address(this).balance}("");
        if (!success) revert ErrorMessage("Withdraw Failed");
        emit Withdraw();
    }

    /// @notice Restricted method used to withdraw any stuck erc20 in this smart-contract.
    /// @dev Restricted to Admin Role.
    /// @param erc20Token The address of stuck erc20 token to release.
    function releaseStuckTokens(address erc20Token) external onlyRole(ADMIN_ROLE) {
        uint256 balance = IERC20(erc20Token).balanceOf(address(this));
        require(IERC20(erc20Token).transfer(_msgSender(), balance));
    }

    /// @notice Restricted method used to set the serviceWallet.
    /// @dev Restricted to Admin Role.
    /// @param _serviceWallet The new account to receive the service fee.
    /// @dev Emits the event { ServiceWalletUpdated }.
    function updateServiceWallet(address payable _serviceWallet) external onlyRole(ADMIN_ROLE) {
       serviceWallet = _serviceWallet;
       emit ServiceWalletUpdated(serviceWallet);
    }

    /// @notice Updates the service fee of the contract.
    /// @dev Restricted to Admin Role.
    /// @param _serviceFee The updated service fee in percentage to charge for selling and buying on our marketplace.
    function updateServiceFee(uint16 _serviceFee) external onlyRole(ADMIN_ROLE) {
        serviceFee = _serviceFee;
    }

    /// --------------------------------- BUYER SERVICE METHODS ---------------------------------

    /// @notice Method used to purchase a marketOrder on behalf of a buyer.
    /// @param one Requires the param to be bool true.
    /// @param orderId The id of the MarketOrder to purchase.
    /// @param buyer The address of the buyer
    function executeOrderForBuyer(bool one, bytes32 orderId, address buyer) 
        external 
        payable
        onlyRole(BUYER_SERVICE_ROLE)
        isActiveOrder(orderId) nonReentrant 
        costs(one, orderId) 
    {
        _executeOrder(one, orderId, buyer);
    }

    /// @notice Method used to batch { createMarketItem and createMarketOrder } into one transaction.
    /// @dev RESTIRCTED to ITEM_CREATOR_ROLE.
    /// @dev ATTENTION this function require approvals from `collection` to transfer tokenId
    /// @param collection Collection address of the nft to add to marketplace. 
    /// @param tokenId The tokenId the token to add on the marketplace.
    /// @param seller The address of the seller of this nft.
    /// @param priceInWei The sales price of this nft. 
    /// @return itemId orderId Will return the bytes32 itemId and orderId.
    function listAndSellNewCollection(address collection, uint256 tokenId, address payable seller, uint256 priceInWei) 
        external 
        onlyRole(ITEM_CREATOR_ROLE) 
        returns (bytes32 itemId, bytes32 orderId) 
    {
        approvedCollections[collection] = true;
        //if (seller != IERC721(collection).ownerOf(tokenId)) revert NotTokenOwner();
        itemId = _createMarketItem(collection, tokenId, seller);
        orderId = createMarketOrder(itemId, priceInWei);
        emit ListedForSale(collection, seller, tokenId, priceInWei, itemId, orderId);
    }

    /// @notice Method used to batch an pre-approved collection into one transaction.
    /// @dev ATTENTION this function require approvals from `collection` to transfer tokenId
    /// @param collection Collection address of the nft to add to marketplace. 
    /// @param tokenId The tokenId the token to add on the marketplace.
    /// @param priceInWei The sales price of this nft. 
    /// @return itemId orderId Will return the bytes32 itemId and orderId.
    function listAndSellPreApprovedCollection(address collection, uint256 tokenId, uint256 priceInWei) 
        external 
        returns (bytes32 itemId, bytes32 orderId) 
    {
        if(!approvedCollections[collection]) revert CollectionNotApproved();
        itemId = _createMarketItem(collection, tokenId, payable(msg.sender));
        orderId = createMarketOrder(itemId, priceInWei);
        emit ListedForSale(collection, msg.sender, tokenId, priceInWei, itemId, orderId);
    }

    /// @notice Method used to add an pre-approved collection.
    /// @param collection contract address to approve
    /// @param isApproved true to add and false to remove collection.
    function approveCollection(address collection, bool isApproved) external onlyRole(ADMIN_ROLE) {
        approvedCollections[collection] = isApproved;
        emit CollectionApproved(collection, isApproved);
    }


   
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 7 of 25 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/IERC20.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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 12 of 25 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)

pragma solidity ^0.8.0;

import "../IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
 */
contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address,
        address,
        uint256,
        bytes memory
    ) public virtual override returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/escrow/Escrow.sol)

pragma solidity ^0.8.0;

import "../../access/Ownable.sol";
import "../Address.sol";

/**
 * @title Escrow
 * @dev Base escrow contract, holds funds designated for a payee until they
 * withdraw them.
 *
 * Intended usage: This contract (and derived escrow contracts) should be a
 * standalone contract, that only interacts with the contract that instantiated
 * it. That way, it is guaranteed that all Ether will be handled according to
 * the `Escrow` rules, and there is no need to check for payable functions or
 * transfers in the inheritance tree. The contract that uses the escrow as its
 * payment method should be its owner, and provide public methods redirecting
 * to the escrow's deposit and withdraw.
 */
contract Escrow is Ownable {
    using Address for address payable;

    event Deposited(address indexed payee, uint256 weiAmount);
    event Withdrawn(address indexed payee, uint256 weiAmount);

    mapping(address => uint256) private _deposits;

    function depositsOf(address payee) public view returns (uint256) {
        return _deposits[payee];
    }

    /**
     * @dev Stores the sent amount as credit to be withdrawn.
     * @param payee The destination address of the funds.
     *
     * Emits a {Deposited} event.
     */
    function deposit(address payee) public payable virtual onlyOwner {
        uint256 amount = msg.value;
        _deposits[payee] += amount;
        emit Deposited(payee, amount);
    }

    /**
     * @dev Withdraw accumulated balance for a payee, forwarding all gas to the
     * recipient.
     *
     * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities.
     * Make sure you trust the recipient, or are either following the
     * checks-effects-interactions pattern or using {ReentrancyGuard}.
     *
     * @param payee The address whose funds will be withdrawn and transferred to.
     *
     * Emits a {Withdrawn} event.
     */
    function withdraw(address payable payee) public virtual onlyOwner {
        uint256 payment = _deposits[payee];

        _deposits[payee] = 0;

        payee.sendValue(payment);

        emit Withdrawn(payee, payment);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Library used to query support of an interface declared via {IERC165}.
 *
 * Note that these functions return the actual result of the query: they do not
 * `revert` if an interface is not supported. It is up to the caller to decide
 * what to do in these cases.
 */
library ERC165Checker {
    // As per the EIP-165 spec, no interface should ever match 0xffffffff
    bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff;

    /**
     * @dev Returns true if `account` supports the {IERC165} interface.
     */
    function supportsERC165(address account) internal view returns (bool) {
        // Any contract that implements ERC165 must explicitly indicate support of
        // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
        return
            supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
            !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID);
    }

    /**
     * @dev Returns true if `account` supports the interface defined by
     * `interfaceId`. Support for {IERC165} itself is queried automatically.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
        // query support of both ERC165 as per the spec and support of _interfaceId
        return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
    }

    /**
     * @dev Returns a boolean array where each value corresponds to the
     * interfaces passed in and whether they're supported or not. This allows
     * you to batch check interfaces for a contract where your expectation
     * is that some interfaces may not be supported.
     *
     * See {IERC165-supportsInterface}.
     *
     * _Available since v3.4._
     */
    function getSupportedInterfaces(address account, bytes4[] memory interfaceIds)
        internal
        view
        returns (bool[] memory)
    {
        // an array of booleans corresponding to interfaceIds and whether they're supported or not
        bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);

        // query support of ERC165 itself
        if (supportsERC165(account)) {
            // query support of each interface in interfaceIds
            for (uint256 i = 0; i < interfaceIds.length; i++) {
                interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
            }
        }

        return interfaceIdsSupported;
    }

    /**
     * @dev Returns true if `account` supports all the interfaces defined in
     * `interfaceIds`. Support for {IERC165} itself is queried automatically.
     *
     * Batch-querying can lead to gas savings by skipping repeated checks for
     * {IERC165} support.
     *
     * See {IERC165-supportsInterface}.
     */
    function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
        // query support of ERC165 itself
        if (!supportsERC165(account)) {
            return false;
        }

        // query support of each interface in interfaceIds
        for (uint256 i = 0; i < interfaceIds.length; i++) {
            if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
                return false;
            }
        }

        // all interfaces supported
        return true;
    }

    /**
     * @notice Query if a contract implements an interface, does not check ERC165 support
     * @param account The address of the contract to query for support of an interface
     * @param interfaceId The interface identifier, as specified in ERC-165
     * @return true if the contract at account indicates support of the interface with
     * identifier interfaceId, false otherwise
     * @dev Assumes that account contains a contract that supports ERC165, otherwise
     * the behavior of this method is undefined. This precondition can be checked
     * with {supportsERC165}.
     * Interface identification is specified in ERC-165.
     */
    function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
        // prepare call
        bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);

        // perform static call
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly {
            success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0x00)
        }

        return success && returnSize >= 0x20 && returnValue > 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/escrow/Escrow.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";

/// @title CentBaseStorageBETA.
/// @author @Dadogg80 - Viken Blockchain Solutions.

/// @notice This is the storage contract containing all the global variables, custom errors, events, 
///         and modifiers inherited by the Centaurify NFT marketplace smart contract.       

contract CentBaseStorageBETA is ERC721Holder, Context, AccessControlEnumerable, ReentrancyGuard {

    /// @notice Enum Status is the different statuses.
    /// @param Listed means token is in our marketplace contract.
    /// @param Order means that a market order is live. 
    /// @param TimedAuction means that a timed auction is live.
    enum Status { Listed, Order, TimedAuction }

    /// @notice Escrow contract that holds the seller funds and pendingReturns.
    /// @return escrow The Escrow contract address.
    Escrow public escrow;

    /// @notice The account that will receive the service fee.
    /// @return serviceWallet The serivce wallet address.
    address payable public serviceWallet;

    /// @notice The service fee cost of listing in BIPS.
    /// @dev 200 BIPS is 2 percent. 
    uint16 public serviceFee; 

    /// @dev Array containing liveMarketItem id's.
    bytes32[] internal activeMarketItems; 

    /// @dev Array containing order ids.
    bytes32[] internal arrayOfOrderIds;

    bytes4 internal constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    bytes4 internal constant _INTERFACE_ID_ERC2981 = 0x2a55205a;

    bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
    bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
    bytes32 public constant ITEM_CREATOR_ROLE = keccak256("ITEM_CREATOR_ROLE");
    bytes32 public constant BUYER_SERVICE_ROLE = keccak256("BUYER_SERVICE_ROLE");

    /// ------------------------------- STRUCTS -------------------------------

    /// @notice A marketItem is a listed token.
    /// @param itemId The uniqe id of this marketItem.
    /// @param tokenOwner The owner of this marketItem.
    /// @param operator The operator is this marketplace contract.
    /// @param escrow The escrow contract address. 
    /// @param nftContract The contract address of this marketItem.
    /// @param TokenId The tokenId of this marketItem.
    /// @param status The current status of this marketItem.
    struct MarketItem {
        bytes32 itemId;
        uint256 index;
        address payable tokenOwner;
        address operator;   
        Escrow escrow; 
        address nftContract;
        uint256 tokenId;
        Status status;
        bool active;
    }

    /// @notice A MarketOrder is a struct with info of a listed NFT token.
    /// @param orderId The id of this marketOrder.
    /// @param itemId The marketItem to sell as this MarketOrder.
    /// @param priceInWei The salesPrice of this MarketOrder.
    /// @param isOrder Is true if this MarketOrder is listed.
    /// @param sold Is true if this MarketOrder is sold.
    struct MarketOrder {
        bytes32 orderId;
        bytes32 itemId;           
        uint256 priceInWei;            
        bool isOrder;
        bool sold;
    }

    /// @notice A marketAuction struct is a marketItem that is in an ongoing timed auction.
    /// @param auctionId The id of the timed auction.
    /// @param itemId The id of the marketitem to sell on timed auction.
    /// @param auctionEndTime The timestamp to end the timed auction.
    /// @param highestBid The current highest bid.
    /// @param ended Is true if ended, false if ongoing.
    /// @param status The current status of this marketItem.
    struct MarketAuction {
        bytes32 auctionId; 
        bytes32 itemId; 
        uint256 auctionEndTime;
        uint256 highestBid;
        address highestBidder;
        bool ended;
    }

    /// ------------------------------- MAPPINGS -------------------------------

    /// @notice Mapping is used to store the MarketItems.
    mapping(bytes32 => MarketItem) public itemsMapping;

    /// @notice From ERC721 registry assetId to MarketOrder (to avoid asset collision).
    mapping(bytes32 => MarketOrder) public ordersMapping;
    
    /// @notice Mapping is used to store the MarketAuctions.
    /// @dev auctionId Pass a auctionId and get the MarketAuction in return. 
    mapping(bytes32 => MarketAuction) public auctionsMapping;

    /// @notice Maps token address to bool for either true (token is accepted as payment).
    mapping(address => bool) public acceptedTokenMap;

    /// @notice Maps user address to amount in pendingReturns.
    mapping(address => uint256) public pendingReturns;

    /// @notice mapping with approved collection addresses.
    mapping(address => bool) public approvedCollections;

    /// ------------------------------- MODIFIERS -------------------------------

    /// @notice Modifier will validate if the itemId is an active marketItem.
    /// @param itemId The itemId of the nft to validate. 
    modifier isActiveItem(bytes32 itemId) {
        MarketItem memory _item = itemsMapping[itemId];
        if (!_item.active) revert NotActive(_item.itemId);
        _;
    }

    /// @notice Modifier will validate if the orderId is an active market order.
    /// @param orderId The orderId of the order to validate. 
    modifier isActiveOrder(bytes32 orderId) {
        MarketOrder memory _order = ordersMapping[orderId];
        if (!_order.isOrder) revert NotActive(_order.orderId);
        _;
    } 

    /// @dev Modifier will validate that the marketItem is not already a live item.
    /// @param itemId The id of the marketItem.
    modifier isNotActive(bytes32 itemId) {
        MarketItem memory _item = itemsMapping[itemId];
        if (_item.active) revert IsActive(_item.itemId, _item.status);
        _;
    }

    /// @dev Modifier will validate if the caller is authorized.
    /// @param itemId The tokenId of the nft to validate.
    modifier isAuthorized(bytes32 itemId) {
        MarketItem memory _item = itemsMapping[itemId];
        if (_item.tokenOwner != _msgSender()) revert NotAuth();
        _;
    }

    /// @dev Modifier will validate if the caller is the seller.
    /// @param seller The account to validate.
    modifier isAuth(address payable seller) {
        if (seller != _msgSender()) revert NotAuth();
        _;
    }

    /// @notice Modifier will validate that the auctionId is a live auction.
    /// @param auctionId The id of the auction to bid on.
    modifier isLiveAuction(bytes32 auctionId) {
        MarketAuction memory _a = auctionsMapping[auctionId];
            if (_a.ended) revert NotActive(_a.auctionId);
        _;
    }

    /// @dev Modifier will validate that the bid is above current highest bid.
    /// @param auctionId The id of the auction to bid on.
    modifier minBid(bytes32 auctionId) {
        MarketAuction memory a = auctionsMapping[auctionId];
        if (msg.value <= a.highestBid) revert LowValue(a.highestBid);
        _;
    }

    /// @dev Modifier will validate that the costs are covered.
    /// @param status The item status, true if ORDER, false if AUCTION.
    /// @param id The id to identify the order/auction.
    modifier costs(bool status, bytes32 id) {
        if (status) {
            MarketOrder memory _order = ordersMapping[id];
            (uint256 serviceAmount, uint256 sellerAmount, ) = _calculateFees(
                _order.priceInWei
            );
            uint256 sum = (_order.priceInWei + serviceAmount);
            if (msg.value < sum) revert LowValue(sum);
        } else {
            MarketAuction memory _auction = auctionsMapping[id];
            (uint256 serviceAmount, uint256 sellerAmount, ) = _calculateFees(
                _auction.highestBid
            );
            uint256 sum = (_auction.highestBid + serviceAmount);
            if (msg.value < sum) revert LowValue(sum);
        }
    _;
    }

    /// ------------------------------- CUSTOM ERRORS -------------------------------

    /// @notice Thrown if 0 is passed as a value.
    error NoZeroValues();

    /// @notice Thrown if caller is not authorized.
    error NotAuth();
   
    /// @notice Thrown if caller is not authorized Role.
    error NotAuthorizedRole();
 
    /// @notice Thrown if caller is not authorized or owner of the token.
    error NotTokenOwner();

    /// @notice Thrown if the msg.value is to low to transact.
    /// @param expected The expected value.
    error LowValue(uint256 expected);

    /// @notice Thrown if the marketItem is not an active market item.
    /// @param id The Id of the market Item.
    error NotActive(bytes32 id);

    /// @notice Thrown if the market item is already a active order or auction.
    /// @param itemId The Id of the market Item.
    /// @param status The status of the market Item.
    error IsActive(bytes32 itemId, Status status);

    /// @notice Thrown if the NFT is already listed as market order.
    /// @param orderId The Id of the market order.
    error ActiveOrder(bytes32 orderId);
 
    /// @notice Thrown if the NFT is not listed as market order.
    /// @param orderId The Id of the market order.
    error NoListing(bytes32 orderId);

    /// @notice Thrown with a string message.
    /// @param message Error message string.
    error ErrorMessage(string message);

    /// @notice Thrown with a string message.
    /// @param failed Error message string describes what transaction failed.
    error FailedTransaction(string failed);

    /// @notice Thrown if the collection is not pre-approved.
    error CollectionNotApproved();

   /// ------------------------------- EVENTS -------------------------------

    /// @notice Emitted when a new marketItem is created.
    /// @param collection Indexed - The address of the collection.
    /// @param isApproved Indexed - The status of the collection.
    event CollectionApproved(
        address indexed collection,
        bool indexed isApproved
    );

    /// @notice Emitted when the serviceWallet is updated.
    /// @param serviceWallet Indexed - The new account to serve as service wallet.
    event ServiceWalletUpdated(
        address indexed serviceWallet
    );

    /// @notice Emitted when the serviceFee transaction is completed.
    /// @param serviceWallet Indexed - The account to receive the fee amount.
    /// @param amount The transacted fee amount.
    event TransferServiceFee(
        address indexed serviceWallet, 
        uint256 amount
    );

    /// @notice Emitted when the serviceFee transaction is completed.
    /// @param receiver Indexed - The account to receive the royalty amount.
    /// @param amount The transacted royalty amount.
    event TransferRoyalty(
        address indexed receiver, 
        uint256 amount
    );

    /// @notice Emitted when a new marketItem is created.
    /// @param itemId Indexed - The Id of this marketItem. 
    /// @param index Indexed - The index position of this marketItem in the "liveMarketItems" array.
    /// @param tokenOwner Indexed - The owner of this marketItem. 
    event MarketItemCreated(
        bytes32 indexed itemId,
        uint256 indexed index,
        address indexed tokenOwner
    );

    /// @notice Emitted when a new marketItem is removed.
    /// @param itemId Indexed - The Id of this marketItem. 
    /// @param tokenOwner Indexed - The owner of this marketItem. 
    event MarketItemRemoved(
        bytes32 indexed itemId,
        address indexed tokenOwner
    );

    /// @notice Emitted when a new marketOrder is created.
    /// @param orderId Indexed - The Id of this marketOrder.
    /// @param itemId Indexed - The marketItemId in this marketOrder. 
    /// @param priceInWei The salesprice nominated in wei.
    /// @param isOrder Indexed - Indicates if this an order or not. 
    event MarketOrderCreated(
        bytes32 indexed orderId,
        bytes32 indexed itemId,                
        uint256 priceInWei,              
        bool indexed isOrder
    );

    /// @notice Emitted when a marketOrder is sold.
    /// @param orderId The Id of this marketOrder.
    /// @param tokenId The tokenId of this marketOrder.
    /// @param priceInWei The salesprice nominated in wei.
    /// @param nftContract Indexed - The smartcontact of this nft.
    /// @param escrow The escrow contract containing the payment.
    /// @param seller Indexed - The seller of this marketOrder.
    /// @param buyer Indexed - The buyer of this marketOrder.
    event MarketOrderSold(
        bytes32 orderId,
        uint256 tokenId,
        uint256 priceInWei,
        address indexed nftContract,
        Escrow escrow,
        address indexed seller,
        address indexed buyer
    );

    /// @notice Emitted when a marketOrder is removed.
    /// @param orderId Indexed - The Id of this marketOrder.
    /// @param tokenOwner Indexed - The tokenOwner of this marketOrder.
    event MarketOrderRemoved(
        bytes32 indexed orderId, 
        address indexed tokenOwner
    );
    
    /// @notice Emitted on marketplace deployment, escrow is deployed by the constructor .
    /// @param escrow Indexed - The contract address of the escrow.
    /// @param operator Indexed - The account authorized to interact with the escrow contract.
    event EscrowDeployed(
        Escrow indexed escrow, 
        address indexed operator
    );

    /// @notice Emitted when a market item has been sold and funds are deposited into escrow.
    /// @param seller Indexed - The receiver of the funds.
    /// @param value The salesprice of the nft, minus the servicefee and royalty amount.
    event DepositToEscrow(
        address indexed seller, 
        uint256 value
    );

    /// @notice Emitted on withdrawals from the escrow contract.
    /// @param seller Indexed - The receiver of the funds.
    event WithdrawFromEscrow(
        address indexed seller
    );
    
    /// @notice Emitted when a new timed auction is created.
    /// @param auctionId Indexed - The auction Id.
    /// @param itemId Indexed - The marketItemId in this auction. 
    /// @param seller Indexed - The seller of this nft.
    event MarketAuctionCreated(
        bytes32 indexed auctionId, 
        bytes32 indexed itemId, 
        address indexed seller
    );
    
    /// @notice Emitted when an auction is claimed.
    /// @param auctionId Indexed - The auctionId.
    /// @param itemId Indexed - The itemId of this auction.
    /// @param winner Indexed - The winner of the auction.
    /// @param amount The amount of the bid.
    event AuctionClaimed(
        bytes32 indexed auctionId, 
        bytes32 indexed itemId, 
        address indexed winner, 
        uint256 amount
    );
    
    
    /// @notice Emitted when an auction is not sold.
    /// @param auctionId Indexed - The auctionId.
    /// @param itemId Indexed - The itemId of this auction.
    event NoBuyer(
        bytes32 indexed auctionId, 
        bytes32 indexed itemId
    );

    /// @notice Emitted when an auction is removed.
    /// @param auctionId Indexed - The auctionId.
    /// @param itemId Indexed - The itemId of this auction.
    /// @param highestBidder Indexed - The winner of the auction.
    /// @param highestBid The highestBid of this auction.
    /// @param timestamp The timestamp when this event was emitted.
    event AuctionRemoved(
        bytes32 indexed auctionId, 
        bytes32 indexed itemId, 
        address indexed highestBidder,
        uint256 highestBid,
        uint256 timestamp
    );

    /// @notice Emitted when a higher bid is registered for an auction.
    /// @param auctionId Indexed - The auctionId.
    /// @param bidder Indexed - The receiver of the funds.
    /// @param amount The amount of the bid.
    event HighestBidIncrease(
        bytes32 indexed auctionId, 
        address indexed bidder, 
        uint256 amount
    );

    /// @notice Emitted on withdrawals from the marketplace contract.
    event Withdraw();

    /// @notice Emitted on withdrawals from the pending returns in escrow.
    /// @param to Indexed - The receiver of the funds.
    /// @param amount The withdraw amount.
    event WithdrawPendingReturns(
        address indexed to, 
        uint256 amount
    );

    /// @notice Emitted after an asset has been purchased and transfered to the new owner
    /// @param to Indexed - The receiver of the ntf.
    /// @param collection Indexed - The NFT smart contract address.
    /// @param tokenId Indexed - The tokenId.
    event AssetSent(
        address indexed to,
        address indexed collection,
        uint256 indexed tokenId
    );

    /// @notice Emitted when an item and order has been batch ready for sale.
    /// @param collection Indexed - The smartcontact address of this nft.
    /// @param seller Indexed - The seller of this marketOrder.
    /// @param tokenId The tokenId of this marketOrder.
    /// @param priceInWei The salesprice nominated in wei.
    /// @param itemId The Id of this marketItem.
    /// @param orderId Indexed - The Id of this marketOrder.
    event ListedForSale(
        address indexed collection, 
        address indexed seller, 
        uint256 tokenId, 
        uint256 priceInWei, 
        bytes32 itemId, 
        bytes32 indexed orderId
    );

    /// @notice Method used to check if the user is a HODLER of a specific nft collection.
    /// @param account The user account.
    /// @param collection The nft contract address to check.
    /// @return balance The amount of nft the user is HODLING.
    function isHodler(address account, address collection) external view returns (uint256 balance){
        return IERC721(collection).balanceOf(account);
    }

    /// @notice Method used to calculate the serviceFee to transfer.
    /// @param _priceInWei the salesPrice.
    /// @return serviceFeeAmount The amount to send to the service wallet.
    /// @return sellerAmount The amount to send to the seller.
    /// @return totalFeeAmount Includes service fee seller side, and service fee buyer side.
    function _calculateFees(uint _priceInWei)
        internal
        view
        returns 
    (
        uint serviceFeeAmount, 
        uint sellerAmount,
        uint totalFeeAmount
    )
    {
        serviceFeeAmount = (serviceFee * _priceInWei) / 10000;
        totalFeeAmount = (serviceFeeAmount * 2);
        sellerAmount = (_priceInWei - totalFeeAmount);
        return (serviceFeeAmount, sellerAmount, totalFeeAmount);
    }

    /// @notice Internal method used to deposit the salesAmount into the Escrow contract.
    /// @param tokenOwner The address of the seller of the MarketOrder.
    /// @param value The priceInWei of the listed order.
    function _sendPaymentToEscrow(address payable tokenOwner, uint256 value)
        internal
    {
        escrow.deposit{value: value}(tokenOwner);
        emit DepositToEscrow(tokenOwner, value);
    }


    /// @notice Internal method used to transfer the royalties and service fee.
    /// @param _item The MarketItem struct.
    /// @param _totalFeeAmount The _totalFeeAmount to transfer.
    /// @param _toSellerAmount The amount to transfer to escrow.
    function _transferRoyaltiesAndServiceFee(
        MarketItem memory _item, 
        uint256 _totalFeeAmount, 
        uint256 _toSellerAmount
    ) 
        internal 
    {

        (address _royaltyReceiver, uint256 _royaltyAmount) = 
            IERC2981(_item.nftContract)
                .royaltyInfo(_item.tokenId, _toSellerAmount);

        uint256 _toEscrow = (_toSellerAmount - _royaltyAmount); 

        (bool success,) = serviceWallet.call{value: _totalFeeAmount}(""); 
        if (!success) revert FailedTransaction("Fees");
        emit TransferServiceFee(serviceWallet, _totalFeeAmount);
        
        (bool _success,) = _royaltyReceiver.call{value: _royaltyAmount}(""); 
        if (!_success) revert FailedTransaction("Royalty");
        
        _sendPaymentToEscrow(_item.tokenOwner, _toEscrow);
        emit TransferRoyalty(_royaltyReceiver, _royaltyAmount);
    }

    /// @notice Allows a seller to withdraw their sales revenue from the escrow contract.
    /// @param seller The seller of the market item.
    /// @dev Only the seller can check their own escrowed balance.
    function withdrawSellerRevenue(address payable seller) public isAuth(seller) {
        _withdrawFromEscrow(seller);
    }

    /// --------------------------------- ESCROW METHODS ---------------------------------

    /// @notice Get the escrowed balance of a token seller.
    /// @dev Only the seller can check their own escrowed balance.
    /// @param seller The seller of a market item.
    /// @return balance The sellers balance in escrow. 
    function balanceInEscrow(address payable seller)external view returns (uint256 balance) {
        return escrow.depositsOf(seller);
    }

    /// @notice Internal method used to withdraw the salesAmount from the Escrow contract.
    /// @param seller The address of the seller of the MarketOrder.
    /// @dev Will also reset pendingReturn to 0.
    function _withdrawFromEscrow(address payable seller) internal {
        pendingReturns[seller] = 0;
        escrow.withdraw(seller);
        emit WithdrawFromEscrow(seller);
    }

    /// @notice Internal method used to send the nft asset to the new token Owner.
    /// @param itemId The itemId of to transfer.
    /// @param receiver The address to receiver the nft.
    function _sendAsset(bytes32 itemId, address receiver) internal {
        IERC721(itemsMapping[itemId].nftContract).safeTransferFrom(
            itemsMapping[itemId].operator,
            receiver,
            itemsMapping[itemId].tokenId
        );

        emit AssetSent(receiver, itemsMapping[itemId].nftContract, itemsMapping[itemId].tokenId);
    }

    function rescue(address collection, uint256[] calldata tokenIds, address receiver) external onlyRole(ADMIN_ROLE) {
        for (uint256 i = 0; i < tokenIds.length; i++) {
            IERC721(collection).safeTransferFrom(address(this), receiver, tokenIds[i]);
        }
    }
        
}

///SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./CentBaseStorageBETA.sol";
import "./CentBaseMarketPlaceBETA.sol";

contract CentBaseTimedAuctionBETA is CentBaseStorageBETA {
    uint256 internal _currentAuctionId;
    uint256 internal _currentAuctionsSold;

    receive() external payable {
        revert ErrorMessage("Not payable receive");
    }

    /// @notice Creates a new Auction from a given market item.
    /// @param itemId The Id of the MarketItem to list for auction.
    /// @param biddingTime The timespan in seconds to collect bids for this auction.
    /// @param minimumBid The minimum bid amount for this auction.
    /// @dev Restricted to only owner account.
    /// @dev Restricted by modifiers { isAuthorized, isNotActive }.
    function createMarketAuction(
        bytes32 itemId,
        uint256 biddingTime,
        uint256 minimumBid
    )
        external
        isAuthorized(itemId)
        isNotActive(itemId)
    {
        if (itemId == 0x0 || biddingTime == 0 || minimumBid == 0) {
            revert NoZeroValues();
        }

        bytes32 _auctionId = bytes32(_currentAuctionId += 1);
        bytes32 _itemId = itemId;
        uint256 _auctionEndTime = block.timestamp + biddingTime;
        uint256 _minBid = minimumBid;

        MarketAuction storage _a = auctionsMapping[_auctionId];
        _a.auctionId = _auctionId;
        _a.itemId = _itemId;
        _a.auctionEndTime= _auctionEndTime;
        _a.highestBid = _minBid;
        _a.highestBidder;
        _a.ended = false;

        itemsMapping[_itemId].status = Status(2);
        itemsMapping[_itemId].active = true;

        emit MarketAuctionCreated(
            _auctionId,
            _itemId,
            itemsMapping[_itemId].tokenOwner
        );
    }

    /// @notice Executes a new bid on a auctionId.
    /// @param two Requires a bool false.
    /// @param auctionId The auctionId to bid on.
    /// @dev Restricted by modifiers { costs, isLiveAuction, minBid }.
    function bid(bool two, bytes32 auctionId)
        public
        payable
        costs(two, auctionId)
        isLiveAuction(auctionId)
        minBid(auctionId)
    {
        MarketAuction storage _a = auctionsMapping[auctionId];
        uint256 _bid = msg.value;
        address payable _bidder = payable(_msgSender());

        if (_msgSender() == _a.highestBidder) revert ErrorMessage("Already highest bidder!");
        if (two != false) revert ErrorMessage("Requires uint value: 2");

        if (_a.highestBidder != address(0)) {
            pendingReturns[_a.highestBidder] += _a.highestBid;
            _sendPaymentToEscrow(payable(_a.highestBidder), _a.highestBid);
        }

        _a.highestBid = _bid;
        _a.highestBidder = _bidder;

        emit HighestBidIncrease(_a.auctionId, _a.highestBidder, _a.highestBid);
    }

    /// @notice For users who lost an auction.This will allow them to withdraw their pending returns from the escrow. 
    /// @dev This method will withdraw all the users funds from the escrow contract.
    /// @return success if transaction is completed succewssfully.
    function withdrawPendingReturns() external returns (bool success) {
        if (pendingReturns[_msgSender()] == 0)
            revert ErrorMessage("No pending Returns!");

        uint256 _amount = pendingReturns[_msgSender()];

        if (_amount > 0) {
            pendingReturns[_msgSender()] = 0;

            withdrawSellerRevenue(payable(_msgSender()));
            emit WithdrawPendingReturns(_msgSender(), _amount);
        }
        return true;
    }



    /// @notice Method used to fetch all current live timed auctions on the marketplace.
    /// @return MarketAuction Returns an bytes32 array of all the current active auctions.
    function fetchMarketAuctions()
        external
        view
        returns (MarketAuction[] memory)
    {
        uint256 auctionCount = _currentAuctionId;
        uint256 unsoldAuctionCount = _currentAuctionId - _currentAuctionsSold;
        uint256 currentIndex = 0;

        MarketAuction[] memory _auctions = new MarketAuction[](
            unsoldAuctionCount
        );
        for (uint256 i = 0; i < auctionCount; i++) {
            bytes32 currentId = bytes32(i + 1);
            MarketAuction memory currentAuction = auctionsMapping[currentId];
            _auctions[currentIndex] = currentAuction;
            currentIndex += 1;
        }
        return _auctions;
    }

    /// @notice Public method to finalise an auction.
    /// @param auctionId The auctionId to claim.
    /// @dev The winner of an auction is able to end the auction they won, by claiming the auction,
    ///      the winner will receive their nft and the payment is transfered to the escrow contract. 
    /// @return bool Returns true is auction has a highest bidder, returns false if the auction had no bids. 
    function claimAuction(bytes32 auctionId) public isLiveAuction(auctionId) returns (bool) {
        MarketAuction storage _a = auctionsMapping[auctionId];
        MarketItem storage _item = itemsMapping[_a.itemId];

        if (block.timestamp < _a.auctionEndTime) revert ErrorMessage("To soon!");
        if (_a.ended) revert NotActive(_a.auctionId);

        _a.ended = true;
        _item.status = Status(0);
        _item.active = false;
        
        if (_a.highestBidder == address(0)) {
            _removeAuction(_a.auctionId);
            emit NoBuyer(_a.auctionId, _item.itemId);
            
            return false;
        }
        
        _currentAuctionsSold += 1;

        ( , uint _toSellerAmount, uint _totalFeeAmount) = _calculateFees(_a.highestBid);

        (bool success) = IERC165(_item.nftContract).supportsInterface(_INTERFACE_ID_ERC2981);
        
        if (!success) {
            if (!payable(serviceWallet).send(_totalFeeAmount)) {
                revert FailedTransaction("Fees");
            }

            _sendPaymentToEscrow(_item.tokenOwner, _toSellerAmount);       
            _sendAsset(_item.itemId, _a.highestBidder);

            emit TransferServiceFee(serviceWallet, _totalFeeAmount);
        
        } else {
            _transferRoyaltiesAndServiceFee(_item, _totalFeeAmount, _toSellerAmount);

            _sendAsset(_item.itemId, _a.highestBidder);
        }

        emit AuctionClaimed(_a.auctionId, _a.itemId, _a.highestBidder, _a.highestBid);
        
        _removeAuction(_a.auctionId);
        
        return true;
    }

    /// @notice Method to get an marketAuction.
    /// @param auctionId The bytes32 auctionId to query.
    /// @return marketAuction Returns the MarketAuction.
    function getMarketAuction(bytes32 auctionId)
        external
        view
        onlyRole(ADMIN_ROLE)
        returns (MarketAuction memory marketAuction)
    {
        MarketAuction memory a = auctionsMapping[auctionId];
        return a;
    }

   
    /// @notice Private method to remove a auction from the auctionsMapping.
    /// @param auctionId The auctionId to remove.
    function _removeAuction(bytes32 auctionId) private {
        MarketAuction memory _a = auctionsMapping[auctionId];
        if (_a.ended) {

            emit AuctionRemoved(
                _a.auctionId,
                _a.itemId,
                _a.highestBidder,
                _a.highestBid,
                block.timestamp
            );

            delete (auctionsMapping[auctionId]);
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 400
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address payable","name":"_serviceWallet","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"ActiveOrder","type":"error"},{"inputs":[],"name":"CollectionNotApproved","type":"error"},{"inputs":[{"internalType":"string","name":"message","type":"string"}],"name":"ErrorMessage","type":"error"},{"inputs":[{"internalType":"string","name":"failed","type":"string"}],"name":"FailedTransaction","type":"error"},{"inputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"enum CentBaseStorageBETA.Status","name":"status","type":"uint8"}],"name":"IsActive","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"LowValue","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"NoListing","type":"error"},{"inputs":[],"name":"NoZeroValues","type":"error"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"NotActive","type":"error"},{"inputs":[],"name":"NotAuth","type":"error"},{"inputs":[],"name":"NotAuthorizedRole","type":"error"},{"inputs":[],"name":"NotTokenOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"AssetSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AuctionClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"highestBidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"highestBid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AuctionRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"CollectionApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DepositToEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract Escrow","name":"escrow","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"}],"name":"EscrowDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"bidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"HighestBidIncrease","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceInWei","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"ListedForSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"MarketAuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"}],"name":"MarketItemCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"}],"name":"MarketItemRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"priceInWei","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isOrder","type":"bool"}],"name":"MarketOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"tokenOwner","type":"address"}],"name":"MarketOrderRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceInWei","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftContract","type":"address"},{"indexed":false,"internalType":"contract Escrow","name":"escrow","type":"address"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"}],"name":"MarketOrderSold","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"itemId","type":"bytes32"}],"name":"NoBuyer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"serviceWallet","type":"address"}],"name":"ServiceWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferRoyalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"serviceWallet","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferServiceFee","type":"event"},{"anonymous":false,"inputs":[],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"WithdrawFromEscrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawPendingReturns","type":"event"},{"inputs":[],"name":"ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUYER_SERVICE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ITEM_CREATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"acceptedTokenMap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"approveCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedCollections","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"auctionsMapping","outputs":[{"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"auctionEndTime","type":"uint256"},{"internalType":"uint256","name":"highestBid","type":"uint256"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"bool","name":"ended","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"seller","type":"address"}],"name":"balanceInEscrow","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"two","type":"bool"},{"internalType":"bytes32","name":"auctionId","type":"bytes32"}],"name":"bid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"auctionId","type":"bytes32"}],"name":"claimAuction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"biddingTime","type":"uint256"},{"internalType":"uint256","name":"minimumBid","type":"uint256"}],"name":"createMarketAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address payable","name":"seller","type":"address"}],"name":"createMarketItem","outputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"priceInWei","type":"uint256"}],"name":"createMarketOrder","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"escrow","outputs":[{"internalType":"contract Escrow","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"one","type":"bool"},{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"executeOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"one","type":"bool"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"address","name":"buyer","type":"address"}],"name":"executeOrderForBuyer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fetchMarketAuctions","outputs":[{"components":[{"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"auctionEndTime","type":"uint256"},{"internalType":"uint256","name":"highestBid","type":"uint256"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"bool","name":"ended","type":"bool"}],"internalType":"struct CentBaseStorageBETA.MarketAuction[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchMarketItems","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchMarketOrders","outputs":[{"components":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"priceInWei","type":"uint256"},{"internalType":"bool","name":"isOrder","type":"bool"},{"internalType":"bool","name":"sold","type":"bool"}],"internalType":"struct CentBaseStorageBETA.MarketOrder[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"auctionId","type":"bytes32"}],"name":"getMarketAuction","outputs":[{"components":[{"internalType":"bytes32","name":"auctionId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"auctionEndTime","type":"uint256"},{"internalType":"uint256","name":"highestBid","type":"uint256"},{"internalType":"address","name":"highestBidder","type":"address"},{"internalType":"bool","name":"ended","type":"bool"}],"internalType":"struct CentBaseStorageBETA.MarketAuction","name":"marketAuction","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"}],"name":"getMarketItem","outputs":[{"components":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address payable","name":"tokenOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract Escrow","name":"escrow","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"enum CentBaseStorageBETA.Status","name":"status","type":"uint8"},{"internalType":"bool","name":"active","type":"bool"}],"internalType":"struct CentBaseStorageBETA.MarketItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"name":"getMarketOrder","outputs":[{"components":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"priceInWei","type":"uint256"},{"internalType":"bool","name":"isOrder","type":"bool"},{"internalType":"bool","name":"sold","type":"bool"}],"internalType":"struct CentBaseStorageBETA.MarketOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"collection","type":"address"}],"name":"isHodler","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"itemsMapping","outputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address payable","name":"tokenOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"contract Escrow","name":"escrow","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"enum CentBaseStorageBETA.Status","name":"status","type":"uint8"},{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address payable","name":"seller","type":"address"},{"internalType":"uint256","name":"priceInWei","type":"uint256"}],"name":"listAndSellNewCollection","outputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"priceInWei","type":"uint256"}],"name":"listAndSellPreApprovedCollection","outputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ordersMapping","outputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes32","name":"itemId","type":"bytes32"},{"internalType":"uint256","name":"priceInWei","type":"uint256"},{"internalType":"bool","name":"isOrder","type":"bool"},{"internalType":"bool","name":"sold","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingReturns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"erc20Token","type":"address"}],"name":"releaseStuckTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"itemId","type":"bytes32"}],"name":"removeItem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"rescue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"serviceFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"serviceWallet","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_serviceFee","type":"uint16"}],"name":"updateServiceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_serviceWallet","type":"address"}],"name":"updateServiceWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPendingReturns","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"seller","type":"address"}],"name":"withdrawSellerRevenue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040523480156200001157600080fd5b50604051620059413803806200594183398101604081905262000034916200030b565b60016002556001600160a01b0382166200004d57600080fd5b6200005a6000336200017f565b620000867f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929826200017f565b620000b27fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775336200017f565b620000de7f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c0826200017f565b600480546001600160a01b0384166001600160b01b031990911617601960a31b1790556040516200010f90620002e4565b604051809103906000f0801580156200012c573d6000803e3d6000fd5b50600380546001600160a01b0319166001600160a01b039290921691821790556040513091907e21c494a404e0badb71d5d51d10ae4924bfa8bdd9dbb6cb89e60b4fb1210f0990600090a350506200034a565b6200018b82826200018f565b5050565b620001a68282620001d260201b620031921760201c565b6000828152600160209081526040909120620001cd9183906200323062000272821b17901c565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff166200018b576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200022e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000289836001600160a01b03841662000292565b90505b92915050565b6000818152600183016020526040812054620002db575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556200028c565b5060006200028c565b6105a9806200539883390190565b6001600160a01b03811681146200030857600080fd5b50565b600080604083850312156200031f57600080fd5b82516200032c81620002f2565b60208401519092506200033f81620002f2565b809150509250929050565b61503e806200035a6000396000f3fe60806040526004361061032d5760003560e01c80637489ec23116101a5578063b7747267116100ec578063e2fdcc1711610095578063ec2902151161006f578063ec29021514610c1a578063f5b541a614610c2f578063f7fec41b14610c63578063f803179214610c7657600080fd5b8063e2fdcc1714610b9d578063eb0ad83d14610bbd578063ec07fb7414610bea57600080fd5b8063d0d1161c116100c6578063d0d1161c14610b4a578063d2ae1d9314610b6a578063d547741f14610b7d57600080fd5b8063b774726714610ae8578063c99562f614610b08578063ca15c87314610b2a57600080fd5b80639010d07c1161014e578063a55efa9411610128578063a55efa94146109e7578063af0eae7914610a07578063b3c76d0214610a3b57600080fd5b80639010d07c1461096e57806391d148541461098e578063a217fddf146109d257600080fd5b80638184a48c1161017f5780638184a48c146108f957806381d1746a146109265780638abdf5aa1461093957600080fd5b80637489ec231461089757806375b238fc146108b757806378d5ffab146108d957600080fd5b806336568abe116102745780634f1d17cc1161021d5780635ff61a18116101f75780635ff61a18146107a457806361a92115146107c457806370bf5941146107e65780637121cf411461087757600080fd5b80634f1d17cc1461072c5780635641f3c31461074c5780635e2fc29b1461078457600080fd5b8063418e4b3c1161024e578063418e4b3c146105fb5780634234d4a41461069257806348a4bbf0146106b257600080fd5b806336568abe146105925780633ccfd60b146105b25780633eddf3cb146105c757600080fd5b806320cf5a40116102d657806326b387bb116102b057806326b387bb146105255780632f2ff15d1461055257806333f0aeba1461057257600080fd5b806320cf5a40146104975780632236d2fd146104b7578063248a9ca3146104e757600080fd5b8063150b7a0211610307578063150b7a02146103fe5780631718c08714610442578063180370451461047757600080fd5b806301ffc9a71461038557806307beac55146103ba5780630f08efe0146103dc57600080fd5b366103805760405163a183e9a560e01b815260206004820152601360248201527f4e6f742070617961626c6520726563656976650000000000000000000000000060448201526064015b60405180910390fd5b600080fd5b34801561039157600080fd5b506103a56103a0366004614694565b610c96565b60405190151581526020015b60405180910390f35b3480156103c657600080fd5b506103da6103d53660046146d3565b610cc1565b005b3480156103e857600080fd5b506103f1610d91565b6040516103b1919061476e565b34801561040a57600080fd5b506104296104193660046147c8565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016103b1565b34801561044e57600080fd5b5061046261045d3660046148a8565b610de9565b604080519283526020830191909152016103b1565b34801561048357600080fd5b506103da6104923660046148f0565b610ebd565b3480156104a357600080fd5b506103da6104b2366004614909565b6110dd565b3480156104c357600080fd5b506103a56104d2366004614909565b600a6020526000908152604090205460ff1681565b3480156104f357600080fd5b506105176105023660046148f0565b60009081526020819052604090206001015490565b6040519081526020016103b1565b34801561053157600080fd5b50610517610540366004614909565b600b6020526000908152604090205481565b34801561055e57600080fd5b506103da61056d366004614926565b6111f1565b34801561057e57600080fd5b5061046261058d366004614956565b611216565b34801561059e57600080fd5b506103da6105ad366004614926565b6112c3565b3480156105be57600080fd5b506103da611341565b3480156105d357600080fd5b506105177f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c081565b34801561060757600080fd5b5061065a6106163660046148f0565b60096020526000908152604090208054600182015460028301546003840154600490940154929391929091906001600160a01b03811690600160a01b900460ff1686565b6040805196875260208701959095529385019290925260608401526001600160a01b03166080830152151560a082015260c0016103b1565b34801561069e57600080fd5b506105176106ad36600461498b565b611411565b3480156106be57600080fd5b506107006106cd3660046148f0565b60086020526000908152604090208054600182015460028301546003909301549192909160ff8082169161010090041685565b60408051958652602086019490945292840191909152151560608301521515608082015260a0016103b1565b34801561073857600080fd5b506103da6107473660046149cd565b611451565b34801561075857600080fd5b5060045461076c906001600160a01b031681565b6040516001600160a01b0390911681526020016103b1565b34801561079057600080fd5b506103da61079f366004614909565b611767565b3480156107b057600080fd5b506105176107bf3660046149f9565b61179a565b3480156107d057600080fd5b506107d961180f565b6040516103b19190614a27565b3480156107f257600080fd5b506108626108013660046148f0565b600760208190526000918252604090912080546001820154600283015460038401546004850154600586015460068701549690970154949693956001600160a01b039384169592841694918416939091169160ff8082169161010090041689565b6040516103b199989796959493929190614ad0565b34801561088357600080fd5b50610517610892366004614909565b611983565b3480156108a357600080fd5b506103da6108b23660046148f0565b6119f2565b3480156108c357600080fd5b50610517600080516020614fe983398151915281565b3480156108e557600080fd5b506103da6108f4366004614b31565b611c1d565b34801561090557600080fd5b506109196109143660046148f0565b611c58565b6040516103b19190614b55565b6103da610934366004614c01565b611d61565b34801561094557600080fd5b5060045461095b90600160a01b900461ffff1681565b60405161ffff90911681526020016103b1565b34801561097a57600080fd5b5061076c610989366004614c2d565b611f69565b34801561099a57600080fd5b506103a56109a9366004614926565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156109de57600080fd5b50610517600081565b3480156109f357600080fd5b506103da610a02366004614c4f565b611f81565b348015610a1357600080fd5b506105177fc0c51901e654d6f7950f502a12544003f395c97494ff89ced7775d34b9bc636981565b348015610a4757600080fd5b50610adb610a563660046148f0565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915250600090815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff80821615156060840152610100909104161515608082015290565b6040516103b19190614c7d565b348015610af457600080fd5b506103a5610b033660046148f0565b611fee565b348015610b1457600080fd5b50610b1d612469565b6040516103b19190614cba565b348015610b3657600080fd5b50610517610b453660046148f0565b6125c6565b348015610b5657600080fd5b506103da610b65366004614909565b6125dd565b6103da610b78366004614d3c565b612640565b348015610b8957600080fd5b506103da610b98366004614926565b61286c565b348015610ba957600080fd5b5060035461076c906001600160a01b031681565b348015610bc957600080fd5b50610bdd610bd83660046148f0565b612891565b6040516103b19190614d5c565b348015610bf657600080fd5b506103a5610c05366004614909565b600c6020526000908152604090205460ff1681565b348015610c2657600080fd5b506103a5612946565b348015610c3b57600080fd5b506105177f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b6103da610c71366004614c01565b612a12565b348015610c8257600080fd5b50610517610c91366004614c2d565b612e22565b60006001600160e01b03198216635a05180f60e01b1480610cbb5750610cbb82613245565b92915050565b600080516020614fe9833981519152610cd98161327a565b60005b83811015610d8957856001600160a01b03166342842e0e3085888886818110610d0757610d07614daa565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610d5e57600080fd5b505af1158015610d72573d6000803e3d6000fd5b505050508080610d8190614dd6565b915050610cdc565b505050505050565b60606005805480602002602001604051908101604052809291908181526020018280548015610ddf57602002820191906000526020600020905b815481526020019060010190808311610dcb575b5050505050905090565b6000807f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c0610e168161327a565b6001600160a01b0387166000908152600c60205260409020805460ff19166001179055610e44878787613287565b9250610e508385612e22565b915081856001600160a01b0316886001600160a01b03167feeb55d6f401444e3135de808fa1026bed54e04e1ef6e688a831fbbc8c6bc0d22898888604051610eab939291909283526020830191909152604082015260600190565b60405180910390a45094509492505050565b6000818152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548594939160e084019160ff1690811115610f4e57610f4e614a98565b6002811115610f5f57610f5f614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614610fb05760405163060a6aeb60e51b815260040160405180910390fd5b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff169081111561104157611041614a98565b600281111561105257611052614a98565b81526020016007820160019054906101000a900460ff1615151515815250509050806101000151156110a057805160e082015160405163142c79d560e21b8152610377929190600401614def565b6110a9856135a3565b604051339086907f76c170d27c079a651a2b27047996fe5849b52f6d7b3730efe62f8fe71b6e9cba90600090a35050505050565b600080516020614fe98339815191526110f58161327a565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561113c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111609190614e03565b90506001600160a01b03831663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156111bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e39190614e1c565b6111ec57600080fd5b505050565b60008281526020819052604090206001015461120c8161327a565b6111ec838361377e565b6001600160a01b0383166000908152600c6020526040812054819060ff1661125157604051630aba3fbb60e31b815260040160405180910390fd5b61125c858533613287565b91506112688284612e22565b6040805186815260208101869052908101849052909150819033906001600160a01b038816907feeb55d6f401444e3135de808fa1026bed54e04e1ef6e688a831fbbc8c6bc0d229060600160405180910390a4935093915050565b6001600160a01b03811633146113335760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610377565b61133d82826137a0565b5050565b600080516020614fe98339815191526113598161327a565b604051600090339047908381818185875af1925050503d806000811461139b576040519150601f19603f3d011682016040523d82523d6000602084013e6113a0565b606091505b50509050806113e45760405163a183e9a560e01b815260206004820152600f60248201526e15da5d1a191c985dc811985a5b1959608a1b6044820152606401610377565b6040517f57ea89b6814fccbbe8728fa89cc8e6b5477e559b2a34e946e105b11112e94b5890600090a15050565b60007f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c061143d8161327a565b611448858585613287565b95945050505050565b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff16908111156114e2576114e2614a98565b60028111156114f3576114f3614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b0316146115445760405163060a6aeb60e51b815260040160405180910390fd5b6000858152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548994939160e084019160ff16908111156115d5576115d5614a98565b60028111156115e6576115e6614a98565b81526020016007820160019054906101000a900460ff16151515158152505090508061010001511561163457805160e082015160405163142c79d560e21b8152610377929190600401614def565b86158061163f575085155b80611648575084155b1561166657604051630373865960e11b815260040160405180910390fd5b60006001600d600082825461167b9190614e39565b9182905550915088905060006116918942614e39565b6000848152600960205260409020848155600181018490556002808201839055600382018b905560048201805460ff60a01b191690559192508991600085815260076020819052604090912001805460ff191660018360028111156116f8576116f8614a98565b02179055506000848152600760208190526040808320918201805461ff00191661010017905560029091015490516001600160a01b0390911691869188917f7eacf015c7364f2216b751b04e760b5b35cfecc012906d01ffea526f4a03bcca91a4505050505050505050505050565b806001600160a01b03811633146117915760405163060a6aeb60e51b815260040160405180910390fd5b61133d826137c2565b6040516370a0823160e01b81526001600160a01b038381166004830152600091908316906370a0823190602401602060405180830381865afa1580156117e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118089190614e03565b9392505050565b6060600061181c60115490565b9050600061182960125490565b6011546118369190614e4c565b90506000808267ffffffffffffffff811115611854576118546147b2565b6040519080825280602002602001820160405280156118ad57816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816118725790505b50905060005b8481101561197a5760006118c8826001614e39565b600081815260086020526040902060038101549192509060ff1615611957576040805160a0810182528254815260018301546020820152600283015491810191909152600382015460ff808216151560608401526101009091041615156080820152845185908790811061193e5761193e614daa565b6020908102919091010152611954600186614e39565b94505b85850361196557505061197a565b5050808061197290614dd6565b9150506118b3565b50949350505050565b6003546040516371d4ed8d60e11b81526001600160a01b038381166004830152600092169063e3a9db1a90602401602060405180830381865afa1580156119ce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb9190614e03565b600081815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff8082161515606084018190526101009092041615156080830152829190611a70578051604051636d9c892f60e11b81526004810191909152602401610377565b600083815260086020908152604080832060019081015480855260078085528386208451610120810186528154815293810154958401959095526002808601546001600160a01b0390811695850195909552600386015485166060850152600486015485166080850152600586015490941660a0840152600685015460c0840152840154909493919260e084019160ff1690811115611b1157611b11614a98565b6002811115611b2257611b22614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614611b735760405163060a6aeb60e51b815260040160405180910390fd5b60008581526008602081815260408084206001810154808652600784529185208a8652939092526003909101805461ffff19169055879290919060078201805460ff19166001836002811115611bcb57611bcb614a98565b021790555060078101805461ff0019169055611be68361386d565b604051339084907f336749273676524b08a5421532bf60f1cf06aab4d884facd39f19814c765738590600090a35050505050505050565b600080516020614fe9833981519152611c358161327a565b506004805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152600082815260076020818152604092839020835161012081018552815481526001820154928101929092526002808201546001600160a01b0390811695840195909552600382015485166060840152600482015485166080840152600582015490941660a0830152600681015460c083015291820154909260e084019160ff1690811115611d3157611d31614a98565b6002811115611d4257611d42614a98565b815260079190910154610100900460ff16151560209091015292915050565b600081815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff8082161515606084018190526101009092041615156080830152829190611ddf578051604051636d9c892f60e11b81526004810191909152602401610377565b611de76138d1565b83838115611e95576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff8082161515606085015261010090910416151560808301529091908190611e4f90613928565b50915091506000828460400151611e669190614e39565b905080341015611e8c5760405163723e6dc160e11b815260048101829052602401610377565b50505050611f4c565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a08301529091908190611f0a90613928565b50915091506000828460600151611f219190614e39565b905080341015611f475760405163723e6dc160e11b815260048101829052602401610377565b505050505b611f57868633613978565b5050611f636001600255565b50505050565b60008281526001602052604081206118089083613d75565b600080516020614fe9833981519152611f998161327a565b6001600160a01b0383166000818152600c6020526040808220805460ff191686151590811790915590519092917f35458355462628654fc1c4ba280f8cbd0e5539f514c06e40e17e1d6cdf40a34291a3505050565b6000818152600960209081526040808320815160c0810183528154815260018201549381019390935260028101549183019190915260038101546060830152600401546001600160a01b0381166080830152600160a01b900460ff1615801560a0830152839190612078578051604051636d9c892f60e11b81526004810191909152602401610377565b600084815260096020908152604080832060018101548452600790925290912060028201544210156120d85760405163a183e9a560e01b8152602060048201526008602482015267546f20736f6f6e2160c01b6044820152606401610377565b6004820154600160a01b900460ff161561210b578154604051636d9c892f60e11b81526004810191909152602401610377565b60048201805460ff60a01b1916600160a01b179055600060078201805460ff1916600183600281111561214057612140614a98565b021790555060078101805461ff001916905560048201546001600160a01b03166121a757815461216f90613d81565b805482546040517fb3964661b9aae5de6c2141c76097498645757fbe0af80f74ef3e421a12deecaf90600090a3600094505050612462565b6001600e60008282546121ba9190614e39565b925050819055506000806121d18460030154613928565b60058601546040516301ffc9a760e01b815263152a902d60e11b6004820152929550909350600092506001600160a01b0316906301ffc9a790602401602060405180830381865afa15801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190614e1c565b90508061232d576004546040516001600160a01b039091169083156108fc029084906000818181858888f193505050506122b4576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b60028401546122cc906001600160a01b031684613e93565b835460048601546122e691906001600160a01b0316613f3b565b6004546040518381526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a26123fd565b604080516101208101825285548152600186015460208201526002808701546001600160a01b0390811693830193909352600387015483166060830152600487015483166080830152600587015490921660a0820152600686015460c082015260078601546123e392879160e084019160ff909116908111156123b2576123b2614a98565b60028111156123c3576123c3614a98565b815260079190910154610100900460ff1615156020909101528385614019565b835460048601546123fd91906001600160a01b0316613f3b565b60048501546001860154865460038801546040519081526001600160a01b03909316927f410b887f470d25379abe64505f9b3ecc244611304d71707d983eddb1d432d9479060200160405180910390a4845461245890613d81565b6001975050505050505b5050919050565b600d54600e54606091906000906124809083614e4c565b90506000808267ffffffffffffffff81111561249e5761249e6147b2565b6040519080825280602002602001820160405280156124fe57816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282526000199092019101816124bc5790505b50905060005b8481101561197a576000612519826001614e39565b600081815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff16151560a0820152845191925090819085908790811061259957612599614daa565b60209081029190910101526125af600186614e39565b9450505080806125be90614dd6565b915050612504565b6000818152600160205260408120610cbb90614269565b600080516020614fe98339815191526125f58161327a565b600480546001600160a01b0319166001600160a01b0384169081179091556040517fb230a0c075837f61328839894753bab90aa32699d692039d4e22ffe3a9ce9f7690600090a25050565b7fc0c51901e654d6f7950f502a12544003f395c97494ff89ced7775d34b9bc636961266a8161327a565b600083815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff80821615156060840181905261010090920416151560808301528491906126e8578051604051636d9c892f60e11b81526004810191909152602401610377565b6126f06138d1565b8585811561279e576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff808216151560608501526101009091041615156080830152909190819061275890613928565b5091509150600082846040015161276f9190614e39565b9050803410156127955760405163723e6dc160e11b815260048101829052602401610377565b50505050612855565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a0830152909190819061281390613928565b5091509150600082846060015161282a9190614e39565b9050803410156128505760405163723e6dc160e11b815260048101829052602401610377565b505050505b612860888888613978565b5050610d896001600255565b6000828152602081905260409020600101546128878161327a565b6111ec83836137a0565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152600080516020614fe98339815191526128db8161327a565b5050600090815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff16151560a082015290565b336000908152600b602052604081205481036129a55760405163a183e9a560e01b815260206004820152601360248201527f4e6f2070656e64696e672052657475726e7321000000000000000000000000006044820152606401610377565b336000908152600b60205260409020548015612a0a57336000818152600b60205260408120556129d490611767565b60405181815233907f776937c4d7f28ffdf4afa12dcfc0bdd3d0ac3ab2315fd5cc109ed2fed8e4d3c39060200160405180910390a25b600191505090565b81818115612ac0576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff8082161515606085015261010090910416151560808301529091908190612a7a90613928565b50915091506000828460400151612a919190614e39565b905080341015612ab75760405163723e6dc160e11b815260048101829052602401610377565b50505050612b77565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a08301529091908190612b3590613928565b50915091506000828460600151612b4c9190614e39565b905080341015612b725760405163723e6dc160e11b815260048101829052602401610377565b505050505b600083815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff1615801560a0830152849190612c04578051604051636d9c892f60e11b81526004810191909152602401610377565b600085815260096020908152604091829020825160c081018452815481526001820154928101929092526002810154928201929092526003820154606082018190526004909201546001600160a01b0381166080830152600160a01b900460ff16151560a082015286913411612c9557806060015160405163723e6dc160e11b815260040161037791815260200190565b60008781526009602052604090206004810154349033906001600160a01b03168103612d045760405163a183e9a560e01b815260206004820152601760248201527f416c7265616479206869676865737420626964646572210000000000000000006044820152606401610377565b8a15612d535760405163a183e9a560e01b815260206004820152601660248201527f52657175697265732075696e742076616c75653a2032000000000000000000006044820152606401610377565b60048301546001600160a01b031615612db957600383015460048401546001600160a01b03166000908152600b602052604081208054909190612d97908490614e39565b909155505060048301546003840154612db9916001600160a01b031690613e93565b600383018290556004830180546001600160a01b0319166001600160a01b03831690811790915583546040518481527fa3eb7fe0be6b3d2c74cc2abe7b4cd0c8c2294a5ed1dcc026feb98da92264f3779060200160405180910390a35050505050505050505050565b6000612e2c6138d1565b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff1690811115612ebd57612ebd614a98565b6002811115612ece57612ece614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614612f1f5760405163060a6aeb60e51b815260040160405180910390fd5b6000858152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548994939160e084019160ff1690811115612fb057612fb0614a98565b6002811115612fc157612fc1614a98565b81526020016007820160019054906101000a900460ff16151515158152505090508061010001511561300f57805160e082015160405163142c79d560e21b8152610377929190600401614def565b6000878152600760205260409020868061303f5760405163723e6dc160e11b815260048101829052602401610377565b61304d601180546001019055565b600061305860115490565b60008181526008602052604090206003015490915060ff161561309157604051632568ba2560e11b815260048101829052602401610377565b6040805160a081018252828152845460208083019182528284018681526001606085018181526000608087018181528982526008865288822097518855955187840155925160028701555160039095018054945115156101000261ff00199615159690961661ffff19958616179590951790945560078801805461010194169390931790925560068054808501825592527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f9091018490558554925185815291929184917ffb2ae9ffe163eff18f43966856529159761fefcaf3f9a56dbad66762ebf63970910160405180910390a49650505050505050610cbb6001600255565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661133d576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556131ec3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611808836001600160a01b038416614273565b60006001600160e01b03198216637965db0b60e01b1480610cbb57506301ffc9a760e01b6001600160e01b0319831614610cbb565b61328481336142c2565b50565b6040516331a9108f60e11b8152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190614e5f565b6001600160a01b0316826001600160a01b031614613324576040516359dc379f60e01b815260040160405180910390fd5b600061332f600f5490565b9050426000336040516bffffffffffffffffffffffff19606092831b811660208301529189901b9091166034820152604881018790526068810183905260880160408051808303601f190181528282528051602091820120610120840183528084529083018690526001600160a01b03888116928401929092523060608401526003548216608084015290891660a083015260c08201889052915060e0810160008152600060209182018190528381526007808352604091829020845181559284015160018481019190915591840151600280850180546001600160a01b039384166001600160a01b0319918216179091556060870151600387018054918516918316919091179055608087015160048701805491851691831691909117905560a08701516005870180549190941691161790915560c0850151600685015560e085015191840180549293909260ff191691849081111561349257613492614a98565b0217905550610100918201516007909101805491151590920261ff0019909116179055600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018190556134f8600f80546001019055565b846001600160a01b031683827f2d22ca4594d9c25baac662e26b521c5bde631c255796ba735367af219869e50460405160405180910390a4604051632142170760e11b81526001600160a01b038681166004830152306024830152604482018890528816906342842e0e90606401600060405180830381600087803b15801561358057600080fd5b505af1158015613594573d6000803e3d6000fd5b50929998505050505050505050565b6000818152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c08401529283015491929160e084019160ff9091169081111561363557613635614a98565b600281111561364657613646614a98565b81526020016007820160019054906101000a900460ff1615151515815250509050806101000151156136a6576000828152600760208190526040918290200154905163142c79d560e21b815261037791849160ff90911690600401614def565b6000828152600760208190526040808320838155600181018490556002810180546001600160a01b03199081169091556003820180548216905560048083018054831690556005830180549092169091556006820194909455909101805461ffff1916905560a08301518382015160c08501519251632142170760e11b815230948101949094526001600160a01b039081166024850152604484019290925216906342842e0e90606401600060405180830381600087803b15801561376a57600080fd5b505af1158015610d89573d6000803e3d6000fd5b6137888282613192565b60008281526001602052604090206111ec9082613230565b6137aa8282614335565b60008281526001602052604090206111ec90826143b4565b6001600160a01b038181166000818152600b60205260408082209190915560035490516351cff8d960e01b81526004810192909252909116906351cff8d990602401600060405180830381600087803b15801561381e57600080fd5b505af1158015613832573d6000803e3d6000fd5b50506040516001600160a01b03841692507f8b893bcbc5bce509a4f8cf62a0fd8308f2ef068d8862ee06aef051027ca2a3229150600090a250565b60008181526008602052604090206003015460ff16156138a357604051632568ba2560e11b815260048101829052602401610377565b6000908152600860205260408120818155600181018290556002810191909155600301805461ffff19169055565b60028054036139225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610377565b60028055565b600454600090819081906127109061394c908690600160a01b900461ffff16614e7c565b6139569190614e93565b9250613963836002614e7c565b905061396f8185614e4c565b91509193909250565b6001831515146139cb5760405163a183e9a560e01b815260206004820152601960248201527f526571756972657320626f6f6c2076616c75653a2074727565000000000000006044820152606401610377565b6000828152600860205260409020600381015460ff16613a0457805460405163753fd89d60e01b81526004810191909152602401610377565b60038101805461ffff1916610100179055613a23601280546001019055565b600181015460009081526007602052604081209060078201805460ff19166001836002811115613a5557613a55614a98565b021790555060078101805461ff001916905560028201546000908190613a7a90613928565b9250925050613a8c846000015461386d565b60058301546040516301ffc9a760e01b815263152a902d60e11b60048201526000916001600160a01b0316906301ffc9a790602401602060405180830381865afa158015613ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b029190614e1c565b905080613bf6576004546040516000916001600160a01b03169084908381818185875af1925050503d8060008114613b56576040519150601f19603f3d011682016040523d82523d6000602084013e613b5b565b606091505b5050905080613b96576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b6002850154613bae906001600160a01b031685613e93565b6004546040518481526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a250613c7b565b604080516101208101825285548152600186015460208201526002808701546001600160a01b0390811693830193909352600387015483166060830152600487015483166080830152600587015490921660a0820152600686015460c08201526007860154613c7b92879160e084019160ff909116908111156123b2576123b2614a98565b60058401546006850154604051632142170760e11b81523060048201526001600160a01b03898116602483015260448201929092529116906342842e0e90606401600060405180830381600087803b158015613cd657600080fd5b505af1158015613cea573d6000803e3d6000fd5b50505050613cf53390565b60028086015460058701546006880154928901546004890154604080518e815260208101969096528501919091526001600160a01b03908116606085015293841693918216929116907f334bee2c213718999aa3a4795ff7cb9c7fa419d7bce93a0b4e3046e2b53310d69060800160405180910390a45050505050505050565b600061180883836143c9565b600081815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff1615801560a083015261133d5780608001516001600160a01b0316816020015182600001517f3050ffbb1483e2c1283ef920c4949924df01eeb5132f83bbc3f8e929d499d6fe846060015142604051613e42929190918252602082015260400190565b60405180910390a450600090815260096020526040812081815560018101829055600281018290556003810191909155600401805474ffffffffffffffffffffffffffffffffffffffffff19169055565b60035460405163f340fa0160e01b81526001600160a01b0384811660048301529091169063f340fa019083906024016000604051808303818588803b158015613edb57600080fd5b505af1158015613eef573d6000803e3d6000fd5b5050505050816001600160a01b03167f0fba8404439890021adb1c06dce3dc283974eb639a2dc521dca0c8d6378f582f82604051613f2f91815260200190565b60405180910390a25050565b60008281526007602052604090819020600581015460038201546006909201549251632142170760e11b81526001600160a01b0392831660048201528483166024820152604481019390935216906342842e0e90606401600060405180830381600087803b158015613fac57600080fd5b505af1158015613fc0573d6000803e3d6000fd5b505050600083815260076020526040808220600681015460059091015491519093506001600160a01b0391821692918516917ff89c3306c782ffbbe4593aa5673e97e9ad6a8c65d240405e8986363fada6639291a45050565b6000808460a001516001600160a01b0316632a55205a8660c00151856040518363ffffffff1660e01b815260040161405b929190918252602082015260400190565b6040805180830381865afa158015614077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061409b9190614eb5565b909250905060006140ac8285614e4c565b6004546040519192506000916001600160a01b039091169087908381818185875af1925050503d80600081146140fe576040519150601f19603f3d011682016040523d82523d6000602084013e614103565b606091505b505090508061413e576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b6004546040518781526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a26000846001600160a01b03168460405160006040518083038185875af1925050503d80600081146141cd576040519150601f19603f3d011682016040523d82523d6000602084013e6141d2565b606091505b505090508061420e576040516314314f9760e31b8152602060048201526007602482015266526f79616c747960c81b6044820152606401610377565b61421c886040015184613e93565b846001600160a01b03167f0975b2c6ad0cff6ea2027e5ea8f0d292f0a5533560a8e130d150bfaac81dbc038560405161425791815260200190565b60405180910390a25050505050505050565b6000610cbb825490565b60008181526001830160205260408120546142ba57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610cbb565b506000610cbb565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661133d576142f3816143f3565b6142fe836020614405565b60405160200161430f929190614f07565b60408051601f198184030181529082905262461bcd60e51b825261037791600401614f88565b6000828152602081815260408083206001600160a01b038516845290915290205460ff161561133d576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611808836001600160a01b0384166145a1565b60008260000182815481106143e0576143e0614daa565b9060005260206000200154905092915050565b6060610cbb6001600160a01b03831660145b60606000614414836002614e7c565b61441f906002614e39565b67ffffffffffffffff811115614437576144376147b2565b6040519080825280601f01601f191660200182016040528015614461576020820181803683370190505b509050600360fc1b8160008151811061447c5761447c614daa565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106144ab576144ab614daa565b60200101906001600160f81b031916908160001a90535060006144cf846002614e7c565b6144da906001614e39565b90505b6001811115614552576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061450e5761450e614daa565b1a60f81b82828151811061452457614524614daa565b60200101906001600160f81b031916908160001a90535060049490941c9361454b81614fbb565b90506144dd565b5083156118085760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610377565b6000818152600183016020526040812054801561468a5760006145c5600183614e4c565b85549091506000906145d990600190614e4c565b905081811461463e5760008660000182815481106145f9576145f9614daa565b906000526020600020015490508087600001848154811061461c5761461c614daa565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061464f5761464f614fd2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610cbb565b6000915050610cbb565b6000602082840312156146a657600080fd5b81356001600160e01b03198116811461180857600080fd5b6001600160a01b038116811461328457600080fd5b600080600080606085870312156146e957600080fd5b84356146f4816146be565b9350602085013567ffffffffffffffff8082111561471157600080fd5b818701915087601f83011261472557600080fd5b81358181111561473457600080fd5b8860208260051b850101111561474957600080fd5b6020830195508094505050506040850135614763816146be565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b818110156147a65783518352928401929184019160010161478a565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b600080600080608085870312156147de57600080fd5b84356147e9816146be565b935060208501356147f9816146be565b925060408501359150606085013567ffffffffffffffff8082111561481d57600080fd5b818701915087601f83011261483157600080fd5b813581811115614843576148436147b2565b604051601f8201601f19908116603f0116810190838211818310171561486b5761486b6147b2565b816040528281528a602084870101111561488457600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600080600080608085870312156148be57600080fd5b84356148c9816146be565b93506020850135925060408501356148e0816146be565b9396929550929360600135925050565b60006020828403121561490257600080fd5b5035919050565b60006020828403121561491b57600080fd5b8135611808816146be565b6000806040838503121561493957600080fd5b82359150602083013561494b816146be565b809150509250929050565b60008060006060848603121561496b57600080fd5b8335614976816146be565b95602085013595506040909401359392505050565b6000806000606084860312156149a057600080fd5b83356149ab816146be565b92506020840135915060408401356149c2816146be565b809150509250925092565b6000806000606084860312156149e257600080fd5b505081359360208301359350604090920135919050565b60008060408385031215614a0c57600080fd5b8235614a17816146be565b9150602083013561494b816146be565b6020808252825182820181905260009190848201906040850190845b818110156147a657614a858385518051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b9284019260a09290920191600101614a43565b634e487b7160e01b600052602160045260246000fd5b60038110614acc57634e487b7160e01b600052602160045260246000fd5b9052565b898152602081018990526001600160a01b03888116604083015287811660608301528681166080830152851660a082015260c081018490526101208101614b1a60e0830185614aae565b8215156101008301529a9950505050505050505050565b600060208284031215614b4357600080fd5b813561ffff8116811461180857600080fd5b600061012082019050825182526020830151602083015260408301516001600160a01b03808216604085015280606086015116606085015250506080830151614ba960808401826001600160a01b03169052565b5060a0830151614bc460a08401826001600160a01b03169052565b5060c083015160c083015260e0830151614be160e0840182614aae565b50610100928301511515919092015290565b801515811461328457600080fd5b60008060408385031215614c1457600080fd5b8235614c1f81614bf3565b946020939093013593505050565b60008060408385031215614c4057600080fd5b50508035926020909101359150565b60008060408385031215614c6257600080fd5b8235614c6d816146be565b9150602083013561494b81614bf3565b60a08101610cbb82848051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b6020808252825182820181905260009190848201906040850190845b818110156147a657614d29838551805182526020810151602083015260408101516040830152606081015160608301526001600160a01b03608082015116608083015260a0810151151560a08301525050565b9284019260c09290920191600101614cd6565b600080600060608486031215614d5157600080fd5b83356149ab81614bf3565b60c08101610cbb8284805182526020810151602083015260408101516040830152606081015160608301526001600160a01b03608082015116608083015260a0810151151560a08301525050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614de857614de8614dc0565b5060010190565b828152604081016118086020830184614aae565b600060208284031215614e1557600080fd5b5051919050565b600060208284031215614e2e57600080fd5b815161180881614bf3565b80820180821115610cbb57610cbb614dc0565b81810381811115610cbb57610cbb614dc0565b600060208284031215614e7157600080fd5b8151611808816146be565b8082028115828204841417610cbb57610cbb614dc0565b600082614eb057634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215614ec857600080fd5b8251614ed3816146be565b6020939093015192949293505050565b60005b83811015614efe578181015183820152602001614ee6565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614f3f816017850160208801614ee3565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614f7c816028840160208801614ee3565b01602801949350505050565b6020815260008251806020840152614fa7816040850160208701614ee3565b601f01601f19169190910160400192915050565b600081614fca57614fca614dc0565b506000190190565b634e487b7160e01b600052603160045260246000fdfea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a26469706673582212205810bca79729bf398f38e9da86f92ba2121f247e4126325a34aeba81ee9dafb764736f6c63430008110033608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61052b8061007e6000396000f3fe6080604052600436106100655760003560e01c8063e3a9db1a11610043578063e3a9db1a146100ce578063f2fde38b14610112578063f340fa011461013257600080fd5b806351cff8d91461006a578063715018a61461008c5780638da5cb5b146100a1575b600080fd5b34801561007657600080fd5b5061008a6100853660046104aa565b610145565b005b34801561009857600080fd5b5061008a6101bc565b3480156100ad57600080fd5b506000546040516001600160a01b0390911681526020015b60405180910390f35b3480156100da57600080fd5b506101046100e93660046104aa565b6001600160a01b031660009081526001602052604090205490565b6040519081526020016100c5565b34801561011e57600080fd5b5061008a61012d3660046104aa565b6101d0565b61008a6101403660046104aa565b61024e565b61014d6102c0565b6001600160a01b0381166000818152600160205260408120805491905590610175908261031a565b816001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5826040516101b091815260200190565b60405180910390a25050565b6101c46102c0565b6101ce6000610438565b565b6101d86102c0565b6001600160a01b0381166102425760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61024b81610438565b50565b6102566102c0565b6001600160a01b0381166000908152600160205260408120805434928392916102809084906104ce565b90915550506040518181526001600160a01b038316907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c4906020016101b0565b6000546001600160a01b031633146101ce5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610239565b8047101561036a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610239565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146103b7576040519150601f19603f3d011682016040523d82523d6000602084013e6103bc565b606091505b50509050806104335760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610239565b505050565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b038116811461024b57600080fd5b6000602082840312156104bc57600080fd5b81356104c781610495565b9392505050565b808201808211156104ef57634e487b7160e01b600052601160045260246000fd5b9291505056fea264697066735822122092fcfe643522c319c7bd68649526625a52dcafbd30e057fab72d8ffc5a152a2064736f6c63430008110033000000000000000000000000d85cc0b76196de86ce1128516d978de5d6dfd21e0000000000000000000000007e5c63372c8c382fc3ffc1700f54b5ace3b93c93

Deployed Bytecode

0x60806040526004361061032d5760003560e01c80637489ec23116101a5578063b7747267116100ec578063e2fdcc1711610095578063ec2902151161006f578063ec29021514610c1a578063f5b541a614610c2f578063f7fec41b14610c63578063f803179214610c7657600080fd5b8063e2fdcc1714610b9d578063eb0ad83d14610bbd578063ec07fb7414610bea57600080fd5b8063d0d1161c116100c6578063d0d1161c14610b4a578063d2ae1d9314610b6a578063d547741f14610b7d57600080fd5b8063b774726714610ae8578063c99562f614610b08578063ca15c87314610b2a57600080fd5b80639010d07c1161014e578063a55efa9411610128578063a55efa94146109e7578063af0eae7914610a07578063b3c76d0214610a3b57600080fd5b80639010d07c1461096e57806391d148541461098e578063a217fddf146109d257600080fd5b80638184a48c1161017f5780638184a48c146108f957806381d1746a146109265780638abdf5aa1461093957600080fd5b80637489ec231461089757806375b238fc146108b757806378d5ffab146108d957600080fd5b806336568abe116102745780634f1d17cc1161021d5780635ff61a18116101f75780635ff61a18146107a457806361a92115146107c457806370bf5941146107e65780637121cf411461087757600080fd5b80634f1d17cc1461072c5780635641f3c31461074c5780635e2fc29b1461078457600080fd5b8063418e4b3c1161024e578063418e4b3c146105fb5780634234d4a41461069257806348a4bbf0146106b257600080fd5b806336568abe146105925780633ccfd60b146105b25780633eddf3cb146105c757600080fd5b806320cf5a40116102d657806326b387bb116102b057806326b387bb146105255780632f2ff15d1461055257806333f0aeba1461057257600080fd5b806320cf5a40146104975780632236d2fd146104b7578063248a9ca3146104e757600080fd5b8063150b7a0211610307578063150b7a02146103fe5780631718c08714610442578063180370451461047757600080fd5b806301ffc9a71461038557806307beac55146103ba5780630f08efe0146103dc57600080fd5b366103805760405163a183e9a560e01b815260206004820152601360248201527f4e6f742070617961626c6520726563656976650000000000000000000000000060448201526064015b60405180910390fd5b600080fd5b34801561039157600080fd5b506103a56103a0366004614694565b610c96565b60405190151581526020015b60405180910390f35b3480156103c657600080fd5b506103da6103d53660046146d3565b610cc1565b005b3480156103e857600080fd5b506103f1610d91565b6040516103b1919061476e565b34801561040a57600080fd5b506104296104193660046147c8565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016103b1565b34801561044e57600080fd5b5061046261045d3660046148a8565b610de9565b604080519283526020830191909152016103b1565b34801561048357600080fd5b506103da6104923660046148f0565b610ebd565b3480156104a357600080fd5b506103da6104b2366004614909565b6110dd565b3480156104c357600080fd5b506103a56104d2366004614909565b600a6020526000908152604090205460ff1681565b3480156104f357600080fd5b506105176105023660046148f0565b60009081526020819052604090206001015490565b6040519081526020016103b1565b34801561053157600080fd5b50610517610540366004614909565b600b6020526000908152604090205481565b34801561055e57600080fd5b506103da61056d366004614926565b6111f1565b34801561057e57600080fd5b5061046261058d366004614956565b611216565b34801561059e57600080fd5b506103da6105ad366004614926565b6112c3565b3480156105be57600080fd5b506103da611341565b3480156105d357600080fd5b506105177f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c081565b34801561060757600080fd5b5061065a6106163660046148f0565b60096020526000908152604090208054600182015460028301546003840154600490940154929391929091906001600160a01b03811690600160a01b900460ff1686565b6040805196875260208701959095529385019290925260608401526001600160a01b03166080830152151560a082015260c0016103b1565b34801561069e57600080fd5b506105176106ad36600461498b565b611411565b3480156106be57600080fd5b506107006106cd3660046148f0565b60086020526000908152604090208054600182015460028301546003909301549192909160ff8082169161010090041685565b60408051958652602086019490945292840191909152151560608301521515608082015260a0016103b1565b34801561073857600080fd5b506103da6107473660046149cd565b611451565b34801561075857600080fd5b5060045461076c906001600160a01b031681565b6040516001600160a01b0390911681526020016103b1565b34801561079057600080fd5b506103da61079f366004614909565b611767565b3480156107b057600080fd5b506105176107bf3660046149f9565b61179a565b3480156107d057600080fd5b506107d961180f565b6040516103b19190614a27565b3480156107f257600080fd5b506108626108013660046148f0565b600760208190526000918252604090912080546001820154600283015460038401546004850154600586015460068701549690970154949693956001600160a01b039384169592841694918416939091169160ff8082169161010090041689565b6040516103b199989796959493929190614ad0565b34801561088357600080fd5b50610517610892366004614909565b611983565b3480156108a357600080fd5b506103da6108b23660046148f0565b6119f2565b3480156108c357600080fd5b50610517600080516020614fe983398151915281565b3480156108e557600080fd5b506103da6108f4366004614b31565b611c1d565b34801561090557600080fd5b506109196109143660046148f0565b611c58565b6040516103b19190614b55565b6103da610934366004614c01565b611d61565b34801561094557600080fd5b5060045461095b90600160a01b900461ffff1681565b60405161ffff90911681526020016103b1565b34801561097a57600080fd5b5061076c610989366004614c2d565b611f69565b34801561099a57600080fd5b506103a56109a9366004614926565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156109de57600080fd5b50610517600081565b3480156109f357600080fd5b506103da610a02366004614c4f565b611f81565b348015610a1357600080fd5b506105177fc0c51901e654d6f7950f502a12544003f395c97494ff89ced7775d34b9bc636981565b348015610a4757600080fd5b50610adb610a563660046148f0565b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915250600090815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff80821615156060840152610100909104161515608082015290565b6040516103b19190614c7d565b348015610af457600080fd5b506103a5610b033660046148f0565b611fee565b348015610b1457600080fd5b50610b1d612469565b6040516103b19190614cba565b348015610b3657600080fd5b50610517610b453660046148f0565b6125c6565b348015610b5657600080fd5b506103da610b65366004614909565b6125dd565b6103da610b78366004614d3c565b612640565b348015610b8957600080fd5b506103da610b98366004614926565b61286c565b348015610ba957600080fd5b5060035461076c906001600160a01b031681565b348015610bc957600080fd5b50610bdd610bd83660046148f0565b612891565b6040516103b19190614d5c565b348015610bf657600080fd5b506103a5610c05366004614909565b600c6020526000908152604090205460ff1681565b348015610c2657600080fd5b506103a5612946565b348015610c3b57600080fd5b506105177f97667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b92981565b6103da610c71366004614c01565b612a12565b348015610c8257600080fd5b50610517610c91366004614c2d565b612e22565b60006001600160e01b03198216635a05180f60e01b1480610cbb5750610cbb82613245565b92915050565b600080516020614fe9833981519152610cd98161327a565b60005b83811015610d8957856001600160a01b03166342842e0e3085888886818110610d0757610d07614daa565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610d5e57600080fd5b505af1158015610d72573d6000803e3d6000fd5b505050508080610d8190614dd6565b915050610cdc565b505050505050565b60606005805480602002602001604051908101604052809291908181526020018280548015610ddf57602002820191906000526020600020905b815481526020019060010190808311610dcb575b5050505050905090565b6000807f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c0610e168161327a565b6001600160a01b0387166000908152600c60205260409020805460ff19166001179055610e44878787613287565b9250610e508385612e22565b915081856001600160a01b0316886001600160a01b03167feeb55d6f401444e3135de808fa1026bed54e04e1ef6e688a831fbbc8c6bc0d22898888604051610eab939291909283526020830191909152604082015260600190565b60405180910390a45094509492505050565b6000818152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548594939160e084019160ff1690811115610f4e57610f4e614a98565b6002811115610f5f57610f5f614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614610fb05760405163060a6aeb60e51b815260040160405180910390fd5b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff169081111561104157611041614a98565b600281111561105257611052614a98565b81526020016007820160019054906101000a900460ff1615151515815250509050806101000151156110a057805160e082015160405163142c79d560e21b8152610377929190600401614def565b6110a9856135a3565b604051339086907f76c170d27c079a651a2b27047996fe5849b52f6d7b3730efe62f8fe71b6e9cba90600090a35050505050565b600080516020614fe98339815191526110f58161327a565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561113c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111609190614e03565b90506001600160a01b03831663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156111bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e39190614e1c565b6111ec57600080fd5b505050565b60008281526020819052604090206001015461120c8161327a565b6111ec838361377e565b6001600160a01b0383166000908152600c6020526040812054819060ff1661125157604051630aba3fbb60e31b815260040160405180910390fd5b61125c858533613287565b91506112688284612e22565b6040805186815260208101869052908101849052909150819033906001600160a01b038816907feeb55d6f401444e3135de808fa1026bed54e04e1ef6e688a831fbbc8c6bc0d229060600160405180910390a4935093915050565b6001600160a01b03811633146113335760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610377565b61133d82826137a0565b5050565b600080516020614fe98339815191526113598161327a565b604051600090339047908381818185875af1925050503d806000811461139b576040519150601f19603f3d011682016040523d82523d6000602084013e6113a0565b606091505b50509050806113e45760405163a183e9a560e01b815260206004820152600f60248201526e15da5d1a191c985dc811985a5b1959608a1b6044820152606401610377565b6040517f57ea89b6814fccbbe8728fa89cc8e6b5477e559b2a34e946e105b11112e94b5890600090a15050565b60007f2e863936c6128df6aeacfe0a88371eadcc9715534957f5f0a495b5481a5f64c061143d8161327a565b611448858585613287565b95945050505050565b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff16908111156114e2576114e2614a98565b60028111156114f3576114f3614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b0316146115445760405163060a6aeb60e51b815260040160405180910390fd5b6000858152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548994939160e084019160ff16908111156115d5576115d5614a98565b60028111156115e6576115e6614a98565b81526020016007820160019054906101000a900460ff16151515158152505090508061010001511561163457805160e082015160405163142c79d560e21b8152610377929190600401614def565b86158061163f575085155b80611648575084155b1561166657604051630373865960e11b815260040160405180910390fd5b60006001600d600082825461167b9190614e39565b9182905550915088905060006116918942614e39565b6000848152600960205260409020848155600181018490556002808201839055600382018b905560048201805460ff60a01b191690559192508991600085815260076020819052604090912001805460ff191660018360028111156116f8576116f8614a98565b02179055506000848152600760208190526040808320918201805461ff00191661010017905560029091015490516001600160a01b0390911691869188917f7eacf015c7364f2216b751b04e760b5b35cfecc012906d01ffea526f4a03bcca91a4505050505050505050505050565b806001600160a01b03811633146117915760405163060a6aeb60e51b815260040160405180910390fd5b61133d826137c2565b6040516370a0823160e01b81526001600160a01b038381166004830152600091908316906370a0823190602401602060405180830381865afa1580156117e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118089190614e03565b9392505050565b6060600061181c60115490565b9050600061182960125490565b6011546118369190614e4c565b90506000808267ffffffffffffffff811115611854576118546147b2565b6040519080825280602002602001820160405280156118ad57816020015b6040805160a0810182526000808252602080830182905292820181905260608201819052608082015282526000199092019101816118725790505b50905060005b8481101561197a5760006118c8826001614e39565b600081815260086020526040902060038101549192509060ff1615611957576040805160a0810182528254815260018301546020820152600283015491810191909152600382015460ff808216151560608401526101009091041615156080820152845185908790811061193e5761193e614daa565b6020908102919091010152611954600186614e39565b94505b85850361196557505061197a565b5050808061197290614dd6565b9150506118b3565b50949350505050565b6003546040516371d4ed8d60e11b81526001600160a01b038381166004830152600092169063e3a9db1a90602401602060405180830381865afa1580156119ce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cbb9190614e03565b600081815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff8082161515606084018190526101009092041615156080830152829190611a70578051604051636d9c892f60e11b81526004810191909152602401610377565b600083815260086020908152604080832060019081015480855260078085528386208451610120810186528154815293810154958401959095526002808601546001600160a01b0390811695850195909552600386015485166060850152600486015485166080850152600586015490941660a0840152600685015460c0840152840154909493919260e084019160ff1690811115611b1157611b11614a98565b6002811115611b2257611b22614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614611b735760405163060a6aeb60e51b815260040160405180910390fd5b60008581526008602081815260408084206001810154808652600784529185208a8652939092526003909101805461ffff19169055879290919060078201805460ff19166001836002811115611bcb57611bcb614a98565b021790555060078101805461ff0019169055611be68361386d565b604051339084907f336749273676524b08a5421532bf60f1cf06aab4d884facd39f19814c765738590600090a35050505050505050565b600080516020614fe9833981519152611c358161327a565b506004805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810191909152600082815260076020818152604092839020835161012081018552815481526001820154928101929092526002808201546001600160a01b0390811695840195909552600382015485166060840152600482015485166080840152600582015490941660a0830152600681015460c083015291820154909260e084019160ff1690811115611d3157611d31614a98565b6002811115611d4257611d42614a98565b815260079190910154610100900460ff16151560209091015292915050565b600081815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff8082161515606084018190526101009092041615156080830152829190611ddf578051604051636d9c892f60e11b81526004810191909152602401610377565b611de76138d1565b83838115611e95576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff8082161515606085015261010090910416151560808301529091908190611e4f90613928565b50915091506000828460400151611e669190614e39565b905080341015611e8c5760405163723e6dc160e11b815260048101829052602401610377565b50505050611f4c565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a08301529091908190611f0a90613928565b50915091506000828460600151611f219190614e39565b905080341015611f475760405163723e6dc160e11b815260048101829052602401610377565b505050505b611f57868633613978565b5050611f636001600255565b50505050565b60008281526001602052604081206118089083613d75565b600080516020614fe9833981519152611f998161327a565b6001600160a01b0383166000818152600c6020526040808220805460ff191686151590811790915590519092917f35458355462628654fc1c4ba280f8cbd0e5539f514c06e40e17e1d6cdf40a34291a3505050565b6000818152600960209081526040808320815160c0810183528154815260018201549381019390935260028101549183019190915260038101546060830152600401546001600160a01b0381166080830152600160a01b900460ff1615801560a0830152839190612078578051604051636d9c892f60e11b81526004810191909152602401610377565b600084815260096020908152604080832060018101548452600790925290912060028201544210156120d85760405163a183e9a560e01b8152602060048201526008602482015267546f20736f6f6e2160c01b6044820152606401610377565b6004820154600160a01b900460ff161561210b578154604051636d9c892f60e11b81526004810191909152602401610377565b60048201805460ff60a01b1916600160a01b179055600060078201805460ff1916600183600281111561214057612140614a98565b021790555060078101805461ff001916905560048201546001600160a01b03166121a757815461216f90613d81565b805482546040517fb3964661b9aae5de6c2141c76097498645757fbe0af80f74ef3e421a12deecaf90600090a3600094505050612462565b6001600e60008282546121ba9190614e39565b925050819055506000806121d18460030154613928565b60058601546040516301ffc9a760e01b815263152a902d60e11b6004820152929550909350600092506001600160a01b0316906301ffc9a790602401602060405180830381865afa15801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190614e1c565b90508061232d576004546040516001600160a01b039091169083156108fc029084906000818181858888f193505050506122b4576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b60028401546122cc906001600160a01b031684613e93565b835460048601546122e691906001600160a01b0316613f3b565b6004546040518381526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a26123fd565b604080516101208101825285548152600186015460208201526002808701546001600160a01b0390811693830193909352600387015483166060830152600487015483166080830152600587015490921660a0820152600686015460c082015260078601546123e392879160e084019160ff909116908111156123b2576123b2614a98565b60028111156123c3576123c3614a98565b815260079190910154610100900460ff1615156020909101528385614019565b835460048601546123fd91906001600160a01b0316613f3b565b60048501546001860154865460038801546040519081526001600160a01b03909316927f410b887f470d25379abe64505f9b3ecc244611304d71707d983eddb1d432d9479060200160405180910390a4845461245890613d81565b6001975050505050505b5050919050565b600d54600e54606091906000906124809083614e4c565b90506000808267ffffffffffffffff81111561249e5761249e6147b2565b6040519080825280602002602001820160405280156124fe57816020015b6040805160c08101825260008082526020808301829052928201819052606082018190526080820181905260a082015282526000199092019101816124bc5790505b50905060005b8481101561197a576000612519826001614e39565b600081815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff16151560a0820152845191925090819085908790811061259957612599614daa565b60209081029190910101526125af600186614e39565b9450505080806125be90614dd6565b915050612504565b6000818152600160205260408120610cbb90614269565b600080516020614fe98339815191526125f58161327a565b600480546001600160a01b0319166001600160a01b0384169081179091556040517fb230a0c075837f61328839894753bab90aa32699d692039d4e22ffe3a9ce9f7690600090a25050565b7fc0c51901e654d6f7950f502a12544003f395c97494ff89ced7775d34b9bc636961266a8161327a565b600083815260086020908152604091829020825160a0810184528154815260018201549281019290925260028101549282019290925260039091015460ff80821615156060840181905261010090920416151560808301528491906126e8578051604051636d9c892f60e11b81526004810191909152602401610377565b6126f06138d1565b8585811561279e576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff808216151560608501526101009091041615156080830152909190819061275890613928565b5091509150600082846040015161276f9190614e39565b9050803410156127955760405163723e6dc160e11b815260048101829052602401610377565b50505050612855565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a0830152909190819061281390613928565b5091509150600082846060015161282a9190614e39565b9050803410156128505760405163723e6dc160e11b815260048101829052602401610377565b505050505b612860888888613978565b5050610d896001600255565b6000828152602081905260409020600101546128878161327a565b6111ec83836137a0565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152600080516020614fe98339815191526128db8161327a565b5050600090815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff16151560a082015290565b336000908152600b602052604081205481036129a55760405163a183e9a560e01b815260206004820152601360248201527f4e6f2070656e64696e672052657475726e7321000000000000000000000000006044820152606401610377565b336000908152600b60205260409020548015612a0a57336000818152600b60205260408120556129d490611767565b60405181815233907f776937c4d7f28ffdf4afa12dcfc0bdd3d0ac3ab2315fd5cc109ed2fed8e4d3c39060200160405180910390a25b600191505090565b81818115612ac0576000818152600860209081526040808320815160a0810183528154815260018201549381019390935260028101549183018290526003015460ff8082161515606085015261010090910416151560808301529091908190612a7a90613928565b50915091506000828460400151612a919190614e39565b905080341015612ab75760405163723e6dc160e11b815260048101829052602401610377565b50505050612b77565b6000818152600960209081526040808320815160c081018352815481526001820154938101939093526002810154918301919091526003810154606083018190526004909101546001600160a01b0381166080840152600160a01b900460ff16151560a08301529091908190612b3590613928565b50915091506000828460600151612b4c9190614e39565b905080341015612b725760405163723e6dc160e11b815260048101829052602401610377565b505050505b600083815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff1615801560a0830152849190612c04578051604051636d9c892f60e11b81526004810191909152602401610377565b600085815260096020908152604091829020825160c081018452815481526001820154928101929092526002810154928201929092526003820154606082018190526004909201546001600160a01b0381166080830152600160a01b900460ff16151560a082015286913411612c9557806060015160405163723e6dc160e11b815260040161037791815260200190565b60008781526009602052604090206004810154349033906001600160a01b03168103612d045760405163a183e9a560e01b815260206004820152601760248201527f416c7265616479206869676865737420626964646572210000000000000000006044820152606401610377565b8a15612d535760405163a183e9a560e01b815260206004820152601660248201527f52657175697265732075696e742076616c75653a2032000000000000000000006044820152606401610377565b60048301546001600160a01b031615612db957600383015460048401546001600160a01b03166000908152600b602052604081208054909190612d97908490614e39565b909155505060048301546003840154612db9916001600160a01b031690613e93565b600383018290556004830180546001600160a01b0319166001600160a01b03831690811790915583546040518481527fa3eb7fe0be6b3d2c74cc2abe7b4cd0c8c2294a5ed1dcc026feb98da92264f3779060200160405180910390a35050505050505050505050565b6000612e2c6138d1565b6000838152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548794939160e084019160ff1690811115612ebd57612ebd614a98565b6002811115612ece57612ece614a98565b815260079190910154610100900460ff1615156020909101529050336001600160a01b031681604001516001600160a01b031614612f1f5760405163060a6aeb60e51b815260040160405180910390fd5b6000858152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c0840152928301548994939160e084019160ff1690811115612fb057612fb0614a98565b6002811115612fc157612fc1614a98565b81526020016007820160019054906101000a900460ff16151515158152505090508061010001511561300f57805160e082015160405163142c79d560e21b8152610377929190600401614def565b6000878152600760205260409020868061303f5760405163723e6dc160e11b815260048101829052602401610377565b61304d601180546001019055565b600061305860115490565b60008181526008602052604090206003015490915060ff161561309157604051632568ba2560e11b815260048101829052602401610377565b6040805160a081018252828152845460208083019182528284018681526001606085018181526000608087018181528982526008865288822097518855955187840155925160028701555160039095018054945115156101000261ff00199615159690961661ffff19958616179590951790945560078801805461010194169390931790925560068054808501825592527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f9091018490558554925185815291929184917ffb2ae9ffe163eff18f43966856529159761fefcaf3f9a56dbad66762ebf63970910160405180910390a49650505050505050610cbb6001600255565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661133d576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556131ec3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611808836001600160a01b038416614273565b60006001600160e01b03198216637965db0b60e01b1480610cbb57506301ffc9a760e01b6001600160e01b0319831614610cbb565b61328481336142c2565b50565b6040516331a9108f60e11b8152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa1580156132cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f39190614e5f565b6001600160a01b0316826001600160a01b031614613324576040516359dc379f60e01b815260040160405180910390fd5b600061332f600f5490565b9050426000336040516bffffffffffffffffffffffff19606092831b811660208301529189901b9091166034820152604881018790526068810183905260880160408051808303601f190181528282528051602091820120610120840183528084529083018690526001600160a01b03888116928401929092523060608401526003548216608084015290891660a083015260c08201889052915060e0810160008152600060209182018190528381526007808352604091829020845181559284015160018481019190915591840151600280850180546001600160a01b039384166001600160a01b0319918216179091556060870151600387018054918516918316919091179055608087015160048701805491851691831691909117905560a08701516005870180549190941691161790915560c0850151600685015560e085015191840180549293909260ff191691849081111561349257613492614a98565b0217905550610100918201516007909101805491151590920261ff0019909116179055600580546001810182556000919091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0018190556134f8600f80546001019055565b846001600160a01b031683827f2d22ca4594d9c25baac662e26b521c5bde631c255796ba735367af219869e50460405160405180910390a4604051632142170760e11b81526001600160a01b038681166004830152306024830152604482018890528816906342842e0e90606401600060405180830381600087803b15801561358057600080fd5b505af1158015613594573d6000803e3d6000fd5b50929998505050505050505050565b6000818152600760208181526040808420815161012081018352815481526001820154938101939093526002808201546001600160a01b0390811693850193909352600382015483166060850152600482015483166080850152600582015490921660a0840152600681015460c08401529283015491929160e084019160ff9091169081111561363557613635614a98565b600281111561364657613646614a98565b81526020016007820160019054906101000a900460ff1615151515815250509050806101000151156136a6576000828152600760208190526040918290200154905163142c79d560e21b815261037791849160ff90911690600401614def565b6000828152600760208190526040808320838155600181018490556002810180546001600160a01b03199081169091556003820180548216905560048083018054831690556005830180549092169091556006820194909455909101805461ffff1916905560a08301518382015160c08501519251632142170760e11b815230948101949094526001600160a01b039081166024850152604484019290925216906342842e0e90606401600060405180830381600087803b15801561376a57600080fd5b505af1158015610d89573d6000803e3d6000fd5b6137888282613192565b60008281526001602052604090206111ec9082613230565b6137aa8282614335565b60008281526001602052604090206111ec90826143b4565b6001600160a01b038181166000818152600b60205260408082209190915560035490516351cff8d960e01b81526004810192909252909116906351cff8d990602401600060405180830381600087803b15801561381e57600080fd5b505af1158015613832573d6000803e3d6000fd5b50506040516001600160a01b03841692507f8b893bcbc5bce509a4f8cf62a0fd8308f2ef068d8862ee06aef051027ca2a3229150600090a250565b60008181526008602052604090206003015460ff16156138a357604051632568ba2560e11b815260048101829052602401610377565b6000908152600860205260408120818155600181018290556002810191909155600301805461ffff19169055565b60028054036139225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610377565b60028055565b600454600090819081906127109061394c908690600160a01b900461ffff16614e7c565b6139569190614e93565b9250613963836002614e7c565b905061396f8185614e4c565b91509193909250565b6001831515146139cb5760405163a183e9a560e01b815260206004820152601960248201527f526571756972657320626f6f6c2076616c75653a2074727565000000000000006044820152606401610377565b6000828152600860205260409020600381015460ff16613a0457805460405163753fd89d60e01b81526004810191909152602401610377565b60038101805461ffff1916610100179055613a23601280546001019055565b600181015460009081526007602052604081209060078201805460ff19166001836002811115613a5557613a55614a98565b021790555060078101805461ff001916905560028201546000908190613a7a90613928565b9250925050613a8c846000015461386d565b60058301546040516301ffc9a760e01b815263152a902d60e11b60048201526000916001600160a01b0316906301ffc9a790602401602060405180830381865afa158015613ade573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b029190614e1c565b905080613bf6576004546040516000916001600160a01b03169084908381818185875af1925050503d8060008114613b56576040519150601f19603f3d011682016040523d82523d6000602084013e613b5b565b606091505b5050905080613b96576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b6002850154613bae906001600160a01b031685613e93565b6004546040518481526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a250613c7b565b604080516101208101825285548152600186015460208201526002808701546001600160a01b0390811693830193909352600387015483166060830152600487015483166080830152600587015490921660a0820152600686015460c08201526007860154613c7b92879160e084019160ff909116908111156123b2576123b2614a98565b60058401546006850154604051632142170760e11b81523060048201526001600160a01b03898116602483015260448201929092529116906342842e0e90606401600060405180830381600087803b158015613cd657600080fd5b505af1158015613cea573d6000803e3d6000fd5b50505050613cf53390565b60028086015460058701546006880154928901546004890154604080518e815260208101969096528501919091526001600160a01b03908116606085015293841693918216929116907f334bee2c213718999aa3a4795ff7cb9c7fa419d7bce93a0b4e3046e2b53310d69060800160405180910390a45050505050505050565b600061180883836143c9565b600081815260096020908152604091829020825160c08101845281548152600182015492810192909252600281015492820192909252600382015460608201526004909101546001600160a01b0381166080830152600160a01b900460ff1615801560a083015261133d5780608001516001600160a01b0316816020015182600001517f3050ffbb1483e2c1283ef920c4949924df01eeb5132f83bbc3f8e929d499d6fe846060015142604051613e42929190918252602082015260400190565b60405180910390a450600090815260096020526040812081815560018101829055600281018290556003810191909155600401805474ffffffffffffffffffffffffffffffffffffffffff19169055565b60035460405163f340fa0160e01b81526001600160a01b0384811660048301529091169063f340fa019083906024016000604051808303818588803b158015613edb57600080fd5b505af1158015613eef573d6000803e3d6000fd5b5050505050816001600160a01b03167f0fba8404439890021adb1c06dce3dc283974eb639a2dc521dca0c8d6378f582f82604051613f2f91815260200190565b60405180910390a25050565b60008281526007602052604090819020600581015460038201546006909201549251632142170760e11b81526001600160a01b0392831660048201528483166024820152604481019390935216906342842e0e90606401600060405180830381600087803b158015613fac57600080fd5b505af1158015613fc0573d6000803e3d6000fd5b505050600083815260076020526040808220600681015460059091015491519093506001600160a01b0391821692918516917ff89c3306c782ffbbe4593aa5673e97e9ad6a8c65d240405e8986363fada6639291a45050565b6000808460a001516001600160a01b0316632a55205a8660c00151856040518363ffffffff1660e01b815260040161405b929190918252602082015260400190565b6040805180830381865afa158015614077573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061409b9190614eb5565b909250905060006140ac8285614e4c565b6004546040519192506000916001600160a01b039091169087908381818185875af1925050503d80600081146140fe576040519150601f19603f3d011682016040523d82523d6000602084013e614103565b606091505b505090508061413e576040516314314f9760e31b8152600401610377906020808252600490820152634665657360e01b604082015260600190565b6004546040518781526001600160a01b03909116907f94de51024db920319ba650b6cff6192073818c87bd2f65b41e2ab86e3cb89f0b9060200160405180910390a26000846001600160a01b03168460405160006040518083038185875af1925050503d80600081146141cd576040519150601f19603f3d011682016040523d82523d6000602084013e6141d2565b606091505b505090508061420e576040516314314f9760e31b8152602060048201526007602482015266526f79616c747960c81b6044820152606401610377565b61421c886040015184613e93565b846001600160a01b03167f0975b2c6ad0cff6ea2027e5ea8f0d292f0a5533560a8e130d150bfaac81dbc038560405161425791815260200190565b60405180910390a25050505050505050565b6000610cbb825490565b60008181526001830160205260408120546142ba57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610cbb565b506000610cbb565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1661133d576142f3816143f3565b6142fe836020614405565b60405160200161430f929190614f07565b60408051601f198184030181529082905262461bcd60e51b825261037791600401614f88565b6000828152602081815260408083206001600160a01b038516845290915290205460ff161561133d576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611808836001600160a01b0384166145a1565b60008260000182815481106143e0576143e0614daa565b9060005260206000200154905092915050565b6060610cbb6001600160a01b03831660145b60606000614414836002614e7c565b61441f906002614e39565b67ffffffffffffffff811115614437576144376147b2565b6040519080825280601f01601f191660200182016040528015614461576020820181803683370190505b509050600360fc1b8160008151811061447c5761447c614daa565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106144ab576144ab614daa565b60200101906001600160f81b031916908160001a90535060006144cf846002614e7c565b6144da906001614e39565b90505b6001811115614552576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061450e5761450e614daa565b1a60f81b82828151811061452457614524614daa565b60200101906001600160f81b031916908160001a90535060049490941c9361454b81614fbb565b90506144dd565b5083156118085760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610377565b6000818152600183016020526040812054801561468a5760006145c5600183614e4c565b85549091506000906145d990600190614e4c565b905081811461463e5760008660000182815481106145f9576145f9614daa565b906000526020600020015490508087600001848154811061461c5761461c614daa565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061464f5761464f614fd2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610cbb565b6000915050610cbb565b6000602082840312156146a657600080fd5b81356001600160e01b03198116811461180857600080fd5b6001600160a01b038116811461328457600080fd5b600080600080606085870312156146e957600080fd5b84356146f4816146be565b9350602085013567ffffffffffffffff8082111561471157600080fd5b818701915087601f83011261472557600080fd5b81358181111561473457600080fd5b8860208260051b850101111561474957600080fd5b6020830195508094505050506040850135614763816146be565b939692955090935050565b6020808252825182820181905260009190848201906040850190845b818110156147a65783518352928401929184019160010161478a565b50909695505050505050565b634e487b7160e01b600052604160045260246000fd5b600080600080608085870312156147de57600080fd5b84356147e9816146be565b935060208501356147f9816146be565b925060408501359150606085013567ffffffffffffffff8082111561481d57600080fd5b818701915087601f83011261483157600080fd5b813581811115614843576148436147b2565b604051601f8201601f19908116603f0116810190838211818310171561486b5761486b6147b2565b816040528281528a602084870101111561488457600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600080600080608085870312156148be57600080fd5b84356148c9816146be565b93506020850135925060408501356148e0816146be565b9396929550929360600135925050565b60006020828403121561490257600080fd5b5035919050565b60006020828403121561491b57600080fd5b8135611808816146be565b6000806040838503121561493957600080fd5b82359150602083013561494b816146be565b809150509250929050565b60008060006060848603121561496b57600080fd5b8335614976816146be565b95602085013595506040909401359392505050565b6000806000606084860312156149a057600080fd5b83356149ab816146be565b92506020840135915060408401356149c2816146be565b809150509250925092565b6000806000606084860312156149e257600080fd5b505081359360208301359350604090920135919050565b60008060408385031215614a0c57600080fd5b8235614a17816146be565b9150602083013561494b816146be565b6020808252825182820181905260009190848201906040850190845b818110156147a657614a858385518051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b9284019260a09290920191600101614a43565b634e487b7160e01b600052602160045260246000fd5b60038110614acc57634e487b7160e01b600052602160045260246000fd5b9052565b898152602081018990526001600160a01b03888116604083015287811660608301528681166080830152851660a082015260c081018490526101208101614b1a60e0830185614aae565b8215156101008301529a9950505050505050505050565b600060208284031215614b4357600080fd5b813561ffff8116811461180857600080fd5b600061012082019050825182526020830151602083015260408301516001600160a01b03808216604085015280606086015116606085015250506080830151614ba960808401826001600160a01b03169052565b5060a0830151614bc460a08401826001600160a01b03169052565b5060c083015160c083015260e0830151614be160e0840182614aae565b50610100928301511515919092015290565b801515811461328457600080fd5b60008060408385031215614c1457600080fd5b8235614c1f81614bf3565b946020939093013593505050565b60008060408385031215614c4057600080fd5b50508035926020909101359150565b60008060408385031215614c6257600080fd5b8235614c6d816146be565b9150602083013561494b81614bf3565b60a08101610cbb82848051825260208101516020830152604081015160408301526060810151151560608301526080810151151560808301525050565b6020808252825182820181905260009190848201906040850190845b818110156147a657614d29838551805182526020810151602083015260408101516040830152606081015160608301526001600160a01b03608082015116608083015260a0810151151560a08301525050565b9284019260c09290920191600101614cd6565b600080600060608486031215614d5157600080fd5b83356149ab81614bf3565b60c08101610cbb8284805182526020810151602083015260408101516040830152606081015160608301526001600160a01b03608082015116608083015260a0810151151560a08301525050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201614de857614de8614dc0565b5060010190565b828152604081016118086020830184614aae565b600060208284031215614e1557600080fd5b5051919050565b600060208284031215614e2e57600080fd5b815161180881614bf3565b80820180821115610cbb57610cbb614dc0565b81810381811115610cbb57610cbb614dc0565b600060208284031215614e7157600080fd5b8151611808816146be565b8082028115828204841417610cbb57610cbb614dc0565b600082614eb057634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215614ec857600080fd5b8251614ed3816146be565b6020939093015192949293505050565b60005b83811015614efe578181015183820152602001614ee6565b50506000910152565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614f3f816017850160208801614ee3565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614f7c816028840160208801614ee3565b01602801949350505050565b6020815260008251806020840152614fa7816040850160208701614ee3565b601f01601f19169190910160400192915050565b600081614fca57614fca614dc0565b506000190190565b634e487b7160e01b600052603160045260246000fdfea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a26469706673582212205810bca79729bf398f38e9da86f92ba2121f247e4126325a34aeba81ee9dafb764736f6c63430008110033

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

000000000000000000000000d85cc0b76196de86ce1128516d978de5d6dfd21e0000000000000000000000007e5c63372c8c382fc3ffc1700f54b5ace3b93c93

-----Decoded View---------------
Arg [0] : _serviceWallet (address): 0xd85CC0b76196dE86CE1128516D978DE5d6dFD21E
Arg [1] : _operator (address): 0x7e5c63372C8C382Fc3fFC1700F54B5acE3b93c93

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d85cc0b76196de86ce1128516d978de5d6dfd21e
Arg [1] : 0000000000000000000000007e5c63372c8c382fc3ffc1700f54b5ace3b93c93


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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