ETH Price: $2,238.08 (-1.30%)

Transaction Decoder

Block:
17681108 at Jul-13-2023 12:42:47 AM +UTC
Transaction Fee:
0.002387421925579808 ETH $5.34
Gas Used:
128,336 Gas / 18.602901178 Gwei

Emitted Events:

198 SuperRareBazaar.AuctionBid( _contractAddress=SovereignNFT, _bidder=[Sender] 0x6cf69059dd4a86987bc8a4c334b83ea8fa9f4037, _tokenId=1, _currencyAddress=0x00000000...000000000, _amount=1010000000000000000, _startedAuction=False, _newAuctionLength=0, _previousBidder=0x9db8e05caf73ec0cfa9ba4458e81521e5c5f739c )

Account State Difference:

  Address   Before After State Difference Code
(builder0x69)
1.543779336646077771 Eth1.543792170246077771 Eth0.0000128336
0x6CF69059...8fa9f4037
2.96424528624046614 Eth
Nonce: 740
1.921557864314886332 Eth
Nonce: 741
1.042687421925579808
0x6D7c4477...68E9a7a42
(SuperRare: Bazaar)
259.203957780331070001 Eth259.315197780331070001 Eth0.11124
0x9db8E05c...E5C5F739c 0.006039439511168012 Eth0.935099439511168012 Eth0.92906

Execution Trace

ETH 1.0403 SuperRareBazaar.bid( _originContract=0xeCfB4d97c2AA13F2B13dEDE21f9834357838ca18, _tokenId=1, _currencyAddress=0x0000000000000000000000000000000000000000, _amount=1010000000000000000 )
  • ETH 1.0403 SuperRareAuctionHouse.bid( _originContract=0xeCfB4d97c2AA13F2B13dEDE21f9834357838ca18, _tokenId=1, _currencyAddress=0x0000000000000000000000000000000000000000, _amount=1010000000000000000 )
    • MarketplaceSettingsV2.calculateMarketplaceFee( _amount=1010000000000000000 ) => ( 30300000000000000 )
    • MarketplaceSettingsV2.STATICCALL( )
    • SovereignNFT.ownerOf( _tokenId=1 ) => ( 0x6D7c44773C52D396F43c2D511B81aa168E9a7a42 )
      • SovereignNFT.ownerOf( _tokenId=1 ) => ( 0x6D7c44773C52D396F43c2D511B81aa168E9a7a42 )
      • ETH 0.92906 Payments.refund( _payee=0x9db8E05cAF73EC0CFA9bA4458e81521E5C5F739c, _amount=929060000000000000 )
        • ETH 0.92906 0x9db8e05caf73ec0cfa9ba4458e81521e5c5f739c.CALL( )
        • MarketplaceSettingsV2.STATICCALL( )
          File 1 of 6: SuperRareBazaar
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-upgradeable-0.7.2/access/OwnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/utils/ReentrancyGuardUpgradeable.sol";
          import "@openzeppelin/contracts-0.7.2/token/ERC721/IERC721.sol";
          import "./storage/SuperRareBazaarStorage.sol";
          import "./ISuperRareBazaar.sol";
          /// @author koloz
          /// @title SuperRareBazaar
          /// @notice The unified contract for the bazaar logic (Marketplace and Auction House).
          /// @dev All storage is inherrited and append only (no modifications) to make upgrade compliant.
          contract SuperRareBazaar is
              ISuperRareBazaar,
              OwnableUpgradeable,
              ReentrancyGuardUpgradeable,
              SuperRareBazaarStorage
          {
              /////////////////////////////////////////////////////////////////////////
              // Initializer
              /////////////////////////////////////////////////////////////////////////
              function initialize(
                  address _marketplaceSettings,
                  address _royaltyRegistry,
                  address _royaltyEngine,
                  address _superRareMarketplace,
                  address _superRareAuctionHouse,
                  address _spaceOperatorRegistry,
                  address _approvedTokenRegistry,
                  address _payments,
                  address _stakingRegistry,
                  address _networkBeneficiary
              ) public initializer {
                  require(_marketplaceSettings != address(0));
                  require(_royaltyRegistry != address(0));
                  require(_royaltyEngine != address(0));
                  require(_superRareMarketplace != address(0));
                  require(_superRareAuctionHouse != address(0));
                  require(_spaceOperatorRegistry != address(0));
                  require(_approvedTokenRegistry != address(0));
                  require(_payments != address(0));
                  require(_networkBeneficiary != address(0));
                  marketplaceSettings = IMarketplaceSettings(_marketplaceSettings);
                  royaltyRegistry = IERC721CreatorRoyalty(_royaltyRegistry);
                  royaltyEngine = IRoyaltyEngineV1(_royaltyEngine);
                  superRareMarketplace = _superRareMarketplace;
                  superRareAuctionHouse = _superRareAuctionHouse;
                  spaceOperatorRegistry = ISpaceOperatorRegistry(_spaceOperatorRegistry);
                  approvedTokenRegistry = IApprovedTokenRegistry(_approvedTokenRegistry);
                  payments = IPayments(_payments);
                  stakingRegistry = _stakingRegistry;
                  networkBeneficiary = _networkBeneficiary;
                  minimumBidIncreasePercentage = 10;
                  maxAuctionLength = 7 days;
                  auctionLengthExtension = 15 minutes;
                  offerCancelationDelay = 5 minutes;
                  __Ownable_init();
                  __ReentrancyGuard_init();
              }
              /////////////////////////////////////////////////////////////////////////
              // Admin Functions
              /////////////////////////////////////////////////////////////////////////
              function setMarketplaceSettings(address _marketplaceSettings)
                  external
                  onlyOwner
              {
                  require(_marketplaceSettings != address(0));
                  marketplaceSettings = IMarketplaceSettings(_marketplaceSettings);
              }
              function setRoyaltyRegistry(address _royaltyRegistry) external onlyOwner {
                  require(_royaltyRegistry != address(0));
                  royaltyRegistry = IERC721CreatorRoyalty(_royaltyRegistry);
              }
              function setRoyaltyEngine(address _royaltyEngine) external onlyOwner {
                  require(_royaltyEngine != address(0));
                  royaltyEngine = IRoyaltyEngineV1(_royaltyEngine);
              }
              function setSuperRareMarketplace(address _superRareMarketplace)
                  external
                  onlyOwner
              {
                  require(_superRareMarketplace != address(0));
                  superRareMarketplace = _superRareMarketplace;
              }
              function setSuperRareAuctionHouse(address _superRareAuctionHouse)
                  external
                  onlyOwner
              {
                  require(_superRareAuctionHouse != address(0));
                  superRareAuctionHouse = _superRareAuctionHouse;
              }
              function setSpaceOperatorRegistry(address _spaceOperatorRegistry)
                  external
                  onlyOwner
              {
                  require(_spaceOperatorRegistry != address(0));
                  spaceOperatorRegistry = ISpaceOperatorRegistry(_spaceOperatorRegistry);
              }
              function setApprovedTokenRegistry(address _approvedTokenRegistry)
                  external
                  onlyOwner
              {
                  require(_approvedTokenRegistry != address(0));
                  approvedTokenRegistry = IApprovedTokenRegistry(_approvedTokenRegistry);
              }
              function setPayments(address _payments) external onlyOwner {
                  require(_payments != address(0));
                  payments = IPayments(_payments);
              }
              function setStakingRegistry(address _stakingRegistry) external onlyOwner {
                  require(_stakingRegistry != address(0));
                  stakingRegistry = _stakingRegistry;
              }
              function setNetworkBeneficiary(address _networkBeneficiary)
                  external
                  onlyOwner
              {
                  require(_networkBeneficiary != address(0));
                  networkBeneficiary = _networkBeneficiary;
              }
              function setMinimumBidIncreasePercentage(
                  uint8 _minimumBidIncreasePercentage
              ) external onlyOwner {
                  minimumBidIncreasePercentage = _minimumBidIncreasePercentage;
              }
              function setMaxAuctionLength(uint8 _maxAuctionLength) external onlyOwner {
                  maxAuctionLength = _maxAuctionLength;
              }
              function setAuctionLengthExtension(uint256 _auctionLengthExtension)
                  external
                  onlyOwner
              {
                  auctionLengthExtension = _auctionLengthExtension;
              }
              function setOfferCancelationDelay(uint256 _offerCancelationDelay)
                  external
                  onlyOwner
              {
                  offerCancelationDelay = _offerCancelationDelay;
              }
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Functions
              /////////////////////////////////////////////////////////////////////////
              /// @notice Place an offer for a given asset
              /// @dev Notice we need to verify that the msg sender has approved us to move funds on their behalf.
              /// @dev Covers use of any currency (0 address is eth).
              /// @dev _amount is the amount of the offer excluding the marketplace fee.
              /// @dev There can be multiple offers of different currencies, but only 1 per currency.
              /// @param _originContract Contract address of the asset being listed.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the token being offered.
              /// @param _amount Amount being offered.
              /// @param _convertible If the offer can be converted into an auction
              function offer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  bool _convertible
              ) external payable override {
                  (bool success, bytes memory data) = superRareMarketplace.delegatecall(
                      abi.encodeWithSelector(
                          this.offer.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _amount,
                          _convertible
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Purchases the token for the current sale price.
              /// @dev Covers use of any currency (0 address is eth).
              /// @dev Need to verify that the buyer (if not using eth) has the marketplace approved for _currencyContract.
              /// @dev Need to verify that the seller has the marketplace approved for _originContract.
              /// @param _originContract Contract address for asset being bought.
              /// @param _tokenId TokenId of asset being bought.
              /// @param _currencyAddress Currency address of asset being used to buy.
              /// @param _amount Amount the piece if being bought for (including marketplace fee).
              function buy(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable override {
                  (bool success, bytes memory data) = superRareMarketplace.delegatecall(
                      abi.encodeWithSelector(
                          this.buy.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _amount
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Cancels an existing offer the sender has placed on a piece.
              /// @param _originContract Contract address of token.
              /// @param _tokenId TokenId that has an offer.
              /// @param _currencyAddress Currency address of the offer.
              function cancelOffer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress
              ) external override {
                  (bool success, bytes memory data) = superRareMarketplace.delegatecall(
                      abi.encodeWithSelector(
                          this.cancelOffer.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Sets a sale price for the given asset(s) directed at the _target address.
              /// @dev Covers use of any currency (0 address is eth).
              /// @dev Sale price for everyone is denoted as the 0 address.
              /// @dev Only 1 currency can be used for the sale price directed at a speicific target.
              /// @dev _listPrice of 0 signifies removing the list price for the provided currency.
              /// @dev This function can be used for counter offers as well.
              /// @param _originContract Contract address of the asset being listed.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Contract address of the currency asset is being listed for.
              /// @param _listPrice Amount of the currency the asset is being listed for (including all decimal points).
              /// @param _target Address of the person this sale price is target to.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function setSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _listPrice,
                  address _target,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  (bool success, bytes memory data) = superRareMarketplace.delegatecall(
                      abi.encodeWithSelector(
                          this.setSalePrice.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _listPrice,
                          _target,
                          _splitAddresses,
                          _splitRatios
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Removes the current sale price of an asset for _target for the given currency.
              /// @dev Sale prices could still exist for different currencies.
              /// @dev Sale prices could still exist for different targets.
              /// @dev Zero address for _currency means that its listed in ether.
              /// @dev _target of zero address is the general sale price.
              /// @param _originContract The origin contract of the asset.
              /// @param _tokenId The tokenId of the asset within the _originContract.
              /// @param _target The address of the person
              function removeSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _target
              ) external override {
                  IERC721 erc721 = IERC721(_originContract);
                  address tokenOwner = erc721.ownerOf(_tokenId);
                  require(
                      msg.sender == tokenOwner,
                      "removeSalePrice::Must be tokenOwner."
                  );
                  delete tokenSalePrices[_originContract][_tokenId][_target];
                  emit SetSalePrice(
                      _originContract,
                      address(0),
                      address(0),
                      0,
                      _tokenId,
                      new address payable[](0),
                      new uint8[](0)
                  );
              }
              /// @notice Accept an offer placed on _originContract : _tokenId.
              /// @dev Zero address for _currency means that the offer being accepted is in ether.
              /// @param _originContract Contract of the asset the offer was made on.
              /// @param _tokenId TokenId of the asset.
              /// @param _currencyAddress Address of the currency used for the offer.
              /// @param _amount Amount the offer was for/and is being accepted.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function acceptOffer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  (bool success, bytes memory data) = superRareMarketplace.delegatecall(
                      abi.encodeWithSelector(
                          this.acceptOffer.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _amount,
                          _splitAddresses,
                          _splitRatios
                      )
                  );
                  require(success, string(data));
              }
              /////////////////////////////////////////////////////////////////////////
              // Auction House Functions
              /////////////////////////////////////////////////////////////////////////
              /// @notice Configures an Auction for a given asset.
              /// @dev If auction type is coldie (reserve) then _startingAmount cant be 0.
              /// @dev _currencyAddress equal to the zero address denotes eth.
              /// @dev All time related params are unix epoch timestamps.
              /// @param _auctionType The type of auction being configured.
              /// @param _originContract Contract address of the asset being put up for auction.
              /// @param _tokenId Token Id of the asset.
              /// @param _startingAmount The reserve price or min bid of an auction.
              /// @param _currencyAddress The currency the auction is being conducted in.
              /// @param _lengthOfAuction The amount of time in seconds that the auction is configured for.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function configureAuction(
                  bytes32 _auctionType,
                  address _originContract,
                  uint256 _tokenId,
                  uint256 _startingAmount,
                  address _currencyAddress,
                  uint256 _lengthOfAuction,
                  uint256 _startTime,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  (bool success, bytes memory data) = superRareAuctionHouse.delegatecall(
                      abi.encodeWithSelector(
                          this.configureAuction.selector,
                          _auctionType,
                          _originContract,
                          _tokenId,
                          _startingAmount,
                          _currencyAddress,
                          _lengthOfAuction,
                          _startTime,
                          _splitAddresses,
                          _splitRatios
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Converts an offer into a coldie auction.
              /// @dev Covers use of any currency (0 address is eth).
              /// @dev Only covers converting an offer to a coldie auction.
              /// @dev Cant convert offer if an auction currently exists.
              /// @param _originContract Contract address of the asset.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the currency being converted.
              /// @param _amount Amount being converted into an auction.
              /// @param _lengthOfAuction Number of seconds the auction will last.
              /// @param _splitAddresses Addresses that the sellers take in will be split amongst.
              /// @param _splitRatios Ratios that the take in will be split by.
              function convertOfferToAuction(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _lengthOfAuction,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  (bool success, bytes memory data) = superRareAuctionHouse.delegatecall(
                      abi.encodeWithSelector(
                          this.convertOfferToAuction.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _amount,
                          _lengthOfAuction,
                          _splitAddresses,
                          _splitRatios
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Cancels a configured Auction that has not started.
              /// @dev Requires the person sending the message to be the auction creator or token owner.
              /// @param _originContract Contract address of the asset pending auction.
              /// @param _tokenId Token Id of the asset.
              function cancelAuction(address _originContract, uint256 _tokenId)
                  external
                  override
              {
                  (bool success, bytes memory data) = superRareAuctionHouse.delegatecall(
                      abi.encodeWithSelector(
                          this.cancelAuction.selector,
                          _originContract,
                          _tokenId
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Places a bid on a valid auction.
              /// @dev Only the configured currency can be used (Zero address for eth)
              /// @param _originContract Contract address of asset being bid on.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of currency being used to bid.
              /// @param _amount Amount of the currency being used for the bid.
              function bid(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable override {
                  (bool success, bytes memory data) = superRareAuctionHouse.delegatecall(
                      abi.encodeWithSelector(
                          this.bid.selector,
                          _originContract,
                          _tokenId,
                          _currencyAddress,
                          _amount
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Settles an auction that has ended.
              /// @dev Anyone is able to settle an auction since non-input params are used.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              function settleAuction(address _originContract, uint256 _tokenId)
                  external
                  override
              {
                  (bool success, bytes memory data) = superRareAuctionHouse.delegatecall(
                      abi.encodeWithSelector(
                          this.settleAuction.selector,
                          _originContract,
                          _tokenId
                      )
                  );
                  require(success, string(data));
              }
              /// @notice Grabs the current auction details for a token.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              /** @return Auction Struct: creatorAddress, creationTime, startingTime, lengthOfAuction,
                          currencyAddress, minimumBid, auctionType, splitRecipients array, and splitRatios array.
              */
              function getAuctionDetails(address _originContract, uint256 _tokenId)
                  external
                  view
                  override
                  returns (
                      address,
                      uint256,
                      uint256,
                      uint256,
                      address,
                      uint256,
                      bytes32,
                      address payable[] memory,
                      uint8[] memory
                  )
              {
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  return (
                      auction.auctionCreator,
                      auction.creationBlock,
                      auction.startingTime,
                      auction.lengthOfAuction,
                      auction.currencyAddress,
                      auction.minimumBid,
                      auction.auctionType,
                      auction.splitRecipients,
                      auction.splitRatios
                  );
              }
              function getSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _target
              )
                  external
                  view
                  override
                  returns (
                      address,
                      address,
                      uint256,
                      address payable[] memory,
                      uint8[] memory
                  )
              {
                  SalePrice memory sp = tokenSalePrices[_originContract][_tokenId][
                      _target
                  ];
                  return (
                      sp.seller,
                      sp.currencyAddress,
                      sp.amount,
                      sp.splitRecipients,
                      sp.splitRatios
                  );
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../utils/ContextUpgradeable.sol";
          import "../proxy/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal initializer {
                  __Context_init_unchained();
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal initializer {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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 {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = 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");
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../proxy/Initializable.sol";
          /**
           * @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 ReentrancyGuardUpgradeable is Initializable {
              // 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;
              function __ReentrancyGuard_init() internal initializer {
                  __ReentrancyGuard_init_unchained();
              }
              function __ReentrancyGuard_init_unchained() internal initializer {
                  _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 make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          import "../../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`, 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 be have been allowed to move this token by either {approve} or {setApprovalForAll}.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Transfers `tokenId` token from `from` to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Gives permission to `to` to transfer `tokenId` token to another account.
               * The approval is cleared when the token is transferred.
               *
               * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
               *
               * Requirements:
               *
               * - The caller must own the token or be an approved operator.
               * - `tokenId` must exist.
               *
               * Emits an {Approval} event.
               */
              function approve(address to, uint256 tokenId) external;
              /**
               * @dev Returns the account approved for `tokenId` token.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function getApproved(uint256 tokenId) external view returns (address operator);
              /**
               * @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 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);
              /**
                * @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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "../../marketplace/IMarketplaceSettings.sol";
          import "../../royalty/creator/IERC721CreatorRoyalty.sol";
          import "../../payments/IPayments.sol";
          import "../../registry/spaces/ISpaceOperatorRegistry.sol";
          import "../../registry/token/IApprovedTokenRegistry.sol";
          import "../../royalty/creator/IRoyaltyEngine.sol";
          /// @author koloz
          /// @title SuperRareBazaar Storage Contract
          /// @dev STORAGE CAN ONLY BE APPENDED NOT INSERTED OR MODIFIED
          contract SuperRareBazaarStorage {
              /////////////////////////////////////////////////////////////////////////
              // Constants
              /////////////////////////////////////////////////////////////////////////
              // Auction Types
              bytes32 public constant COLDIE_AUCTION = "COLDIE_AUCTION";
              bytes32 public constant SCHEDULED_AUCTION = "SCHEDULED_AUCTION";
              bytes32 public constant NO_AUCTION = bytes32(0);
              /////////////////////////////////////////////////////////////////////////
              // Structs
              /////////////////////////////////////////////////////////////////////////
              // The Offer truct for a given token:
              // buyer - address of person making the offer
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // amount - offer in wei/full erc20 value
              // marketplaceFee - the amount that is taken by the network on offer acceptance.
              struct Offer {
                  address payable buyer;
                  uint256 amount;
                  uint256 timestamp;
                  uint8 marketplaceFee;
                  bool convertible;
              }
              // The Sale Price struct for a given token:
              // seller - address of the person selling the token
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // amount - offer in wei/full erc20 value
              struct SalePrice {
                  address payable seller;
                  address currencyAddress;
                  uint256 amount;
                  address payable[] splitRecipients;
                  uint8[] splitRatios;
              }
              // Structure of an Auction:
              // auctionCreator - creator of the auction
              // creationBlock - time that the auction was created/configured
              // startingBlock - time that the auction starts on
              // lengthOfAuction - how long the auction is
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // minimumBid - min amount a bidder can bid at the start of an auction.
              // auctionType - type of auction, represented as the formatted bytes 32 string
              struct Auction {
                  address payable auctionCreator;
                  uint256 creationBlock;
                  uint256 startingTime;
                  uint256 lengthOfAuction;
                  address currencyAddress;
                  uint256 minimumBid;
                  bytes32 auctionType;
                  address payable[] splitRecipients;
                  uint8[] splitRatios;
              }
              struct Bid {
                  address payable bidder;
                  address currencyAddress;
                  uint256 amount;
                  uint8 marketplaceFee;
              }
              /////////////////////////////////////////////////////////////////////////
              // Events
              /////////////////////////////////////////////////////////////////////////
              event Sold(
                  address indexed _originContract,
                  address indexed _buyer,
                  address indexed _seller,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId
              );
              event SetSalePrice(
                  address indexed _originContract,
                  address indexed _currencyAddress,
                  address _target,
                  uint256 _amount,
                  uint256 _tokenId,
                  address payable[] _splitRecipients,
                  uint8[] _splitRatios
              );
              event OfferPlaced(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId,
                  bool _convertible
              );
              event AcceptOffer(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _seller,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId,
                  address payable[] _splitAddresses,
                  uint8[] _splitRatios
              );
              event CancelOffer(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId
              );
              event NewAuction(
                  address indexed _contractAddress,
                  uint256 indexed _tokenId,
                  address indexed _auctionCreator,
                  address _currencyAddress,
                  uint256 _startingTime,
                  uint256 _minimumBid,
                  uint256 _lengthOfAuction
              );
              event CancelAuction(
                  address indexed _contractAddress,
                  uint256 indexed _tokenId,
                  address indexed _auctionCreator
              );
              event AuctionBid(
                  address indexed _contractAddress,
                  address indexed _bidder,
                  uint256 indexed _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  bool _startedAuction,
                  uint256 _newAuctionLength,
                  address _previousBidder
              );
              event AuctionSettled(
                  address indexed _contractAddress,
                  address indexed _bidder,
                  address _seller,
                  uint256 indexed _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              );
              /////////////////////////////////////////////////////////////////////////
              // State Variables
              /////////////////////////////////////////////////////////////////////////
              // Current marketplace settings implementation to be used
              IMarketplaceSettings public marketplaceSettings;
              // Current creator royalty implementation to be used
              IERC721CreatorRoyalty public royaltyRegistry;
              // Address of the global royalty engine being used.
              IRoyaltyEngineV1 public royaltyEngine;
              // Current SuperRareMarketplace implementation to be used
              address public superRareMarketplace;
              // Current SuperRareAuctionHouse implementation to be used
              address public superRareAuctionHouse;
              // Current SpaceOperatorRegistry implementation to be used.
              ISpaceOperatorRegistry public spaceOperatorRegistry;
              // Current ApprovedTokenRegistry implementation being used for currencies.
              IApprovedTokenRegistry public approvedTokenRegistry;
              // Current payments contract to use
              IPayments public payments;
              // Address to be used for staking registry.
              address public stakingRegistry;
              // Address of the network beneficiary
              address public networkBeneficiary;
              // A minimum increase in bid amount when out bidding someone.
              uint8 public minimumBidIncreasePercentage; // 10 = 10%
              // Maximum length that an auction can be.
              uint256 public maxAuctionLength;
              // Extension length for an auction
              uint256 public auctionLengthExtension;
              // Offer cancellation delay
              uint256 public offerCancelationDelay;
              // Mapping from contract to mapping of tokenId to mapping of target to sale price.
              mapping(address => mapping(uint256 => mapping(address => SalePrice)))
                  public tokenSalePrices;
              // Mapping from contract to mapping of tokenId to mapping of currency address to Current Offer.
              mapping(address => mapping(uint256 => mapping(address => Offer)))
                  public tokenCurrentOffers;
              // Mapping from contract to mapping of tokenId to Auction.
              mapping(address => mapping(uint256 => Auction)) public tokenAuctions;
              // Mapping from contract to mapping of tokenId to Bid.
              mapping(address => mapping(uint256 => Bid)) public auctionBids;
              uint256[50] private __gap;
              /// ALL NEW STORAGE MUST COME AFTER THIS
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title ISuperRareBazaar
          /// @notice Interface for the SuperRareBazaar Contract
          interface ISuperRareBazaar {
              // Marketplace Functions
              // Buyer
              /// @notice Create an offer for a given asset
              /// @param _originContract Contract address of the asset being listed.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the token being offered.
              /// @param _amount Amount being offered.
              /// @param _convertible If the offer can be converted into an auction
              function offer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  bool _convertible
              ) external payable;
              /// @notice Purchases the token for the current sale price.
              /// @param _originContract Contract address for asset being bought.
              /// @param _tokenId TokenId of asset being bought.
              /// @param _currencyAddress Currency address of asset being used to buy.
              /// @param _amount Amount the piece if being bought for.
              function buy(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable;
              /// @notice Cancels an existing offer the sender has placed on a piece.
              /// @param _originContract Contract address of token.
              /// @param _tokenId TokenId that has an offer.
              /// @param _currencyAddress Currency address of the offer.
              function cancelOffer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress
              ) external;
              // Seller
              /// @notice Sets a sale price for the given asset(s).
              /// @param _originContract Contract address of the asset being listed.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Contract address of the currency asset is being listed for.
              /// @param _listPrice Amount of the currency the asset is being listed for (including all decimal points).
              /// @param _target Address of the person this sale price is target to.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function setSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _listPrice,
                  address _target,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              /// @notice Removes the current sale price of an asset for the given currency.
              /// @param _originContract The origin contract of the asset.
              /// @param _tokenId The tokenId of the asset within the _originContract.
              /// @param _target The address of the person
              function removeSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _target
              ) external;
              /// @notice Accept an offer placed on _originContract : _tokenId.
              /// @param _originContract Contract of the asset the offer was made on.
              /// @param _tokenId TokenId of the asset.
              /// @param _currencyAddress Address of the currency used for the offer.
              /// @param _amount Amount the offer was for/and is being accepted.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function acceptOffer(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              // Auction House
              // Anyone
              /// @notice Settles an auction that has ended.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              function settleAuction(address _originContract, uint256 _tokenId) external;
              // Buyer
              /// @notice Places a bid on a valid auction.
              /// @param _originContract Contract address of asset being bid on.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of currency being used to bid.
              /// @param _amount Amount of the currency being used for the bid.
              function bid(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable;
              // Seller
              /// @notice Configures an Auction for a given asset.
              /// @param _auctionType The type of auction being configured.
              /// @param _originContract Contract address of the asset being put up for auction.
              /// @param _tokenId Token Id of the asset.
              /// @param _startingAmount The reserve price or min bid of an auction.
              /// @param _currencyAddress The currency the auction is being conducted in.
              /// @param _lengthOfAuction The amount of time in seconds that the auction is configured for.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function configureAuction(
                  bytes32 _auctionType,
                  address _originContract,
                  uint256 _tokenId,
                  uint256 _startingAmount,
                  address _currencyAddress,
                  uint256 _lengthOfAuction,
                  uint256 _startTime,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              /// @notice Cancels a configured Auction that has not started.
              /// @param _originContract Contract address of the asset pending auction.
              /// @param _tokenId Token Id of the asset.
              function cancelAuction(address _originContract, uint256 _tokenId) external;
              /// @notice Converts an offer into a coldie auction.
              /// @param _originContract Contract address of the asset.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the currency being converted.
              /// @param _amount Amount being converted into an auction.
              /// @param _lengthOfAuction Number of seconds the auction will last.
              /// @param _splitAddresses Addresses that the sellers take in will be split amongst.
              /// @param _splitRatios Ratios that the take in will be split by.
              function convertOfferToAuction(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _lengthOfAuction,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              /// @notice Grabs the current auction details for a token.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              /** @return Auction Struct: creatorAddress, creationTime, startingTime, lengthOfAuction,
                          currencyAddress, minimumBid, auctionType, splitRecipients array, and splitRatios array.
              */
              function getAuctionDetails(address _originContract, uint256 _tokenId)
                  external
                  view
                  returns (
                      address,
                      uint256,
                      uint256,
                      uint256,
                      address,
                      uint256,
                      bytes32,
                      address payable[] calldata,
                      uint8[] calldata
                  );
              function getSalePrice(
                  address _originContract,
                  uint256 _tokenId,
                  address _target
              )
                  external
                  view
                  returns (
                      address,
                      address,
                      uint256,
                      address payable[] memory,
                      uint8[] memory
                  );
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "../proxy/Initializable.sol";
          /*
           * @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 GSN 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 ContextUpgradeable is Initializable {
              function __Context_init() internal initializer {
                  __Context_init_unchained();
              }
              function __Context_init_unchained() internal initializer {
              }
              function _msgSender() internal view virtual returns (address payable) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.4.24 <0.8.0;
          import "../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               */
              bool private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Modifier to protect an initializer function from being invoked twice.
               */
              modifier initializer() {
                  require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
                  bool isTopLevelCall = !_initializing;
                  if (isTopLevelCall) {
                      _initializing = true;
                      _initialized = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                  }
              }
              /// @dev Returns true if and only if the function is running in the constructor
              function _isConstructor() private view returns (bool) {
                  return !AddressUpgradeable.isContract(address(this));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <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
          pragma solidity 0.7.3;
          /**
           * @title IMarketplaceSettings Settings governing a marketplace.
           */
          interface IMarketplaceSettings {
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Min and Max Values
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMaxValue() external view returns (uint256);
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMinValue() external view returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the marketplace fee percentage.
               * @return uint8 wei fee.
               */
              function getMarketplaceFeePercentage() external view returns (uint8);
              /**
               * @dev Utility function for calculating the marketplace fee for given amount of wei.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculateMarketplaceFee(uint256 _amount)
                  external
                  view
                  returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Primary Sale Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the primary sale fee percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @return uint8 wei primary sale fee.
               */
              function getERC721ContractPrimarySaleFeePercentage(address _contractAddress)
                  external
                  view
                  returns (uint8);
              /**
               * @dev Utility function for calculating the primary sale fee for given amount of wei
               * @param _contractAddress address ERC721Contract address.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculatePrimarySaleFee(address _contractAddress, uint256 _amount)
                  external
                  view
                  returns (uint256);
              /**
               * @dev Check whether the ERC721 token has sold at least once.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @return bool of whether the token has sold.
               */
              function hasERC721TokenSold(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  returns (bool);
              /**
               * @dev Mark a token as sold.
               * Requirements:
               *
               * - `_contractAddress` cannot be the zero address.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @param _hasSold bool of whether the token should be marked sold or not.
               */
              function markERC721Token(
                  address _contractAddress,
                  uint256 _tokenId,
                  bool _hasSold
              ) external;
              function setERC721ContractPrimarySaleFeePercentage(
                  address _contractAddress,
                  uint8 _percentage
              ) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "../../token/ERC721/IERC721TokenCreator.sol";
          /**
           * @title IERC721CreatorRoyalty Token level royalty interface.
           */
          interface IERC721CreatorRoyalty is IERC721TokenCreator {
              /**
               * @dev Get the royalty fee percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @return uint8 wei royalty fee.
               */
              function getERC721TokenRoyaltyPercentage(
                  address _contractAddress,
                  uint256 _tokenId
              ) external view returns (uint8);
              /**
               * @dev Utililty function to calculate the royalty fee for a token.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculateRoyaltyFee(
                  address _contractAddress,
                  uint256 _tokenId,
                  uint256 _amount
              ) external view returns (uint256);
              /**
               * @dev Utililty function to set the royalty percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @param _percentage percentage for royalty
               */
              function setPercentageForSetERC721ContractRoyalty(
                  address _contractAddress,
                  uint8 _percentage
              ) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title IPayments
          /// @notice Interface for the Payments contract used.
          interface IPayments {
              function refund(address _payee, uint256 _amount) external payable;
              function payout(address[] calldata _splits, uint256[] calldata _amounts)
                  external
                  payable;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title ISpaceOperatorRegistry
          /// @notice The interface for the SpaceOperatorRegistry
          interface ISpaceOperatorRegistry {
              function getPlatformCommission(address _operator)
                  external
                  view
                  returns (uint8);
              function setPlatformCommission(address _operator, uint8 _commission)
                  external;
              function isApprovedSpaceOperator(address _operator)
                  external
                  view
                  returns (bool);
              function setSpaceOperatorApproved(address _operator, bool _approved)
                  external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          interface IApprovedTokenRegistry {
              /// @notice Returns if a token has been approved or not.
              /// @param _tokenContract Contract of token being checked.
              /// @return True if the token is allowed, false otherwise.
              function isApprovedToken(address _tokenContract)
                  external
                  view
                  returns (bool);
              /// @notice Adds a token to the list of approved tokens.
              /// @param _tokenContract Contract of token being approved.
              function addApprovedToken(address _tokenContract) external;
              /// @notice Removes a token from the approved tokens list.
              /// @param _tokenContract Contract of token being approved.
              function removeApprovedToken(address _tokenContract) external;
              /// @notice Sets whether all token contracts should be approved.
              /// @param _allTokensApproved Bool denoting if all tokens should be approved.
              function setAllTokensApproved(bool _allTokensApproved) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author: manifold.xyz
          /**
           * @dev Lookup engine interface
           */
          interface IRoyaltyEngineV1 {
              /**
               * Get the royalty for a given token (address, id) and value amount.  Does not cache the bps/amounts.  Caches the spec for a given token address
               *
               * @param tokenAddress - The address of the token
               * @param tokenId      - The id of the token
               * @param value        - The value you wish to get the royalty of
               *
               * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
               */
              function getRoyalty(
                  address tokenAddress,
                  uint256 tokenId,
                  uint256 value
              )
                  external
                  returns (address payable[] memory recipients, uint256[] memory amounts);
              /**
               * View only version of getRoyalty
               *
               * @param tokenAddress - The address of the token
               * @param tokenId      - The id of the token
               * @param value        - The value you wish to get the royalty of
               *
               * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
               */
              function getRoyaltyView(
                  address tokenAddress,
                  uint256 tokenId,
                  uint256 value
              )
                  external
                  view
                  returns (address payable[] memory recipients, uint256[] memory amounts);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          interface IERC721TokenCreator {
              function tokenCreator(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  returns (address payable);
          }
          

          File 2 of 6: SuperRareAuctionHouse
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-upgradeable-0.7.2/access/OwnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/utils/ReentrancyGuardUpgradeable.sol";
          import "./ISuperRareAuctionHouse.sol";
          import "../SuperRareBazaarBase.sol";
          /// @author koloz
          /// @title SuperRareAuctionHouse
          /// @notice The logic for all functions related to the SuperRareAuctionHouse.
          contract SuperRareAuctionHouse is
              ISuperRareAuctionHouse,
              OwnableUpgradeable,
              ReentrancyGuardUpgradeable,
              SuperRareBazaarBase
          {
              using SafeMath for uint256;
              using SafeERC20 for IERC20;
              /////////////////////////////////////////////////////////////////////////
              // Initializer
              /////////////////////////////////////////////////////////////////////////
              function initialize(
                  address _marketplaceSettings,
                  address _royaltyRegistry,
                  address _royaltyEngine,
                  address _spaceOperatorRegistry,
                  address _approvedTokenRegistry,
                  address _payments,
                  address _stakingRegistry,
                  address _networkBeneficiary
              ) public initializer {
                  require(_marketplaceSettings != address(0));
                  require(_royaltyRegistry != address(0));
                  require(_royaltyEngine != address(0));
                  require(_spaceOperatorRegistry != address(0));
                  require(_approvedTokenRegistry != address(0));
                  require(_payments != address(0));
                  require(_networkBeneficiary != address(0));
                  marketplaceSettings = IMarketplaceSettings(_marketplaceSettings);
                  royaltyRegistry = IERC721CreatorRoyalty(_royaltyRegistry);
                  royaltyEngine = IRoyaltyEngineV1(_royaltyEngine);
                  spaceOperatorRegistry = ISpaceOperatorRegistry(_spaceOperatorRegistry);
                  approvedTokenRegistry = IApprovedTokenRegistry(_approvedTokenRegistry);
                  payments = IPayments(_payments);
                  stakingRegistry = _stakingRegistry;
                  networkBeneficiary = _networkBeneficiary;
                  minimumBidIncreasePercentage = 10;
                  maxAuctionLength = 7 days;
                  auctionLengthExtension = 15 minutes;
                  offerCancelationDelay = 5 minutes;
                  __Ownable_init();
                  __ReentrancyGuard_init();
              }
              /// @notice Configures an Auction for a given asset.
              /// @dev If auction type is coldie (reserve) then _startingAmount cant be 0.
              /// @dev _currencyAddress equal to the zero address denotes eth.
              /// @dev All time related params are unix epoch timestamps.
              /// @param _auctionType The type of auction being configured.
              /// @param _originContract Contract address of the asset being put up for auction.
              /// @param _tokenId Token Id of the asset.
              /// @param _startingAmount The reserve price or min bid of an auction.
              /// @param _currencyAddress The currency the auction is being conducted in.
              /// @param _lengthOfAuction The amount of time in seconds that the auction is configured for.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function configureAuction(
                  bytes32 _auctionType,
                  address _originContract,
                  uint256 _tokenId,
                  uint256 _startingAmount,
                  address _currencyAddress,
                  uint256 _lengthOfAuction,
                  uint256 _startTime,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  _checkIfCurrencyIsApproved(_currencyAddress);
                  _senderMustBeTokenOwner(_originContract, _tokenId);
                  _ownerMustHaveMarketplaceApprovedForNFT(_originContract, _tokenId);
                  _checkSplits(_splitAddresses, _splitRatios);
                  _checkValidAuctionType(_auctionType);
                  require(
                      _lengthOfAuction <= maxAuctionLength,
                      "configureAuction::Auction too long."
                  );
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  require(
                      auction.auctionType == NO_AUCTION ||
                          auction.auctionCreator != msg.sender,
                      "configureAuction::Cannot have a current auction."
                  );
                  require(_lengthOfAuction > 0, "configureAuction::Length must be > 0");
                  if (_auctionType == COLDIE_AUCTION) {
                      require(
                          _startingAmount > 0,
                          "configureAuction::Coldie starting price must be > 0"
                      );
                  } else if (_auctionType == SCHEDULED_AUCTION) {
                      require(
                          _startTime > block.timestamp,
                          "configureAuction::Scheduled auction cannot start in past."
                      );
                  }
                  require(
                      _startingAmount <= marketplaceSettings.getMarketplaceMaxValue(),
                      "configureAuction::Cannot set starting price higher than max value."
                  );
                  tokenAuctions[_originContract][_tokenId] = Auction(
                      msg.sender,
                      block.number,
                      _auctionType == COLDIE_AUCTION ? 0 : _startTime,
                      _lengthOfAuction,
                      _currencyAddress,
                      _startingAmount,
                      _auctionType,
                      _splitAddresses,
                      _splitRatios
                  );
                  if (_auctionType == SCHEDULED_AUCTION) {
                      IERC721 erc721 = IERC721(_originContract);
                      erc721.transferFrom(msg.sender, address(this), _tokenId);
                  }
                  emit NewAuction(
                      _originContract,
                      _tokenId,
                      msg.sender,
                      _currencyAddress,
                      _startTime,
                      _startingAmount,
                      _lengthOfAuction
                  );
              }
              /// @notice Converts an offer into a coldie auction.
              /// @param _originContract Contract address of the asset.
              /// @dev Covers use of any currency (0 address is eth).
              /// @dev Only covers converting an offer to a coldie auction.
              /// @dev Cant convert offer if an auction currently exists.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the currency being converted.
              /// @param _amount Amount being converted into an auction.
              /// @param _lengthOfAuction Number of seconds the auction will last.
              /// @param _splitAddresses Addresses that the sellers take in will be split amongst.
              /// @param _splitRatios Ratios that the take in will be split by.
              function convertOfferToAuction(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _lengthOfAuction,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external override {
                  _senderMustBeTokenOwner(_originContract, _tokenId);
                  _ownerMustHaveMarketplaceApprovedForNFT(_originContract, _tokenId);
                  _checkSplits(_splitAddresses, _splitRatios);
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  require(
                      auction.auctionType == NO_AUCTION ||
                          auction.auctionCreator != msg.sender,
                      "convertOfferToAuction::Cannot have a current auction."
                  );
                  require(
                      _lengthOfAuction <= maxAuctionLength,
                      "convertOfferToAuction::Auction too long."
                  );
                  Offer memory currOffer = tokenCurrentOffers[_originContract][_tokenId][
                      _currencyAddress
                  ];
                  require(currOffer.buyer != msg.sender, "convert::own offer");
                  require(
                      currOffer.convertible,
                      "convertOfferToAuction::Offer is not convertible"
                  );
                  require(
                      currOffer.amount == _amount,
                      "convertOfferToAuction::Converting offer with different amount."
                  );
                  tokenAuctions[_originContract][_tokenId] = Auction(
                      msg.sender,
                      block.number,
                      block.timestamp,
                      _lengthOfAuction,
                      _currencyAddress,
                      currOffer.amount,
                      COLDIE_AUCTION,
                      _splitAddresses,
                      _splitRatios
                  );
                  delete tokenCurrentOffers[_originContract][_tokenId][_currencyAddress];
                  auctionBids[_originContract][_tokenId] = Bid(
                      currOffer.buyer,
                      _currencyAddress,
                      _amount,
                      marketplaceSettings.getMarketplaceFeePercentage()
                  );
                  IERC721 erc721 = IERC721(_originContract);
                  erc721.transferFrom(msg.sender, address(this), _tokenId);
                  emit NewAuction(
                      _originContract,
                      _tokenId,
                      msg.sender,
                      _currencyAddress,
                      block.timestamp,
                      _amount,
                      _lengthOfAuction
                  );
                  emit AuctionBid(
                      _originContract,
                      currOffer.buyer,
                      _tokenId,
                      _currencyAddress,
                      _amount,
                      true,
                      0,
                      address(0)
                  );
              }
              /// @notice Cancels a configured Auction that has not started.
              /// @dev Requires the person sending the message to be the auction creator or token owner.
              /// @param _originContract Contract address of the asset pending auction.
              /// @param _tokenId Token Id of the asset.
              function cancelAuction(address _originContract, uint256 _tokenId)
                  external
                  override
              {
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  IERC721 erc721 = IERC721(_originContract);
                  require(
                      auction.auctionType != NO_AUCTION,
                      "cancelAuction::Must have an auction configured."
                  );
                  require(
                      auction.startingTime == 0 || block.timestamp < auction.startingTime,
                      "cancelAuction::Auction must not have started."
                  );
                  require(
                      auction.auctionCreator == msg.sender ||
                          erc721.ownerOf(_tokenId) == msg.sender,
                      "cancelAuction::Must be creator or owner."
                  );
                  delete tokenAuctions[_originContract][_tokenId];
                  if (erc721.ownerOf(_tokenId) == address(this)) {
                      erc721.transferFrom(address(this), msg.sender, _tokenId);
                  }
                  emit CancelAuction(_originContract, _tokenId, auction.auctionCreator);
              }
              /// @notice Places a bid on a valid auction.
              /// @dev Only the configured currency can be used (Zero address for eth)
              /// @param _originContract Contract address of asset being bid on.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of currency being used to bid.
              /// @param _amount Amount of the currency being used for the bid.
              function bid(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable override nonReentrant {
                  uint256 requiredAmount = _amount.add(
                      marketplaceSettings.calculateMarketplaceFee(_amount)
                  );
                  _senderMustHaveMarketplaceApproved(_currencyAddress, requiredAmount);
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  require(
                      auction.auctionType != NO_AUCTION,
                      "bid::Must have a current auction."
                  );
                  require(
                      auction.auctionCreator != msg.sender,
                      "bid::Cannot bid on your own auction."
                  );
                  require(
                      block.timestamp >= auction.startingTime,
                      "bid::Auction not active."
                  );
                  require(
                      _currencyAddress == auction.currencyAddress,
                      "bid::Currency must be in configured denomination"
                  );
                  require(_amount > 0, "bid::Cannot be 0");
                  require(
                      _amount <= marketplaceSettings.getMarketplaceMaxValue(),
                      "bid::Must be less than max value."
                  );
                  require(
                      _amount >= auction.minimumBid,
                      "bid::Cannot be lower than minimum bid."
                  );
                  require(
                      auction.startingTime == 0 ||
                          block.timestamp <
                          auction.startingTime.add(auction.lengthOfAuction),
                      "bid::Must be active."
                  );
                  Bid memory currBid = auctionBids[_originContract][_tokenId];
                  require(
                      _amount >=
                          currBid.amount.add(
                              currBid.amount.mul(minimumBidIncreasePercentage).div(100)
                          ),
                      "bid::Must be higher than prev bid + min increase."
                  );
                  IERC721 erc721 = IERC721(_originContract);
                  address tokenOwner = erc721.ownerOf(_tokenId);
                  require(
                      auction.auctionCreator == tokenOwner || tokenOwner == address(this),
                      "bid::Auction creator must be owner."
                  );
                  if (auction.auctionCreator == tokenOwner) {
                      _ownerMustHaveMarketplaceApprovedForNFT(_originContract, _tokenId);
                  }
                  _checkAmountAndTransfer(_currencyAddress, requiredAmount);
                  _refund(
                      _currencyAddress,
                      currBid.amount,
                      currBid.marketplaceFee,
                      currBid.bidder
                  );
                  auctionBids[_originContract][_tokenId] = Bid(
                      msg.sender,
                      _currencyAddress,
                      _amount,
                      marketplaceSettings.getMarketplaceFeePercentage()
                  );
                  bool startedAuction = false;
                  uint256 newAuctionLength = 0;
                  if (auction.startingTime == 0) {
                      tokenAuctions[_originContract][_tokenId].startingTime = block
                          .timestamp;
                      erc721.transferFrom(
                          auction.auctionCreator,
                          address(this),
                          _tokenId
                      );
                      startedAuction = true;
                  } else if (
                      auction.startingTime.add(auction.lengthOfAuction).sub(
                          block.timestamp
                      ) < auctionLengthExtension
                  ) {
                      newAuctionLength = block.timestamp.add(auctionLengthExtension).sub(
                          auction.startingTime
                      );
                      tokenAuctions[_originContract][_tokenId]
                          .lengthOfAuction = newAuctionLength;
                  }
                  emit AuctionBid(
                      _originContract,
                      msg.sender,
                      _tokenId,
                      _currencyAddress,
                      _amount,
                      startedAuction,
                      newAuctionLength,
                      currBid.bidder
                  );
              }
              /// @notice Settles an auction that has ended.
              /// @dev Anyone is able to settle an auction since non-input params are used.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              function settleAuction(address _originContract, uint256 _tokenId)
                  external
                  override
              {
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  require(
                      auction.auctionType != NO_AUCTION && auction.startingTime != 0,
                      "settleAuction::Must have a current valid auction."
                  );
                  require(
                      block.timestamp >=
                          auction.startingTime.add(auction.lengthOfAuction),
                      "settleAuction::Can only settle ended auctions."
                  );
                  Bid memory currBid = auctionBids[_originContract][_tokenId];
                  delete tokenAuctions[_originContract][_tokenId];
                  delete auctionBids[_originContract][_tokenId];
                  IERC721 erc721 = IERC721(_originContract);
                  if (currBid.bidder == address(0)) {
                      erc721.transferFrom(
                          address(this),
                          auction.auctionCreator,
                          _tokenId
                      );
                  } else {
                      erc721.transferFrom(address(this), currBid.bidder, _tokenId);
                      _payout(
                          _originContract,
                          _tokenId,
                          auction.currencyAddress,
                          currBid.amount,
                          auction.auctionCreator,
                          auction.splitRecipients,
                          auction.splitRatios
                      );
                      marketplaceSettings.markERC721Token(
                          _originContract,
                          _tokenId,
                          true
                      );
                  }
                  emit AuctionSettled(
                      _originContract,
                      currBid.bidder,
                      auction.auctionCreator,
                      _tokenId,
                      auction.currencyAddress,
                      currBid.amount
                  );
              }
              /// @notice Grabs the current auction details for a token.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              /** @return Auction Struct: creatorAddress, creationTime, startingTime, lengthOfAuction,
                          currencyAddress, minimumBid, auctionType, splitRecipients array, and splitRatios array.
              */
              function getAuctionDetails(address _originContract, uint256 _tokenId)
                  external
                  view
                  override
                  returns (
                      address,
                      uint256,
                      uint256,
                      uint256,
                      address,
                      uint256,
                      bytes32,
                      address payable[] memory,
                      uint8[] memory
                  )
              {
                  Auction memory auction = tokenAuctions[_originContract][_tokenId];
                  return (
                      auction.auctionCreator,
                      auction.creationBlock,
                      auction.startingTime,
                      auction.lengthOfAuction,
                      auction.currencyAddress,
                      auction.minimumBid,
                      auction.auctionType,
                      auction.splitRecipients,
                      auction.splitRatios
                  );
              }
              function _checkValidAuctionType(bytes32 _auctionType) internal pure {
                  if (
                      _auctionType != COLDIE_AUCTION && _auctionType != SCHEDULED_AUCTION
                  ) {
                      revert("Invalid Auction Type");
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../utils/ContextUpgradeable.sol";
          import "../proxy/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal initializer {
                  __Context_init_unchained();
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal initializer {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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 {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = 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");
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../proxy/Initializable.sol";
          /**
           * @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 ReentrancyGuardUpgradeable is Initializable {
              // 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;
              function __ReentrancyGuard_init() internal initializer {
                  __ReentrancyGuard_init_unchained();
              }
              function __ReentrancyGuard_init_unchained() internal initializer {
                  _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 make it call a
               * `private` function that does the actual work.
               */
              modifier nonReentrant() {
                  // On the first call to nonReentrant, _notEntered will be true
                  require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
                  // Any calls to nonReentrant after this point will fail
                  _status = _ENTERED;
                  _;
                  // By storing the original value once again, a refund is triggered (see
                  // https://eips.ethereum.org/EIPS/eip-2200)
                  _status = _NOT_ENTERED;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title ISuperRareAuctionHouse
          /// @notice The interface for the SuperRareAuctionHouse Functions.
          interface ISuperRareAuctionHouse {
              /// @notice Configures an Auction for a given asset.
              /// @param _auctionType The type of auction being configured.
              /// @param _originContract Contract address of the asset being put up for auction.
              /// @param _tokenId Token Id of the asset.
              /// @param _startingAmount The reserve price or min bid of an auction.
              /// @param _currencyAddress The currency the auction is being conducted in.
              /// @param _lengthOfAuction The amount of time in seconds that the auction is configured for.
              /// @param _splitAddresses Addresses to split the sellers commission with.
              /// @param _splitRatios The ratio for the split corresponding to each of the addresses being split with.
              function configureAuction(
                  bytes32 _auctionType,
                  address _originContract,
                  uint256 _tokenId,
                  uint256 _startingAmount,
                  address _currencyAddress,
                  uint256 _lengthOfAuction,
                  uint256 _startTime,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              /// @notice Converts an offer into a coldie auction.
              /// @param _originContract Contract address of the asset.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of the currency being converted.
              /// @param _amount Amount being converted into an auction.
              /// @param _lengthOfAuction Number of seconds the auction will last.
              /// @param _splitAddresses Addresses that the sellers take in will be split amongst.
              /// @param _splitRatios Ratios that the take in will be split by.
              function convertOfferToAuction(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _lengthOfAuction,
                  address payable[] calldata _splitAddresses,
                  uint8[] calldata _splitRatios
              ) external;
              /// @notice Cancels a configured Auction that has not started.
              /// @param _originContract Contract address of the asset pending auction.
              /// @param _tokenId Token Id of the asset.
              function cancelAuction(address _originContract, uint256 _tokenId) external;
              /// @notice Places a bid on a valid auction.
              /// @param _originContract Contract address of asset being bid on.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of currency being used to bid.
              /// @param _amount Amount of the currency being used for the bid.
              function bid(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              ) external payable;
              /// @notice Settles an auction that has ended.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              function settleAuction(address _originContract, uint256 _tokenId) external;
              /// @notice Grabs the current auction details for a token.
              /// @param _originContract Contract address of asset.
              /// @param _tokenId Token Id of the asset.
              /** @return Auction Struct: creatorAddress, creationTime, startingTime, lengthOfAuction,
                          currencyAddress, minimumBid, auctionType, splitRecipients array, and splitRatios array.
              */
              function getAuctionDetails(address _originContract, uint256 _tokenId)
                  external
                  view
                  returns (
                      address,
                      uint256,
                      uint256,
                      uint256,
                      address,
                      uint256,
                      bytes32,
                      address payable[] memory,
                      uint8[] memory
                  );
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-0.7.2/token/ERC721/IERC721.sol";
          import "@openzeppelin/contracts-0.7.2/token/ERC20/IERC20.sol";
          import "@openzeppelin/contracts-0.7.2/token/ERC20/SafeERC20.sol";
          import "@openzeppelin/contracts-0.7.2/math/SafeMath.sol";
          import "./storage/SuperRareBazaarStorage.sol";
          /// @author koloz
          /// @title SuperRareBazaarBase
          /// @notice Base contract containing the internal functions for the SuperRareBazaar.
          abstract contract SuperRareBazaarBase is SuperRareBazaarStorage {
              using SafeMath for uint256;
              using SafeMath for uint8;
              using SafeERC20 for IERC20;
              /////////////////////////////////////////////////////////////////////////
              // Internal Functions
              /////////////////////////////////////////////////////////////////////////
              /// @notice Checks to see if the currenccy address is eth or an approved erc20 token.
              /// @param _currencyAddress Address of currency (Zero address if eth).
              function _checkIfCurrencyIsApproved(address _currencyAddress)
                  internal
                  view
              {
                  require(
                      _currencyAddress == address(0) ||
                          approvedTokenRegistry.isApprovedToken(_currencyAddress),
                      "Not approved currency"
                  );
              }
              /// @notice Checks to see if the owner of the token has the marketplace approved.
              /// @param _originContract Contract address of the token being checked.
              /// @param _tokenId Token Id of the asset.
              function _ownerMustHaveMarketplaceApprovedForNFT(
                  address _originContract,
                  uint256 _tokenId
              ) internal view {
                  IERC721 erc721 = IERC721(_originContract);
                  address owner = erc721.ownerOf(_tokenId);
                  require(
                      erc721.isApprovedForAll(owner, address(this)),
                      "owner must have approved contract"
                  );
              }
              /// @notice Checks to see if the msg sender owns the token.
              /// @param _originContract Contract address of the token being checked.
              /// @param _tokenId Token Id of the asset.
              function _senderMustBeTokenOwner(address _originContract, uint256 _tokenId)
                  internal
                  view
              {
                  IERC721 erc721 = IERC721(_originContract);
                  require(
                      erc721.ownerOf(_tokenId) == msg.sender,
                      "sender must be the token owner"
                  );
              }
              /// @notice Verifies that the splits supplied are valid.
              /// @dev A valid split has the same number of splits and ratios.
              /// @dev There can only be a max of 5 parties split with.
              /// @dev Total of the ratios should be 100 which is relative.
              /// @param _splits The addresses the amount is being split with.
              /// @param _ratios The ratios each address in _splits is getting.
              function _checkSplits(
                  address payable[] calldata _splits,
                  uint8[] calldata _ratios
              ) internal pure {
                  require(_splits.length > 0, "checkSplits::Must have at least 1 split");
                  require(_splits.length <= 5, "checkSplits::Split exceeded max size");
                  require(
                      _splits.length == _ratios.length,
                      "checkSplits::Splits and ratios must be equal"
                  );
                  uint256 totalRatio = 0;
                  for (uint256 i = 0; i < _ratios.length; i++) {
                      totalRatio += _ratios[i];
                  }
                  require(totalRatio == 100, "checkSplits::Total must be equal to 100");
              }
              /// @notice Checks to see if the sender has approved the marketplace to move tokens.
              /// @dev This is for offers/buys/bids and the allowance of erc20 tokens.
              /// @dev Returns on zero address because no allowance is needed for eth.
              /// @param _contract The address of the currency being checked.
              /// @param _amount The total amount being checked.
              function _senderMustHaveMarketplaceApproved(
                  address _contract,
                  uint256 _amount
              ) internal view {
                  if (_contract == address(0)) {
                      return;
                  }
                  IERC20 erc20 = IERC20(_contract);
                  require(
                      erc20.allowance(msg.sender, address(this)) >= _amount,
                      "sender needs to approve marketplace for currency"
                  );
              }
              /// @notice Checks the user has the correct amount and transfers to the marketplace.
              /// @dev If the currency used is eth (zero address) the msg value is checked.
              /// @dev If eth isnt used and eth is sent we revert the txn.
              /// @dev We need to check this contracts balance before and after the transfer to ensure no fee.
              /// @param _currencyAddress Currency address being checked and transfered.
              /// @param _amount Total amount of currency.
              function _checkAmountAndTransfer(address _currencyAddress, uint256 _amount)
                  internal
              {
                  if (_currencyAddress == address(0)) {
                      require(msg.value == _amount, "not enough eth sent");
                      return;
                  }
                  require(msg.value == 0, "msg.value should be 0 when not using eth");
                  IERC20 erc20 = IERC20(_currencyAddress);
                  uint256 balanceBefore = erc20.balanceOf(address(this));
                  erc20.safeTransferFrom(msg.sender, address(this), _amount);
                  uint256 balanceAfter = erc20.balanceOf(address(this));
                  require(
                      balanceAfter.sub(balanceBefore) == _amount,
                      "not enough tokens transfered"
                  );
              }
              /// @notice Refunds an address the designated amount.
              /// @dev Return if amount being refunded is zero.
              /// @dev Forwards to payment contract if eth is being refunded.
              /// @param _currencyAddress Address of currency being refunded.
              /// @param _amount Amount being refunded.
              /// @param _marketplaceFee Marketplace Fee (percentage) paid by _recipient.
              /// @param _recipient Address amount is being refunded to.
              function _refund(
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _marketplaceFee,
                  address _recipient
              ) internal {
                  if (_amount == 0) {
                      return;
                  }
                  uint256 requiredAmount = _amount.add(
                      _amount.mul(_marketplaceFee).div(100)
                  );
                  if (_currencyAddress == address(0)) {
                      (bool success, bytes memory data) = address(payments).call{
                          value: requiredAmount
                      }(
                          abi.encodeWithSignature(
                              "refund(address,uint256)",
                              _recipient,
                              requiredAmount
                          )
                      );
                      require(success, string(data));
                      return;
                  }
                  IERC20 erc20 = IERC20(_currencyAddress);
                  erc20.safeTransfer(_recipient, requiredAmount);
              }
              /// @notice Sends a payout to all the necessary parties.
              /// @dev Sends payments to the network, royalty if applicable, and splits for the rest.
              /// @dev Forwards payments to the payment contract if payout is happening in eth.
              /// @dev Total amount of ratios should be 100 and is relative to the total ratio left.
              /// @param _originContract Contract address of asset triggering a payout.
              /// @param _tokenId Token Id of the asset.
              /// @param _currencyAddress Address of currency being paid out.
              /// @param _amount Total amount to be paid out.
              /// @param _seller Address of the person selling the asset.
              /// @param _splitAddrs Addresses that funds need to be split against.
              /// @param _splitRatios Ratios for split pertaining to each address.
              function _payout(
                  address _originContract,
                  uint256 _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  address _seller,
                  address payable[] memory _splitAddrs,
                  uint8[] memory _splitRatios
              ) internal {
                  require(
                      _splitAddrs.length == _splitRatios.length,
                      "Number of split addresses and ratios must be equal."
                  );
                  /*
                  The overall flow for payouts is:
                      1. Payout marketplace fee
                      2. Primary/Secondary Payouts
                          a. Primary -> If space sale, query space operator registry for platform comission and payout
                                        Else query marketplace setting for primary sale comission and payout
                          b. Secondary -> Query global royalty registry for recipients and amounts and payout
                      3. Calculate the amount for each _splitAddr based on remaining amount and payout
                   */
                  uint256 remainingAmount = _amount;
                  // Marketplace fee
                  uint256 marketplaceFee = marketplaceSettings.calculateMarketplaceFee(
                      _amount
                  );
                  address payable[] memory mktFeeRecip = new address payable[](1);
                  mktFeeRecip[0] = payable(networkBeneficiary);
                  uint256[] memory mktFee = new uint256[](1);
                  mktFee[0] = marketplaceFee;
                  _performPayouts(_currencyAddress, marketplaceFee, mktFeeRecip, mktFee);
                  if (
                      !marketplaceSettings.hasERC721TokenSold(_originContract, _tokenId)
                  ) {
                      uint256[] memory platformFee = new uint256[](1);
                      if (spaceOperatorRegistry.isApprovedSpaceOperator(_seller)) {
                          uint256 platformCommission = spaceOperatorRegistry
                              .getPlatformCommission(_seller);
                          remainingAmount = remainingAmount.sub(
                              _amount.mul(platformCommission).div(100)
                          );
                          platformFee[0] = _amount.mul(platformCommission).div(100);
                          _performPayouts(
                              _currencyAddress,
                              platformFee[0],
                              mktFeeRecip,
                              platformFee
                          );
                      } else {
                          uint256 platformCommission = marketplaceSettings
                              .getERC721ContractPrimarySaleFeePercentage(_originContract);
                          remainingAmount = remainingAmount.sub(
                              _amount.mul(platformCommission).div(100)
                          );
                          platformFee[0] = _amount.mul(platformCommission).div(100);
                          _performPayouts(
                              _currencyAddress,
                              platformFee[0],
                              mktFeeRecip,
                              platformFee
                          );
                      }
                  } else {
                      (
                          address payable[] memory receivers,
                          uint256[] memory royalties
                      ) = royaltyEngine.getRoyalty(_originContract, _tokenId, _amount);
                      uint256 totalRoyalties = 0;
                      for (uint256 i = 0; i < royalties.length; i++) {
                          totalRoyalties = totalRoyalties.add(royalties[i]);
                      }
                      remainingAmount = remainingAmount.sub(totalRoyalties);
                      _performPayouts(
                          _currencyAddress,
                          totalRoyalties,
                          receivers,
                          royalties
                      );
                  }
                  uint256[] memory remainingAmts = new uint256[](_splitAddrs.length);
                  uint256 totalSplit = 0;
                  for (uint256 i = 0; i < _splitAddrs.length; i++) {
                      remainingAmts[i] = remainingAmount.mul(_splitRatios[i]).div(100);
                      totalSplit = totalSplit.add(
                          remainingAmount.mul(_splitRatios[i]).div(100)
                      );
                  }
                  _performPayouts(
                      _currencyAddress,
                      totalSplit,
                      _splitAddrs,
                      remainingAmts
                  );
              }
              function _performPayouts(
                  address _currencyAddress,
                  uint256 _amount,
                  address payable[] memory _recipients,
                  uint256[] memory _amounts
              ) internal {
                  if (_currencyAddress == address(0)) {
                      (bool success, bytes memory data) = address(payments).call{
                          value: _amount
                      }(
                          abi.encodeWithSelector(
                              IPayments.payout.selector,
                              _recipients,
                              _amounts
                          )
                      );
                      require(success, string(data));
                  } else {
                      IERC20 erc20 = IERC20(_currencyAddress);
                      for (uint256 i = 0; i < _recipients.length; i++) {
                          erc20.safeTransfer(_recipients[i], _amounts[i]);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "../proxy/Initializable.sol";
          /*
           * @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 GSN 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 ContextUpgradeable is Initializable {
              function __Context_init() internal initializer {
                  __Context_init_unchained();
              }
              function __Context_init_unchained() internal initializer {
              }
              function _msgSender() internal view virtual returns (address payable) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.4.24 <0.8.0;
          import "../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               */
              bool private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Modifier to protect an initializer function from being invoked twice.
               */
              modifier initializer() {
                  require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
                  bool isTopLevelCall = !_initializing;
                  if (isTopLevelCall) {
                      _initializing = true;
                      _initialized = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                  }
              }
              /// @dev Returns true if and only if the function is running in the constructor
              function _isConstructor() private view returns (bool) {
                  return !AddressUpgradeable.isContract(address(this));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          import "../../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`, 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 be have been allowed to move this token by either {approve} or {setApprovalForAll}.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Transfers `tokenId` token from `from` to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Gives permission to `to` to transfer `tokenId` token to another account.
               * The approval is cleared when the token is transferred.
               *
               * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
               *
               * Requirements:
               *
               * - The caller must own the token or be an approved operator.
               * - `tokenId` must exist.
               *
               * Emits an {Approval} event.
               */
              function approve(address to, uint256 tokenId) external;
              /**
               * @dev Returns the account approved for `tokenId` token.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function getApproved(uint256 tokenId) external view returns (address operator);
              /**
               * @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 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);
              /**
                * @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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          /**
           * @dev Interface of the ERC20 standard as defined in the EIP.
           */
          interface IERC20 {
              /**
               * @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 `recipient`.
               *
               * Returns a boolean value indicating whether the operation succeeded.
               *
               * Emits a {Transfer} event.
               */
              function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);
              /**
               * @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);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "./IERC20.sol";
          import "../../math/SafeMath.sol";
          import "../../utils/Address.sol";
          /**
           * @title SafeERC20
           * @dev Wrappers around ERC20 operations that throw on failure (when the token
           * contract returns false). Tokens that return no value (and instead revert or
           * throw on failure) are also supported, non-reverting calls are assumed to be
           * successful.
           * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
           * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
           */
          library SafeERC20 {
              using SafeMath for uint256;
              using Address for address;
              function safeTransfer(IERC20 token, address to, uint256 value) internal {
                  _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
              }
              function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                  _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
              }
              /**
               * @dev Deprecated. This function has issues similar to the ones found in
               * {IERC20-approve}, and its usage is discouraged.
               *
               * Whenever possible, use {safeIncreaseAllowance} and
               * {safeDecreaseAllowance} instead.
               */
              function safeApprove(IERC20 token, address spender, uint256 value) internal {
                  // safeApprove should only be called when setting an initial allowance,
                  // or when resetting it to zero. To increase and decrease it, use
                  // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                  // solhint-disable-next-line max-line-length
                  require((value == 0) || (token.allowance(address(this), spender) == 0),
                      "SafeERC20: approve from non-zero to non-zero allowance"
                  );
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
              }
              function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                  uint256 newAllowance = token.allowance(address(this), spender).add(value);
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
              function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                  uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
              /**
               * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
               * on the return value: the return value is optional (but if data is returned, it must not be false).
               * @param token The token targeted by the call.
               * @param data The call data (encoded using abi.encode or one of its variants).
               */
              function _callOptionalReturn(IERC20 token, bytes memory data) private {
                  // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                  // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                  // the target address contains contract code and also asserts for success in the low-level call.
                  bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                  if (returndata.length > 0) { // Return data is optional
                      // solhint-disable-next-line max-line-length
                      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          /**
           * @dev Wrappers over Solidity's arithmetic operations with added overflow
           * checks.
           *
           * Arithmetic operations in Solidity wrap on overflow. This can easily result
           * in bugs, because programmers usually assume that an overflow raises an
           * error, which is the standard behavior in high level programming languages.
           * `SafeMath` restores this intuition by reverting the transaction when an
           * operation overflows.
           *
           * Using this library instead of the unchecked operations eliminates an entire
           * class of bugs, so it's recommended to use it always.
           */
          library SafeMath {
              /**
               * @dev Returns the addition of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the substraction of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the division of two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
              /**
               * @dev Returns the addition of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `+` operator.
               *
               * Requirements:
               *
               * - Addition cannot overflow.
               */
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  require(c >= a, "SafeMath: addition overflow");
                  return c;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting on
               * overflow (when the result is negative).
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b <= a, "SafeMath: subtraction overflow");
                  return a - b;
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `*` operator.
               *
               * Requirements:
               *
               * - Multiplication cannot overflow.
               */
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) return 0;
                  uint256 c = a * b;
                  require(c / a == b, "SafeMath: multiplication overflow");
                  return c;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting on
               * division by zero. The result is rounded towards zero.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: division by zero");
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting when dividing by zero.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: modulo by zero");
                  return a % b;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
               * overflow (when the result is negative).
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {trySub}.
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b <= a, errorMessage);
                  return a - b;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting with custom message on
               * division by zero. The result is rounded towards zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryDiv}.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting with custom message when dividing by zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryMod}.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a % b;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "../../marketplace/IMarketplaceSettings.sol";
          import "../../royalty/creator/IERC721CreatorRoyalty.sol";
          import "../../payments/IPayments.sol";
          import "../../registry/spaces/ISpaceOperatorRegistry.sol";
          import "../../registry/token/IApprovedTokenRegistry.sol";
          import "../../royalty/creator/IRoyaltyEngine.sol";
          /// @author koloz
          /// @title SuperRareBazaar Storage Contract
          /// @dev STORAGE CAN ONLY BE APPENDED NOT INSERTED OR MODIFIED
          contract SuperRareBazaarStorage {
              /////////////////////////////////////////////////////////////////////////
              // Constants
              /////////////////////////////////////////////////////////////////////////
              // Auction Types
              bytes32 public constant COLDIE_AUCTION = "COLDIE_AUCTION";
              bytes32 public constant SCHEDULED_AUCTION = "SCHEDULED_AUCTION";
              bytes32 public constant NO_AUCTION = bytes32(0);
              /////////////////////////////////////////////////////////////////////////
              // Structs
              /////////////////////////////////////////////////////////////////////////
              // The Offer truct for a given token:
              // buyer - address of person making the offer
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // amount - offer in wei/full erc20 value
              // marketplaceFee - the amount that is taken by the network on offer acceptance.
              struct Offer {
                  address payable buyer;
                  uint256 amount;
                  uint256 timestamp;
                  uint8 marketplaceFee;
                  bool convertible;
              }
              // The Sale Price struct for a given token:
              // seller - address of the person selling the token
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // amount - offer in wei/full erc20 value
              struct SalePrice {
                  address payable seller;
                  address currencyAddress;
                  uint256 amount;
                  address payable[] splitRecipients;
                  uint8[] splitRatios;
              }
              // Structure of an Auction:
              // auctionCreator - creator of the auction
              // creationBlock - time that the auction was created/configured
              // startingBlock - time that the auction starts on
              // lengthOfAuction - how long the auction is
              // currencyAddress - address of the erc20 token used for an offer
              //                   or the zero address for eth
              // minimumBid - min amount a bidder can bid at the start of an auction.
              // auctionType - type of auction, represented as the formatted bytes 32 string
              struct Auction {
                  address payable auctionCreator;
                  uint256 creationBlock;
                  uint256 startingTime;
                  uint256 lengthOfAuction;
                  address currencyAddress;
                  uint256 minimumBid;
                  bytes32 auctionType;
                  address payable[] splitRecipients;
                  uint8[] splitRatios;
              }
              struct Bid {
                  address payable bidder;
                  address currencyAddress;
                  uint256 amount;
                  uint8 marketplaceFee;
              }
              /////////////////////////////////////////////////////////////////////////
              // Events
              /////////////////////////////////////////////////////////////////////////
              event Sold(
                  address indexed _originContract,
                  address indexed _buyer,
                  address indexed _seller,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId
              );
              event SetSalePrice(
                  address indexed _originContract,
                  address indexed _currencyAddress,
                  address _target,
                  uint256 _amount,
                  uint256 _tokenId,
                  address payable[] _splitRecipients,
                  uint8[] _splitRatios
              );
              event OfferPlaced(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId,
                  bool _convertible
              );
              event AcceptOffer(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _seller,
                  address _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId,
                  address payable[] _splitAddresses,
                  uint8[] _splitRatios
              );
              event CancelOffer(
                  address indexed _originContract,
                  address indexed _bidder,
                  address indexed _currencyAddress,
                  uint256 _amount,
                  uint256 _tokenId
              );
              event NewAuction(
                  address indexed _contractAddress,
                  uint256 indexed _tokenId,
                  address indexed _auctionCreator,
                  address _currencyAddress,
                  uint256 _startingTime,
                  uint256 _minimumBid,
                  uint256 _lengthOfAuction
              );
              event CancelAuction(
                  address indexed _contractAddress,
                  uint256 indexed _tokenId,
                  address indexed _auctionCreator
              );
              event AuctionBid(
                  address indexed _contractAddress,
                  address indexed _bidder,
                  uint256 indexed _tokenId,
                  address _currencyAddress,
                  uint256 _amount,
                  bool _startedAuction,
                  uint256 _newAuctionLength,
                  address _previousBidder
              );
              event AuctionSettled(
                  address indexed _contractAddress,
                  address indexed _bidder,
                  address _seller,
                  uint256 indexed _tokenId,
                  address _currencyAddress,
                  uint256 _amount
              );
              /////////////////////////////////////////////////////////////////////////
              // State Variables
              /////////////////////////////////////////////////////////////////////////
              // Current marketplace settings implementation to be used
              IMarketplaceSettings public marketplaceSettings;
              // Current creator royalty implementation to be used
              IERC721CreatorRoyalty public royaltyRegistry;
              // Address of the global royalty engine being used.
              IRoyaltyEngineV1 public royaltyEngine;
              // Current SuperRareMarketplace implementation to be used
              address public superRareMarketplace;
              // Current SuperRareAuctionHouse implementation to be used
              address public superRareAuctionHouse;
              // Current SpaceOperatorRegistry implementation to be used.
              ISpaceOperatorRegistry public spaceOperatorRegistry;
              // Current ApprovedTokenRegistry implementation being used for currencies.
              IApprovedTokenRegistry public approvedTokenRegistry;
              // Current payments contract to use
              IPayments public payments;
              // Address to be used for staking registry.
              address public stakingRegistry;
              // Address of the network beneficiary
              address public networkBeneficiary;
              // A minimum increase in bid amount when out bidding someone.
              uint8 public minimumBidIncreasePercentage; // 10 = 10%
              // Maximum length that an auction can be.
              uint256 public maxAuctionLength;
              // Extension length for an auction
              uint256 public auctionLengthExtension;
              // Offer cancellation delay
              uint256 public offerCancelationDelay;
              // Mapping from contract to mapping of tokenId to mapping of target to sale price.
              mapping(address => mapping(uint256 => mapping(address => SalePrice)))
                  public tokenSalePrices;
              // Mapping from contract to mapping of tokenId to mapping of currency address to Current Offer.
              mapping(address => mapping(uint256 => mapping(address => Offer)))
                  public tokenCurrentOffers;
              // Mapping from contract to mapping of tokenId to Auction.
              mapping(address => mapping(uint256 => Auction)) public tokenAuctions;
              // Mapping from contract to mapping of tokenId to Bid.
              mapping(address => mapping(uint256 => Bid)) public auctionBids;
              uint256[50] private __gap;
              /// ALL NEW STORAGE MUST COME AFTER THIS
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <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
          pragma solidity >=0.6.2 <0.8.0;
          /**
           * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: delegate call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /**
           * @title IMarketplaceSettings Settings governing a marketplace.
           */
          interface IMarketplaceSettings {
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Min and Max Values
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMaxValue() external view returns (uint256);
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMinValue() external view returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the marketplace fee percentage.
               * @return uint8 wei fee.
               */
              function getMarketplaceFeePercentage() external view returns (uint8);
              /**
               * @dev Utility function for calculating the marketplace fee for given amount of wei.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculateMarketplaceFee(uint256 _amount)
                  external
                  view
                  returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Primary Sale Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the primary sale fee percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @return uint8 wei primary sale fee.
               */
              function getERC721ContractPrimarySaleFeePercentage(address _contractAddress)
                  external
                  view
                  returns (uint8);
              /**
               * @dev Utility function for calculating the primary sale fee for given amount of wei
               * @param _contractAddress address ERC721Contract address.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculatePrimarySaleFee(address _contractAddress, uint256 _amount)
                  external
                  view
                  returns (uint256);
              /**
               * @dev Check whether the ERC721 token has sold at least once.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @return bool of whether the token has sold.
               */
              function hasERC721TokenSold(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  returns (bool);
              /**
               * @dev Mark a token as sold.
               * Requirements:
               *
               * - `_contractAddress` cannot be the zero address.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @param _hasSold bool of whether the token should be marked sold or not.
               */
              function markERC721Token(
                  address _contractAddress,
                  uint256 _tokenId,
                  bool _hasSold
              ) external;
              function setERC721ContractPrimarySaleFeePercentage(
                  address _contractAddress,
                  uint8 _percentage
              ) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "../../token/ERC721/IERC721TokenCreator.sol";
          /**
           * @title IERC721CreatorRoyalty Token level royalty interface.
           */
          interface IERC721CreatorRoyalty is IERC721TokenCreator {
              /**
               * @dev Get the royalty fee percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @return uint8 wei royalty fee.
               */
              function getERC721TokenRoyaltyPercentage(
                  address _contractAddress,
                  uint256 _tokenId
              ) external view returns (uint8);
              /**
               * @dev Utililty function to calculate the royalty fee for a token.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculateRoyaltyFee(
                  address _contractAddress,
                  uint256 _tokenId,
                  uint256 _amount
              ) external view returns (uint256);
              /**
               * @dev Utililty function to set the royalty percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @param _percentage percentage for royalty
               */
              function setPercentageForSetERC721ContractRoyalty(
                  address _contractAddress,
                  uint8 _percentage
              ) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title IPayments
          /// @notice Interface for the Payments contract used.
          interface IPayments {
              function refund(address _payee, uint256 _amount) external payable;
              function payout(address[] calldata _splits, uint256[] calldata _amounts)
                  external
                  payable;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title ISpaceOperatorRegistry
          /// @notice The interface for the SpaceOperatorRegistry
          interface ISpaceOperatorRegistry {
              function getPlatformCommission(address _operator)
                  external
                  view
                  returns (uint8);
              function setPlatformCommission(address _operator, uint8 _commission)
                  external;
              function isApprovedSpaceOperator(address _operator)
                  external
                  view
                  returns (bool);
              function setSpaceOperatorApproved(address _operator, bool _approved)
                  external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          interface IApprovedTokenRegistry {
              /// @notice Returns if a token has been approved or not.
              /// @param _tokenContract Contract of token being checked.
              /// @return True if the token is allowed, false otherwise.
              function isApprovedToken(address _tokenContract)
                  external
                  view
                  returns (bool);
              /// @notice Adds a token to the list of approved tokens.
              /// @param _tokenContract Contract of token being approved.
              function addApprovedToken(address _tokenContract) external;
              /// @notice Removes a token from the approved tokens list.
              /// @param _tokenContract Contract of token being approved.
              function removeApprovedToken(address _tokenContract) external;
              /// @notice Sets whether all token contracts should be approved.
              /// @param _allTokensApproved Bool denoting if all tokens should be approved.
              function setAllTokensApproved(bool _allTokensApproved) external;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author: manifold.xyz
          /**
           * @dev Lookup engine interface
           */
          interface IRoyaltyEngineV1 {
              /**
               * Get the royalty for a given token (address, id) and value amount.  Does not cache the bps/amounts.  Caches the spec for a given token address
               *
               * @param tokenAddress - The address of the token
               * @param tokenId      - The id of the token
               * @param value        - The value you wish to get the royalty of
               *
               * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
               */
              function getRoyalty(
                  address tokenAddress,
                  uint256 tokenId,
                  uint256 value
              )
                  external
                  returns (address payable[] memory recipients, uint256[] memory amounts);
              /**
               * View only version of getRoyalty
               *
               * @param tokenAddress - The address of the token
               * @param tokenId      - The id of the token
               * @param value        - The value you wish to get the royalty of
               *
               * returns Two arrays of equal length, royalty recipients and the corresponding amount each recipient should get
               */
              function getRoyaltyView(
                  address tokenAddress,
                  uint256 tokenId,
                  uint256 value
              )
                  external
                  view
                  returns (address payable[] memory recipients, uint256[] memory amounts);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          interface IERC721TokenCreator {
              function tokenCreator(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  returns (address payable);
          }
          

          File 3 of 6: MarketplaceSettingsV2
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.10;
          import {IMarketplaceSettings} from "./IMarketplaceSettings.sol";
          import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
          import {AccessControl} from "openzeppelin-contracts/access/AccessControl.sol";
          import {ITokenCreator} from "../token/ITokenCreator.sol";
          import {IERC721} from "openzeppelin-contracts/token/ERC721/IERC721.sol";
          import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
          contract MarketplaceSettingsV2 is Ownable, AccessControl, IMarketplaceSettings {
              bytes32 public constant TOKEN_MARK_ROLE = keccak256("TOKEN_MARK_ROLE");
              // This is meant to be the MarketplaceSettings contract located in the V1 folder
              IMarketplaceSettings private oldMarketplaceSettings;
              // EnumerableSet library method
              using EnumerableSet for EnumerableSet.AddressSet;
              // EnumerableSet of contracts marked sold
              EnumerableSet.AddressSet private contractSold;
              uint256 private maxValue;
              uint256 private minValue;
              uint8 private marketplaceFeePercentage;
              uint8 private primarySaleFeePercentage;
              constructor(address newOwner, address oldSettings) {
                  maxValue = 2**254;
                  minValue = 1000;
                  marketplaceFeePercentage = 3;
                  primarySaleFeePercentage = 15;
                  require(
                      newOwner != address(0),
                      "constructor::New owner address cannot be null"
                  );
                  require(
                      oldSettings != address(0),
                      "constructor::Old Marketplace Settings address cannot be null"
                  );
                  _setupRole(AccessControl.DEFAULT_ADMIN_ROLE, newOwner);
                  _setupRole(TOKEN_MARK_ROLE, newOwner);
                  transferOwnership(newOwner);
                  oldMarketplaceSettings = IMarketplaceSettings(oldSettings);
              }
              function grantMarketplaceAccess(address _account) external {
                  require(
                      hasRole(AccessControl.DEFAULT_ADMIN_ROLE, _msgSender()),
                      "grantMarketplaceAccess::Must be admin to call method"
                  );
                  grantRole(TOKEN_MARK_ROLE, _account);
              }
              function getMarketplaceMaxValue() external view override returns (uint256) {
                  return maxValue;
              }
              function setPrimarySaleFeePercentage(uint8 _primarySaleFeePercentage)
                  external
                  onlyOwner
              {
                  primarySaleFeePercentage = _primarySaleFeePercentage;
              }
              function setMarketplaceMaxValue(uint256 _maxValue) external onlyOwner {
                  maxValue = _maxValue;
              }
              function getMarketplaceMinValue() external view override returns (uint256) {
                  return minValue;
              }
              function setMarketplaceMinValue(uint256 _minValue) external onlyOwner {
                  minValue = _minValue;
              }
              function getMarketplaceFeePercentage()
                  external
                  view
                  override
                  returns (uint8)
              {
                  return marketplaceFeePercentage;
              }
              function setMarketplaceFeePercentage(uint8 _percentage) external onlyOwner {
                  require(
                      _percentage <= 100,
                      "setMarketplaceFeePercentage::_percentage must be <= 100"
                  );
                  marketplaceFeePercentage = _percentage;
              }
              function calculateMarketplaceFee(uint256 _amount)
                  external
                  view
                  override
                  returns (uint256)
              {
                  return (_amount * marketplaceFeePercentage) / 100;
              }
              function getERC721ContractPrimarySaleFeePercentage(address)
                  external
                  view
                  override
                  returns (uint8)
              {
                  return primarySaleFeePercentage;
              }
              function setERC721ContractPrimarySaleFeePercentage(
                  address _contractAddress,
                  uint8 _percentage
              ) external override {}
              function calculatePrimarySaleFee(address, uint256 _amount)
                  external
                  view
                  override
                  returns (uint256)
              {
                  return (_amount * primarySaleFeePercentage) / 100;
              }
              function hasERC721TokenSold(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  override
                  returns (bool)
              {
                  bool contractHasSold = contractSold.contains(_contractAddress);
                  if (contractHasSold) return true;
                  return
                      oldMarketplaceSettings.hasERC721TokenSold(
                          _contractAddress,
                          _tokenId
                      );
              }
              function markERC721Token(
                  address _contractAddress,
                  uint256 _tokenId,
                  bool _hasSold
              ) public override {
                  require(
                      hasRole(TOKEN_MARK_ROLE, msg.sender),
                      "markERC721Token::Must have TOKEN_MARK_ROLE role to call method"
                  );
                  oldMarketplaceSettings.markERC721Token(
                      _contractAddress,
                      _tokenId,
                      _hasSold
                  );
              }
              function markTokensAsSold(
                  address _originContract,
                  uint256[] calldata _tokenIds
              ) external {
                  require(
                      hasRole(TOKEN_MARK_ROLE, msg.sender),
                      "markERC721Token::Must have TOKEN_MARK_ROLE role to call method"
                  );
                  // limit to batches of 2000
                  require(
                      _tokenIds.length <= 2000,
                      "markTokensAsSold::Attempted to mark more than 2000 tokens as sold"
                  );
                  // Mark provided tokens as sold.
                  for (uint256 i = 0; i < _tokenIds.length; i++) {
                      markERC721Token(_originContract, _tokenIds[i], true);
                  }
              }
              function markContractAsSold(address _contractAddress)
                  external
                  returns (bool)
              {
                  require(
                      hasRole(TOKEN_MARK_ROLE, msg.sender),
                      "markContract::Must have TOKEN_MARK_ROLE role to call method"
                  );
                  // Prevents contract address from being marked multiple times
                  require(
                      !contractSold.contains(_contractAddress),
                      "markContract::Contract already marked as sold"
                  );
                  // Adds contract address to set
                  return contractSold.add(_contractAddress);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.10;
          /**
           * @title IMarketplaceSettings Settings governing a marketplace.
           */
          interface IMarketplaceSettings {
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Min and Max Values
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMaxValue() external view returns (uint256);
              /**
               * @dev Get the max value to be used with the marketplace.
               * @return uint256 wei value.
               */
              function getMarketplaceMinValue() external view returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Marketplace Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the marketplace fee percentage.
               * @return uint8 wei fee.
               */
              function getMarketplaceFeePercentage() external view returns (uint8);
              /**
               * @dev Utility function for calculating the marketplace fee for given amount of wei.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculateMarketplaceFee(uint256 _amount)
                  external
                  view
                  returns (uint256);
              /////////////////////////////////////////////////////////////////////////
              // Primary Sale Fee
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Get the primary sale fee percentage for a specific ERC721 contract.
               * @param _contractAddress address ERC721Contract address.
               * @return uint8 wei primary sale fee.
               */
              function getERC721ContractPrimarySaleFeePercentage(address _contractAddress)
                  external
                  view
                  returns (uint8);
              /**
               * @dev Utility function for calculating the primary sale fee for given amount of wei
               * @param _contractAddress address ERC721Contract address.
               * @param _amount uint256 wei amount.
               * @return uint256 wei fee.
               */
              function calculatePrimarySaleFee(address _contractAddress, uint256 _amount)
                  external
                  view
                  returns (uint256);
              /**
               * @dev Check whether the ERC721 token has sold at least once.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @return bool of whether the token has sold.
               */
              function hasERC721TokenSold(address _contractAddress, uint256 _tokenId)
                  external
                  view
                  returns (bool);
              /**
               * @dev Mark a token as sold.
               * Requirements:
               *
               * - `_contractAddress` cannot be the zero address.
               * @param _contractAddress address ERC721Contract address.
               * @param _tokenId uint256 token ID.
               * @param _hasSold bool of whether the token should be marked sold or not.
               */
              function markERC721Token(
                  address _contractAddress,
                  uint256 _tokenId,
                  bool _hasSold
              ) external;
              function setERC721ContractPrimarySaleFeePercentage(
                  address _contractAddress,
                  uint8 _percentage
              ) external;
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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);
              }
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.6.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(uint160(account), 20),
                                  " 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.
               */
              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.
               */
              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`.
               */
              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.
               *
               * [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.
               */
              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.
               */
              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
          pragma solidity 0.8.10;
          interface ITokenCreator {
              // bytes4(keccak256(tokenCreator(uint256))) == 0x40c1a064
              function tokenCreator(uint256 _tokenId)
                  external
                  view
                  returns (address payable);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.6.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 be have been allowed to move this token by either {approve} or {setApprovalForAll}.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function safeTransferFrom(
                  address from,
                  address to,
                  uint256 tokenId
              ) external;
              /**
               * @dev Transfers `tokenId` token from `from` to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(
                  address from,
                  address to,
                  uint256 tokenId
              ) external;
              /**
               * @dev Gives permission to `to` to transfer `tokenId` token to another account.
               * The approval is cleared when the token is transferred.
               *
               * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
               *
               * Requirements:
               *
               * - The caller must own the token or be an approved operator.
               * - `tokenId` must exist.
               *
               * Emits an {Approval} event.
               */
              function approve(address to, uint256 tokenId) external;
              /**
               * @dev Approve or remove `operator` as an operator for the caller.
               * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
               *
               * Requirements:
               *
               * - The `operator` cannot be the caller.
               *
               * Emits an {ApprovalForAll} event.
               */
              function setApprovalForAll(address operator, bool _approved) external;
              /**
               * @dev Returns the account approved for `tokenId` token.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function getApproved(uint256 tokenId) external view returns (address operator);
              /**
               * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
               *
               * See {setApprovalForAll}
               */
              function isApprovedForAll(address owner, address operator) external view returns (bool);
          }
          // SPDX-License-Identifier: MIT
          // OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol)
          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.
           */
          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) {
                  return _values(set._inner);
              }
              // 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;
                  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 on 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;
                  assembly {
                      result := store
                  }
                  return result;
              }
          }
          // 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 (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 (utils/Strings.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev String operations.
           */
          library Strings {
              bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
              /**
               * @dev Converts a `uint256` to its ASCII `string` decimal representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  while (value != 0) {
                      digits -= 1;
                      buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                      value /= 10;
                  }
                  return string(buffer);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
               */
              function toHexString(uint256 value) internal pure returns (string memory) {
                  if (value == 0) {
                      return "0x00";
                  }
                  uint256 temp = value;
                  uint256 length = 0;
                  while (temp != 0) {
                      length++;
                      temp >>= 8;
                  }
                  return toHexString(value, length);
              }
              /**
               * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
               */
              function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                  bytes memory buffer = new bytes(2 * length + 2);
                  buffer[0] = "0";
                  buffer[1] = "x";
                  for (uint256 i = 2 * length + 1; i > 1; --i) {
                      buffer[i] = _HEX_SYMBOLS[value & 0xf];
                      value >>= 4;
                  }
                  require(value == 0, "Strings: hex length insufficient");
                  return string(buffer);
              }
          }
          // 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 v4.4.1 (utils/introspection/IERC165.sol)
          pragma solidity ^0.8.0;
          /**
           * @dev Interface of the ERC165 standard, as defined in the
           * https://eips.ethereum.org/EIPS/eip-165[EIP].
           *
           * Implementers can declare support of contract interfaces, which can then be
           * queried by others ({ERC165Checker}).
           *
           * For an implementation, see {ERC165}.
           */
          interface IERC165 {
              /**
               * @dev Returns true if this contract implements the interface defined by
               * `interfaceId`. See the corresponding
               * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
               * to learn more about how these ids are created.
               *
               * This function call must use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) external view returns (bool);
          }
          

          File 4 of 6: SovereignNFT
          // contracts/token/ERC721/sovereign/SovereignNFT.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          pragma experimental ABIEncoderV2;
          import "@openzeppelin/contracts-upgradeable-0.7.2/token/ERC721/ERC721Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/token/ERC721/ERC721BurnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/introspection/ERC165Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/access/OwnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/utils/CountersUpgradeable.sol";
          import "../IERC721Creator.sol";
          import "../../../royalty/ERC2981Upgradeable.sol";
          contract SovereignNFT is
              OwnableUpgradeable,
              ERC165Upgradeable,
              ERC721Upgradeable,
              IERC721Creator,
              ERC721BurnableUpgradeable,
              ERC2981Upgradeable
          {
              using SafeMathUpgradeable for uint256;
              using StringsUpgradeable for uint256;
              using CountersUpgradeable for CountersUpgradeable.Counter;
              struct MintBatch {
                  uint256 startTokenId;
                  uint256 endTokenId;
                  string baseURI;
              }
              bool public disabled;
              // Mapping from token ID to the creator's address
              mapping(uint256 => address) private tokenCreators;
              // Mapping from tokenId to if it was burned or not (for batch minting)
              mapping(uint256 => bool) private tokensBurned;
              // Mapping from token ID to approved address
              mapping(uint256 => address) private _tokenApprovals;
              // Counter to keep track of the current token id.
              CountersUpgradeable.Counter private tokenIdCounter;
              MintBatch[] private mintBatches;
              // Default royalty percentage
              uint256 public defaultRoyaltyPercentage;
              event ContractDisabled(address indexed user);
              event ConsecutiveTransfer(
                  uint256 indexed fromTokenId,
                  uint256 toTokenId,
                  address indexed fromAddress,
                  address indexed toAddress
              );
              function init(
                  string calldata _name,
                  string calldata _symbol,
                  address _creator
              ) public initializer {
                  require(_creator != address(0));
                  defaultRoyaltyPercentage = 10;
                  disabled = false;
                  __Ownable_init();
                  __ERC721_init(_name, _symbol);
                  __ERC165_init();
                  __ERC2981__init();
                  _setDefaultRoyaltyReceiver(_creator);
                  _registerInterface(calcIERC721CreatorInterfaceId());
                  super.transferOwnership(_creator);
              }
              modifier onlyTokenOwner(uint256 _tokenId) {
                  require(ownerOf(_tokenId) == msg.sender, "Must be owner of token.");
                  _;
              }
              modifier ifNotDisabled() {
                  require(!disabled, "Contract must not be disabled.");
                  _;
              }
              function batchMint(string calldata _baseURI, uint256 _numberOfTokens)
                  public
                  onlyOwner
                  ifNotDisabled
              {
                  uint256 startTokenId = tokenIdCounter.current() + 1;
                  uint256 endTokenId = startTokenId + _numberOfTokens - 1;
                  tokenIdCounter = CountersUpgradeable.Counter(endTokenId);
                  mintBatches.push(MintBatch(startTokenId, endTokenId, _baseURI));
                  emit ConsecutiveTransfer(startTokenId, endTokenId, address(0), owner());
              }
              function addNewToken(string memory _uri) public onlyOwner ifNotDisabled {
                  _createToken(
                      _uri,
                      msg.sender,
                      msg.sender,
                      defaultRoyaltyPercentage,
                      msg.sender
                  );
              }
              function mintTo(
                  string calldata _uri,
                  address _receiver,
                  address _royaltyReceiver
              ) external onlyOwner ifNotDisabled {
                  _createToken(
                      _uri,
                      msg.sender,
                      _receiver,
                      defaultRoyaltyPercentage,
                      _royaltyReceiver
                  );
              }
              function renounceOwnership() public view override onlyOwner {
                  revert("unsupported");
              }
              function transferOwnership(address) public view override onlyOwner {
                  revert("unsupported");
              }
              function deleteToken(uint256 _tokenId) public onlyTokenOwner(_tokenId) {
                  burn(_tokenId);
              }
              function burn(uint256 _tokenId) public virtual override {
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  tokensBurned[_tokenId] = true;
                  if (wasBatchMinted && !ERC721Upgradeable._exists(_tokenId)) {
                      return;
                  }
                  ERC721BurnableUpgradeable.burn(_tokenId);
              }
              function tokenCreator(uint256)
                  public
                  view
                  override
                  returns (address payable)
              {
                  return payable(owner());
              }
              function disableContract() public onlyOwner {
                  disabled = true;
                  emit ContractDisabled(msg.sender);
              }
              function setDefaultRoyaltyReceiver(address _receiver) external onlyOwner {
                  _setDefaultRoyaltyReceiver(_receiver);
              }
              function setRoyaltyReceiverForToken(address _receiver, uint256 _tokenId)
                  external
                  onlyOwner
              {
                  royaltyReceivers[_tokenId] = _receiver;
              }
              function _setTokenCreator(uint256 _tokenId, address _creator) internal {
                  tokenCreators[_tokenId] = _creator;
              }
              function _createToken(
                  string memory _uri,
                  address _creator,
                  address _to,
                  uint256 _royaltyPercentage,
                  address _royaltyReceiver
              ) internal returns (uint256) {
                  tokenIdCounter.increment();
                  uint256 tokenId = tokenIdCounter.current();
                  _safeMint(_to, tokenId);
                  _setTokenURI(tokenId, _uri);
                  _setTokenCreator(tokenId, _creator);
                  _setRoyaltyPercentage(tokenId, _royaltyPercentage);
                  _setRoyaltyReceiver(tokenId, _royaltyReceiver);
                  return tokenId;
              }
              ///////////////////////////////////////////////
              // Overriding Methods to support batch mints
              ///////////////////////////////////////////////
              function tokenURI(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (string memory)
              {
                  (bool wasBatchMinted, , string memory baseTokenUri) = _batchMintInfo(
                      _tokenId
                  );
                  if (!wasBatchMinted) {
                      return super.tokenURI(_tokenId);
                  } else {
                      return
                          string(
                              abi.encodePacked(
                                  baseTokenUri,
                                  "/",
                                  _tokenId.toString(),
                                  ".json"
                              )
                          );
                  }
              }
              function ownerOf(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (address)
              {
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  if (!wasBatchMinted) {
                      return ERC721Upgradeable.ownerOf(_tokenId);
                  } else if (tokensBurned[_tokenId]) {
                      return ERC721Upgradeable.ownerOf(_tokenId);
                  } else {
                      if (!ERC721Upgradeable._exists(_tokenId)) {
                          return owner();
                      } else {
                          return ERC721Upgradeable.ownerOf(_tokenId);
                      }
                  }
              }
              function approve(address to, uint256 tokenId) public virtual override {
                  address owner = ownerOf(tokenId);
                  require(to != owner, "ERC721: approval to current owner");
                  require(
                      _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                      "ERC721: approve caller is not owner nor approved for all"
                  );
                  _approve(to, tokenId);
              }
              function _isApprovedOrOwner(address _spender, uint256 _tokenId)
                  internal
                  view
                  virtual
                  override
                  returns (bool)
              {
                  address owner = ownerOf(_tokenId);
                  return (_spender == owner ||
                      getApproved(_tokenId) == _spender ||
                      isApprovedForAll(owner, _spender));
              }
              /**
               * @dev Approve `to` to operate on `tokenId`
               *
               * Emits an {Approval} event.
               */
              function _approve(address to, uint256 tokenId) internal override {
                  _tokenApprovals[tokenId] = to;
                  emit Approval(ownerOf(tokenId), to, tokenId); // internal owner
              }
              /**
               * @dev See {IERC721-getApproved}.
               */
              function getApproved(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (address)
              {
                  address receiver = royaltyReceivers[_tokenId];
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  bool exists = (wasBatchMinted || receiver != address(0)) &&
                      !tokensBurned[_tokenId];
                  require(exists, "ERC721: approved query for nonexistent token");
                  return _tokenApprovals[_tokenId];
              }
              function _transfer(
                  address _from,
                  address _to,
                  uint256 _tokenId
              ) internal virtual override {
                  require(_tokenId != 0);
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  if (
                      wasBatchMinted &&
                      !ERC721Upgradeable._exists(_tokenId) &&
                      !tokensBurned[_tokenId]
                  ) {
                      _mint(_from, _tokenId);
                  }
                  ERC721Upgradeable._transfer(_from, _to, _tokenId);
              }
              function totalSupply() public view virtual override returns (uint256) {
                  return tokenIdCounter.current();
              }
              function _batchMintInfo(uint256 _tokenId)
                  internal
                  view
                  returns (
                      bool _wasBatchMinted,
                      uint256 _batchIndex,
                      string memory _baseTokenUri
                  )
              {
                  for (uint256 i = 0; i < mintBatches.length; i++) {
                      if (
                          _tokenId >= mintBatches[i].startTokenId &&
                          _tokenId <= mintBatches[i].endTokenId
                      ) {
                          return (true, i, mintBatches[i].baseURI);
                      }
                  }
                  return (false, 0, "");
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../utils/ContextUpgradeable.sol";
          import "./IERC721Upgradeable.sol";
          import "./IERC721MetadataUpgradeable.sol";
          import "./IERC721EnumerableUpgradeable.sol";
          import "./IERC721ReceiverUpgradeable.sol";
          import "../../introspection/ERC165Upgradeable.sol";
          import "../../math/SafeMathUpgradeable.sol";
          import "../../utils/AddressUpgradeable.sol";
          import "../../utils/EnumerableSetUpgradeable.sol";
          import "../../utils/EnumerableMapUpgradeable.sol";
          import "../../utils/StringsUpgradeable.sol";
          import "../../proxy/Initializable.sol";
          /**
           * @title ERC721 Non-Fungible Token Standard basic implementation
           * @dev see https://eips.ethereum.org/EIPS/eip-721
           */
          contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable, IERC721EnumerableUpgradeable {
              using SafeMathUpgradeable for uint256;
              using AddressUpgradeable for address;
              using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet;
              using EnumerableMapUpgradeable for EnumerableMapUpgradeable.UintToAddressMap;
              using StringsUpgradeable for uint256;
              // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
              // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
              bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
              // Mapping from holder address to their (enumerable) set of owned tokens
              mapping (address => EnumerableSetUpgradeable.UintSet) private _holderTokens;
              // Enumerable mapping from token ids to their owners
              EnumerableMapUpgradeable.UintToAddressMap private _tokenOwners;
              // Mapping from token ID to approved address
              mapping (uint256 => address) private _tokenApprovals;
              // Mapping from owner to operator approvals
              mapping (address => mapping (address => bool)) private _operatorApprovals;
              // Token name
              string private _name;
              // Token symbol
              string private _symbol;
              // Optional mapping for token URIs
              mapping (uint256 => string) private _tokenURIs;
              // Base URI
              string private _baseURI;
              /*
               *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
               *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
               *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
               *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
               *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
               *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
               *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
               *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
               *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
               *
               *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
               *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
               */
              bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
              /*
               *     bytes4(keccak256('name()')) == 0x06fdde03
               *     bytes4(keccak256('symbol()')) == 0x95d89b41
               *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
               *
               *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
               */
              bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
              /*
               *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
               *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
               *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
               *
               *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
               */
              bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
              /**
               * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
               */
              function __ERC721_init(string memory name_, string memory symbol_) internal initializer {
                  __Context_init_unchained();
                  __ERC165_init_unchained();
                  __ERC721_init_unchained(name_, symbol_);
              }
              function __ERC721_init_unchained(string memory name_, string memory symbol_) internal initializer {
                  _name = name_;
                  _symbol = symbol_;
                  // register the supported interfaces to conform to ERC721 via ERC165
                  _registerInterface(_INTERFACE_ID_ERC721);
                  _registerInterface(_INTERFACE_ID_ERC721_METADATA);
                  _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
              }
              /**
               * @dev See {IERC721-balanceOf}.
               */
              function balanceOf(address owner) public view virtual override returns (uint256) {
                  require(owner != address(0), "ERC721: balance query for the zero address");
                  return _holderTokens[owner].length();
              }
              /**
               * @dev See {IERC721-ownerOf}.
               */
              function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                  return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
              }
              /**
               * @dev See {IERC721Metadata-name}.
               */
              function name() public view virtual override returns (string memory) {
                  return _name;
              }
              /**
               * @dev See {IERC721Metadata-symbol}.
               */
              function symbol() public view virtual override returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev See {IERC721Metadata-tokenURI}.
               */
              function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                  require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
                  string memory _tokenURI = _tokenURIs[tokenId];
                  string memory base = baseURI();
                  // If there is no base URI, return the token URI.
                  if (bytes(base).length == 0) {
                      return _tokenURI;
                  }
                  // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
                  if (bytes(_tokenURI).length > 0) {
                      return string(abi.encodePacked(base, _tokenURI));
                  }
                  // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
                  return string(abi.encodePacked(base, tokenId.toString()));
              }
              /**
              * @dev Returns the base URI set via {_setBaseURI}. This will be
              * automatically added as a prefix in {tokenURI} to each token's URI, or
              * to the token ID if no specific URI is set for that token ID.
              */
              function baseURI() public view virtual returns (string memory) {
                  return _baseURI;
              }
              /**
               * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
               */
              function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
                  return _holderTokens[owner].at(index);
              }
              /**
               * @dev See {IERC721Enumerable-totalSupply}.
               */
              function totalSupply() public view virtual override returns (uint256) {
                  // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
                  return _tokenOwners.length();
              }
              /**
               * @dev See {IERC721Enumerable-tokenByIndex}.
               */
              function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
                  (uint256 tokenId, ) = _tokenOwners.at(index);
                  return tokenId;
              }
              /**
               * @dev See {IERC721-approve}.
               */
              function approve(address to, uint256 tokenId) public virtual override {
                  address owner = ERC721Upgradeable.ownerOf(tokenId);
                  require(to != owner, "ERC721: approval to current owner");
                  require(_msgSender() == owner || ERC721Upgradeable.isApprovedForAll(owner, _msgSender()),
                      "ERC721: approve caller is not owner nor approved for all"
                  );
                  _approve(to, tokenId);
              }
              /**
               * @dev See {IERC721-getApproved}.
               */
              function getApproved(uint256 tokenId) public view virtual override returns (address) {
                  require(_exists(tokenId), "ERC721: approved query for nonexistent token");
                  return _tokenApprovals[tokenId];
              }
              /**
               * @dev See {IERC721-setApprovalForAll}.
               */
              function setApprovalForAll(address operator, bool approved) public virtual override {
                  require(operator != _msgSender(), "ERC721: approve to caller");
                  _operatorApprovals[_msgSender()][operator] = approved;
                  emit ApprovalForAll(_msgSender(), operator, approved);
              }
              /**
               * @dev See {IERC721-isApprovedForAll}.
               */
              function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                  return _operatorApprovals[owner][operator];
              }
              /**
               * @dev See {IERC721-transferFrom}.
               */
              function transferFrom(address from, address to, uint256 tokenId) public virtual override {
                  //solhint-disable-next-line max-line-length
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                  _transfer(from, to, tokenId);
              }
              /**
               * @dev See {IERC721-safeTransferFrom}.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
                  safeTransferFrom(from, to, tokenId, "");
              }
              /**
               * @dev See {IERC721-safeTransferFrom}.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                  _safeTransfer(from, to, tokenId, _data);
              }
              /**
               * @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.
               *
               * `_data` is additional data, it has no specified format and it is sent in call to `to`.
               *
               * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
               * implement alternative mechanisms to perform token transfer, such as signature-based.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must exist and be owned by `from`.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
                  _transfer(from, to, tokenId);
                  require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
              }
              /**
               * @dev Returns whether `tokenId` exists.
               *
               * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
               *
               * Tokens start existing when they are minted (`_mint`),
               * and stop existing when they are burned (`_burn`).
               */
              function _exists(uint256 tokenId) internal view virtual returns (bool) {
                  return _tokenOwners.contains(tokenId);
              }
              /**
               * @dev Returns whether `spender` is allowed to manage `tokenId`.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
                  require(_exists(tokenId), "ERC721: operator query for nonexistent token");
                  address owner = ERC721Upgradeable.ownerOf(tokenId);
                  return (spender == owner || getApproved(tokenId) == spender || ERC721Upgradeable.isApprovedForAll(owner, spender));
              }
              /**
               * @dev Safely mints `tokenId` and transfers it to `to`.
               *
               * Requirements:
               d*
               * - `tokenId` must not exist.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function _safeMint(address to, uint256 tokenId) internal virtual {
                  _safeMint(to, tokenId, "");
              }
              /**
               * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
               * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
               */
              function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
                  _mint(to, tokenId);
                  require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
              }
              /**
               * @dev Mints `tokenId` and transfers it to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
               *
               * Requirements:
               *
               * - `tokenId` must not exist.
               * - `to` cannot be the zero address.
               *
               * Emits a {Transfer} event.
               */
              function _mint(address to, uint256 tokenId) internal virtual {
                  require(to != address(0), "ERC721: mint to the zero address");
                  require(!_exists(tokenId), "ERC721: token already minted");
                  _beforeTokenTransfer(address(0), to, tokenId);
                  _holderTokens[to].add(tokenId);
                  _tokenOwners.set(tokenId, to);
                  emit Transfer(address(0), to, tokenId);
              }
              /**
               * @dev Destroys `tokenId`.
               * The approval is cleared when the token is burned.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               *
               * Emits a {Transfer} event.
               */
              function _burn(uint256 tokenId) internal virtual {
                  address owner = ERC721Upgradeable.ownerOf(tokenId); // internal owner
                  _beforeTokenTransfer(owner, address(0), tokenId);
                  // Clear approvals
                  _approve(address(0), tokenId);
                  // Clear metadata (if any)
                  if (bytes(_tokenURIs[tokenId]).length != 0) {
                      delete _tokenURIs[tokenId];
                  }
                  _holderTokens[owner].remove(tokenId);
                  _tokenOwners.remove(tokenId);
                  emit Transfer(owner, address(0), tokenId);
              }
              /**
               * @dev Transfers `tokenId` from `from` to `to`.
               *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               *
               * Emits a {Transfer} event.
               */
              function _transfer(address from, address to, uint256 tokenId) internal virtual {
                  require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
                  require(to != address(0), "ERC721: transfer to the zero address");
                  _beforeTokenTransfer(from, to, tokenId);
                  // Clear approvals from the previous owner
                  _approve(address(0), tokenId);
                  _holderTokens[from].remove(tokenId);
                  _holderTokens[to].add(tokenId);
                  _tokenOwners.set(tokenId, to);
                  emit Transfer(from, to, tokenId);
              }
              /**
               * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
                  require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
                  _tokenURIs[tokenId] = _tokenURI;
              }
              /**
               * @dev Internal function to set the base URI for all token IDs. It is
               * automatically added as a prefix to the value returned in {tokenURI},
               * or to the token ID if {tokenURI} is empty.
               */
              function _setBaseURI(string memory baseURI_) internal virtual {
                  _baseURI = baseURI_;
              }
              /**
               * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
               * The call is not executed if the target address is not a contract.
               *
               * @param from address representing the previous owner of the given token ID
               * @param to target address that will receive the tokens
               * @param tokenId uint256 ID of the token to be transferred
               * @param _data bytes optional data to send along with the call
               * @return bool whether the call correctly returned the expected magic value
               */
              function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
                  private returns (bool)
              {
                  if (!to.isContract()) {
                      return true;
                  }
                  bytes memory returndata = to.functionCall(abi.encodeWithSelector(
                      IERC721ReceiverUpgradeable(to).onERC721Received.selector,
                      _msgSender(),
                      from,
                      tokenId,
                      _data
                  ), "ERC721: transfer to non ERC721Receiver implementer");
                  bytes4 retval = abi.decode(returndata, (bytes4));
                  return (retval == _ERC721_RECEIVED);
              }
              /**
               * @dev Approve `to` to operate on `tokenId`
               *
               * Emits an {Approval} event.
               */
              function _approve(address to, uint256 tokenId) internal virtual {
                  _tokenApprovals[tokenId] = to;
                  emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); // internal owner
              }
              /**
               * @dev Hook that is called before any token transfer. This includes minting
               * and burning.
               *
               * Calling conditions:
               *
               * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
               * transferred to `to`.
               * - When `from` is zero, `tokenId` will be minted for `to`.
               * - When `to` is zero, ``from``'s `tokenId` will be burned.
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               *
               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
               */
              function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
              uint256[41] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../utils/ContextUpgradeable.sol";
          import "./ERC721Upgradeable.sol";
          import "../../proxy/Initializable.sol";
          /**
           * @title ERC721 Burnable Token
           * @dev ERC721 Token that can be irreversibly burned (destroyed).
           */
          abstract contract ERC721BurnableUpgradeable is Initializable, ContextUpgradeable, ERC721Upgradeable {
              function __ERC721Burnable_init() internal initializer {
                  __Context_init_unchained();
                  __ERC165_init_unchained();
                  __ERC721Burnable_init_unchained();
              }
              function __ERC721Burnable_init_unchained() internal initializer {
              }
              /**
               * @dev Burns `tokenId`. See {ERC721-_burn}.
               *
               * Requirements:
               *
               * - The caller must own `tokenId` or be an approved operator.
               */
              function burn(uint256 tokenId) public virtual {
                  //solhint-disable-next-line max-line-length
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
                  _burn(tokenId);
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC165Upgradeable.sol";
          import "../proxy/Initializable.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
              function __ERC165_init() internal initializer {
                  __ERC165_init_unchained();
              }
              function __ERC165_init_unchained() internal initializer {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal virtual {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../utils/ContextUpgradeable.sol";
          import "../proxy/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal initializer {
                  __Context_init_unchained();
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal initializer {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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 {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = 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");
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../math/SafeMathUpgradeable.sol";
          /**
           * @title Counters
           * @author Matt Condon (@shrugs)
           * @dev Provides counters that can only be incremented or decremented by one. 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;`
           * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
           * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
           * directly accessed.
           */
          library CountersUpgradeable {
              using SafeMathUpgradeable for uint256;
              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 {
                  // The {SafeMath} overflow check can be skipped here, see the comment at the top
                  counter._value += 1;
              }
              function decrement(Counter storage counter) internal {
                  counter._value = counter._value.sub(1);
              }
          }
          // contracts/token/ERC721/IERC721Creator.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /**
           * @title IERC721 Non-Fungible Token Creator basic interface
           */
          abstract contract IERC721Creator {
              /**
               * @dev Gets the creator of the token
               * @param _tokenId uint256 ID of the token
               * @return address of the creator
               */
              function tokenCreator(uint256 _tokenId)
                  public
                  view
                  virtual
                  returns (address payable);
              function calcIERC721CreatorInterfaceId() public pure returns (bytes4) {
                  return this.tokenCreator.selector;
              }
          }
          // contracts/royalty/ERC2981.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-upgradeable-0.7.2/introspection/ERC165Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/math/SafeMathUpgradeable.sol";
          import "./IERC2981.sol";
          abstract contract ERC2981Upgradeable is IERC2981, ERC165Upgradeable {
              using SafeMathUpgradeable for uint256;
              // bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
              bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
              address public defaultRoyaltyReceiver;
              mapping(uint256 => address) royaltyReceivers;
              mapping(uint256 => uint256) royaltyPercentages;
              constructor() {}
              function __ERC2981__init() internal initializer {
                  __ERC165_init();
                  _registerInterface(_INTERFACE_ID_ERC2981);
              }
              function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
                  public
                  view
                  virtual
                  override
                  returns (address receiver, uint256 royaltyAmount)
              {
                  receiver = royaltyReceivers[_tokenId] != address(0)
                      ? royaltyReceivers[_tokenId]
                      : defaultRoyaltyReceiver;
                  royaltyAmount = _salePrice.mul(royaltyPercentages[_tokenId]).div(100);
              }
              function _setDefaultRoyaltyReceiver(address _receiver) internal {
                  defaultRoyaltyReceiver = _receiver;
              }
              function _setRoyaltyReceiver(uint256 _tokenId, address _newReceiver)
                  internal
              {
                  royaltyReceivers[_tokenId] = _newReceiver;
              }
              function _setRoyaltyPercentage(uint256 _tokenId, uint256 _percentage)
                  internal
              {
                  royaltyPercentages[_tokenId] = _percentage;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "../proxy/Initializable.sol";
          /*
           * @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 GSN 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 ContextUpgradeable is Initializable {
              function __Context_init() internal initializer {
                  __Context_init_unchained();
              }
              function __Context_init_unchained() internal initializer {
              }
              function _msgSender() internal view virtual returns (address payable) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../introspection/IERC165Upgradeable.sol";
          /**
           * @dev Required interface of an ERC721 compliant contract.
           */
          interface IERC721Upgradeable is IERC165Upgradeable {
              /**
               * @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`, 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 be have been allowed to move this token by either {approve} or {setApprovalForAll}.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Transfers `tokenId` token from `from` to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Gives permission to `to` to transfer `tokenId` token to another account.
               * The approval is cleared when the token is transferred.
               *
               * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
               *
               * Requirements:
               *
               * - The caller must own the token or be an approved operator.
               * - `tokenId` must exist.
               *
               * Emits an {Approval} event.
               */
              function approve(address to, uint256 tokenId) external;
              /**
               * @dev Returns the account approved for `tokenId` token.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function getApproved(uint256 tokenId) external view returns (address operator);
              /**
               * @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 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);
              /**
                * @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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC721Upgradeable.sol";
          /**
           * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
           * @dev See https://eips.ethereum.org/EIPS/eip-721
           */
          interface IERC721MetadataUpgradeable is IERC721Upgradeable {
              /**
               * @dev Returns the token collection name.
               */
              function name() external view returns (string memory);
              /**
               * @dev Returns the token collection symbol.
               */
              function symbol() external view returns (string memory);
              /**
               * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
               */
              function tokenURI(uint256 tokenId) external view returns (string memory);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC721Upgradeable.sol";
          /**
           * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
           * @dev See https://eips.ethereum.org/EIPS/eip-721
           */
          interface IERC721EnumerableUpgradeable is IERC721Upgradeable {
              /**
               * @dev Returns the total amount of tokens stored by the contract.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
               * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
               */
              function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
              /**
               * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
               * Use along with {totalSupply} to enumerate all tokens.
               */
              function tokenByIndex(uint256 index) external view returns (uint256);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @title ERC721 token receiver interface
           * @dev Interface for any contract that wants to support safeTransfers
           * from ERC721 asset contracts.
           */
          interface IERC721ReceiverUpgradeable {
              /**
               * @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 `IERC721.onERC721Received.selector`.
               */
              function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Wrappers over Solidity's arithmetic operations with added overflow
           * checks.
           *
           * Arithmetic operations in Solidity wrap on overflow. This can easily result
           * in bugs, because programmers usually assume that an overflow raises an
           * error, which is the standard behavior in high level programming languages.
           * `SafeMath` restores this intuition by reverting the transaction when an
           * operation overflows.
           *
           * Using this library instead of the unchecked operations eliminates an entire
           * class of bugs, so it's recommended to use it always.
           */
          library SafeMathUpgradeable {
              /**
               * @dev Returns the addition of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the substraction of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the division of two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
              /**
               * @dev Returns the addition of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `+` operator.
               *
               * Requirements:
               *
               * - Addition cannot overflow.
               */
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  require(c >= a, "SafeMath: addition overflow");
                  return c;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting on
               * overflow (when the result is negative).
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b <= a, "SafeMath: subtraction overflow");
                  return a - b;
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `*` operator.
               *
               * Requirements:
               *
               * - Multiplication cannot overflow.
               */
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) return 0;
                  uint256 c = a * b;
                  require(c / a == b, "SafeMath: multiplication overflow");
                  return c;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting on
               * division by zero. The result is rounded towards zero.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: division by zero");
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting when dividing by zero.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: modulo by zero");
                  return a % b;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
               * overflow (when the result is negative).
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {trySub}.
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b <= a, errorMessage);
                  return a - b;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting with custom message on
               * division by zero. The result is rounded towards zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryDiv}.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting with custom message when dividing by zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryMod}.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a % b;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.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.
           */
          library EnumerableSetUpgradeable {
              // 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;
                      // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                      // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                      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] = toDeleteIndex + 1; // All indexes are 1-based
                      // 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) {
                  require(set._values.length > index, "EnumerableSet: index out of bounds");
                  return set._values[index];
              }
              // 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);
              }
              // 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))));
              }
              // 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 on 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));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Library for managing an enumerable variant of Solidity's
           * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
           * type.
           *
           * Maps have the following properties:
           *
           * - Entries are added, removed, and checked for existence in constant time
           * (O(1)).
           * - Entries are enumerated in O(n). No guarantees are made on the ordering.
           *
           * ```
           * contract Example {
           *     // Add the library methods
           *     using EnumerableMap for EnumerableMap.UintToAddressMap;
           *
           *     // Declare a set state variable
           *     EnumerableMap.UintToAddressMap private myMap;
           * }
           * ```
           *
           * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
           * supported.
           */
          library EnumerableMapUpgradeable {
              // To implement this library for multiple types with as little code
              // repetition as possible, we write it in terms of a generic Map type with
              // bytes32 keys and values.
              // The Map implementation uses private functions, and user-facing
              // implementations (such as Uint256ToAddressMap) are just wrappers around
              // the underlying Map.
              // This means that we can only create new EnumerableMaps for types that fit
              // in bytes32.
              struct MapEntry {
                  bytes32 _key;
                  bytes32 _value;
              }
              struct Map {
                  // Storage of map keys and values
                  MapEntry[] _entries;
                  // Position of the entry defined by a key in the `entries` array, plus 1
                  // because index 0 means a key is not in the map.
                  mapping (bytes32 => uint256) _indexes;
              }
              /**
               * @dev Adds a key-value pair to a map, or updates the value for an existing
               * key. O(1).
               *
               * Returns true if the key was added to the map, that is if it was not
               * already present.
               */
              function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
                  // We read and store the key's index to prevent multiple reads from the same storage slot
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex == 0) { // Equivalent to !contains(map, key)
                      map._entries.push(MapEntry({ _key: key, _value: value }));
                      // The entry is stored at length-1, but we add 1 to all indexes
                      // and use 0 as a sentinel value
                      map._indexes[key] = map._entries.length;
                      return true;
                  } else {
                      map._entries[keyIndex - 1]._value = value;
                      return false;
                  }
              }
              /**
               * @dev Removes a key-value pair from a map. O(1).
               *
               * Returns true if the key was removed from the map, that is if it was present.
               */
              function _remove(Map storage map, bytes32 key) private returns (bool) {
                  // We read and store the key's index to prevent multiple reads from the same storage slot
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex != 0) { // Equivalent to contains(map, key)
                      // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
                      // in the array, and then remove the last entry (sometimes called as 'swap and pop').
                      // This modifies the order of the array, as noted in {at}.
                      uint256 toDeleteIndex = keyIndex - 1;
                      uint256 lastIndex = map._entries.length - 1;
                      // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
                      // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                      MapEntry storage lastEntry = map._entries[lastIndex];
                      // Move the last entry to the index where the entry to delete is
                      map._entries[toDeleteIndex] = lastEntry;
                      // Update the index for the moved entry
                      map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
                      // Delete the slot where the moved entry was stored
                      map._entries.pop();
                      // Delete the index for the deleted slot
                      delete map._indexes[key];
                      return true;
                  } else {
                      return false;
                  }
              }
              /**
               * @dev Returns true if the key is in the map. O(1).
               */
              function _contains(Map storage map, bytes32 key) private view returns (bool) {
                  return map._indexes[key] != 0;
              }
              /**
               * @dev Returns the number of key-value pairs in the map. O(1).
               */
              function _length(Map storage map) private view returns (uint256) {
                  return map._entries.length;
              }
             /**
              * @dev Returns the key-value pair stored at position `index` in the map. O(1).
              *
              * Note that there are no guarantees on the ordering of entries inside the
              * array, and it may change when more entries are added or removed.
              *
              * Requirements:
              *
              * - `index` must be strictly less than {length}.
              */
              function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
                  require(map._entries.length > index, "EnumerableMap: index out of bounds");
                  MapEntry storage entry = map._entries[index];
                  return (entry._key, entry._value);
              }
              /**
               * @dev Tries to returns the value associated with `key`.  O(1).
               * Does not revert if `key` is not in the map.
               */
              function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
                  return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
              }
              /**
               * @dev Returns the value associated with `key`.  O(1).
               *
               * Requirements:
               *
               * - `key` must be in the map.
               */
              function _get(Map storage map, bytes32 key) private view returns (bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
                  return map._entries[keyIndex - 1]._value; // All indexes are 1-based
              }
              /**
               * @dev Same as {_get}, with a custom error message when `key` is not in the map.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {_tryGet}.
               */
              function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
                  return map._entries[keyIndex - 1]._value; // All indexes are 1-based
              }
              // UintToAddressMap
              struct UintToAddressMap {
                  Map _inner;
              }
              /**
               * @dev Adds a key-value pair to a map, or updates the value for an existing
               * key. O(1).
               *
               * Returns true if the key was added to the map, that is if it was not
               * already present.
               */
              function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
                  return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
              }
              /**
               * @dev Removes a value from a set. O(1).
               *
               * Returns true if the key was removed from the map, that is if it was present.
               */
              function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
                  return _remove(map._inner, bytes32(key));
              }
              /**
               * @dev Returns true if the key is in the map. O(1).
               */
              function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
                  return _contains(map._inner, bytes32(key));
              }
              /**
               * @dev Returns the number of elements in the map. O(1).
               */
              function length(UintToAddressMap storage map) internal view returns (uint256) {
                  return _length(map._inner);
              }
             /**
              * @dev Returns the element 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
                  (bytes32 key, bytes32 value) = _at(map._inner, index);
                  return (uint256(key), address(uint160(uint256(value))));
              }
              /**
               * @dev Tries to returns the value associated with `key`.  O(1).
               * Does not revert if `key` is not in the map.
               *
               * _Available since v3.4._
               */
              function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
                  (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
                  return (success, address(uint160(uint256(value))));
              }
              /**
               * @dev Returns the value associated with `key`.  O(1).
               *
               * Requirements:
               *
               * - `key` must be in the map.
               */
              function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
                  return address(uint160(uint256(_get(map._inner, bytes32(key)))));
              }
              /**
               * @dev Same as {get}, with a custom error message when `key` is not in the map.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryGet}.
               */
              function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
                  return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev String operations.
           */
          library StringsUpgradeable {
              /**
               * @dev Converts a `uint256` to its ASCII `string` representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  uint256 index = digits - 1;
                  temp = value;
                  while (temp != 0) {
                      buffer[index--] = bytes1(uint8(48 + temp % 10));
                      temp /= 10;
                  }
                  return string(buffer);
              }
          }
          // SPDX-License-Identifier: MIT
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.4.24 <0.8.0;
          import "../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               */
              bool private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Modifier to protect an initializer function from being invoked twice.
               */
              modifier initializer() {
                  require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
                  bool isTopLevelCall = !_initializing;
                  if (isTopLevelCall) {
                      _initializing = true;
                      _initialized = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                  }
              }
              /// @dev Returns true if and only if the function is running in the constructor
              function _isConstructor() private view returns (bool) {
                  return !AddressUpgradeable.isContract(address(this));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.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 IERC165Upgradeable {
              /**
               * @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);
          }
          // contracts/royalty/IERC2981.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @dev Interface for the NFT Royalty Standard
          interface IERC2981 {
              /// ERC165 bytes to add to interface array - set in parent contract
              /// implementing this standard
              ///
              /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
              /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
              /// _registerInterface(_INTERFACE_ID_ERC2981);
              /// @notice Called with the sale price to determine how much royalty
              //          is owed and to whom.
              /// @param _tokenId - the NFT asset queried for royalty information
              /// @param _salePrice - the sale price of the NFT asset specified by _tokenId
              /// @return receiver - address of who should be sent the royalty payment
              /// @return royaltyAmount - the royalty payment amount for _salePrice
              function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
                  external
                  view
                  returns (address receiver, uint256 royaltyAmount);
          }
          

          File 5 of 6: SovereignNFT
          // contracts/token/ERC721/sovereign/SovereignNFT.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          pragma experimental ABIEncoderV2;
          import "@openzeppelin/contracts-upgradeable-0.7.2/token/ERC721/ERC721Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/token/ERC721/ERC721BurnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/introspection/ERC165Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/access/OwnableUpgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/utils/CountersUpgradeable.sol";
          import "../IERC721Creator.sol";
          import "../../../royalty/ERC2981Upgradeable.sol";
          contract SovereignNFT is
              OwnableUpgradeable,
              ERC165Upgradeable,
              ERC721Upgradeable,
              IERC721Creator,
              ERC721BurnableUpgradeable,
              ERC2981Upgradeable
          {
              using SafeMathUpgradeable for uint256;
              using StringsUpgradeable for uint256;
              using CountersUpgradeable for CountersUpgradeable.Counter;
              struct MintBatch {
                  uint256 startTokenId;
                  uint256 endTokenId;
                  string baseURI;
              }
              bool public disabled;
              // Mapping from token ID to the creator's address
              mapping(uint256 => address) private tokenCreators;
              // Mapping from tokenId to if it was burned or not (for batch minting)
              mapping(uint256 => bool) private tokensBurned;
              // Mapping from token ID to approved address
              mapping(uint256 => address) private _tokenApprovals;
              // Counter to keep track of the current token id.
              CountersUpgradeable.Counter private tokenIdCounter;
              MintBatch[] private mintBatches;
              // Default royalty percentage
              uint256 public defaultRoyaltyPercentage;
              event ContractDisabled(address indexed user);
              event ConsecutiveTransfer(
                  uint256 indexed fromTokenId,
                  uint256 toTokenId,
                  address indexed fromAddress,
                  address indexed toAddress
              );
              function init(
                  string calldata _name,
                  string calldata _symbol,
                  address _creator
              ) public initializer {
                  require(_creator != address(0));
                  defaultRoyaltyPercentage = 10;
                  disabled = false;
                  __Ownable_init();
                  __ERC721_init(_name, _symbol);
                  __ERC165_init();
                  __ERC2981__init();
                  _setDefaultRoyaltyReceiver(_creator);
                  _registerInterface(calcIERC721CreatorInterfaceId());
                  super.transferOwnership(_creator);
              }
              modifier onlyTokenOwner(uint256 _tokenId) {
                  require(ownerOf(_tokenId) == msg.sender, "Must be owner of token.");
                  _;
              }
              modifier ifNotDisabled() {
                  require(!disabled, "Contract must not be disabled.");
                  _;
              }
              function batchMint(string calldata _baseURI, uint256 _numberOfTokens)
                  public
                  onlyOwner
                  ifNotDisabled
              {
                  uint256 startTokenId = tokenIdCounter.current() + 1;
                  uint256 endTokenId = startTokenId + _numberOfTokens - 1;
                  tokenIdCounter = CountersUpgradeable.Counter(endTokenId);
                  mintBatches.push(MintBatch(startTokenId, endTokenId, _baseURI));
                  emit ConsecutiveTransfer(startTokenId, endTokenId, address(0), owner());
              }
              function addNewToken(string memory _uri) public onlyOwner ifNotDisabled {
                  _createToken(
                      _uri,
                      msg.sender,
                      msg.sender,
                      defaultRoyaltyPercentage,
                      msg.sender
                  );
              }
              function mintTo(
                  string calldata _uri,
                  address _receiver,
                  address _royaltyReceiver
              ) external onlyOwner ifNotDisabled {
                  _createToken(
                      _uri,
                      msg.sender,
                      _receiver,
                      defaultRoyaltyPercentage,
                      _royaltyReceiver
                  );
              }
              function renounceOwnership() public view override onlyOwner {
                  revert("unsupported");
              }
              function transferOwnership(address) public view override onlyOwner {
                  revert("unsupported");
              }
              function deleteToken(uint256 _tokenId) public onlyTokenOwner(_tokenId) {
                  burn(_tokenId);
              }
              function burn(uint256 _tokenId) public virtual override {
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  tokensBurned[_tokenId] = true;
                  if (wasBatchMinted && !ERC721Upgradeable._exists(_tokenId)) {
                      return;
                  }
                  ERC721BurnableUpgradeable.burn(_tokenId);
              }
              function tokenCreator(uint256)
                  public
                  view
                  override
                  returns (address payable)
              {
                  return payable(owner());
              }
              function disableContract() public onlyOwner {
                  disabled = true;
                  emit ContractDisabled(msg.sender);
              }
              function setDefaultRoyaltyReceiver(address _receiver) external onlyOwner {
                  _setDefaultRoyaltyReceiver(_receiver);
              }
              function setRoyaltyReceiverForToken(address _receiver, uint256 _tokenId)
                  external
                  onlyOwner
              {
                  royaltyReceivers[_tokenId] = _receiver;
              }
              function _setTokenCreator(uint256 _tokenId, address _creator) internal {
                  tokenCreators[_tokenId] = _creator;
              }
              function _createToken(
                  string memory _uri,
                  address _creator,
                  address _to,
                  uint256 _royaltyPercentage,
                  address _royaltyReceiver
              ) internal returns (uint256) {
                  tokenIdCounter.increment();
                  uint256 tokenId = tokenIdCounter.current();
                  _safeMint(_to, tokenId);
                  _setTokenURI(tokenId, _uri);
                  _setTokenCreator(tokenId, _creator);
                  _setRoyaltyPercentage(tokenId, _royaltyPercentage);
                  _setRoyaltyReceiver(tokenId, _royaltyReceiver);
                  return tokenId;
              }
              ///////////////////////////////////////////////
              // Overriding Methods to support batch mints
              ///////////////////////////////////////////////
              function tokenURI(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (string memory)
              {
                  (bool wasBatchMinted, , string memory baseTokenUri) = _batchMintInfo(
                      _tokenId
                  );
                  if (!wasBatchMinted) {
                      return super.tokenURI(_tokenId);
                  } else {
                      return
                          string(
                              abi.encodePacked(
                                  baseTokenUri,
                                  "/",
                                  _tokenId.toString(),
                                  ".json"
                              )
                          );
                  }
              }
              function ownerOf(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (address)
              {
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  if (!wasBatchMinted) {
                      return ERC721Upgradeable.ownerOf(_tokenId);
                  } else if (tokensBurned[_tokenId]) {
                      return ERC721Upgradeable.ownerOf(_tokenId);
                  } else {
                      if (!ERC721Upgradeable._exists(_tokenId)) {
                          return owner();
                      } else {
                          return ERC721Upgradeable.ownerOf(_tokenId);
                      }
                  }
              }
              function approve(address to, uint256 tokenId) public virtual override {
                  address owner = ownerOf(tokenId);
                  require(to != owner, "ERC721: approval to current owner");
                  require(
                      _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                      "ERC721: approve caller is not owner nor approved for all"
                  );
                  _approve(to, tokenId);
              }
              function _isApprovedOrOwner(address _spender, uint256 _tokenId)
                  internal
                  view
                  virtual
                  override
                  returns (bool)
              {
                  address owner = ownerOf(_tokenId);
                  return (_spender == owner ||
                      getApproved(_tokenId) == _spender ||
                      isApprovedForAll(owner, _spender));
              }
              /**
               * @dev Approve `to` to operate on `tokenId`
               *
               * Emits an {Approval} event.
               */
              function _approve(address to, uint256 tokenId) internal override {
                  _tokenApprovals[tokenId] = to;
                  emit Approval(ownerOf(tokenId), to, tokenId); // internal owner
              }
              /**
               * @dev See {IERC721-getApproved}.
               */
              function getApproved(uint256 _tokenId)
                  public
                  view
                  virtual
                  override
                  returns (address)
              {
                  address receiver = royaltyReceivers[_tokenId];
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  bool exists = (wasBatchMinted || receiver != address(0)) &&
                      !tokensBurned[_tokenId];
                  require(exists, "ERC721: approved query for nonexistent token");
                  return _tokenApprovals[_tokenId];
              }
              function _transfer(
                  address _from,
                  address _to,
                  uint256 _tokenId
              ) internal virtual override {
                  require(_tokenId != 0);
                  (bool wasBatchMinted, , ) = _batchMintInfo(_tokenId);
                  if (
                      wasBatchMinted &&
                      !ERC721Upgradeable._exists(_tokenId) &&
                      !tokensBurned[_tokenId]
                  ) {
                      _mint(_from, _tokenId);
                  }
                  ERC721Upgradeable._transfer(_from, _to, _tokenId);
              }
              function totalSupply() public view virtual override returns (uint256) {
                  return tokenIdCounter.current();
              }
              function _batchMintInfo(uint256 _tokenId)
                  internal
                  view
                  returns (
                      bool _wasBatchMinted,
                      uint256 _batchIndex,
                      string memory _baseTokenUri
                  )
              {
                  for (uint256 i = 0; i < mintBatches.length; i++) {
                      if (
                          _tokenId >= mintBatches[i].startTokenId &&
                          _tokenId <= mintBatches[i].endTokenId
                      ) {
                          return (true, i, mintBatches[i].baseURI);
                      }
                  }
                  return (false, 0, "");
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../utils/ContextUpgradeable.sol";
          import "./IERC721Upgradeable.sol";
          import "./IERC721MetadataUpgradeable.sol";
          import "./IERC721EnumerableUpgradeable.sol";
          import "./IERC721ReceiverUpgradeable.sol";
          import "../../introspection/ERC165Upgradeable.sol";
          import "../../math/SafeMathUpgradeable.sol";
          import "../../utils/AddressUpgradeable.sol";
          import "../../utils/EnumerableSetUpgradeable.sol";
          import "../../utils/EnumerableMapUpgradeable.sol";
          import "../../utils/StringsUpgradeable.sol";
          import "../../proxy/Initializable.sol";
          /**
           * @title ERC721 Non-Fungible Token Standard basic implementation
           * @dev see https://eips.ethereum.org/EIPS/eip-721
           */
          contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable, IERC721EnumerableUpgradeable {
              using SafeMathUpgradeable for uint256;
              using AddressUpgradeable for address;
              using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet;
              using EnumerableMapUpgradeable for EnumerableMapUpgradeable.UintToAddressMap;
              using StringsUpgradeable for uint256;
              // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
              // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
              bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
              // Mapping from holder address to their (enumerable) set of owned tokens
              mapping (address => EnumerableSetUpgradeable.UintSet) private _holderTokens;
              // Enumerable mapping from token ids to their owners
              EnumerableMapUpgradeable.UintToAddressMap private _tokenOwners;
              // Mapping from token ID to approved address
              mapping (uint256 => address) private _tokenApprovals;
              // Mapping from owner to operator approvals
              mapping (address => mapping (address => bool)) private _operatorApprovals;
              // Token name
              string private _name;
              // Token symbol
              string private _symbol;
              // Optional mapping for token URIs
              mapping (uint256 => string) private _tokenURIs;
              // Base URI
              string private _baseURI;
              /*
               *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
               *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
               *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
               *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
               *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
               *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
               *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
               *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
               *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
               *
               *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
               *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
               */
              bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
              /*
               *     bytes4(keccak256('name()')) == 0x06fdde03
               *     bytes4(keccak256('symbol()')) == 0x95d89b41
               *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
               *
               *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
               */
              bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
              /*
               *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
               *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
               *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
               *
               *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
               */
              bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
              /**
               * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
               */
              function __ERC721_init(string memory name_, string memory symbol_) internal initializer {
                  __Context_init_unchained();
                  __ERC165_init_unchained();
                  __ERC721_init_unchained(name_, symbol_);
              }
              function __ERC721_init_unchained(string memory name_, string memory symbol_) internal initializer {
                  _name = name_;
                  _symbol = symbol_;
                  // register the supported interfaces to conform to ERC721 via ERC165
                  _registerInterface(_INTERFACE_ID_ERC721);
                  _registerInterface(_INTERFACE_ID_ERC721_METADATA);
                  _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
              }
              /**
               * @dev See {IERC721-balanceOf}.
               */
              function balanceOf(address owner) public view virtual override returns (uint256) {
                  require(owner != address(0), "ERC721: balance query for the zero address");
                  return _holderTokens[owner].length();
              }
              /**
               * @dev See {IERC721-ownerOf}.
               */
              function ownerOf(uint256 tokenId) public view virtual override returns (address) {
                  return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
              }
              /**
               * @dev See {IERC721Metadata-name}.
               */
              function name() public view virtual override returns (string memory) {
                  return _name;
              }
              /**
               * @dev See {IERC721Metadata-symbol}.
               */
              function symbol() public view virtual override returns (string memory) {
                  return _symbol;
              }
              /**
               * @dev See {IERC721Metadata-tokenURI}.
               */
              function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
                  require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
                  string memory _tokenURI = _tokenURIs[tokenId];
                  string memory base = baseURI();
                  // If there is no base URI, return the token URI.
                  if (bytes(base).length == 0) {
                      return _tokenURI;
                  }
                  // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
                  if (bytes(_tokenURI).length > 0) {
                      return string(abi.encodePacked(base, _tokenURI));
                  }
                  // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
                  return string(abi.encodePacked(base, tokenId.toString()));
              }
              /**
              * @dev Returns the base URI set via {_setBaseURI}. This will be
              * automatically added as a prefix in {tokenURI} to each token's URI, or
              * to the token ID if no specific URI is set for that token ID.
              */
              function baseURI() public view virtual returns (string memory) {
                  return _baseURI;
              }
              /**
               * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
               */
              function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
                  return _holderTokens[owner].at(index);
              }
              /**
               * @dev See {IERC721Enumerable-totalSupply}.
               */
              function totalSupply() public view virtual override returns (uint256) {
                  // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
                  return _tokenOwners.length();
              }
              /**
               * @dev See {IERC721Enumerable-tokenByIndex}.
               */
              function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
                  (uint256 tokenId, ) = _tokenOwners.at(index);
                  return tokenId;
              }
              /**
               * @dev See {IERC721-approve}.
               */
              function approve(address to, uint256 tokenId) public virtual override {
                  address owner = ERC721Upgradeable.ownerOf(tokenId);
                  require(to != owner, "ERC721: approval to current owner");
                  require(_msgSender() == owner || ERC721Upgradeable.isApprovedForAll(owner, _msgSender()),
                      "ERC721: approve caller is not owner nor approved for all"
                  );
                  _approve(to, tokenId);
              }
              /**
               * @dev See {IERC721-getApproved}.
               */
              function getApproved(uint256 tokenId) public view virtual override returns (address) {
                  require(_exists(tokenId), "ERC721: approved query for nonexistent token");
                  return _tokenApprovals[tokenId];
              }
              /**
               * @dev See {IERC721-setApprovalForAll}.
               */
              function setApprovalForAll(address operator, bool approved) public virtual override {
                  require(operator != _msgSender(), "ERC721: approve to caller");
                  _operatorApprovals[_msgSender()][operator] = approved;
                  emit ApprovalForAll(_msgSender(), operator, approved);
              }
              /**
               * @dev See {IERC721-isApprovedForAll}.
               */
              function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
                  return _operatorApprovals[owner][operator];
              }
              /**
               * @dev See {IERC721-transferFrom}.
               */
              function transferFrom(address from, address to, uint256 tokenId) public virtual override {
                  //solhint-disable-next-line max-line-length
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                  _transfer(from, to, tokenId);
              }
              /**
               * @dev See {IERC721-safeTransferFrom}.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
                  safeTransferFrom(from, to, tokenId, "");
              }
              /**
               * @dev See {IERC721-safeTransferFrom}.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
                  _safeTransfer(from, to, tokenId, _data);
              }
              /**
               * @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.
               *
               * `_data` is additional data, it has no specified format and it is sent in call to `to`.
               *
               * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
               * implement alternative mechanisms to perform token transfer, such as signature-based.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must exist and be owned by `from`.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
                  _transfer(from, to, tokenId);
                  require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
              }
              /**
               * @dev Returns whether `tokenId` exists.
               *
               * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
               *
               * Tokens start existing when they are minted (`_mint`),
               * and stop existing when they are burned (`_burn`).
               */
              function _exists(uint256 tokenId) internal view virtual returns (bool) {
                  return _tokenOwners.contains(tokenId);
              }
              /**
               * @dev Returns whether `spender` is allowed to manage `tokenId`.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
                  require(_exists(tokenId), "ERC721: operator query for nonexistent token");
                  address owner = ERC721Upgradeable.ownerOf(tokenId);
                  return (spender == owner || getApproved(tokenId) == spender || ERC721Upgradeable.isApprovedForAll(owner, spender));
              }
              /**
               * @dev Safely mints `tokenId` and transfers it to `to`.
               *
               * Requirements:
               d*
               * - `tokenId` must not exist.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function _safeMint(address to, uint256 tokenId) internal virtual {
                  _safeMint(to, tokenId, "");
              }
              /**
               * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
               * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
               */
              function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
                  _mint(to, tokenId);
                  require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
              }
              /**
               * @dev Mints `tokenId` and transfers it to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
               *
               * Requirements:
               *
               * - `tokenId` must not exist.
               * - `to` cannot be the zero address.
               *
               * Emits a {Transfer} event.
               */
              function _mint(address to, uint256 tokenId) internal virtual {
                  require(to != address(0), "ERC721: mint to the zero address");
                  require(!_exists(tokenId), "ERC721: token already minted");
                  _beforeTokenTransfer(address(0), to, tokenId);
                  _holderTokens[to].add(tokenId);
                  _tokenOwners.set(tokenId, to);
                  emit Transfer(address(0), to, tokenId);
              }
              /**
               * @dev Destroys `tokenId`.
               * The approval is cleared when the token is burned.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               *
               * Emits a {Transfer} event.
               */
              function _burn(uint256 tokenId) internal virtual {
                  address owner = ERC721Upgradeable.ownerOf(tokenId); // internal owner
                  _beforeTokenTransfer(owner, address(0), tokenId);
                  // Clear approvals
                  _approve(address(0), tokenId);
                  // Clear metadata (if any)
                  if (bytes(_tokenURIs[tokenId]).length != 0) {
                      delete _tokenURIs[tokenId];
                  }
                  _holderTokens[owner].remove(tokenId);
                  _tokenOwners.remove(tokenId);
                  emit Transfer(owner, address(0), tokenId);
              }
              /**
               * @dev Transfers `tokenId` from `from` to `to`.
               *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
               *
               * Requirements:
               *
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               *
               * Emits a {Transfer} event.
               */
              function _transfer(address from, address to, uint256 tokenId) internal virtual {
                  require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
                  require(to != address(0), "ERC721: transfer to the zero address");
                  _beforeTokenTransfer(from, to, tokenId);
                  // Clear approvals from the previous owner
                  _approve(address(0), tokenId);
                  _holderTokens[from].remove(tokenId);
                  _holderTokens[to].add(tokenId);
                  _tokenOwners.set(tokenId, to);
                  emit Transfer(from, to, tokenId);
              }
              /**
               * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
                  require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
                  _tokenURIs[tokenId] = _tokenURI;
              }
              /**
               * @dev Internal function to set the base URI for all token IDs. It is
               * automatically added as a prefix to the value returned in {tokenURI},
               * or to the token ID if {tokenURI} is empty.
               */
              function _setBaseURI(string memory baseURI_) internal virtual {
                  _baseURI = baseURI_;
              }
              /**
               * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
               * The call is not executed if the target address is not a contract.
               *
               * @param from address representing the previous owner of the given token ID
               * @param to target address that will receive the tokens
               * @param tokenId uint256 ID of the token to be transferred
               * @param _data bytes optional data to send along with the call
               * @return bool whether the call correctly returned the expected magic value
               */
              function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
                  private returns (bool)
              {
                  if (!to.isContract()) {
                      return true;
                  }
                  bytes memory returndata = to.functionCall(abi.encodeWithSelector(
                      IERC721ReceiverUpgradeable(to).onERC721Received.selector,
                      _msgSender(),
                      from,
                      tokenId,
                      _data
                  ), "ERC721: transfer to non ERC721Receiver implementer");
                  bytes4 retval = abi.decode(returndata, (bytes4));
                  return (retval == _ERC721_RECEIVED);
              }
              /**
               * @dev Approve `to` to operate on `tokenId`
               *
               * Emits an {Approval} event.
               */
              function _approve(address to, uint256 tokenId) internal virtual {
                  _tokenApprovals[tokenId] = to;
                  emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId); // internal owner
              }
              /**
               * @dev Hook that is called before any token transfer. This includes minting
               * and burning.
               *
               * Calling conditions:
               *
               * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
               * transferred to `to`.
               * - When `from` is zero, `tokenId` will be minted for `to`.
               * - When `to` is zero, ``from``'s `tokenId` will be burned.
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               *
               * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
               */
              function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { }
              uint256[41] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../utils/ContextUpgradeable.sol";
          import "./ERC721Upgradeable.sol";
          import "../../proxy/Initializable.sol";
          /**
           * @title ERC721 Burnable Token
           * @dev ERC721 Token that can be irreversibly burned (destroyed).
           */
          abstract contract ERC721BurnableUpgradeable is Initializable, ContextUpgradeable, ERC721Upgradeable {
              function __ERC721Burnable_init() internal initializer {
                  __Context_init_unchained();
                  __ERC165_init_unchained();
                  __ERC721Burnable_init_unchained();
              }
              function __ERC721Burnable_init_unchained() internal initializer {
              }
              /**
               * @dev Burns `tokenId`. See {ERC721-_burn}.
               *
               * Requirements:
               *
               * - The caller must own `tokenId` or be an approved operator.
               */
              function burn(uint256 tokenId) public virtual {
                  //solhint-disable-next-line max-line-length
                  require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
                  _burn(tokenId);
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC165Upgradeable.sol";
          import "../proxy/Initializable.sol";
          /**
           * @dev Implementation of the {IERC165} interface.
           *
           * Contracts may inherit from this and call {_registerInterface} to declare
           * their support of an interface.
           */
          abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
              /*
               * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
               */
              bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
              /**
               * @dev Mapping of interface ids to whether or not it's supported.
               */
              mapping(bytes4 => bool) private _supportedInterfaces;
              function __ERC165_init() internal initializer {
                  __ERC165_init_unchained();
              }
              function __ERC165_init_unchained() internal initializer {
                  // Derived contracts need only register support for their own interfaces,
                  // we register support for ERC165 itself here
                  _registerInterface(_INTERFACE_ID_ERC165);
              }
              /**
               * @dev See {IERC165-supportsInterface}.
               *
               * Time complexity O(1), guaranteed to always use less than 30 000 gas.
               */
              function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                  return _supportedInterfaces[interfaceId];
              }
              /**
               * @dev Registers the contract as an implementer of the interface defined by
               * `interfaceId`. Support of the actual ERC165 interface is automatic and
               * registering its interface id is not required.
               *
               * See {IERC165-supportsInterface}.
               *
               * Requirements:
               *
               * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
               */
              function _registerInterface(bytes4 interfaceId) internal virtual {
                  require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
                  _supportedInterfaces[interfaceId] = true;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../utils/ContextUpgradeable.sol";
          import "../proxy/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
              address private _owner;
              event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
              /**
               * @dev Initializes the contract setting the deployer as the initial owner.
               */
              function __Ownable_init() internal initializer {
                  __Context_init_unchained();
                  __Ownable_init_unchained();
              }
              function __Ownable_init_unchained() internal initializer {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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 {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = 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");
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
              }
              uint256[49] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../math/SafeMathUpgradeable.sol";
          /**
           * @title Counters
           * @author Matt Condon (@shrugs)
           * @dev Provides counters that can only be incremented or decremented by one. 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;`
           * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath}
           * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never
           * directly accessed.
           */
          library CountersUpgradeable {
              using SafeMathUpgradeable for uint256;
              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 {
                  // The {SafeMath} overflow check can be skipped here, see the comment at the top
                  counter._value += 1;
              }
              function decrement(Counter storage counter) internal {
                  counter._value = counter._value.sub(1);
              }
          }
          // contracts/token/ERC721/IERC721Creator.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /**
           * @title IERC721 Non-Fungible Token Creator basic interface
           */
          abstract contract IERC721Creator {
              /**
               * @dev Gets the creator of the token
               * @param _tokenId uint256 ID of the token
               * @return address of the creator
               */
              function tokenCreator(uint256 _tokenId)
                  public
                  view
                  virtual
                  returns (address payable);
              function calcIERC721CreatorInterfaceId() public pure returns (bytes4) {
                  return this.tokenCreator.selector;
              }
          }
          // contracts/royalty/ERC2981.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-upgradeable-0.7.2/introspection/ERC165Upgradeable.sol";
          import "@openzeppelin/contracts-upgradeable-0.7.2/math/SafeMathUpgradeable.sol";
          import "./IERC2981.sol";
          abstract contract ERC2981Upgradeable is IERC2981, ERC165Upgradeable {
              using SafeMathUpgradeable for uint256;
              // bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
              bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
              address public defaultRoyaltyReceiver;
              mapping(uint256 => address) royaltyReceivers;
              mapping(uint256 => uint256) royaltyPercentages;
              constructor() {}
              function __ERC2981__init() internal initializer {
                  __ERC165_init();
                  _registerInterface(_INTERFACE_ID_ERC2981);
              }
              function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
                  public
                  view
                  virtual
                  override
                  returns (address receiver, uint256 royaltyAmount)
              {
                  receiver = royaltyReceivers[_tokenId] != address(0)
                      ? royaltyReceivers[_tokenId]
                      : defaultRoyaltyReceiver;
                  royaltyAmount = _salePrice.mul(royaltyPercentages[_tokenId]).div(100);
              }
              function _setDefaultRoyaltyReceiver(address _receiver) internal {
                  defaultRoyaltyReceiver = _receiver;
              }
              function _setRoyaltyReceiver(uint256 _tokenId, address _newReceiver)
                  internal
              {
                  royaltyReceivers[_tokenId] = _newReceiver;
              }
              function _setRoyaltyPercentage(uint256 _tokenId, uint256 _percentage)
                  internal
              {
                  royaltyPercentages[_tokenId] = _percentage;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "../proxy/Initializable.sol";
          /*
           * @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 GSN 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 ContextUpgradeable is Initializable {
              function __Context_init() internal initializer {
                  __Context_init_unchained();
              }
              function __Context_init_unchained() internal initializer {
              }
              function _msgSender() internal view virtual returns (address payable) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
              uint256[50] private __gap;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "../../introspection/IERC165Upgradeable.sol";
          /**
           * @dev Required interface of an ERC721 compliant contract.
           */
          interface IERC721Upgradeable is IERC165Upgradeable {
              /**
               * @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`, 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 be have been allowed to move this token by either {approve} or {setApprovalForAll}.
               * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
               *
               * Emits a {Transfer} event.
               */
              function safeTransferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Transfers `tokenId` token from `from` to `to`.
               *
               * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
               *
               * Requirements:
               *
               * - `from` cannot be the zero address.
               * - `to` cannot be the zero address.
               * - `tokenId` token must be owned by `from`.
               * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
               *
               * Emits a {Transfer} event.
               */
              function transferFrom(address from, address to, uint256 tokenId) external;
              /**
               * @dev Gives permission to `to` to transfer `tokenId` token to another account.
               * The approval is cleared when the token is transferred.
               *
               * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
               *
               * Requirements:
               *
               * - The caller must own the token or be an approved operator.
               * - `tokenId` must exist.
               *
               * Emits an {Approval} event.
               */
              function approve(address to, uint256 tokenId) external;
              /**
               * @dev Returns the account approved for `tokenId` token.
               *
               * Requirements:
               *
               * - `tokenId` must exist.
               */
              function getApproved(uint256 tokenId) external view returns (address operator);
              /**
               * @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 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);
              /**
                * @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;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC721Upgradeable.sol";
          /**
           * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
           * @dev See https://eips.ethereum.org/EIPS/eip-721
           */
          interface IERC721MetadataUpgradeable is IERC721Upgradeable {
              /**
               * @dev Returns the token collection name.
               */
              function name() external view returns (string memory);
              /**
               * @dev Returns the token collection symbol.
               */
              function symbol() external view returns (string memory);
              /**
               * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
               */
              function tokenURI(uint256 tokenId) external view returns (string memory);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          import "./IERC721Upgradeable.sol";
          /**
           * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
           * @dev See https://eips.ethereum.org/EIPS/eip-721
           */
          interface IERC721EnumerableUpgradeable is IERC721Upgradeable {
              /**
               * @dev Returns the total amount of tokens stored by the contract.
               */
              function totalSupply() external view returns (uint256);
              /**
               * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
               * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
               */
              function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);
              /**
               * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
               * Use along with {totalSupply} to enumerate all tokens.
               */
              function tokenByIndex(uint256 index) external view returns (uint256);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @title ERC721 token receiver interface
           * @dev Interface for any contract that wants to support safeTransfers
           * from ERC721 asset contracts.
           */
          interface IERC721ReceiverUpgradeable {
              /**
               * @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 `IERC721.onERC721Received.selector`.
               */
              function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Wrappers over Solidity's arithmetic operations with added overflow
           * checks.
           *
           * Arithmetic operations in Solidity wrap on overflow. This can easily result
           * in bugs, because programmers usually assume that an overflow raises an
           * error, which is the standard behavior in high level programming languages.
           * `SafeMath` restores this intuition by reverting the transaction when an
           * operation overflows.
           *
           * Using this library instead of the unchecked operations eliminates an entire
           * class of bugs, so it's recommended to use it always.
           */
          library SafeMathUpgradeable {
              /**
               * @dev Returns the addition of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the substraction of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the division of two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
              /**
               * @dev Returns the addition of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `+` operator.
               *
               * Requirements:
               *
               * - Addition cannot overflow.
               */
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  require(c >= a, "SafeMath: addition overflow");
                  return c;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting on
               * overflow (when the result is negative).
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b <= a, "SafeMath: subtraction overflow");
                  return a - b;
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `*` operator.
               *
               * Requirements:
               *
               * - Multiplication cannot overflow.
               */
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) return 0;
                  uint256 c = a * b;
                  require(c / a == b, "SafeMath: multiplication overflow");
                  return c;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting on
               * division by zero. The result is rounded towards zero.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: division by zero");
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting when dividing by zero.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: modulo by zero");
                  return a % b;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
               * overflow (when the result is negative).
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {trySub}.
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b <= a, errorMessage);
                  return a - b;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting with custom message on
               * division by zero. The result is rounded towards zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryDiv}.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting with custom message when dividing by zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryMod}.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a % b;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Collection of functions related to the address type
           */
          library AddressUpgradeable {
              /**
               * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.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.
           */
          library EnumerableSetUpgradeable {
              // 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;
                      // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                      // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                      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] = toDeleteIndex + 1; // All indexes are 1-based
                      // 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) {
                  require(set._values.length > index, "EnumerableSet: index out of bounds");
                  return set._values[index];
              }
              // 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);
              }
              // 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))));
              }
              // 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 on 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));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev Library for managing an enumerable variant of Solidity's
           * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
           * type.
           *
           * Maps have the following properties:
           *
           * - Entries are added, removed, and checked for existence in constant time
           * (O(1)).
           * - Entries are enumerated in O(n). No guarantees are made on the ordering.
           *
           * ```
           * contract Example {
           *     // Add the library methods
           *     using EnumerableMap for EnumerableMap.UintToAddressMap;
           *
           *     // Declare a set state variable
           *     EnumerableMap.UintToAddressMap private myMap;
           * }
           * ```
           *
           * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
           * supported.
           */
          library EnumerableMapUpgradeable {
              // To implement this library for multiple types with as little code
              // repetition as possible, we write it in terms of a generic Map type with
              // bytes32 keys and values.
              // The Map implementation uses private functions, and user-facing
              // implementations (such as Uint256ToAddressMap) are just wrappers around
              // the underlying Map.
              // This means that we can only create new EnumerableMaps for types that fit
              // in bytes32.
              struct MapEntry {
                  bytes32 _key;
                  bytes32 _value;
              }
              struct Map {
                  // Storage of map keys and values
                  MapEntry[] _entries;
                  // Position of the entry defined by a key in the `entries` array, plus 1
                  // because index 0 means a key is not in the map.
                  mapping (bytes32 => uint256) _indexes;
              }
              /**
               * @dev Adds a key-value pair to a map, or updates the value for an existing
               * key. O(1).
               *
               * Returns true if the key was added to the map, that is if it was not
               * already present.
               */
              function _set(Map storage map, bytes32 key, bytes32 value) private returns (bool) {
                  // We read and store the key's index to prevent multiple reads from the same storage slot
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex == 0) { // Equivalent to !contains(map, key)
                      map._entries.push(MapEntry({ _key: key, _value: value }));
                      // The entry is stored at length-1, but we add 1 to all indexes
                      // and use 0 as a sentinel value
                      map._indexes[key] = map._entries.length;
                      return true;
                  } else {
                      map._entries[keyIndex - 1]._value = value;
                      return false;
                  }
              }
              /**
               * @dev Removes a key-value pair from a map. O(1).
               *
               * Returns true if the key was removed from the map, that is if it was present.
               */
              function _remove(Map storage map, bytes32 key) private returns (bool) {
                  // We read and store the key's index to prevent multiple reads from the same storage slot
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex != 0) { // Equivalent to contains(map, key)
                      // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
                      // in the array, and then remove the last entry (sometimes called as 'swap and pop').
                      // This modifies the order of the array, as noted in {at}.
                      uint256 toDeleteIndex = keyIndex - 1;
                      uint256 lastIndex = map._entries.length - 1;
                      // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
                      // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                      MapEntry storage lastEntry = map._entries[lastIndex];
                      // Move the last entry to the index where the entry to delete is
                      map._entries[toDeleteIndex] = lastEntry;
                      // Update the index for the moved entry
                      map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
                      // Delete the slot where the moved entry was stored
                      map._entries.pop();
                      // Delete the index for the deleted slot
                      delete map._indexes[key];
                      return true;
                  } else {
                      return false;
                  }
              }
              /**
               * @dev Returns true if the key is in the map. O(1).
               */
              function _contains(Map storage map, bytes32 key) private view returns (bool) {
                  return map._indexes[key] != 0;
              }
              /**
               * @dev Returns the number of key-value pairs in the map. O(1).
               */
              function _length(Map storage map) private view returns (uint256) {
                  return map._entries.length;
              }
             /**
              * @dev Returns the key-value pair stored at position `index` in the map. O(1).
              *
              * Note that there are no guarantees on the ordering of entries inside the
              * array, and it may change when more entries are added or removed.
              *
              * Requirements:
              *
              * - `index` must be strictly less than {length}.
              */
              function _at(Map storage map, uint256 index) private view returns (bytes32, bytes32) {
                  require(map._entries.length > index, "EnumerableMap: index out of bounds");
                  MapEntry storage entry = map._entries[index];
                  return (entry._key, entry._value);
              }
              /**
               * @dev Tries to returns the value associated with `key`.  O(1).
               * Does not revert if `key` is not in the map.
               */
              function _tryGet(Map storage map, bytes32 key) private view returns (bool, bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
                  return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
              }
              /**
               * @dev Returns the value associated with `key`.  O(1).
               *
               * Requirements:
               *
               * - `key` must be in the map.
               */
              function _get(Map storage map, bytes32 key) private view returns (bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
                  return map._entries[keyIndex - 1]._value; // All indexes are 1-based
              }
              /**
               * @dev Same as {_get}, with a custom error message when `key` is not in the map.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {_tryGet}.
               */
              function _get(Map storage map, bytes32 key, string memory errorMessage) private view returns (bytes32) {
                  uint256 keyIndex = map._indexes[key];
                  require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
                  return map._entries[keyIndex - 1]._value; // All indexes are 1-based
              }
              // UintToAddressMap
              struct UintToAddressMap {
                  Map _inner;
              }
              /**
               * @dev Adds a key-value pair to a map, or updates the value for an existing
               * key. O(1).
               *
               * Returns true if the key was added to the map, that is if it was not
               * already present.
               */
              function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
                  return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
              }
              /**
               * @dev Removes a value from a set. O(1).
               *
               * Returns true if the key was removed from the map, that is if it was present.
               */
              function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
                  return _remove(map._inner, bytes32(key));
              }
              /**
               * @dev Returns true if the key is in the map. O(1).
               */
              function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
                  return _contains(map._inner, bytes32(key));
              }
              /**
               * @dev Returns the number of elements in the map. O(1).
               */
              function length(UintToAddressMap storage map) internal view returns (uint256) {
                  return _length(map._inner);
              }
             /**
              * @dev Returns the element 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
                  (bytes32 key, bytes32 value) = _at(map._inner, index);
                  return (uint256(key), address(uint160(uint256(value))));
              }
              /**
               * @dev Tries to returns the value associated with `key`.  O(1).
               * Does not revert if `key` is not in the map.
               *
               * _Available since v3.4._
               */
              function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
                  (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
                  return (success, address(uint160(uint256(value))));
              }
              /**
               * @dev Returns the value associated with `key`.  O(1).
               *
               * Requirements:
               *
               * - `key` must be in the map.
               */
              function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
                  return address(uint160(uint256(_get(map._inner, bytes32(key)))));
              }
              /**
               * @dev Same as {get}, with a custom error message when `key` is not in the map.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryGet}.
               */
              function get(UintToAddressMap storage map, uint256 key, string memory errorMessage) internal view returns (address) {
                  return address(uint160(uint256(_get(map._inner, bytes32(key), errorMessage))));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.0;
          /**
           * @dev String operations.
           */
          library StringsUpgradeable {
              /**
               * @dev Converts a `uint256` to its ASCII `string` representation.
               */
              function toString(uint256 value) internal pure returns (string memory) {
                  // Inspired by OraclizeAPI's implementation - MIT licence
                  // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
                  if (value == 0) {
                      return "0";
                  }
                  uint256 temp = value;
                  uint256 digits;
                  while (temp != 0) {
                      digits++;
                      temp /= 10;
                  }
                  bytes memory buffer = new bytes(digits);
                  uint256 index = digits - 1;
                  temp = value;
                  while (temp != 0) {
                      buffer[index--] = bytes1(uint8(48 + temp % 10));
                      temp /= 10;
                  }
                  return string(buffer);
              }
          }
          // SPDX-License-Identifier: MIT
          // solhint-disable-next-line compiler-version
          pragma solidity >=0.4.24 <0.8.0;
          import "../utils/AddressUpgradeable.sol";
          /**
           * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
           * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
           * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
           * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
           *
           * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
           * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}.
           *
           * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
           * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
           */
          abstract contract Initializable {
              /**
               * @dev Indicates that the contract has been initialized.
               */
              bool private _initialized;
              /**
               * @dev Indicates that the contract is in the process of being initialized.
               */
              bool private _initializing;
              /**
               * @dev Modifier to protect an initializer function from being invoked twice.
               */
              modifier initializer() {
                  require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized");
                  bool isTopLevelCall = !_initializing;
                  if (isTopLevelCall) {
                      _initializing = true;
                      _initialized = true;
                  }
                  _;
                  if (isTopLevelCall) {
                      _initializing = false;
                  }
              }
              /// @dev Returns true if and only if the function is running in the constructor
              function _isConstructor() private view returns (bool) {
                  return !AddressUpgradeable.isContract(address(this));
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity ^0.7.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 IERC165Upgradeable {
              /**
               * @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);
          }
          // contracts/royalty/IERC2981.sol
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @dev Interface for the NFT Royalty Standard
          interface IERC2981 {
              /// ERC165 bytes to add to interface array - set in parent contract
              /// implementing this standard
              ///
              /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
              /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
              /// _registerInterface(_INTERFACE_ID_ERC2981);
              /// @notice Called with the sale price to determine how much royalty
              //          is owed and to whom.
              /// @param _tokenId - the NFT asset queried for royalty information
              /// @param _salePrice - the sale price of the NFT asset specified by _tokenId
              /// @return receiver - address of who should be sent the royalty payment
              /// @return royaltyAmount - the royalty payment amount for _salePrice
              function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
                  external
                  view
                  returns (address receiver, uint256 royaltyAmount);
          }
          

          File 6 of 6: Payments
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          import "@openzeppelin/contracts-0.7.2/payment/PullPayment.sol";
          import "@openzeppelin/contracts-0.7.2/math/SafeMath.sol";
          import "./IPayments.sol";
          /**
           * @title Payments contract for SuperRare Marketplaces.
           */
          contract Payments is IPayments, PullPayment {
              using SafeMath for uint256;
              /////////////////////////////////////////////////////////////////////////
              // refund
              /////////////////////////////////////////////////////////////////////////
              /**
               * @dev Internal function to refund an address. Typically for canceled bids or offers.
               * Requirements:
               *
               *  - _payee cannot be the zero address
               *
               * @param _amount uint256 value to be split.
               * @param _payee address seller of the token.
               */
              function refund(address _payee, uint256 _amount) external payable override {
                  require(
                      _payee != address(0),
                      "refund::no payees can be the zero address"
                  );
                  require(msg.value == _amount);
                  if (_amount > 0) {
                      (bool success, ) = address(_payee).call{value: _amount}("");
                      if (!success) {
                          _asyncTransfer(_payee, _amount);
                      }
                  }
              }
              /////////////////////////////////////////////////////////////////////////
              // payout
              /////////////////////////////////////////////////////////////////////////
              function payout(address[] calldata _splits, uint256[] calldata _amounts)
                  external
                  payable
                  override
              {
                  uint256 totalAmount = 0;
                  for (uint256 i = 0; i < _splits.length; i++) {
                      totalAmount = totalAmount.add(_amounts[i]);
                      if (_splits[i] != address(0)) {
                          (bool success, ) = address(_splits[i]).call{value: _amounts[i]}(
                              ""
                          );
                          if (!success) {
                              _asyncTransfer(_splits[i], _amounts[i]);
                          }
                      }
                  }
                  require(msg.value == totalAmount, "payout::not enough sent");
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          import "./escrow/Escrow.sol";
          /**
           * @dev Simple implementation of a
           * https://consensys.github.io/smart-contract-best-practices/recommendations/#favor-pull-over-push-for-external-calls[pull-payment]
           * strategy, where the paying contract doesn't interact directly with the
           * receiver account, which must withdraw its payments itself.
           *
           * Pull-payments are often considered the best practice when it comes to sending
           * Ether, security-wise. It prevents recipients from blocking execution, and
           * eliminates reentrancy concerns.
           *
           * 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].
           *
           * To use, derive from the `PullPayment` contract, and use {_asyncTransfer}
           * instead of Solidity's `transfer` function. Payees can query their due
           * payments with {payments}, and retrieve them with {withdrawPayments}.
           */
          abstract contract PullPayment {
              Escrow private _escrow;
              constructor () internal {
                  _escrow = new Escrow();
              }
              /**
               * @dev Withdraw accumulated payments, forwarding all gas to the recipient.
               *
               * Note that _any_ account can call this function, not just the `payee`.
               * This means that contracts unaware of the `PullPayment` protocol can still
               * receive funds this way, by having a separate account call
               * {withdrawPayments}.
               *
               * 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 Whose payments will be withdrawn.
               */
              function withdrawPayments(address payable payee) public virtual {
                  _escrow.withdraw(payee);
              }
              /**
               * @dev Returns the payments owed to an address.
               * @param dest The creditor's address.
               */
              function payments(address dest) public view returns (uint256) {
                  return _escrow.depositsOf(dest);
              }
              /**
               * @dev Called by the payer to store the sent amount as credit to be pulled.
               * Funds sent in this way are stored in an intermediate {Escrow} contract, so
               * there is no danger of them being spent before withdrawal.
               *
               * @param dest The destination address of the funds.
               * @param amount The amount to transfer.
               */
              function _asyncTransfer(address dest, uint256 amount) internal virtual {
                  _escrow.deposit{ value: amount }(dest);
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          /**
           * @dev Wrappers over Solidity's arithmetic operations with added overflow
           * checks.
           *
           * Arithmetic operations in Solidity wrap on overflow. This can easily result
           * in bugs, because programmers usually assume that an overflow raises an
           * error, which is the standard behavior in high level programming languages.
           * `SafeMath` restores this intuition by reverting the transaction when an
           * operation overflows.
           *
           * Using this library instead of the unchecked operations eliminates an entire
           * class of bugs, so it's recommended to use it always.
           */
          library SafeMath {
              /**
               * @dev Returns the addition of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  uint256 c = a + b;
                  if (c < a) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the substraction of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b > a) return (false, 0);
                  return (true, a - b);
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
               *
               * _Available since v3.4._
               */
              function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                  // benefit is lost if 'b' is also tested.
                  // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                  if (a == 0) return (true, 0);
                  uint256 c = a * b;
                  if (c / a != b) return (false, 0);
                  return (true, c);
              }
              /**
               * @dev Returns the division of two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a / b);
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
               *
               * _Available since v3.4._
               */
              function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                  if (b == 0) return (false, 0);
                  return (true, a % b);
              }
              /**
               * @dev Returns the addition of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `+` operator.
               *
               * Requirements:
               *
               * - Addition cannot overflow.
               */
              function add(uint256 a, uint256 b) internal pure returns (uint256) {
                  uint256 c = a + b;
                  require(c >= a, "SafeMath: addition overflow");
                  return c;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting on
               * overflow (when the result is negative).
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b <= a, "SafeMath: subtraction overflow");
                  return a - b;
              }
              /**
               * @dev Returns the multiplication of two unsigned integers, reverting on
               * overflow.
               *
               * Counterpart to Solidity's `*` operator.
               *
               * Requirements:
               *
               * - Multiplication cannot overflow.
               */
              function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                  if (a == 0) return 0;
                  uint256 c = a * b;
                  require(c / a == b, "SafeMath: multiplication overflow");
                  return c;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting on
               * division by zero. The result is rounded towards zero.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: division by zero");
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting when dividing by zero.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                  require(b > 0, "SafeMath: modulo by zero");
                  return a % b;
              }
              /**
               * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
               * overflow (when the result is negative).
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {trySub}.
               *
               * Counterpart to Solidity's `-` operator.
               *
               * Requirements:
               *
               * - Subtraction cannot overflow.
               */
              function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b <= a, errorMessage);
                  return a - b;
              }
              /**
               * @dev Returns the integer division of two unsigned integers, reverting with custom message on
               * division by zero. The result is rounded towards zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryDiv}.
               *
               * Counterpart to Solidity's `/` operator. Note: this function uses a
               * `revert` opcode (which leaves remaining gas untouched) while Solidity
               * uses an invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a / b;
              }
              /**
               * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
               * reverting with custom message when dividing by zero.
               *
               * CAUTION: This function is deprecated because it requires allocating memory for the error
               * message unnecessarily. For custom revert reasons use {tryMod}.
               *
               * Counterpart to Solidity's `%` operator. This function uses a `revert`
               * opcode (which leaves remaining gas untouched) while Solidity uses an
               * invalid opcode to revert (consuming all remaining gas).
               *
               * Requirements:
               *
               * - The divisor cannot be zero.
               */
              function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                  require(b > 0, errorMessage);
                  return a % b;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity 0.7.3;
          /// @author koloz
          /// @title IPayments
          /// @notice Interface for the Payments contract used.
          interface IPayments {
              function refund(address _payee, uint256 _amount) external payable;
              function payout(address[] calldata _splits, uint256[] calldata _amounts)
                  external
                  payable;
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <0.8.0;
          import "../../math/SafeMath.sol";
          import "../../access/Ownable.sol";
          import "../../utils/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 SafeMath for uint256;
              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.
               */
              function deposit(address payee) public payable virtual onlyOwner {
                  uint256 amount = msg.value;
                  _deposits[payee] = _deposits[payee].add(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.
               */
              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
          pragma solidity >=0.6.0 <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 () internal {
                  address msgSender = _msgSender();
                  _owner = msgSender;
                  emit OwnershipTransferred(address(0), msgSender);
              }
              /**
               * @dev Returns the address of the current owner.
               */
              function owner() public view virtual returns (address) {
                  return _owner;
              }
              /**
               * @dev Throws if called by any account other than the owner.
               */
              modifier onlyOwner() {
                  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 {
                  emit OwnershipTransferred(_owner, address(0));
                  _owner = 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");
                  emit OwnershipTransferred(_owner, newOwner);
                  _owner = newOwner;
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.2 <0.8.0;
          /**
           * @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
               * ====
               */
              function isContract(address account) internal view returns (bool) {
                  // This method relies on extcodesize, which returns 0 for contracts in
                  // construction, since the code is only stored at the end of the
                  // constructor execution.
                  uint256 size;
                  // solhint-disable-next-line no-inline-assembly
                  assembly { size := extcodesize(account) }
                  return size > 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");
                  // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                  (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 functionCall(target, data, "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");
                  require(isContract(target), "Address: call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.call{ value: value }(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: static call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.staticcall(data);
                  return _verifyCallResult(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) {
                  require(isContract(target), "Address: delegate call to non-contract");
                  // solhint-disable-next-line avoid-low-level-calls
                  (bool success, bytes memory returndata) = target.delegatecall(data);
                  return _verifyCallResult(success, returndata, errorMessage);
              }
              function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                  if (success) {
                      return returndata;
                  } else {
                      // 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
                          // solhint-disable-next-line no-inline-assembly
                          assembly {
                              let returndata_size := mload(returndata)
                              revert(add(32, returndata), returndata_size)
                          }
                      } else {
                          revert(errorMessage);
                      }
                  }
              }
          }
          // SPDX-License-Identifier: MIT
          pragma solidity >=0.6.0 <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 GSN 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 payable) {
                  return msg.sender;
              }
              function _msgData() internal view virtual returns (bytes memory) {
                  this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                  return msg.data;
              }
          }