ETH Price: $2,650.86 (-0.94%)

Contract

0x009a1dc9F1A6e2134aD4236Fcd75B1aE62858507
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Buy Single Listi...208554492024-09-29 9:38:2315 hrs ago1727602703IN
0x009a1dc9...E62858507
0 ETH0.001512846.35721361
Buy Single Listi...208494422024-09-28 13:30:2335 hrs ago1727530223IN
0x009a1dc9...E62858507
0 ETH0.001831628.34808804
Revoke Single No...207708792024-09-17 14:18:4712 days ago1726582727IN
0x009a1dc9...E62858507
0 ETH0.0009175618.6539039
Revoke Single No...207620482024-09-16 8:39:1113 days ago1726475951IN
0x009a1dc9...E62858507
0 ETH0.0006621713.4619257
Revoke Single No...207554382024-09-15 10:32:2314 days ago1726396343IN
0x009a1dc9...E62858507
0 ETH0.000097771.98770582
Revoke Single No...206809152024-09-05 0:50:4725 days ago1725497447IN
0x009a1dc9...E62858507
0 ETH0.000201424.09492759
Buy Single Listi...206788622024-09-04 17:58:2325 days ago1725472703IN
0x009a1dc9...E62858507
0 ETH0.000720593.31967812
Revoke Single No...206733392024-09-03 23:28:1126 days ago1725406091IN
0x009a1dc9...E62858507
0 ETH0.000057121.16128913
Buy Batch Of Lis...206664162024-09-03 0:17:5927 days ago1725322679IN
0x009a1dc9...E62858507
0 ETH0.000527041.56943259
Buy Single Listi...206321112024-08-29 5:19:2331 days ago1724908763IN
0x009a1dc9...E62858507
0 ETH0.000246621.27986648
Revoke Single No...206291822024-08-28 19:29:2332 days ago1724873363IN
0x009a1dc9...E62858507
0 ETH0.000083551.69868666
Revoke Single No...206291082024-08-28 19:14:3532 days ago1724872475IN
0x009a1dc9...E62858507
0 ETH0.000148953.02827696
Revoke Single No...206290552024-08-28 19:03:5932 days ago1724871839IN
0x009a1dc9...E62858507
0 ETH0.000200524.07653776
Buy Single Listi...206289952024-08-28 18:51:5932 days ago1724871119IN
0x009a1dc9...E62858507
0 ETH0.000550992.40224659
Buy Single Listi...206058472024-08-25 13:16:4735 days ago1724591807IN
0x009a1dc9...E62858507
0 ETH0.000232911.00921265
Buy Single Listi...206022272024-08-25 1:08:1136 days ago1724548091IN
0x009a1dc9...E62858507
0 ETH0.000168020.76925702
Revoke Single No...206009152024-08-24 20:43:2336 days ago1724532203IN
0x009a1dc9...E62858507
0 ETH0.000047720.97014718
Revoke Single No...206007052024-08-24 20:00:4736 days ago1724529647IN
0x009a1dc9...E62858507
0 ETH0.000057231.16354247
Revoke Single No...205916232024-08-23 13:33:4737 days ago1724420027IN
0x009a1dc9...E62858507
0 ETH0.000173863.53463792
Revoke Single No...205865932024-08-22 20:39:5938 days ago1724359199IN
0x009a1dc9...E62858507
0 ETH0.00005991.21795448
Buy Single Listi...205764662024-08-21 10:41:3539 days ago1724236895IN
0x009a1dc9...E62858507
0.04 ETH0.000077740.7496583
Buy Single Listi...205470522024-08-17 8:08:2343 days ago1723882103IN
0x009a1dc9...E62858507
0.026 ETH0.000187971.81275069
Buy Single Listi...205469852024-08-17 7:54:5943 days ago1723881299IN
0x009a1dc9...E62858507
0.026 ETH0.000183091.76566407
Buy Single Listi...205469822024-08-17 7:54:2343 days ago1723881263IN
0x009a1dc9...E62858507
0.026 ETH0.000195061.88118075
Buy Single Listi...205469572024-08-17 7:49:2343 days ago1723880963IN
0x009a1dc9...E62858507
0.026 ETH0.000192941.86065307
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
208104002024-09-23 2:48:236 days ago1727059703
0x009a1dc9...E62858507
0.019602 ETH
208104002024-09-23 2:48:236 days ago1727059703
0x009a1dc9...E62858507
0.000198 ETH
208104002024-09-23 2:48:236 days ago1727059703
0x009a1dc9...E62858507
0.0198 ETH
199463552024-05-25 10:40:11127 days ago1716633611
0x009a1dc9...E62858507
0.03255 ETH
199463552024-05-25 10:40:11127 days ago1716633611
0x009a1dc9...E62858507
0.00035 ETH
199463552024-05-25 10:40:11127 days ago1716633611
0x009a1dc9...E62858507
0.0021 ETH
199026882024-05-19 8:07:23133 days ago1716106043
0x009a1dc9...E62858507
0.0342 ETH
199026882024-05-19 8:07:23133 days ago1716106043
0x009a1dc9...E62858507
0.0018 ETH
198898872024-05-17 13:07:47135 days ago1715951267
0x009a1dc9...E62858507
0.06346 ETH
198898872024-05-17 13:07:47135 days ago1715951267
0x009a1dc9...E62858507
0.00334 ETH
198095632024-05-06 7:30:35146 days ago1714980635
0x009a1dc9...E62858507
0.075042 ETH
198095632024-05-06 7:30:35146 days ago1714980635
0x009a1dc9...E62858507
0.000758 ETH
197417802024-04-26 20:03:23156 days ago1714161803
0x009a1dc9...E62858507
0.244055 ETH
197417802024-04-26 20:03:23156 days ago1714161803
0x009a1dc9...E62858507
0.001995 ETH
197417802024-04-26 20:03:23156 days ago1714161803
0x009a1dc9...E62858507
0.01995 ETH
197312672024-04-25 8:44:11157 days ago1714034651
0x009a1dc9...E62858507
0.02945 ETH
197312672024-04-25 8:44:11157 days ago1714034651
0x009a1dc9...E62858507
0.00155 ETH
197281182024-04-24 22:10:11158 days ago1713996611
0x009a1dc9...E62858507
0.2559825 ETH
197281182024-04-24 22:10:11158 days ago1713996611
0x009a1dc9...E62858507
0.0020925 ETH
197281182024-04-24 22:10:11158 days ago1713996611
0x009a1dc9...E62858507
0.020925 ETH
197203382024-04-23 19:59:47159 days ago1713902387
0x009a1dc9...E62858507
0.244055 ETH
197203382024-04-23 19:59:47159 days ago1713902387
0x009a1dc9...E62858507
0.001995 ETH
197203382024-04-23 19:59:47159 days ago1713902387
0x009a1dc9...E62858507
0.01995 ETH
197141092024-04-22 23:06:47160 days ago1713827207
0x009a1dc9...E62858507
0.025365 ETH
197141092024-04-22 23:06:47160 days ago1713827207
0x009a1dc9...E62858507
0.001335 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PaymentProcessor

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 600 runs

Other Settings:
london EvmVersion
File 1 of 23 : PaymentProcessor.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "./IOwnable.sol";
import "./IPaymentProcessor.sol";
import "@openzeppelin/contracts/access/IAccessControl.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/**
 * @title  PaymentProcessor
 * @author Limit Break, Inc.
 * @notice The world's first ERC721-C compatible marketplace contract!  
 * @notice Use ERC721-C to whitelist this contract or other marketplace contracts that process royalties entirely 
 *         on-chain manner to make them 100% enforceable and fully programmable! 
 *
 * @notice <h4>Features</h4>
 *
 * @notice <ul>
 *            <li>Creator Defined Security Profiles</li>
 *            <ul>
 *             <li>Exchange Whitelist On/Off</li>
 *             <li>Payment Method Whitelist On/Off</li>
 *             <li>Pricing Constraints On/Off</li>
 *             <li>Private Sales On/Off</li>
 *             <li>Delegate Purchase Wallets On/Off</li>
 *             <li>Smart Contract Buyers/Sellers On/Off</li>
 *             <li>Exchange Whitelist Bypass for EOAs On/Off</li>
 *            </ul>
 *           <li>Enforceable/Programmable Fees</li>
 *           <ul>
 *             <li>Built-in EIP-2981 Royalty Enforcement</li>
 *             <li>Built-in Marketplace Fee Enforcement</li>
 *           </ul>
 *           <li>Multi-Standard Support</li>
 *           <ul>
 *             <li>ERC721-C</li>
 *             <li>ERC1155-C</li>
 *             <li>ERC721 + EIP-2981</li>
 *             <li>ERC1155 + EIP-2981</li>
 *           </ul>
 *           <li>Payments</li>
 *           <ul>
 *             <li>Native Currency (ETH or Equivalent)</li>
 *             <li>ERC-20 Coin Payments</li>
 *           </ul>
 *           <li>A Multitude of Supported Sale Types</li>
 *           <ul>
 *             <li>Buy Single Listing</li>
 *             <ul>
 *               <li>Collection-Level Offers</li>
 *               <li>Item-Specific Offers</li>
 *             </ul>
 *             <li>Buy Batch of Listings (Shopping Cart)</li>
 *             <li>Buy Bundled Listing (From One Collection)</li>
 *             <li>Sweep Listings (From One Collection)</li>
 *             <li>Partial Order Fills (When ERC-20 Payment Method Is Used)</li>
 *           </ul>
 *         </ul>
 *
 * @notice <h4>Security Considerations for Users</h4>
 *
 * @notice Virtually all on-chain marketplace contracts have the potential to be front-run.
 *         When purchasing high-value items, whether individually or in a batch/bundle it is highly
 *         recommended to execute transactions using Flashbots RPC Relay/private mempool to avoid
 *         sniper bots.  Partial fills are available for batched purchases, bundled listing purchases,
 *         and collection sweeps when the method of payment is an ERC-20 token, but not for purchases
 *         using native currency.  It is preferable to use wrapped ETH (or equivalent) when buying
 *         multiple tokens and it is highly advisable to use Flashbots whenever possible.  [Read the
 *         quickstart guide for more information](https://docs.flashbots.net/flashbots-protect/rpc/quick-start).
 */
contract PaymentProcessor is ERC165, EIP712, Ownable, Pausable, IPaymentProcessor {

    error PaymentProcessor__AddressCannotBeZero();
    error PaymentProcessor__AmountForERC721SalesMustEqualOne();
    error PaymentProcessor__AmountForERC1155SalesGreaterThanZero();
    error PaymentProcessor__BundledOfferPriceMustEqualSumOfAllListingPrices();
    error PaymentProcessor__BuyerDidNotAuthorizePurchase();
    error PaymentProcessor__BuyerMustBeDesignatedPrivateBuyer();
    error PaymentProcessor__CallerDoesNotOwnSecurityPolicy();
    error PaymentProcessor__CallerIsNotTheDelegatedPurchaser();
    error PaymentProcessor__CallerIsNotWhitelistedMarketplace();
    error PaymentProcessor__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
    error PaymentProcessor__CannotIncludeNativeFundsWhenPaymentMethodIsAnERC20Coin();
    error PaymentProcessor__CeilingPriceMustBeGreaterThanFloorPrice();
    error PaymentProcessor__CoinDoesNotImplementDecimalsAndLikelyIsNotAnERC20Token();
    error PaymentProcessor__CoinIsApproved();
    error PaymentProcessor__CoinIsNotApproved();
    error PaymentProcessor__CollectionLevelOrItemLevelOffersCanOnlyBeMadeUsingERC20PaymentMethods();
    error PaymentProcessor__DispensingTokenWasUnsuccessful();
    error PaymentProcessor__EIP1271SignaturesAreDisabled();
    error PaymentProcessor__EIP1271SignatureInvalid();
    error PaymentProcessor__ExchangeIsWhitelisted();
    error PaymentProcessor__ExchangeIsNotWhitelisted();
    error PaymentProcessor__FailedToTransferProceeds();
    error PaymentProcessor__InputArrayLengthCannotBeZero();
    error PaymentProcessor__InputArrayLengthMismatch();
    error PaymentProcessor__MarketplaceAndRoyaltyFeesWillExceedSalePrice();
    error PaymentProcessor__NativeCurrencyIsNotAnApprovedPaymentMethod();
    error PaymentProcessor__OfferHasExpired();
    error PaymentProcessor__OfferPriceMustEqualSalePrice();
    error PaymentProcessor__OnchainRoyaltiesExceedMaximumApprovedRoyaltyFee();
    error PaymentProcessor__OverpaidNativeFunds();
    error PaymentProcessor__PaymentCoinIsNotAnApprovedPaymentMethod();
    error PaymentProcessor__PricingBoundsAreImmutable();
    error PaymentProcessor__RanOutOfNativeFunds();
    error PaymentProcessor__SaleHasExpired();
    error PaymentProcessor__SalePriceAboveMaximumCeiling();
    error PaymentProcessor__SalePriceBelowMinimumFloor();
    error PaymentProcessor__SalePriceBelowSellerApprovedMinimum();
    error PaymentProcessor__SecurityPolicyDoesNotExist();
    error PaymentProcessor__SecurityPolicyOwnershipCannotBeTransferredToZeroAddress();
    error PaymentProcessor__SellerDidNotAuthorizeSale();
    error PaymentProcessor__SignatureAlreadyUsedOrRevoked();
    error PaymentProcessor__TokenSecurityPolicyDoesNotAllowDelegatedPurchases();
    error PaymentProcessor__TokenSecurityPolicyDoesNotAllowEOACallers();
    error PaymentProcessor__TokenSecurityPolicyDoesNotAllowPrivateListings();

    /// @dev Convenience to avoid magic number in bitmask get/set logic.
    uint256 private constant ONE = uint256(1);

    /// @notice The default admin role for NFT collections using Access Control.
    bytes32 private constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x00;

    /// @notice The default security policy id.
    uint256 public constant DEFAULT_SECURITY_POLICY_ID = 0;

    /// @notice The denominator used when calculating the marketplace fee.
    /// @dev    0.5% fee numerator is 50, 1% fee numerator is 100, 10% fee numerator is 1,000 and so on.
    uint256 public constant FEE_DENOMINATOR = 10_000;

    /// @notice keccack256("OfferApproval(uint8 protocol,address marketplace,uint256 marketplaceFeeNumerator,address delegatedPurchaser,address buyer,address tokenAddress,uint256 tokenId,uint256 amount,uint256 price,uint256 expiration,uint256 nonce,uint256 masterNonce,address coin)")
    bytes32 public constant OFFER_APPROVAL_HASH = 0x2008a1ab898fdaa2d8f178bc39e807035d2d6e330dac5e42e913ca727ab56038;

    /// @notice keccack256("CollectionOfferApproval(uint8 protocol,bool collectionLevelOffer,address marketplace,uint256 marketplaceFeeNumerator,address delegatedPurchaser,address buyer,address tokenAddress,uint256 amount,uint256 price,uint256 expiration,uint256 nonce,uint256 masterNonce,address coin)")
    bytes32 public constant COLLECTION_OFFER_APPROVAL_HASH = 0x0bc3075778b80a2341ce445063e81924b88d61eb5f21c815e8f9cc824af096d0;

    /// @notice keccack256("BundledOfferApproval(uint8 protocol,address marketplace,uint256 marketplaceFeeNumerator,address delegatedPurchaser,address buyer,address tokenAddress,uint256 price,uint256 expiration,uint256 nonce,uint256 masterNonce,address coin,uint256[] tokenIds,uint256[] amounts,uint256[] itemSalePrices)")
    bytes32 public constant BUNDLED_OFFER_APPROVAL_HASH = 0x126520d0bca0cfa7e5852d004cc4335723ce67c638cbd55cd530fe992a089e7b;

    /// @notice keccack256("SaleApproval(uint8 protocol,bool sellerAcceptedOffer,address marketplace,uint256 marketplaceFeeNumerator,uint256 maxRoyaltyFeeNumerator,address privateBuyer,address seller,address tokenAddress,uint256 tokenId,uint256 amount,uint256 minPrice,uint256 expiration,uint256 nonce,uint256 masterNonce,address coin)")
    bytes32 public constant SALE_APPROVAL_HASH = 0xd3f4273db8ff5262b6bc5f6ee07d139463b4f826cce90c05165f63062f3686dc;

    /// @notice keccack256("BundledSaleApproval(uint8 protocol,address marketplace,uint256 marketplaceFeeNumerator,address privateBuyer,address seller,address tokenAddress,uint256 expiration,uint256 nonce,uint256 masterNonce,address coin,uint256[] tokenIds,uint256[] amounts,uint256[] maxRoyaltyFeeNumerators,uint256[] itemPrices)")
    bytes32 public constant BUNDLED_SALE_APPROVAL_HASH = 0x80244acca7a02d7199149a3038653fc8cb10ca984341ec429a626fab631e1662;

    /// @dev Tracks the most recently created security profile id
    uint256 private lastSecurityPolicyId;

    /// @dev Mapping of token address (NFT collection) to a security policy id.
    mapping(address => uint256) private tokenSecurityPolicies;

    /// @dev Mapping of whitelisted exchange addresses, organized by security policy id.
    mapping(uint256 => mapping(address => bool)) private exchangeWhitelist;

    /// @dev Mapping of coin addresses that are approved for payments, organized by security policy id.
    mapping(uint256 => mapping(address => bool)) private paymentMethodWhitelist;

    /// @dev Mapping of security policy id to security policy settings.
    mapping(uint256 => SecurityPolicy) private securityPolicies;

    /**
     * @notice User-specific master nonce that allows buyers and sellers to efficiently cancel all listings or offers
     *         they made previously. The master nonce for a user only changes when they explicitly request to revoke all
     *         existing listings and offers.
     *
     * @dev    When prompting sellers to sign a listing or offer, marketplaces must query the current master nonce of
     *         the user and include it in the listing/offer signature data.
     */
    mapping(address => uint256) public masterNonces;

    /**
     * @dev The mapping key is the keccak256 hash of marketplace address and user address.
     *
     * @dev ```keccak256(abi.encodePacked(marketplace, user))```
     *
     * @dev The mapping value is another nested mapping of "slot" (key) to a bitmap (value) containing boolean flags
     *      indicating whether or not a nonce has been used or invalidated.
     *
     * @dev Marketplaces MUST track their own nonce by user, incrementing it for every signed listing or offer the user
     *      creates.  Listings and purchases may be executed out of order, and they may never be executed if orders
     *      are not matched prior to expriation.
     *
     * @dev The slot and the bit offset within the mapped value are computed as:
     *
     * @dev ```slot = nonce / 256;```
     * @dev ```offset = nonce % 256;```
     */
    mapping(bytes32 => mapping(uint256 => uint256)) private invalidatedSignatures;

    /**
     * @dev Mapping of token contract addresses to the address of the ERC-20 payment coin tokens are priced in.
     *      When unspecified, the default currency for collections is the native currency.
     *
     * @dev If the designated ERC-20 payment coin is not in the list of approved coins, sales cannot be executed
     *      until the designated coin is set to an approved payment coin.
     */
    mapping (address => address) public collectionPaymentCoins;

    /**
     * @dev Mapping of token contract addresses to the collection-level pricing boundaries (floor and ceiling price).
     */
    mapping (address => PricingBounds) private collectionPricingBounds;

    /**
     * @dev Mapping of token contract addresses to the token-level pricing boundaries (floor and ceiling price).
     */
    mapping (address => mapping (uint256 => PricingBounds)) private tokenPricingBounds;

    constructor(
        address defaultContractOwner_,
        uint32 defaultPushPaymentGasLimit_, 
        address[] memory defaultPaymentMethods) EIP712("PaymentProcessor", "1") {

        securityPolicies[DEFAULT_SECURITY_POLICY_ID] = SecurityPolicy({
            enforceExchangeWhitelist: false,
            enforcePaymentMethodWhitelist: true,
            enforcePricingConstraints: false,
            disablePrivateListings: false,
            disableDelegatedPurchases: false,
            disableEIP1271Signatures: false,
            disableExchangeWhitelistEOABypass: false,
            pushPaymentGasLimit: defaultPushPaymentGasLimit_,
            policyOwner: address(0)
        });

        emit CreatedOrUpdatedSecurityPolicy(
            DEFAULT_SECURITY_POLICY_ID, 
            false,
            true,
            false,
            false,
            false,
            false,
            false,
            defaultPushPaymentGasLimit_,
            "DEFAULT SECURITY POLICY");

        for (uint256 i = 0; i < defaultPaymentMethods.length;) {
            address coin = defaultPaymentMethods[i];

            paymentMethodWhitelist[DEFAULT_SECURITY_POLICY_ID][coin] = true;
            emit PaymentMethodAddedToWhitelist(DEFAULT_SECURITY_POLICY_ID, coin);

            unchecked {
                ++i;
            }
        }

        _transferOwnership(defaultContractOwner_);
    }

    /**
     * @notice Allows Payment Processor contract owner to pause trading on this contract.  This is only to be used
     *         in case a future vulnerability emerges to allow a migration to an updated contract.
     *
     * @dev    Throws when caller is not the contract owner.
     * @dev    Throws when contract is already paused.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The contract has been placed in the `paused` state.
     * @dev    2. Trading is frozen.
     */
    function pause() external {
        _checkOwner();
        _pause();
    }

    /**
     * @notice Allows Payment Processor contract owner to resume trading on this contract.  This is only to be used
     *         in case a pause was not necessary and trading can safely resume.
     *
     * @dev    Throws when caller is not the contract owner.
     * @dev    Throws when contract is not currently paused.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The contract has been placed in the `unpaused` state.
     * @dev    2. Trading is resumed.
     */
    function unpause() external {
        _checkOwner();
        _unpause();
    }

    /**
     * @notice Allows any user to create a new security policy for the payment processor.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The security policy id tracker has been incremented by `1`.
     * @dev    2. The security policy has been added to the security policies mapping.
     * @dev    3. The caller has been assigned as the owner of the security policy.
     * @dev    4. A `CreatedOrUpdatedSecurityPolicy` event has been emitted.
     *
     * @param  enforceExchangeWhitelist          Requires external exchange contracts be whitelisted to make buy calls.
     * @param  enforcePaymentMethodWhitelist     Requires that ERC-20 payment methods be pre-approved.
     * @param  enforcePricingConstraints         Allows the creator to specify exactly one approved payment method, 
     *                                           a minimum floor price and a maximum ceiling price.  
     *                                           When true, this value supercedes `enforcePaymentMethodWhitelist`.
     * @param  disablePrivateListings            Prevents private sales.
     * @param  disableDelegatedPurchases         Prevents delegated purchases.
     * @param  disableEIP1271Signatures          Prevents EIP-1271 compliant smart contracts such as multi-sig wallets
     *                                           from buying or selling.  Forces buyers and sellers to be EOAs.
     * @param  disableExchangeWhitelistEOABypass When exchange whitelists are enforced, prevents EOAs from executing
     *                                           purchases directly and bypassing whitelisted exchange contracts.
     * @param  pushPaymentGasLimit               The amount of gas to forward when pushing native proceeds.
     * @param  registryName                      A human readable name that describes the security policy.
     */
    function createSecurityPolicy(
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string calldata registryName) external override returns (uint256) {
        uint256 securityPolicyId;
        
        unchecked {
            securityPolicyId = ++lastSecurityPolicyId;
        }
        
        _createOrUpdateSecurityPolicy(
            securityPolicyId,
            enforceExchangeWhitelist,
            enforcePaymentMethodWhitelist,
            enforcePricingConstraints,
            disablePrivateListings,
            disableDelegatedPurchases,
            disableEIP1271Signatures,
            disableExchangeWhitelistEOABypass,
            pushPaymentGasLimit,
            registryName
        );

        return securityPolicyId;
    }

    /**
     * @notice Allows security policy owners to update existing security policies.
     * 
     * @dev    Throws when caller is not the owner of the specified security policy.
     * @dev    Throws when the specified security policy id does not exist.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The security policy details have been updated in the security policies mapping.
     * @dev    2. A `CreatedOrUpdatedSecurityPolicy` event has been emitted.
     *
     * @param  enforceExchangeWhitelist          Requires external exchange contracts be whitelisted to make buy calls.
     * @param  enforcePaymentMethodWhitelist     Requires that ERC-20 payment methods be pre-approved.
     * @param  enforcePricingConstraints         Allows the creator to specify exactly one approved payment method, 
     *                                           a minimum floor price and a maximum ceiling price.  
     *                                           When true, this value supercedes `enforcePaymentMethodWhitelist`.
     * @param  disablePrivateListings            Prevents private sales.
     * @param  disableDelegatedPurchases         Prevents delegated purchases.
     * @param  disableEIP1271Signatures          Prevents EIP-1271 compliant smart contracts such as multi-sig wallets
     *                                           from buying or selling.  Forces buyers and sellers to be EOAs.
     * @param  disableExchangeWhitelistEOABypass When exchange whitelists are enforced, prevents EOAs from executing
     *                                           purchases directly and bypassing whitelisted exchange contracts.
     * @param  pushPaymentGasLimit               The amount of gas to forward when pushing native proceeds.
     * @param  registryName                      A human readable name that describes the security policy.
     */
    function updateSecurityPolicy(
        uint256 securityPolicyId,
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string calldata registryName) external override {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        _createOrUpdateSecurityPolicy(
            securityPolicyId,
            enforceExchangeWhitelist,
            enforcePaymentMethodWhitelist,
            enforcePricingConstraints,
            disablePrivateListings,
            disableDelegatedPurchases,
            disableEIP1271Signatures,
            disableExchangeWhitelistEOABypass,
            pushPaymentGasLimit,
            registryName
        );
    }

    /**
     * @notice Allow security policy owners to transfer ownership of their security policy to a new account.
     *
     * @dev    Throws when `newOwner` is the zero address.
     * @dev    Throws when caller is not the owner of the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The security policy owner has been updated in the security policies mapping.
     * @dev    2. A `SecurityPolicyOwnershipTransferred` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     * @param  newOwner         The new policy owner address.
     */
    function transferSecurityPolicyOwnership(uint256 securityPolicyId, address newOwner) external override {
        if(newOwner == address(0)) {
            revert PaymentProcessor__SecurityPolicyOwnershipCannotBeTransferredToZeroAddress();
        }

        _transferSecurityPolicyOwnership(securityPolicyId, newOwner);
    }

    /**
     * @notice Allow security policy owners to transfer ownership of their security policy to the zero address.
     *         This can be done to make a security policy permanently immutable.
     *
     * @dev    Throws when caller is not the owner of the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The security policy owner has been set to the zero address in the security policies mapping.
     * @dev    2. A `SecurityPolicyOwnershipTransferred` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     */
    function renounceSecurityPolicyOwnership(uint256 securityPolicyId) external override {
        _transferSecurityPolicyOwnership(securityPolicyId, address(0));
    }

    /**
     * @notice Allows the smart contract, the contract owner, or the contract admin of any NFT collection to 
     *         set the security policy for their collection..
     *
     * @dev    Throws when the specified tokenAddress is address(0).
     * @dev    Throws when the caller is not the contract, the owner or the administrator of the specified collection.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The `tokenSecurityPolicies` mapping has be updated to reflect the designated security policy id.
     * @dev    2. An `UpdatedCollectionSecurityPolicy` event has been emitted.
     *
     * @param  tokenAddress     The smart contract address of the NFT collection.
     * @param  securityPolicyId The security policy id to use for the collection.
     */
    function setCollectionSecurityPolicy(address tokenAddress, uint256 securityPolicyId) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(tokenAddress);

        if (securityPolicyId > lastSecurityPolicyId) {
            revert PaymentProcessor__SecurityPolicyDoesNotExist();
        }

        tokenSecurityPolicies[tokenAddress] = securityPolicyId;
        emit UpdatedCollectionSecurityPolicy(tokenAddress, securityPolicyId);
    }

    /**
     * @notice Allows the smart contract, the contract owner, or the contract admin of any NFT collection to 
     *         specify the currency their collection is priced in.  Only applicable when `enforcePricingConstraints` 
     *         security setting is in effect for a collection.
     *
     * @dev    Throws when the specified tokenAddress is address(0).
     * @dev    Throws when the caller is not the contract, the owner or the administrator of the specified tokenAddress.
     * @dev    Throws when the specified coin address non-zero and does not implement decimals() > 0.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The `collectionPaymentCoins` mapping has be updated to reflect the designated payment coin.
     * @dev    2. An `UpdatedCollectionPaymentCoin` event has been emitted.
     *
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @param  coin         The address of the designated ERC-20 payment coin smart contract.
     *                      Specify address(0) to designate native currency as the payment currency.
     */
    function setCollectionPaymentCoin(address tokenAddress, address coin) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(tokenAddress);
        collectionPaymentCoins[tokenAddress] = coin;
        emit UpdatedCollectionPaymentCoin(tokenAddress, coin);
    }

    /**
     * @notice Allows the smart contract, the contract owner, or the contract admin of any NFT collection to 
     *         specify their own bounded price at the collection level.
     *
     * @dev    Throws when the specified tokenAddress is address(0).
     * @dev    Throws when the caller is not the contract, the owner or the administrator of the specified tokenAddress.
     * @dev    Throws when the previously set pricing bounds were set to be immutable.
     * @dev    Throws when the specified floor price is greater than the ceiling price.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The collection-level pricing bounds for the specified tokenAddress has been set.
     * @dev    2. An `UpdatedCollectionLevelPricingBoundaries` event has been emitted.
     *
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @param  pricingBounds Including the floor price, ceiling price, and an immutability flag.
     */
    function setCollectionPricingBounds(address tokenAddress, PricingBounds calldata pricingBounds) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(tokenAddress);

        if(collectionPricingBounds[tokenAddress].isImmutable) {
            revert PaymentProcessor__PricingBoundsAreImmutable();
        }

        if(pricingBounds.floorPrice > pricingBounds.ceilingPrice) {
            revert PaymentProcessor__CeilingPriceMustBeGreaterThanFloorPrice();
        }
        
        collectionPricingBounds[tokenAddress] = pricingBounds;
        
        emit UpdatedCollectionLevelPricingBoundaries(
            tokenAddress, 
            pricingBounds.floorPrice, 
            pricingBounds.ceilingPrice);
    }

    /**
     * @notice Allows the smart contract, the contract owner, or the contract admin of any NFT collection to 
     *         specify their own bounded price at the individual token level.
     *
     * @dev    Throws when the specified tokenAddress is address(0).
     * @dev    Throws when the caller is not the contract, the owner or the administrator of the specified tokenAddress.
     * @dev    Throws when the lengths of the tokenIds and pricingBounds array don't match.
     * @dev    Throws when the tokenIds or pricingBounds array length is zero.     
     * @dev    Throws when the previously set pricing bounds of a token were set to be immutable.
     * @dev    Throws when the any of the specified floor prices is greater than the ceiling price for that token id.
     * 
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The token-level pricing bounds for the specified tokenAddress and token ids has been set.
     * @dev    2. An `UpdatedTokenLevelPricingBoundaries` event has been emitted.
     *
     * @param  tokenAddress  The smart contract address of the NFT collection.
     * @param  tokenIds      An array of token ids for which pricing bounds are being set.
     * @param  pricingBounds An array of pricing bounds used to set the floor, ceiling and immutability flag on the 
     *                       individual token level.
     */
    function setTokenPricingBounds(
        address tokenAddress, 
        uint256[] calldata tokenIds, 
        PricingBounds[] calldata pricingBounds) external override {
        _requireCallerIsNFTOrContractOwnerOrAdmin(tokenAddress);

        if(tokenIds.length != pricingBounds.length) {
            revert PaymentProcessor__InputArrayLengthMismatch();
        }

        if(tokenIds.length == 0) {
            revert PaymentProcessor__InputArrayLengthCannotBeZero();
        }

        mapping (uint256 => PricingBounds) storage ptrTokenPricingBounds = tokenPricingBounds[tokenAddress];

        uint256 tokenId;
        for(uint256 i = 0; i < tokenIds.length;) {
            tokenId = tokenIds[i];
            PricingBounds memory pricingBounds_ = pricingBounds[i];

            if(ptrTokenPricingBounds[tokenId].isImmutable) {
                revert PaymentProcessor__PricingBoundsAreImmutable();
            }

            if(pricingBounds_.floorPrice > pricingBounds_.ceilingPrice) {
                revert PaymentProcessor__CeilingPriceMustBeGreaterThanFloorPrice();
            }

            ptrTokenPricingBounds[tokenId] = pricingBounds_;

            emit UpdatedTokenLevelPricingBoundaries(
                tokenAddress, 
                tokenId, 
                pricingBounds_.floorPrice, 
                pricingBounds_.ceilingPrice);
            
            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice Allows security policy owners to whitelist an exchange.
     *
     * @dev    Throws when caller is not the owner of the specified security policy.
     * @dev    Throws when the specified address is address(0).
     * @dev    Throws when the specified address is already whitelisted under the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. `account` has been whitelisted in `exchangeWhitelist` mapping.
     * @dev    2. An `ExchangeAddedToWhitelist` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     * @param  account          The address of the exchange to whitelist.
     */
    function whitelistExchange(uint256 securityPolicyId, address account) external override {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        if (account == address(0)) {
            revert PaymentProcessor__AddressCannotBeZero();
        }

        mapping (address => bool) storage ptrExchangeWhitelist = exchangeWhitelist[securityPolicyId];

        if (ptrExchangeWhitelist[account]) {
            revert PaymentProcessor__ExchangeIsWhitelisted();
        }

        ptrExchangeWhitelist[account] = true;
        emit ExchangeAddedToWhitelist(securityPolicyId, account);
    }

    /**
     * @notice Allows security policy owners to remove an exchange from the whitelist.
     *
     * @dev    Throws when caller is not the owner of the specified security policy.
     * @dev    Throws when the specified address is not whitelisted under the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. `account` has been unwhitelisted and removed from the `exchangeWhitelist` mapping.
     * @dev    2. An `ExchangeRemovedFromWhitelist` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     * @param  account          The address of the exchange to unwhitelist.
     */
    function unwhitelistExchange(uint256 securityPolicyId, address account) external override {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        mapping (address => bool) storage ptrExchangeWhitelist = exchangeWhitelist[securityPolicyId];

        if (!ptrExchangeWhitelist[account]) {
            revert PaymentProcessor__ExchangeIsNotWhitelisted();
        }

        delete ptrExchangeWhitelist[account];
        emit ExchangeRemovedFromWhitelist(securityPolicyId, account);
    }

    /**
     * @notice Allows security policy owners to approve a new coin for use as a payment currency.
     *
     * @dev    Throws when caller is not the owner of the specified security policy.
     * @dev    Throws when the specified coin address is address(0).
     * @dev    Throws when the specified coin does not implement the decimals() that returns a non-zero value. 
     * @dev    Throws when the specified coin is already approved under the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. `coin` has been approved in `paymentMethodWhitelist` mapping.
     * @dev    2. A `PaymentMethodAddedToWhitelist` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     * @param  coin             The address of the coin to approve.
     */
    function whitelistPaymentMethod(uint256 securityPolicyId, address coin) external override {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        mapping (address => bool) storage ptrPaymentMethodWhitelist = paymentMethodWhitelist[securityPolicyId];

        if (ptrPaymentMethodWhitelist[coin]) {
            revert PaymentProcessor__CoinIsApproved();
        }

        ptrPaymentMethodWhitelist[coin] = true;
        emit PaymentMethodAddedToWhitelist(securityPolicyId, coin);
    }

    /**
     * @notice Allows security policy owners to remove a coin from the list of approved payment currencies.
     *
     * @dev    Throws when caller is not the owner of the specified security policy.
     * @dev    Throws when the specified coin is not currently approved under the specified security policy.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. `coin` has been removed from the `paymentMethodWhitelist` mapping.
     * @dev    2. A `PaymentMethodRemovedFromWhitelist` event has been emitted.
     *
     * @param  securityPolicyId The id of the security policy to update.
     * @param  coin             The address of the coin to disapprove.
     */
    function unwhitelistPaymentMethod(uint256 securityPolicyId, address coin) external override {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        mapping (address => bool) storage ptrPaymentMethodWhitelist = paymentMethodWhitelist[securityPolicyId];

        if (!ptrPaymentMethodWhitelist[coin]) {
            revert PaymentProcessor__CoinIsNotApproved();
        }

        delete ptrPaymentMethodWhitelist[coin];
        emit PaymentMethodRemovedFromWhitelist(securityPolicyId, coin);
    }

    /**
     * @notice Allows a user to revoke/cancel all prior signatures of listings and offers.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The user's master nonce has been incremented by `1` in contract storage, rendering all signed
     *            approvals using the prior nonce unusable.
     * @dev    2. A `MasterNonceInvalidated` event has been emitted.
     */
    function revokeMasterNonce() external override {
        emit MasterNonceInvalidated(masterNonces[_msgSender()], _msgSender());

        unchecked {
            ++masterNonces[_msgSender()];
        }
    }

    /**
     * @notice Allows a user to revoke/cancel a single, previously signed listing or offer by specifying the marketplace
     *         and nonce of the listing or offer.
     *
     * @dev    Throws when the user has already revoked the nonce.
     * @dev    Throws when the nonce was already used to successfully buy or sell an NFT.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The specified `nonce` for the specified `marketplace` and `msg.sender` pair has been revoked and can
     *            no longer be used to execute a sale or purchase.
     * @dev    2. A `RevokedListingOrOffer` event has been emitted.
     *
     * @param  marketplace The marketplace where the `msg.sender` signed the listing or offer.
     * @param  nonce       The nonce that was signed in the revoked listing or offer.
     */
    function revokeSingleNonce(address marketplace, uint256 nonce) external override {
        _checkAndInvalidateNonce(marketplace, _msgSender(), nonce, true);
    }

    /**
     * @notice Executes the sale of one ERC-721 or ERC-1155 token.
     *
     * @notice The seller's signature must be provided that proves that they approved the sale.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         SaleApproval(
     *           uint8 protocol,
     *           bool sellerAcceptedOffer,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           uint256 maxRoyaltyFeeNumerator,
     *           address privateBuyer,
     *           address seller,
     *           address tokenAddress,
     *           uint256 tokenId,
     *           uint256 amount,
     *           uint256 minPrice,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @notice The buyer's signature must be provided that proves that they approved the purchase.  There are two
     *         formats for this approval, one format to be used for collection-level offers when a specific token id is 
     *         not specified and one format to be used for item-level offers when a specific token id is specified.
     *
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         OfferApproval(
     *           uint8 protocol,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 tokenId,
     *           uint256 amount,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @notice OR
     *
     * @notice ```
     *         CollectionOfferApproval(
     *           uint8 protocol,
     *           bool collectionLevelOffer,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 amount,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @dev    WARNING: Calling marketplaces MUST be aware that for ERC-1155 sales, a `safeTransferFrom` function is
     *         called which provides surface area for cross-contract re-entrancy.  Marketplace contracts are responsible
     *         for ensuring this is safely handled.
     *
     * @dev    Throws when payment processor has been `paused`.
     * @dev    Throws when payment method is ETH/native currency and offer price does not equal `msg.value`.
     * @dev    Throws when payment method is ETH/native currency and the order was a collection or item offer.
     * @dev    Throws when payment method is an ERC-20 coin and `msg.value` is not equal to zero.
     * @dev    Throws when the protocol is ERC-721 and amount is not equal to `1`.
     * @dev    Throws when the protocol is ERC-1155 and amount is equal to `0`.
     * @dev    Throws when the expiration timestamp of the listing or offer is in the past/expired.
     * @dev    Throws when the offer price is less than the seller-approved minimum price.
     * @dev    Throws when the marketplace fee + royalty fee numerators exceeds 10,000 (100%).
     * @dev    Throws when the collection security policy enforces pricing constraints and the payment/sale price
     *         violates the constraints.
     * @dev    Throws when a private buyer is specified and the buyer does not match the private buyer.
     * @dev    Throws when a private buyer is specified and private listings are disabled by collection security policy.
     * @dev    Throws when a delegated purchaser is specified and the `msg.sender` is not the delegated purchaser.
     * @dev    Throws when a delegated purchaser is specified and delegated purchases are disabled by collection 
     *         security policy.
     * @dev    Throws when the seller or buyer is a smart contract and EIP-1271 signatures are disabled by collection
     *         security policy.
     * @dev    Throws when the exchange whitelist is enforced by collection security policy and `msg.sender` is a 
     *         smart contract that is not on the whitelist.
     * @dev    Throws when the exchange whitelist is enforced AND exchange whitelist EOA bypass is disabled by 
     *         collection security policy and `msg.sender` is an EOA that is not whitelisted. 
     * @dev    Throws when the seller's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the seller's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the `masterNonce` in the signed listing is not equal to the seller's current `masterNonce.
     * @dev    Throws when the `masterNonce` in the signed offer is not equal to the buyer's current `masterNonce.
     * @dev    Throws when the seller is an EOA and ECDSA recover operation on the SaleApproval EIP-712 signature 
     *         does not return the seller's address, meaning the seller did not approve the sale with the provided 
     *         sale details.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied listing signature.
     * @dev    Throws when the buyer is an EOA and ECDSA recover operation on the OfferApproval EIP-712 signature 
     *         does not return the buyer's address, meaning the buyer did not approve the purchase with the provided 
     *         purchase details.
     * @dev    Throws when the buyer is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied offer signature.
     * @dev    Throws when the onchain royalty amount exceeds the seller-approved maximum royalty fee.
     * @dev    Throws when the seller has not approved the Payment Processor contract for transfers of the specified
     *         token or collection.
     * @dev    Throws when transferFrom (ERC-721) or safeTransferFrom (ERC-1155) fails to transfer the token from the
     *         seller to the buyer.
     * @dev    Throws when the transfer of ERC-20 coin payment tokens from the purchaser fails.
     * @dev    Throws when the distribution of native proceeds cannot be accepted or fails for any reason.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The listing nonce for the specified marketplace and seller has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    2. The offer nonce for the specified marketplace and buyer has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    3. Applicable royalties have been paid to the address designated with EIP-2981 (when implemented on the
     *            NFT contract).
     * @dev    4. Applicable marketplace fees have been paid to the designated marketplace.
     * @dev    5. All remaining funds have been paid to the seller of the token.
     * @dev    6. The `BuySingleListing` event has been emitted.
     * @dev    7. The token has been transferred from the seller to the buyer.
     *
     * @param saleDetails   See `MatchedOrder` struct.
     * @param signedListing See `SignatureECSA` struct.
     * @param signedOffer   See `SignatureECSA` struct.
     */
    function buySingleListing(
        MatchedOrder memory saleDetails,
        SignatureECDSA memory signedListing,
        SignatureECDSA memory signedOffer
    ) external payable override {
        _requireNotPaused();
        if (!_executeMatchedOrderSale(msg.value, saleDetails, signedListing, signedOffer)) {
            revert PaymentProcessor__DispensingTokenWasUnsuccessful();
        }
    }

    /**
     * @notice Executes the sale of multiple ERC-721 or ERC-1155 tokens.
     *
     * @notice Sales may be a combination of native currency and ERC-20 payments.  Matched orders may be any combination
     *         of ERC-721 or ERC-1155 sales, as each matched order signature is validated independently against
     *         individual listings/orders associated with the matched orders.
     *
     * @notice A batch of orders will be partially filled in the case where an NFT is not available at the time of sale,
     *         but only if the method of payment is an ERC-20 token.  Partial fills are not supported for native
     *         payments to limit re-entrancy risks associated with issuing refunds.
     *
     * @notice The seller's signatures must be provided that proves that they approved the sales of each item.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         SaleApproval(
     *           uint8 protocol,
     *           bool sellerAcceptedOffer,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           uint256 maxRoyaltyFeeNumerator,
     *           address privateBuyer,
     *           address seller,
     *           address tokenAddress,
     *           uint256 tokenId,
     *           uint256 amount,
     *           uint256 minPrice,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @notice The buyer's signature must be provided that proves that they approved the purchase of each item.
     *         There are two formats for this approval, one format to be used for collection-level offers when a 
     *         specific token id is not specified and one format to be used for item-level offers when a specific token 
     *         id is specified.
     *
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         OfferApproval(
     *           uint8 protocol,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 tokenId,
     *           uint256 amount,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @notice OR
     *
     * @notice ```
     *         CollectionOfferApproval(
     *           uint8 protocol,
     *           bool collectionLevelOffer,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 amount,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @dev    Throws when payment processor has been `paused`.
     * @dev    Throws when any of the input arrays have mismatched lengths.
     * @dev    Throws when any of the input arrays are empty.
     * @dev    Throws when the the amount of native funds included isn't exactly equal to the sum of the native sale
     *         prices of individual items.
     * @dev    Throws when the the amount of ERC-20 funds approved is less than the sum of the ERC-20
     *         prices of individual items.
     *
     * @dev    WARNING: Calling marketplaces MUST be aware that for ERC-1155 sales, a `safeTransferFrom` function is
     *         called which provides surface area for cross-contract re-entrancy.  Marketplace contracts are responsible
     *         for ensuring this is safely handled.
     *
     * @dev    For each individual matched order to process:
     *
     * @dev    Throws when payment method is ETH/native currency and the order was a collection or item offer.
     * @dev    Throws when payment method is an ERC-20 coin and supplied ETH/native funds for item is not equal to zero.
     * @dev    Throws when the protocol is ERC-721 and amount is not equal to `1`.
     * @dev    Throws when the protocol is ERC-1155 and amount is equal to `0`.
     * @dev    Throws when the expiration timestamp of the listing or offer is in the past/expired.
     * @dev    Throws when the offer price is less than the seller-approved minimum price.
     * @dev    Throws when the marketplace fee + royalty fee numerators exceeds 10,000 (100%).
     * @dev    Throws when the collection security policy enforces pricing constraints and the payment/sale price
     *         violates the constraints.
     * @dev    Throws when a private buyer is specified and the buyer does not match the private buyer.
     * @dev    Throws when a private buyer is specified and private listings are disabled by collection security policy.
     * @dev    Throws when a delegated purchaser is specified and the `msg.sender` is not the delegated purchaser.
     * @dev    Throws when a delegated purchaser is specified and delegated purchases are disabled by collection 
     *         security policy.
     * @dev    Throws when the seller or buyer is a smart contract and EIP-1271 signatures are disabled by collection
     *         security policy.
     * @dev    Throws when the exchange whitelist is enforced by collection security policy and `msg.sender` is a 
     *         smart contract that is not on the whitelist.
     * @dev    Throws when the exchange whitelist is enforced AND exchange whitelist EOA bypass is disabled by 
     *         collection security policy and `msg.sender` is an EOA that is not whitelisted. 
     * @dev    Throws when the seller's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the seller's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the `masterNonce` in the signed listing is not equal to the seller's current `masterNonce.
     * @dev    Throws when the `masterNonce` in the signed offer is not equal to the buyer's current `masterNonce.
     * @dev    Throws when the seller is an EOA and ECDSA recover operation on the SaleApproval EIP-712 signature 
     *         does not return the seller's address, meaning the seller did not approve the sale with the provided 
     *         sale details.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied listing signature.
     * @dev    Throws when the buyer is an EOA and ECDSA recover operation on the OfferApproval EIP-712 signature 
     *         does not return the buyer's address, meaning the buyer did not approve the purchase with the provided 
     *         purchase details.
     * @dev    Throws when the buyer is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied offer signature.
     * @dev    Throws when the onchain royalty amount exceeds the seller-approved maximum royalty fee.
     * @dev    Throws when the seller has not approved the Payment Processor contract for transfers of the specified
     *         token or collection.
     * @dev    Throws when transferFrom (ERC-721) or safeTransferFrom (ERC-1155) fails to transfer the token from the
     *         seller to the buyer and method of payment is native currency. (Partial fills allowed for ERC-20 payments).
     * @dev    Throws when the transfer of ERC-20 coin payment tokens from the purchaser fails.
     * @dev    Throws when the distribution of native proceeds cannot be accepted or fails for any reason.
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    For each item:
     *
     * @dev    1. The listing nonce for the specified marketplace and seller has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    2. The offer nonce for the specified marketplace and buyer has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    3. Applicable royalties have been paid to the address designated with EIP-2981 (when implemented on the
     *            NFT contract).
     * @dev    4. Applicable marketplace fees have been paid to the designated marketplace.
     * @dev    5. All remaining funds have been paid to the seller of the token.
     * @dev    6. The `BuySingleListing` event has been emitted.
     * @dev    7. The token has been transferred from the seller to the buyer.
     *
     * @param saleDetailsArray An array of `MatchedOrder` structs.
     * @param signedListings   An array of `SignatureECDSA` structs.
     * @param signedOffers     An array of `SignatureECDSA` structs.
     */
    function buyBatchOfListings(
        MatchedOrder[] calldata saleDetailsArray,
        SignatureECDSA[] calldata signedListings,
        SignatureECDSA[] calldata signedOffers
    ) external payable override {
        _requireNotPaused();

        if (saleDetailsArray.length != signedListings.length || 
            saleDetailsArray.length != signedOffers.length) {
            revert PaymentProcessor__InputArrayLengthMismatch();
        }

        if (saleDetailsArray.length == 0) {
            revert PaymentProcessor__InputArrayLengthCannotBeZero();
        }

        uint256 runningBalanceNativeProceeds = msg.value;

        MatchedOrder memory saleDetails;
        SignatureECDSA memory signedListing;
        SignatureECDSA memory signedOffer;
        uint256 msgValue;

        for (uint256 i = 0; i < saleDetailsArray.length;) {
            saleDetails = saleDetailsArray[i];
            signedListing = signedListings[i];
            signedOffer = signedOffers[i];
            msgValue = 0;

            if(saleDetails.paymentCoin == address(0)) {
                msgValue = saleDetails.offerPrice;

                if (runningBalanceNativeProceeds < msgValue) {
                    revert PaymentProcessor__RanOutOfNativeFunds();
                }

                unchecked {
                    runningBalanceNativeProceeds -= msgValue;
                }

                if (!_executeMatchedOrderSale(msgValue, saleDetails, signedListing, signedOffer)) {
                    revert PaymentProcessor__DispensingTokenWasUnsuccessful();
                }
            } else {
                _executeMatchedOrderSale(msgValue, saleDetails, signedListing, signedOffer);
            }

            unchecked {
                ++i;
            }
        }

        if (runningBalanceNativeProceeds > 0) {
            revert PaymentProcessor__OverpaidNativeFunds();
        }
    }

    /**
     * @notice Executes the bundled sale of ERC-721 or ERC-1155 token listed by a single seller for a single collection.
     *
     * @notice Orders will be partially filled in the case where an NFT is not available at the time of sale,
     *         but only if the method of payment is an ERC-20 token.  Partial fills are not supported for native
     *         payments to limit re-entrancy risks associated with issuing refunds.
     *
     * @notice The seller's signature must be provided that proves that they approved the sale of each token.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         BundledSaleApproval(
     *           uint8 protocol,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address privateBuyer,
     *           address seller,
     *           address tokenAddress,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin,
     *           uint256[] tokenIds,
     *           uint256[] amounts,
     *           uint256[] maxRoyaltyFeeNumerators,
     *           uint256[] itemPrices)
     *         ```
     *
     * @notice The buyer's signature must be provided that proves that they approved the purchase of each token.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         BundledOfferApproval(
     *           uint8 protocol,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin,
     *           uint256[] tokenIds,
     *           uint256[] amounts,
     *           uint256[] itemSalePrices)
     *         ```
     *
     * @dev    WARNING: Calling marketplaces MUST be aware that for ERC-1155 sales, a `safeTransferFrom` function is
     *         called which provides surface area for cross-contract re-entrancy.  Marketplace contracts are responsible
     *         for ensuring this is safely handled.
     *
     * @dev    Throws when payment processor has been `paused`.
     * @dev    Throws when the bundled items array has a length of zero.
     * @dev    Throws when payment method is ETH/native currency and offer price does not equal `msg.value`.
     * @dev    Throws when payment method is an ERC-20 coin and `msg.value` is not equal to zero.
     * @dev    Throws when the offer price does not equal the sum of the individual item prices in the listing.
     * @dev    Throws when the expiration timestamp of the offer is in the past/expired.
     * @dev    Throws when a private buyer is specified and the buyer does not match the private buyer.
     * @dev    Throws when a private buyer is specified and private listings are disabled by collection security policy.
     * @dev    Throws when a delegated purchaser is specified and the `msg.sender` is not the delegated purchaser.
     * @dev    Throws when a delegated purchaser is specified and delegated purchases are disabled by collection 
     *         security policy.
     * @dev    Throws when the exchange whitelist is enforced by collection security policy and `msg.sender` is a 
     *         smart contract that is not on the whitelist.
     * @dev    Throws when the exchange whitelist is enforced AND exchange whitelist EOA bypass is disabled by 
     *         collection security policy and `msg.sender` is an EOA that is not whitelisted. 
     * @dev    Throws when the seller's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the seller's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the `masterNonce` in the signed listing is not equal to the seller's current `masterNonce.
     * @dev    Throws when the `masterNonce` in the signed offer is not equal to the buyer's current `masterNonce.
     * @dev    Throws when the seller is an EOA and ECDSA recover operation on the SaleApproval EIP-712 signature 
     *         does not return the seller's address, meaning the seller did not approve the sale with the provided 
     *         sale details.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied listing signature.
     * @dev    Throws when the buyer is an EOA and ECDSA recover operation on the OfferApproval EIP-712 signature 
     *         does not return the buyer's address, meaning the buyer did not approve the purchase with the provided 
     *         purchase details.
     * @dev    Throws when the buyer is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied offer signature.
     * @dev    Throws when the transfer of ERC-20 coin payment tokens from the purchaser fails.
     * @dev    Throws when the distribution of native proceeds cannot be accepted or fails for any reason.
     *
     * @dev    For each item in the bundled listing:
     *
     * @dev    Throws when the protocol is ERC-721 and amount is not equal to `1`.
     * @dev    Throws when the protocol is ERC-1155 and amount is equal to `0`.
     * @dev    Throws when the marketplace fee + royalty fee numerators exceeds 10,000 (100%).
     * @dev    Throws when the collection security policy enforces pricing constraints and the payment/sale price
     *         violates the constraints.
     * @dev    Throws when the expiration timestamp of the listing is in the past/expired.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signatures are disabled by collection
     *         security policy.
     * @dev    Throws when the onchain royalty amount exceeds the seller-approved maximum royalty fee.
     * @dev    Throws when the seller has not approved the Payment Processor contract for transfers of the specified
     *         tokens in the collection.
     * @dev    Throws when transferFrom (ERC-721) or safeTransferFrom (ERC-1155) fails to transfer the tokens from the
     *         seller to the buyer and method of payment is native currency. (Partial fills allowed for ERC-20 payments).
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The listing nonce for the specified marketplace and seller has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    2. The offer nonce for the specified marketplace and buyer has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    3. Applicable royalties have been paid to the address designated with EIP-2981 (when implemented on the
     *            NFT contract).
     * @dev    4. Applicable marketplace fees have been paid to the designated marketplace.
     * @dev    5. All remaining funds have been paid to the seller of the token.
     * @dev    6. The `BuyBundledListingERC721` or `BuyBundledListingERC1155`  event has been emitted.
     * @dev    7. The tokens in the bundle has been transferred from the seller to the buyer.
     *
     * @param signedListing See `SignatureECSA` struct.
     * @param signedOffer   See `SignatureECSA` struct.
     * @param bundleDetails See `MatchedOrderBundleExtended` struct.
     * @param bundleItems   See `BundledItem` struct. 
     */
    function buyBundledListing(
        SignatureECDSA memory signedListing,
        SignatureECDSA memory signedOffer,
        MatchedOrderBundleExtended memory bundleDetails,
        BundledItem[] calldata bundleItems) external payable override {
        _requireNotPaused();

        if (bundleItems.length == 0) {
            revert PaymentProcessor__InputArrayLengthCannotBeZero();
        }

        (uint256 securityPolicyId, SecurityPolicy storage securityPolicy) = 
            _getTokenSecurityPolicy(bundleDetails.bundleBase.tokenAddress);

        SignatureECDSA[] memory signedListingAsSingletonArray = new SignatureECDSA[](1);
        signedListingAsSingletonArray[0] = signedListing;

        (Accumulator memory accumulator, MatchedOrder[] memory saleDetailsBatch) = 
        _validateBundledItems(
            false,
            securityPolicy,
            bundleDetails,
            bundleItems,
            signedListingAsSingletonArray
        );

        _validateBundledOffer(
            securityPolicyId,
            securityPolicy,
            bundleDetails.bundleBase,
            accumulator,
            signedOffer
        );

        bool[] memory unsuccessfulFills = _computeAndDistributeProceeds(
            ComputeAndDistributeProceedsArgs({
                pushPaymentGasLimit: securityPolicy.pushPaymentGasLimit,
                purchaser: bundleDetails.bundleBase.delegatedPurchaser == address(0) ? bundleDetails.bundleBase.buyer : bundleDetails.bundleBase.delegatedPurchaser,
                paymentCoin: IERC20(bundleDetails.bundleBase.paymentCoin),
                funcPayout: bundleDetails.bundleBase.paymentCoin == address(0) ? _payoutNativeCurrency : _payoutCoinCurrency,
                funcDispenseToken: bundleDetails.bundleBase.protocol == TokenProtocols.ERC1155 ? _dispenseERC1155Token : _dispenseERC721Token
            }),
            saleDetailsBatch
        );

        if (bundleDetails.bundleBase.protocol == TokenProtocols.ERC1155) {
            emit BuyBundledListingERC1155(
                    bundleDetails.bundleBase.marketplace,
                    bundleDetails.bundleBase.tokenAddress,
                    bundleDetails.bundleBase.paymentCoin,
                    bundleDetails.bundleBase.buyer,
                    bundleDetails.seller,
                    unsuccessfulFills,
                    accumulator.tokenIds,
                    accumulator.amounts,
                    accumulator.salePrices);
        } else {
            emit BuyBundledListingERC721(
                    bundleDetails.bundleBase.marketplace,
                    bundleDetails.bundleBase.tokenAddress,
                    bundleDetails.bundleBase.paymentCoin,
                    bundleDetails.bundleBase.buyer,
                    bundleDetails.seller,
                    unsuccessfulFills,
                    accumulator.tokenIds,
                    accumulator.salePrices);
        }
    }

    /**
     * @notice Executes the bundled purchase of ERC-721 or ERC-1155 tokens individually listed for a single collection.
     *
     * @notice The seller's signatures must be provided that proves that they approved the sales of each item.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         SaleApproval(
     *           uint8 protocol,
     *           bool sellerAcceptedOffer,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           uint256 maxRoyaltyFeeNumerator,
     *           address privateBuyer,
     *           address seller,
     *           address tokenAddress,
     *           uint256 tokenId,
     *           uint256 amount,
     *           uint256 minPrice,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin)
     *         ```
     *
     * @notice The buyer's signature must be provided that proves that they approved the purchase of each token.
     * @notice This an an EIP-712 signature with the following data format.
     * @notice ```EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)```
     * @notice ```
     *         BundledOfferApproval(
     *           uint8 protocol,
     *           address marketplace,
     *           uint256 marketplaceFeeNumerator,
     *           address delegatedPurchaser,
     *           address buyer,
     *           address tokenAddress,
     *           uint256 price,
     *           uint256 expiration,
     *           uint256 nonce,
     *           uint256 masterNonce,
     *           address coin,
     *           uint256[] tokenIds,
     *           uint256[] amounts,
     *           uint256[] itemSalePrices)
     *         ```
     *
     * @dev    WARNING: Calling marketplaces MUST be aware that for ERC-1155 sales, a `safeTransferFrom` function is
     *         called which provides surface area for cross-contract re-entrancy.  Marketplace contracts are responsible
     *         for ensuring this is safely handled.
     *
     * @dev    Throws when payment processor has been `paused`.
     * @dev    Throws when any of the input arrays have mismatched lengths.
     * @dev    Throws when any of the input array have a length of zero.
     * @dev    Throws when payment method is ETH/native currency and offer price does not equal `msg.value`.
     * @dev    Throws when payment method is an ERC-20 coin and `msg.value` is not equal to zero.
     * @dev    Throws when the offer price does not equal the sum of the individual item prices in the listing.
     * @dev    Throws when the expiration timestamp of the offer is in the past/expired.
     * @dev    Throws when a private buyer is specified and the buyer does not match the private buyer.
     * @dev    Throws when a private buyer is specified and private listings are disabled by collection security policy.
     * @dev    Throws when a delegated purchaser is specified and the `msg.sender` is not the delegated purchaser.
     * @dev    Throws when a delegated purchaser is specified and delegated purchases are disabled by collection 
     *         security policy.
     * @dev    Throws when the exchange whitelist is enforced by collection security policy and `msg.sender` is a 
     *         smart contract that is not on the whitelist.
     * @dev    Throws when the exchange whitelist is enforced AND exchange whitelist EOA bypass is disabled by 
     *         collection security policy and `msg.sender` is an EOA that is not whitelisted. 
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the buyer's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the `masterNonce` in the signed offer is not equal to the buyer's current `masterNonce.
     * @dev    Throws when the buyer is an EOA and ECDSA recover operation on the OfferApproval EIP-712 signature 
     *         does not return the buyer's address, meaning the buyer did not approve the purchase with the provided 
     *         purchase details.
     * @dev    Throws when the buyer is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied offer signature.
     * @dev    Throws when the transfer of ERC-20 coin payment tokens from the purchaser fails.
     * @dev    Throws when the distribution of native proceeds cannot be accepted or fails for any reason.
     *
     * @dev    For each item in the bundled listing:
     *
     * @dev    Throws when the protocol is ERC-721 and amount is not equal to `1`.
     * @dev    Throws when the protocol is ERC-1155 and amount is equal to `0`.
     * @dev    Throws when the marketplace fee + royalty fee numerators exceeds 10,000 (100%).
     * @dev    Throws when the collection security policy enforces pricing constraints and the payment/sale price
     *         violates the constraints.
     * @dev    Throws when the expiration timestamp of the listing is in the past/expired.
     * @dev    Throws when the seller's nonce on the specified marketplace has already been used to execute a sale.
     * @dev    Throws when the seller's nonce on the specified marketplace has already been revoked/canceled.
     * @dev    Throws when the `masterNonce` in the signed listing is not equal to the seller's current `masterNonce.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signatures are disabled by collection
     *         security policy.
     * @dev    Throws when the seller is an EOA and ECDSA recover operation on the SaleApproval EIP-712 signature 
     *         does not return the seller's address, meaning the seller did not approve the sale with the provided 
     *         sale details.
     * @dev    Throws when the seller is a smart contract and EIP-1271 signature validation returns false for the
     *         supplied listing signature.
     * @dev    Throws when the onchain royalty amount exceeds the seller-approved maximum royalty fee.
     * @dev    Throws when the seller has not approved the Payment Processor contract for transfers of the specified
     *         tokens in the collection.
     * @dev    Throws when transferFrom (ERC-721) or safeTransferFrom (ERC-1155) fails to transfer the tokens from the
     *         seller to the buyer and method of payment is native currency. (Partial fills allowed for ERC-20 payments).
     *
     * @dev    <h4>Postconditions:</h4>
     * @dev    1. The listing nonce for the specified marketplace and seller has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    2. The offer nonce for the specified marketplace and buyer has been marked as invalidated so that it 
     *            cannot be replayed/used again.
     * @dev    3. Applicable royalties have been paid to the address designated with EIP-2981 (when implemented on the
     *            NFT contract).
     * @dev    4. Applicable marketplace fees have been paid to the designated marketplace.
     * @dev    5. All remaining funds have been paid to the seller of the token.
     * @dev    6. The `SweepCollectionERC721` or `SweepCollectionERC1155`  event has been emitted.
     * @dev    7. The tokens in the bundle has been transferred from the seller to the buyer.
     *
     * @param signedOffer    See `SignatureECSA` struct.
     * @param bundleDetails  See `MatchedOrderBundleBase` struct.
     * @param bundleItems    See `BundledItem` struct. 
     * @param signedListings See `SignatureECSA` struct.
     */
    function sweepCollection(
        SignatureECDSA memory signedOffer,
        MatchedOrderBundleBase memory bundleDetails,
        BundledItem[] calldata bundleItems,
        SignatureECDSA[] calldata signedListings) external payable override {
        _requireNotPaused();

        if (bundleItems.length != signedListings.length) {
            revert PaymentProcessor__InputArrayLengthMismatch();
        }

        if (bundleItems.length == 0) {
            revert PaymentProcessor__InputArrayLengthCannotBeZero();
        }

        (uint256 securityPolicyId, SecurityPolicy storage securityPolicy) = 
            _getTokenSecurityPolicy(bundleDetails.tokenAddress);

        (Accumulator memory accumulator, MatchedOrder[] memory saleDetailsBatch) = 
        _validateBundledItems(
            true,
            securityPolicy,
            MatchedOrderBundleExtended({
                bundleBase: bundleDetails,
                seller: address(0),
                listingNonce: 0,
                listingExpiration: 0
            }),
            bundleItems,
            signedListings
        );

        _validateBundledOffer(
            securityPolicyId,
            securityPolicy,
            bundleDetails,
            accumulator,
            signedOffer
        );

        bool[] memory unsuccessfulFills = _computeAndDistributeProceeds(
            ComputeAndDistributeProceedsArgs({
                pushPaymentGasLimit: securityPolicy.pushPaymentGasLimit,
                purchaser: bundleDetails.delegatedPurchaser == address(0) ? bundleDetails.buyer : bundleDetails.delegatedPurchaser,
                paymentCoin: IERC20(bundleDetails.paymentCoin),
                funcPayout: bundleDetails.paymentCoin == address(0) ? _payoutNativeCurrency : _payoutCoinCurrency,
                funcDispenseToken: bundleDetails.protocol == TokenProtocols.ERC1155 ? _dispenseERC1155Token : _dispenseERC721Token
            }),
            saleDetailsBatch
        );

        if (bundleDetails.protocol == TokenProtocols.ERC1155) {
            emit SweepCollectionERC1155(
                    bundleDetails.marketplace,
                    bundleDetails.tokenAddress,
                    bundleDetails.paymentCoin,
                    bundleDetails.buyer,
                    unsuccessfulFills,
                    accumulator.sellers,
                    accumulator.tokenIds,
                    accumulator.amounts,
                    accumulator.salePrices);
        } else {
            emit SweepCollectionERC721(
                    bundleDetails.marketplace,
                    bundleDetails.tokenAddress,
                    bundleDetails.paymentCoin,
                    bundleDetails.buyer,
                    unsuccessfulFills,
                    accumulator.sellers,
                    accumulator.tokenIds,
                    accumulator.salePrices);
        }
    }

    /**
     * @notice Returns the EIP-712 domain separator for this contract.
     */
    function getDomainSeparator() external view override returns (bytes32) {
        return _domainSeparatorV4();
    }

    /**
     * @notice Returns the security policy details for the specified security policy id.
     * 
     * @param  securityPolicyId The security policy id to lookup.
     * @return securityPolicy   The security policy details.
     */
    function getSecurityPolicy(uint256 securityPolicyId) external view override returns (SecurityPolicy memory) {
        return securityPolicies[securityPolicyId];
    }

    /**
     * @notice Returns whitelist status of the exchange address for the specified security policy id.
     *
     * @param  securityPolicyId The security policy id to lookup.
     * @param  account          The address to check.
     * @return isWhitelisted    True if the address is whitelisted, false otherwise.
     */
    function isWhitelisted(uint256 securityPolicyId, address account) external view override returns (bool) {
        return exchangeWhitelist[securityPolicyId][account];
    }

    /**
     * @notice Returns approval status of the payment coin address for the specified security policy id.
     *
     * @param  securityPolicyId        The security policy id to lookup.
     * @param  coin                    The coin address to check.
     * @return isPaymentMethodApproved True if the coin address is approved, false otherwise.
     */
    function isPaymentMethodApproved(uint256 securityPolicyId, address coin) external view override returns (bool) {
        return paymentMethodWhitelist[securityPolicyId][coin];
    }

    /**
     * @notice Returns the current security policy id for the specified collection address.
     * 
     * @param  collectionAddress The address of the collection to lookup.
     * @return securityPolicyId  The current security policy id for the specifed collection.
     */
    function getTokenSecurityPolicyId(address collectionAddress) external view override returns (uint256) {
        return tokenSecurityPolicies[collectionAddress];
    }

    /**
     * @notice Returns whether or not the price of a collection is immutable.
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @return True if the floor and ceiling price for the specified token contract has been set immutably, false otherwise.
     */
    function isCollectionPricingImmutable(address tokenAddress) external view override returns (bool) {
        return collectionPricingBounds[tokenAddress].isImmutable;
    }

    /**
     * @notice Returns whether or not the price of a specific token is immutable.
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @param  tokenId      The token id.
     * @return True if the floor and ceiling price for the specified token contract and tokenId has been set immutably, false otherwise.
     */
    function isTokenPricingImmutable(address tokenAddress, uint256 tokenId) external view override returns (bool) {
        return tokenPricingBounds[tokenAddress][tokenId].isImmutable;
    }

    /**
     * @notice Gets the floor price for the specified nft contract address and token id.
     *
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @param  tokenId      The token id.
     * @return The floor price.
     */
    function getFloorPrice(address tokenAddress, uint256 tokenId) external view override returns (uint256) {
        (uint256 floorPrice,) = _getFloorAndCeilingPrices(tokenAddress, tokenId);
        return floorPrice;
    }

    /**
     * @notice Gets the ceiling price for the specified nft contract address and token id.
     *
     * @param  tokenAddress The smart contract address of the NFT collection.
     * @param  tokenId      The token id.
     * @return The ceiling price.
     */
    function getCeilingPrice(address tokenAddress, uint256 tokenId) external view override returns (uint256) {
        (, uint256 ceilingPrice) = _getFloorAndCeilingPrices(tokenAddress, tokenId);
        return ceilingPrice;
    }

    /**
     * @notice ERC-165 Interface Introspection Support.
     * @dev    Supports `IPaymentProcessor` interface as well as parent contract interfaces.
     * @param  interfaceId The interface to query.
     * @return True if the interface is supported, false otherwise.
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IPaymentProcessor).interfaceId || super.supportsInterface(interfaceId);
    }

    function _payoutNativeCurrency(
        address payee, 
        address /*payer*/, 
        IERC20 /*paymentCoin*/, 
        uint256 proceeds, 
        uint256 gasLimit_) internal {
        _pushProceeds(payee, proceeds, gasLimit_);
    }

    function _payoutCoinCurrency(
        address payee, 
        address payer, 
        IERC20 paymentCoin, 
        uint256 proceeds, 
        uint256 /*gasLimit_*/) internal {
        SafeERC20.safeTransferFrom(paymentCoin, payer, payee, proceeds);
    }

    function _dispenseERC721Token(
        address from, 
        address to, 
        address tokenAddress, 
        uint256 tokenId, 
        uint256 /*amount*/) internal returns (bool) {
        try IERC721(tokenAddress).transferFrom(from, to, tokenId) {
            return true;
        } catch {
            return false;
        }
    }

    function _dispenseERC1155Token(
        address from, 
        address to, 
        address tokenAddress, 
        uint256 tokenId, 
        uint256 amount) internal returns (bool) {
        try IERC1155(tokenAddress).safeTransferFrom(from, to, tokenId, amount, "") {
            return true;
        } catch {
            return false;
        }
    }

    function _requireCallerIsNFTOrContractOwnerOrAdmin(address tokenAddress) internal view {
        bool callerHasPermissions = false;
        
        callerHasPermissions = _msgSender() == tokenAddress;
        if(!callerHasPermissions) {
            try IOwnable(tokenAddress).owner() returns (address contractOwner) {
                callerHasPermissions = _msgSender() == contractOwner;
            } catch {}

            if(!callerHasPermissions) {
                try IAccessControl(tokenAddress).hasRole(DEFAULT_ACCESS_CONTROL_ADMIN_ROLE, _msgSender()) 
                    returns (bool callerIsContractAdmin) {
                    callerHasPermissions = callerIsContractAdmin;
                } catch {}
            }
        }

        if(!callerHasPermissions) {
            revert PaymentProcessor__CallerMustHaveElevatedPermissionsForSpecifiedNFT();
        }
    }

    function _verifyPaymentCoinIsApproved(
        uint256 securityPolicyId, 
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        address tokenAddress, 
        address coin) internal view virtual {
        if (enforcePricingConstraints) {
            if(collectionPaymentCoins[tokenAddress] != coin) {
                revert PaymentProcessor__PaymentCoinIsNotAnApprovedPaymentMethod();
            }
        } else if (enforcePaymentMethodWhitelist) {
            if (!paymentMethodWhitelist[securityPolicyId][coin]) {
                revert PaymentProcessor__PaymentCoinIsNotAnApprovedPaymentMethod();
            }
        }
    }

    function _createOrUpdateSecurityPolicy(
        uint256 securityPolicyId,
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string calldata registryName) private {

        securityPolicies[securityPolicyId] = SecurityPolicy({
            enforceExchangeWhitelist: enforceExchangeWhitelist,
            enforcePaymentMethodWhitelist: enforcePaymentMethodWhitelist,
            enforcePricingConstraints: enforcePricingConstraints,
            disablePrivateListings: disablePrivateListings,
            disableDelegatedPurchases: disableDelegatedPurchases,
            disableEIP1271Signatures: disableEIP1271Signatures,
            disableExchangeWhitelistEOABypass: disableExchangeWhitelistEOABypass,
            pushPaymentGasLimit: pushPaymentGasLimit,
            policyOwner: _msgSender()
        });

        emit CreatedOrUpdatedSecurityPolicy(
            securityPolicyId, 
            enforceExchangeWhitelist,
            enforcePaymentMethodWhitelist,
            enforcePricingConstraints,
            disablePrivateListings,
            disableDelegatedPurchases,
            disableEIP1271Signatures,
            disableExchangeWhitelistEOABypass,
            pushPaymentGasLimit,
            registryName);
    }

    function _transferSecurityPolicyOwnership(uint256 securityPolicyId, address newOwner) private {
        _requireCallerOwnsSecurityPolicy(securityPolicyId);

        SecurityPolicy storage securityPolicy = securityPolicies[securityPolicyId];

        address oldOwner = securityPolicy.policyOwner;
        securityPolicy.policyOwner = newOwner;
        emit SecurityPolicyOwnershipTransferred(oldOwner, newOwner);
    }

    function _executeMatchedOrderSale(
        uint256 msgValue,
        MatchedOrder memory saleDetails,
        SignatureECDSA memory signedListing,
        SignatureECDSA memory signedOffer
    ) private returns (bool tokenDispensedSuccessfully) {
        uint256 securityPolicyId = tokenSecurityPolicies[saleDetails.tokenAddress];
        SecurityPolicy memory securityPolicy = securityPolicies[securityPolicyId];

        if (saleDetails.paymentCoin == address(0)) {
            if (saleDetails.offerPrice != msgValue) {
                revert PaymentProcessor__OfferPriceMustEqualSalePrice();
            }

            if (saleDetails.sellerAcceptedOffer || saleDetails.seller == tx.origin) {
                revert PaymentProcessor__CollectionLevelOrItemLevelOffersCanOnlyBeMadeUsingERC20PaymentMethods();
            }
        } else {
            if (msgValue > 0) {
                revert PaymentProcessor__CannotIncludeNativeFundsWhenPaymentMethodIsAnERC20Coin();
            }

            _verifyPaymentCoinIsApproved(
                securityPolicyId, 
                securityPolicy.enforcePaymentMethodWhitelist, 
                securityPolicy.enforcePricingConstraints,
                saleDetails.tokenAddress, 
                saleDetails.paymentCoin);
        }
        
        if (saleDetails.protocol == TokenProtocols.ERC1155) {
            if (saleDetails.amount == 0) {
                revert PaymentProcessor__AmountForERC1155SalesGreaterThanZero();
            }
        } else {
            if (saleDetails.amount != ONE) {
                revert PaymentProcessor__AmountForERC721SalesMustEqualOne();
            }
        }

        if (block.timestamp > saleDetails.listingExpiration) {
            revert PaymentProcessor__SaleHasExpired();
        }

        if (block.timestamp > saleDetails.offerExpiration) {
            revert PaymentProcessor__OfferHasExpired();
        }

        if (saleDetails.offerPrice < saleDetails.listingMinPrice) {
            revert PaymentProcessor__SalePriceBelowSellerApprovedMinimum();
        }

        if (saleDetails.marketplaceFeeNumerator + saleDetails.maxRoyaltyFeeNumerator > FEE_DENOMINATOR) {
            revert PaymentProcessor__MarketplaceAndRoyaltyFeesWillExceedSalePrice();
        }

        if (saleDetails.privateBuyer != address(0)) {
            if (saleDetails.buyer != saleDetails.privateBuyer) {
                revert PaymentProcessor__BuyerMustBeDesignatedPrivateBuyer();
            }
    
            if (securityPolicy.disablePrivateListings) {
                revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowPrivateListings();
            }
        }

        if (saleDetails.delegatedPurchaser != address(0)) {
            if (_msgSender() != saleDetails.delegatedPurchaser) {
                revert PaymentProcessor__CallerIsNotTheDelegatedPurchaser();
            }

            if(securityPolicy.disableDelegatedPurchases) {
                revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowDelegatedPurchases();
            }
        }

        if(securityPolicy.disableEIP1271Signatures) {
            if (saleDetails.seller.code.length > 0) {
                revert PaymentProcessor__EIP1271SignaturesAreDisabled();
            }

            if (saleDetails.buyer.code.length > 0) {
                revert PaymentProcessor__EIP1271SignaturesAreDisabled();
            }
        }

        if (securityPolicy.enforceExchangeWhitelist) {
            if (_msgSender() != tx.origin) {
                if (!exchangeWhitelist[securityPolicyId][_msgSender()]) {
                    revert PaymentProcessor__CallerIsNotWhitelistedMarketplace();
                }
            } else if (securityPolicy.disableExchangeWhitelistEOABypass) {
                if (!exchangeWhitelist[securityPolicyId][_msgSender()]) {
                    revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowEOACallers();
                }
            }
        }

        if (securityPolicy.enforcePricingConstraints) {
            if (saleDetails.paymentCoin == address(0)) {
                if(collectionPaymentCoins[saleDetails.tokenAddress] != address(0)) {
                    revert PaymentProcessor__NativeCurrencyIsNotAnApprovedPaymentMethod();
                }
            }

            _verifySalePriceInRange(
                saleDetails.tokenAddress, 
                saleDetails.tokenId, 
                saleDetails.amount, 
                saleDetails.offerPrice);
        }

        _verifySignedItemListing(saleDetails, signedListing);

        if (saleDetails.collectionLevelOffer) {
            _verifySignedCollectionOffer(saleDetails, signedOffer);
        } else {
            _verifySignedItemOffer(saleDetails, signedOffer);
        }

        MatchedOrder[] memory saleDetailsSingletonBatch = new MatchedOrder[](1);
        saleDetailsSingletonBatch[0] = saleDetails;

        bool[] memory unsuccessfulFills = _computeAndDistributeProceeds(
            ComputeAndDistributeProceedsArgs({
                pushPaymentGasLimit: securityPolicy.pushPaymentGasLimit,
                purchaser: saleDetails.delegatedPurchaser == address(0) ? saleDetails.buyer : saleDetails.delegatedPurchaser,
                paymentCoin: IERC20(saleDetails.paymentCoin),
                funcPayout: saleDetails.paymentCoin == address(0) ? _payoutNativeCurrency : _payoutCoinCurrency,
                funcDispenseToken: saleDetails.protocol == TokenProtocols.ERC1155 ? _dispenseERC1155Token : _dispenseERC721Token
            }),
            saleDetailsSingletonBatch
        );

        tokenDispensedSuccessfully = !unsuccessfulFills[0];

        if (tokenDispensedSuccessfully) {
            emit BuySingleListing(
                saleDetails.marketplace,
                saleDetails.tokenAddress,
                saleDetails.paymentCoin,
                saleDetails.buyer,
                saleDetails.seller,
                saleDetails.tokenId,
                saleDetails.amount,
                saleDetails.offerPrice);
        }
    }

    function _validateBundledOffer(
        uint256 securityPolicyId,
        SecurityPolicy storage securityPolicy,
        MatchedOrderBundleBase memory bundleDetails,
        Accumulator memory accumulator,
        SignatureECDSA memory signedOffer) private {
        if (bundleDetails.paymentCoin != address(0)) {
            if (msg.value > 0) {
                revert PaymentProcessor__CannotIncludeNativeFundsWhenPaymentMethodIsAnERC20Coin();
            }
    
            _verifyPaymentCoinIsApproved(
                securityPolicyId, 
                securityPolicy.enforcePaymentMethodWhitelist, 
                securityPolicy.enforcePricingConstraints,
                bundleDetails.tokenAddress, 
                bundleDetails.paymentCoin);
        } else {
            if (msg.value != bundleDetails.offerPrice) {
                revert PaymentProcessor__OfferPriceMustEqualSalePrice();
            }

            if (securityPolicy.enforcePricingConstraints) {
                if(collectionPaymentCoins[bundleDetails.tokenAddress] != address(0)) {
                    revert PaymentProcessor__NativeCurrencyIsNotAnApprovedPaymentMethod();
                }
            }
        }

        if (block.timestamp > bundleDetails.offerExpiration) {
            revert PaymentProcessor__OfferHasExpired();
        }

        if (bundleDetails.delegatedPurchaser != address(0)) {
            if (_msgSender() != bundleDetails.delegatedPurchaser) {
                revert PaymentProcessor__CallerIsNotTheDelegatedPurchaser();
            }

            if(securityPolicy.disableDelegatedPurchases) {
                revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowDelegatedPurchases();
            }
        }

        if(securityPolicy.disableEIP1271Signatures) {
            if (bundleDetails.buyer.code.length > 0) {
                revert PaymentProcessor__EIP1271SignaturesAreDisabled();
            }
        }

        if (securityPolicy.enforceExchangeWhitelist) {
            if (_msgSender() != tx.origin) {
                if (!exchangeWhitelist[securityPolicyId][_msgSender()]) {
                    revert PaymentProcessor__CallerIsNotWhitelistedMarketplace();
                }
            } else if (securityPolicy.disableExchangeWhitelistEOABypass) {
                if (!exchangeWhitelist[securityPolicyId][_msgSender()]) {
                    revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowEOACallers();
                }
            }
        }

        if (accumulator.sumListingPrices != bundleDetails.offerPrice) {
            revert PaymentProcessor__BundledOfferPriceMustEqualSumOfAllListingPrices();
        }

        _verifySignedOfferForBundledItems(
            keccak256(abi.encodePacked(accumulator.tokenIds)),
            keccak256(abi.encodePacked(accumulator.amounts)),
            keccak256(abi.encodePacked(accumulator.salePrices)),
            bundleDetails,
            signedOffer
        );
    }

    function _validateBundledItems(
        bool individualListings,
        SecurityPolicy storage securityPolicy,
        MatchedOrderBundleExtended memory bundleDetails,
        BundledItem[] memory bundledOfferItems,
        SignatureECDSA[] memory signedListings) 
        private returns (Accumulator memory accumulator, MatchedOrder[] memory saleDetailsBatch) {

        saleDetailsBatch = new MatchedOrder[](bundledOfferItems.length);
        accumulator = Accumulator({
            tokenIds: new uint256[](bundledOfferItems.length),
            amounts: new uint256[](bundledOfferItems.length),
            salePrices: new uint256[](bundledOfferItems.length),
            maxRoyaltyFeeNumerators: new uint256[](bundledOfferItems.length),
            sellers: new address[](bundledOfferItems.length),
            sumListingPrices: 0
        });

        for (uint256 i = 0; i < bundledOfferItems.length;) {

            address seller = bundleDetails.seller;
            uint256 listingNonce = bundleDetails.listingNonce;
            uint256 listingExpiration = bundleDetails.listingExpiration;

            if (individualListings) {
                seller = bundledOfferItems[i].seller;
                listingNonce = bundledOfferItems[i].listingNonce;
                listingExpiration = bundledOfferItems[i].listingExpiration;
            }
            
            MatchedOrder memory saleDetails = 
                MatchedOrder({
                    sellerAcceptedOffer: false,
                    collectionLevelOffer: false,
                    protocol: bundleDetails.bundleBase.protocol,
                    paymentCoin: bundleDetails.bundleBase.paymentCoin,
                    tokenAddress: bundleDetails.bundleBase.tokenAddress,
                    seller: seller,
                    privateBuyer: bundleDetails.bundleBase.privateBuyer,
                    buyer: bundleDetails.bundleBase.buyer,
                    delegatedPurchaser: bundleDetails.bundleBase.delegatedPurchaser,
                    marketplace: bundleDetails.bundleBase.marketplace,
                    marketplaceFeeNumerator: bundleDetails.bundleBase.marketplaceFeeNumerator,
                    maxRoyaltyFeeNumerator: bundledOfferItems[i].maxRoyaltyFeeNumerator,
                    listingNonce: listingNonce,
                    offerNonce: bundleDetails.bundleBase.offerNonce,
                    listingMinPrice: bundledOfferItems[i].itemPrice,
                    offerPrice: bundledOfferItems[i].itemPrice,
                    listingExpiration: listingExpiration,
                    offerExpiration: bundleDetails.bundleBase.offerExpiration,
                    tokenId: bundledOfferItems[i].tokenId,
                    amount: bundledOfferItems[i].amount
                });

            saleDetailsBatch[i] = saleDetails;

            accumulator.tokenIds[i] = saleDetails.tokenId;
            accumulator.amounts[i] = saleDetails.amount;
            accumulator.salePrices[i] = saleDetails.listingMinPrice;
            accumulator.maxRoyaltyFeeNumerators[i] = saleDetails.maxRoyaltyFeeNumerator;
            accumulator.sellers[i] = saleDetails.seller;
            accumulator.sumListingPrices += saleDetails.listingMinPrice;

            if (saleDetails.protocol == TokenProtocols.ERC1155) {
                if (saleDetails.amount == 0) {
                    revert PaymentProcessor__AmountForERC1155SalesGreaterThanZero();
                }
            } else {
                if (saleDetails.amount != ONE) {
                    revert PaymentProcessor__AmountForERC721SalesMustEqualOne();
                }
            }

            if (saleDetails.marketplaceFeeNumerator + saleDetails.maxRoyaltyFeeNumerator > FEE_DENOMINATOR) {
                revert PaymentProcessor__MarketplaceAndRoyaltyFeesWillExceedSalePrice();
            }

            if (securityPolicy.enforcePricingConstraints) {
                _verifySalePriceInRange(
                    saleDetails.tokenAddress, 
                    saleDetails.tokenId, 
                    saleDetails.amount, 
                    saleDetails.offerPrice);
            }
   
            if (individualListings) {
                if (block.timestamp > saleDetails.listingExpiration) {
                    revert PaymentProcessor__SaleHasExpired();
                }

                if (saleDetails.privateBuyer != address(0)) {
                    if (saleDetails.buyer != saleDetails.privateBuyer) {
                        revert PaymentProcessor__BuyerMustBeDesignatedPrivateBuyer();
                    }
    
                    if (securityPolicy.disablePrivateListings) {
                        revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowPrivateListings();
                    }
                }
        
                if(securityPolicy.disableEIP1271Signatures) {
                    if (saleDetails.seller.code.length > 0) {
                        revert PaymentProcessor__EIP1271SignaturesAreDisabled();
                    }
                }
    
                _verifySignedItemListing(saleDetails, signedListings[i]);
            }

            unchecked {
                ++i;
            }
        }

        if(!individualListings) {
            if (block.timestamp > bundleDetails.listingExpiration) {
                revert PaymentProcessor__SaleHasExpired();
            }

            if (bundleDetails.bundleBase.privateBuyer != address(0)) {
                if (bundleDetails.bundleBase.buyer != bundleDetails.bundleBase.privateBuyer) {
                    revert PaymentProcessor__BuyerMustBeDesignatedPrivateBuyer();
                }
    
                if (securityPolicy.disablePrivateListings) {
                    revert PaymentProcessor__TokenSecurityPolicyDoesNotAllowPrivateListings();
                }
            }

            if(securityPolicy.disableEIP1271Signatures) {
                if (bundleDetails.seller.code.length > 0) {
                    revert PaymentProcessor__EIP1271SignaturesAreDisabled();
                }
            }

            _verifySignedBundleListing(
                AccumulatorHashes({
                    tokenIdsKeccakHash: keccak256(abi.encodePacked(accumulator.tokenIds)),
                    amountsKeccakHash: keccak256(abi.encodePacked(accumulator.amounts)),
                    maxRoyaltyFeeNumeratorsKeccakHash: keccak256(abi.encodePacked(accumulator.maxRoyaltyFeeNumerators)),
                    itemPricesKeccakHash: keccak256(abi.encodePacked(accumulator.salePrices))
                }),
                bundleDetails, 
                signedListings[0]);
        }
    }

    function _verifySignedItemOffer(
        MatchedOrder memory saleDetails,
        SignatureECDSA memory signedOffer) private {
        bytes32 digest = 
            _hashTypedDataV4(keccak256(
                bytes.concat(
                    abi.encode(
                        OFFER_APPROVAL_HASH,
                        uint8(saleDetails.protocol),
                        saleDetails.marketplace,
                        saleDetails.marketplaceFeeNumerator,
                        saleDetails.delegatedPurchaser,
                        saleDetails.buyer,
                        saleDetails.tokenAddress,
                        saleDetails.tokenId,
                        saleDetails.amount,
                        saleDetails.offerPrice
                    ),
                    abi.encode(
                        saleDetails.offerExpiration,
                        saleDetails.offerNonce,
                        _checkAndInvalidateNonce(
                            saleDetails.marketplace, 
                            saleDetails.buyer, 
                            saleDetails.offerNonce,
                            false
                        ),
                        saleDetails.paymentCoin
                    )
                )
            )
        );

        if(saleDetails.buyer.code.length > 0) {
            _verifyEIP1271Signature(saleDetails.buyer, digest, signedOffer);
        } else if (saleDetails.buyer != ECDSA.recover(digest, signedOffer.v, signedOffer.r, signedOffer.s)) {
            revert PaymentProcessor__BuyerDidNotAuthorizePurchase();
        }
    }

    function _verifySignedCollectionOffer(
        MatchedOrder memory saleDetails,
        SignatureECDSA memory signedOffer) private {
        bytes32 digest = 
            _hashTypedDataV4(keccak256(
                bytes.concat(
                    abi.encode(
                        COLLECTION_OFFER_APPROVAL_HASH,
                        uint8(saleDetails.protocol),
                        saleDetails.collectionLevelOffer,
                        saleDetails.marketplace,
                        saleDetails.marketplaceFeeNumerator,
                        saleDetails.delegatedPurchaser,
                        saleDetails.buyer,
                        saleDetails.tokenAddress,
                        saleDetails.amount,
                        saleDetails.offerPrice
                    ),
                    abi.encode(
                        saleDetails.offerExpiration,
                        saleDetails.offerNonce,
                        _checkAndInvalidateNonce(
                            saleDetails.marketplace, 
                            saleDetails.buyer, 
                            saleDetails.offerNonce,
                            false
                        ),
                        saleDetails.paymentCoin
                    )
                )
            )
        );

        if(saleDetails.buyer.code.length > 0) {
            _verifyEIP1271Signature(saleDetails.buyer, digest, signedOffer);
        } else if (saleDetails.buyer != ECDSA.recover(digest, signedOffer.v, signedOffer.r, signedOffer.s)) {
            revert PaymentProcessor__BuyerDidNotAuthorizePurchase();
        }
    }

    function _verifySignedOfferForBundledItems(
        bytes32 tokenIdsKeccakHash,
        bytes32 amountsKeccakHash,
        bytes32 salePricesKeccakHash,
        MatchedOrderBundleBase memory bundledOfferDetails,
        SignatureECDSA memory signedOffer) private {

        bytes32 digest = 
            _hashTypedDataV4(keccak256(
                bytes.concat(
                    abi.encode(
                        BUNDLED_OFFER_APPROVAL_HASH,
                        uint8(bundledOfferDetails.protocol),
                        bundledOfferDetails.marketplace,
                        bundledOfferDetails.marketplaceFeeNumerator,
                        bundledOfferDetails.delegatedPurchaser,
                        bundledOfferDetails.buyer,
                        bundledOfferDetails.tokenAddress,
                        bundledOfferDetails.offerPrice
                    ),
                    abi.encode(
                        bundledOfferDetails.offerExpiration,
                        bundledOfferDetails.offerNonce,
                        _checkAndInvalidateNonce(
                            bundledOfferDetails.marketplace, 
                            bundledOfferDetails.buyer, 
                            bundledOfferDetails.offerNonce,
                            false
                        ),
                        bundledOfferDetails.paymentCoin,
                        tokenIdsKeccakHash,
                        amountsKeccakHash,
                        salePricesKeccakHash
                    )
                )
            )
        );

        if(bundledOfferDetails.buyer.code.length > 0) {
            _verifyEIP1271Signature(bundledOfferDetails.buyer, digest, signedOffer);
        } else if (bundledOfferDetails.buyer != ECDSA.recover(digest, signedOffer.v, signedOffer.r, signedOffer.s)) {
            revert PaymentProcessor__BuyerDidNotAuthorizePurchase();
        }
    }

    function _verifySignedBundleListing(
        AccumulatorHashes memory accumulatorHashes,
        MatchedOrderBundleExtended memory bundleDetails,
        SignatureECDSA memory signedListing) private {

        bytes32 digest = 
            _hashTypedDataV4(keccak256(
                bytes.concat(
                    abi.encode(
                        BUNDLED_SALE_APPROVAL_HASH,
                        uint8(bundleDetails.bundleBase.protocol),
                        bundleDetails.bundleBase.marketplace,
                        bundleDetails.bundleBase.marketplaceFeeNumerator,
                        bundleDetails.bundleBase.privateBuyer,
                        bundleDetails.seller,
                        bundleDetails.bundleBase.tokenAddress
                    ),
                    abi.encode(
                        bundleDetails.listingExpiration,
                        bundleDetails.listingNonce,
                        _checkAndInvalidateNonce(
                            bundleDetails.bundleBase.marketplace, 
                            bundleDetails.seller, 
                            bundleDetails.listingNonce,
                            false
                        ),
                        bundleDetails.bundleBase.paymentCoin,
                        accumulatorHashes.tokenIdsKeccakHash,
                        accumulatorHashes.amountsKeccakHash,
                        accumulatorHashes.maxRoyaltyFeeNumeratorsKeccakHash,
                        accumulatorHashes.itemPricesKeccakHash
                    )
                )
            )
        );

        if(bundleDetails.seller.code.length > 0) {
            _verifyEIP1271Signature(bundleDetails.seller, digest, signedListing);
        } else if (bundleDetails.seller != ECDSA.recover(digest, signedListing.v, signedListing.r, signedListing.s)) {
            revert PaymentProcessor__SellerDidNotAuthorizeSale();
        }
    }

    function _verifySignedItemListing(
        MatchedOrder memory saleDetails,
        SignatureECDSA memory signedListing) private {
        bytes32 digest = 
            _hashTypedDataV4(keccak256(
                bytes.concat(
                    abi.encode(
                        SALE_APPROVAL_HASH,
                        uint8(saleDetails.protocol),
                        saleDetails.sellerAcceptedOffer,
                        saleDetails.marketplace,
                        saleDetails.marketplaceFeeNumerator,
                        saleDetails.maxRoyaltyFeeNumerator,
                        saleDetails.privateBuyer
                    ),
                    abi.encode(
                        saleDetails.seller,
                        saleDetails.tokenAddress,
                        saleDetails.tokenId,
                        saleDetails.amount,
                        saleDetails.listingMinPrice,
                        saleDetails.listingExpiration,
                        saleDetails.listingNonce,
                        _checkAndInvalidateNonce(
                            saleDetails.marketplace, 
                            saleDetails.seller, 
                            saleDetails.listingNonce,
                            false
                        ),
                        saleDetails.paymentCoin
                    )
                )
            )
        );

        if(saleDetails.seller.code.length > 0) {
            _verifyEIP1271Signature(saleDetails.seller, digest, signedListing);
        } else if (saleDetails.seller != ECDSA.recover(digest, signedListing.v, signedListing.r, signedListing.s)) {
            revert PaymentProcessor__SellerDidNotAuthorizeSale();
        }
    }

    function _checkAndInvalidateNonce(
        address marketplace, 
        address account, 
        uint256 nonce, 
        bool wasCancellation) private returns (uint256) {

        mapping(uint256 => uint256) storage ptrInvalidatedSignatureBitmap =
            invalidatedSignatures[keccak256(abi.encodePacked(marketplace, account))];

        unchecked {
            uint256 slot = nonce / 256;
            uint256 offset = nonce % 256;
            uint256 slotValue = ptrInvalidatedSignatureBitmap[slot];

            if (((slotValue >> offset) & ONE) == ONE) {
                revert PaymentProcessor__SignatureAlreadyUsedOrRevoked();
            }

            ptrInvalidatedSignatureBitmap[slot] = (slotValue | ONE << offset);
        }

        emit NonceInvalidated(nonce, account, marketplace, wasCancellation);

        return masterNonces[account];
    }

    function _computeAndDistributeProceeds(
        ComputeAndDistributeProceedsArgs memory args,
        MatchedOrder[] memory saleDetailsBatch) private returns (bool[] memory unsuccessfulFills) {

        unsuccessfulFills = new bool[](saleDetailsBatch.length);

        PayoutsAccumulator memory accumulator = PayoutsAccumulator({
            lastSeller: address(0),
            lastMarketplace: address(0),
            lastRoyaltyRecipient: address(0),
            accumulatedSellerProceeds: 0,
            accumulatedMarketplaceProceeds: 0,
            accumulatedRoyaltyProceeds: 0
        });

        for (uint256 i = 0; i < saleDetailsBatch.length;) {
            MatchedOrder memory saleDetails = saleDetailsBatch[i];

            bool successfullyDispensedToken = 
                args.funcDispenseToken(
                    saleDetails.seller, 
                    saleDetails.buyer, 
                    saleDetails.tokenAddress, 
                    saleDetails.tokenId, 
                    saleDetails.amount);

            if (!successfullyDispensedToken) {
                if (address(args.paymentCoin) == address(0)) {
                    revert PaymentProcessor__DispensingTokenWasUnsuccessful();
                }

                unsuccessfulFills[i] = true;
            } else {
                SplitProceeds memory proceeds =
                    _computePaymentSplits(
                        saleDetails.offerPrice,
                        saleDetails.tokenAddress,
                        saleDetails.tokenId,
                        saleDetails.marketplace,
                        saleDetails.marketplaceFeeNumerator,
                        saleDetails.maxRoyaltyFeeNumerator
                    );
    
                if (proceeds.royaltyRecipient != accumulator.lastRoyaltyRecipient) {
                    if(accumulator.accumulatedRoyaltyProceeds > 0) {
                        args.funcPayout(accumulator.lastRoyaltyRecipient, args.purchaser, args.paymentCoin, accumulator.accumulatedRoyaltyProceeds, args.pushPaymentGasLimit);
                    }
    
                    accumulator.lastRoyaltyRecipient = proceeds.royaltyRecipient;
                    accumulator.accumulatedRoyaltyProceeds = 0;
                }
    
                if (saleDetails.marketplace != accumulator.lastMarketplace) {
                    if(accumulator.accumulatedMarketplaceProceeds > 0) {
                        args.funcPayout(accumulator.lastMarketplace, args.purchaser, args.paymentCoin, accumulator.accumulatedMarketplaceProceeds, args.pushPaymentGasLimit);
                    }
    
                    accumulator.lastMarketplace = saleDetails.marketplace;
                    accumulator.accumulatedMarketplaceProceeds = 0;
                }
    
                if (saleDetails.seller != accumulator.lastSeller) {
                    if(accumulator.accumulatedSellerProceeds > 0) {
                        args.funcPayout(accumulator.lastSeller, args.purchaser, args.paymentCoin, accumulator.accumulatedSellerProceeds, args.pushPaymentGasLimit);
                    }
    
                    accumulator.lastSeller = saleDetails.seller;
                    accumulator.accumulatedSellerProceeds = 0;
                }

                unchecked {
                    accumulator.accumulatedRoyaltyProceeds += proceeds.royaltyProceeds;
                    accumulator.accumulatedMarketplaceProceeds += proceeds.marketplaceProceeds;
                    accumulator.accumulatedSellerProceeds += proceeds.sellerProceeds;
                }
            }

            unchecked {
                ++i;
            }
        }

        if(accumulator.accumulatedRoyaltyProceeds > 0) {
            args.funcPayout(accumulator.lastRoyaltyRecipient, args.purchaser, args.paymentCoin, accumulator.accumulatedRoyaltyProceeds, args.pushPaymentGasLimit);
        }

        if(accumulator.accumulatedMarketplaceProceeds > 0) {
            args.funcPayout(accumulator.lastMarketplace, args.purchaser, args.paymentCoin, accumulator.accumulatedMarketplaceProceeds, args.pushPaymentGasLimit);
        }

        if(accumulator.accumulatedSellerProceeds > 0) {
            args.funcPayout(accumulator.lastSeller, args.purchaser, args.paymentCoin, accumulator.accumulatedSellerProceeds, args.pushPaymentGasLimit);
        }

        return unsuccessfulFills;
    }

    function _pushProceeds(address to, uint256 proceeds, uint256 pushPaymentGasLimit_) private {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(pushPaymentGasLimit_, to, proceeds, 0, 0, 0, 0)
        }

        if (!success) {
            revert PaymentProcessor__FailedToTransferProceeds();
        }
    }

    function _computePaymentSplits(
        uint256 salePrice,
        address tokenAddress,
        uint256 tokenId,
        address marketplaceFeeRecipient,
        uint256 marketplaceFeeNumerator,
        uint256 maxRoyaltyFeeNumerator) private view returns (SplitProceeds memory proceeds) {

        proceeds.sellerProceeds = salePrice;

        try IERC2981(tokenAddress).royaltyInfo(
            tokenId, 
            salePrice) 
            returns (address royaltyReceiver, uint256 royaltyAmount) {
            if (royaltyReceiver == address(0)) {
                royaltyAmount = 0;
            }

            if (royaltyAmount > 0) {
                if (royaltyAmount > (salePrice * maxRoyaltyFeeNumerator) / FEE_DENOMINATOR) {
                    revert PaymentProcessor__OnchainRoyaltiesExceedMaximumApprovedRoyaltyFee();
                }

                proceeds.royaltyRecipient = royaltyReceiver;
                proceeds.royaltyProceeds = royaltyAmount;

                unchecked {
                    proceeds.sellerProceeds -= royaltyAmount;
                }
            }
        } catch (bytes memory) {}

        proceeds.marketplaceProceeds =
            marketplaceFeeRecipient != address(0) ? (salePrice * marketplaceFeeNumerator) / FEE_DENOMINATOR : 0;
        if (proceeds.marketplaceProceeds > 0) {
            unchecked {
                proceeds.sellerProceeds -= proceeds.marketplaceProceeds;
            }
        }
    }

    function _getTokenSecurityPolicy(address tokenAddress) private view returns (uint256, SecurityPolicy storage) {
        uint256 securityPolicyId = tokenSecurityPolicies[tokenAddress];
        SecurityPolicy storage securityPolicy = securityPolicies[securityPolicyId];
        return (securityPolicyId, securityPolicy);
    }

    function _requireCallerOwnsSecurityPolicy(uint256 securityPolicyId) private view {
        if(_msgSender() != securityPolicies[securityPolicyId].policyOwner) {
            revert PaymentProcessor__CallerDoesNotOwnSecurityPolicy();
        }
    }

    function _getFloorAndCeilingPrices(
        address tokenAddress, 
        uint256 tokenId) private view returns (uint256, uint256) {

        PricingBounds memory tokenLevelPricingBounds = tokenPricingBounds[tokenAddress][tokenId];
        if (tokenLevelPricingBounds.isEnabled) {
            return (tokenLevelPricingBounds.floorPrice, tokenLevelPricingBounds.ceilingPrice);
        } else {
            PricingBounds memory collectionLevelPricingBounds = collectionPricingBounds[tokenAddress];
            if (collectionLevelPricingBounds.isEnabled) {
                return (collectionLevelPricingBounds.floorPrice, collectionLevelPricingBounds.ceilingPrice);
            }
        }

        return (0, type(uint256).max);
    }

    function _verifySalePriceInRange(
        address tokenAddress, 
        uint256 tokenId, 
        uint256 amount, 
        uint256 salePrice) private view {

        uint256 salePricePerUnit = salePrice / amount;

        (uint256 floorPrice, uint256 ceilingPrice) = _getFloorAndCeilingPrices(tokenAddress, tokenId);

        if(salePricePerUnit < floorPrice) {
            revert PaymentProcessor__SalePriceBelowMinimumFloor();
        }

        if(salePricePerUnit > ceilingPrice) {
            revert PaymentProcessor__SalePriceAboveMaximumCeiling();
        }
    }

    function _verifyEIP1271Signature(
        address signer, 
        bytes32 hash, 
        SignatureECDSA memory signatureComponents) private view {
        bool isValidSignatureNow;
        
        try IERC1271(signer).isValidSignature(
            hash, 
            abi.encodePacked(signatureComponents.r, signatureComponents.s, signatureComponents.v)) 
            returns (bytes4 magicValue) {
            isValidSignatureNow = magicValue == IERC1271.isValidSignature.selector;
        } catch {}

        if (!isValidSignatureNow) {
            revert PaymentProcessor__EIP1271SignatureInvalid();
        }
    }
}

File 2 of 23 : IOwnable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IOwnable {
    function owner() external view returns (address);
}

File 3 of 23 : IPaymentProcessor.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "./PaymentProcessorDataTypes.sol";
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
 * @title IPaymentProcessor
 * @author Limit Break, Inc.
 * @notice Interface definition for payment processor contracts.
 */
interface IPaymentProcessor is IERC165 {

    /// @notice Emitted when a bundle of ERC-721 tokens is successfully purchased using `buyBundledListing`
    event BuyBundledListingERC721(
        address indexed marketplace,
        address indexed tokenAddress,
        address indexed paymentCoin,
        address buyer,
        address seller,
        bool[] unsuccessfulFills,
        uint256[] tokenIds,
        uint256[] salePrices);

    /// @notice Emitted when a bundle of ERC-1155 tokens is successfully purchased using `buyBundledListing`
    event BuyBundledListingERC1155(
        address indexed marketplace,
        address indexed tokenAddress,
        address indexed paymentCoin,
        address buyer,
        address seller,
        bool[] unsuccessfulFills,
        uint256[] tokenIds,
        uint256[] amounts,
        uint256[] salePrices);

    /// @notice Emitted for each token successfully purchased using either `buySingleLising` or `buyBatchOfListings`
    event BuySingleListing(
        address indexed marketplace,
        address indexed tokenAddress,
        address indexed paymentCoin,
        address buyer,
        address seller,
        uint256 tokenId,
        uint256 amount,
        uint256 salePrice);

    /// @notice Emitted when a security policy is either created or modified
    event CreatedOrUpdatedSecurityPolicy(
        uint256 indexed securityPolicyId, 
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string policyName);

    /// @notice Emitted when an address is added to the exchange whitelist for a security policy
    event ExchangeAddedToWhitelist(uint256 indexed securityPolicyId, address indexed exchange);

    /// @notice Emitted when an address is removed from the exchange whitelist for a security policy
    event ExchangeRemovedFromWhitelist(uint256 indexed securityPolicyId, address indexed exchange);

    /// @notice Emitted when a user revokes all of their existing listings or offers that share the master nonce.
    event MasterNonceInvalidated(uint256 indexed nonce, address indexed account);

    /// @notice Emitted when a user revokes a single listing or offer nonce for a specific marketplace.
    event NonceInvalidated(
        uint256 indexed nonce, 
        address indexed account, 
        address indexed marketplace, 
        bool wasCancellation);

    /// @notice Emitted when a coin is added to the approved coins mapping for a security policy
    event PaymentMethodAddedToWhitelist(uint256 indexed securityPolicyId, address indexed coin);

    /// @notice Emitted when a coin is removed from the approved coins mapping for a security policy
    event PaymentMethodRemovedFromWhitelist(uint256 indexed securityPolicyId, address indexed coin);

    /// @notice Emitted when the ownership of a security policy is transferred to a new account
    event SecurityPolicyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice Emitted when a collection of ERC-721 tokens is successfully swept using `sweepCollection`
    event SweepCollectionERC721(
        address indexed marketplace,
        address indexed tokenAddress,
        address indexed paymentCoin,
        address buyer,
        bool[] unsuccessfulFills,
        address[] sellers,
        uint256[] tokenIds,
        uint256[] salePrices);

    /// @notice Emitted when a collection of ERC-1155 tokens is successfully swept using `sweepCollection`
    event SweepCollectionERC1155(
        address indexed marketplace,
        address indexed tokenAddress,
        address indexed paymentCoin,
        address buyer,
        bool[] unsuccessfulFills,
        address[] sellers,
        uint256[] tokenIds,
        uint256[] amounts,
        uint256[] salePrices);

    /// @notice Emitted whenever the designated security policy id changes for a collection.
    event UpdatedCollectionSecurityPolicy(address indexed tokenAddress, uint256 indexed securityPolicyId);

    /// @notice Emitted whenever the supported ERC-20 payment is set for price-constrained collections.
    event UpdatedCollectionPaymentCoin(address indexed tokenAddress, address indexed paymentCoin);

    /// @notice Emitted whenever pricing bounds change at a collection level for price-constrained collections.
    event UpdatedCollectionLevelPricingBoundaries(
        address indexed tokenAddress, 
        uint256 floorPrice, 
        uint256 ceilingPrice);

    /// @notice Emitted whenever pricing bounds change at a token level for price-constrained collections.
    event UpdatedTokenLevelPricingBoundaries(
        address indexed tokenAddress, 
        uint256 indexed tokenId, 
        uint256 floorPrice, 
        uint256 ceilingPrice);
    
    function createSecurityPolicy(
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string calldata registryName) external returns (uint256);

    function updateSecurityPolicy(
        uint256 securityPolicyId,
        bool enforceExchangeWhitelist,
        bool enforcePaymentMethodWhitelist,
        bool enforcePricingConstraints,
        bool disablePrivateListings,
        bool disableDelegatedPurchases,
        bool disableEIP1271Signatures,
        bool disableExchangeWhitelistEOABypass,
        uint32 pushPaymentGasLimit,
        string calldata registryName) external;

    function transferSecurityPolicyOwnership(uint256 securityPolicyId, address newOwner) external;
    function renounceSecurityPolicyOwnership(uint256 securityPolicyId) external;
    function setCollectionSecurityPolicy(address tokenAddress, uint256 securityPolicyId) external;
    function setCollectionPaymentCoin(address tokenAddress, address coin) external;
    function setCollectionPricingBounds(address tokenAddress, PricingBounds calldata pricingBounds) external;

    function setTokenPricingBounds(
        address tokenAddress, 
        uint256[] calldata tokenIds, 
        PricingBounds[] calldata pricingBounds) external;

    function whitelistExchange(uint256 securityPolicyId, address account) external;
    function unwhitelistExchange(uint256 securityPolicyId, address account) external;
    function whitelistPaymentMethod(uint256 securityPolicyId, address coin) external;
    function unwhitelistPaymentMethod(uint256 securityPolicyId, address coin) external;
    function revokeMasterNonce() external;
    function revokeSingleNonce(address marketplace, uint256 nonce) external;

    function buySingleListing(
        MatchedOrder memory saleDetails, 
        SignatureECDSA memory signedListing, 
        SignatureECDSA memory signedOffer
    ) external payable;

    function buyBatchOfListings(
        MatchedOrder[] calldata saleDetailsArray,
        SignatureECDSA[] calldata signedListings,
        SignatureECDSA[] calldata signedOffers
    ) external payable;

    function buyBundledListing(
        SignatureECDSA memory signedListing,
        SignatureECDSA memory signedOffer,
        MatchedOrderBundleExtended memory bundleDetails,
        BundledItem[] calldata bundleItems) external payable;

    function sweepCollection(
        SignatureECDSA memory signedOffer,
        MatchedOrderBundleBase memory bundleDetails,
        BundledItem[] calldata bundleItems,
        SignatureECDSA[] calldata signedListings) external payable;

    function getDomainSeparator() external view returns (bytes32);
    function getSecurityPolicy(uint256 securityPolicyId) external view returns (SecurityPolicy memory);
    function isWhitelisted(uint256 securityPolicyId, address account) external view returns (bool);
    function isPaymentMethodApproved(uint256 securityPolicyId, address coin) external view returns (bool);
    function getTokenSecurityPolicyId(address collectionAddress) external view returns (uint256);
    function isCollectionPricingImmutable(address tokenAddress) external view returns (bool);
    function isTokenPricingImmutable(address tokenAddress, uint256 tokenId) external view returns (bool);
    function getFloorPrice(address tokenAddress, uint256 tokenId) external view returns (uint256);
    function getCeilingPrice(address tokenAddress, uint256 tokenId) external view returns (uint256);
}

File 4 of 23 : IAccessControl.sol
// 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;
}

File 5 of 23 : IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 6 of 23 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 8 of 23 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 9 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 10 of 23 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 11 of 23 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.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 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'
        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) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @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
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 12 of 23 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

File 13 of 23 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 14 of 23 : ERC165.sol
// 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;
    }
}

File 15 of 23 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 16 of 23 : draft-EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;
    address private immutable _CACHED_THIS;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _CACHED_THIS = address(this);
        _TYPE_HASH = typeHash;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}

File 17 of 23 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 1;
        }

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

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

File 18 of 23 : PaymentProcessorDataTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

enum TokenProtocols { ERC721, ERC1155 }

/**
 * @dev The `v`, `r`, and `s` components of an ECDSA signature.  For more information
 *      [refer to this article](https://medium.com/mycrypto/the-magic-of-digital-signatures-on-ethereum-98fe184dc9c7).
 */
struct SignatureECDSA {
    uint8 v;
    bytes32 r;
    bytes32 s;
}

/**
 * @dev This struct is used as input to `buySingleListing` and `buyBatchOfListings` calls after an exchange matches
 * @dev a buyer and seller.
 *
 * @dev **sellerAcceptedOffer**: Denotes that the transaction was initiated by the seller account by accepting an offer.
 * @dev When true, ETH/native payments are not accepted, and only ERC-20 payment methods can be used.
 * @dev **collectionLevelOffer**: Denotes that the offer that was accepted was at the collection level.  When `true`,
 * @dev the Buyer should be prompted to sign the the collection offer approval stucture.  When false, the Buyer should
 * @dev prompted to sign the offer approval structure.
 * @dev **protocol**: 0 for ERC-721 or 1 for ERC-1155.  See `TokenProtocols`.
 * @dev **paymentCoin**: `address(0)` denotes native currency sale.  Otherwise ERC-20 payment coin address.
 * @dev **tokenAddress**: The smart contract address of the ERC-721 or ERC-1155 token being sold.
 * @dev **seller**: The seller/current owner of the token.
 * @dev **privateBuyer**: `address(0)` denotes a listing available to any buyer.  Otherwise, this denotes the privately
 * @dev designated buyer.
 * @dev **buyer**: The buyer/new owner of the token.
 * @dev **delegatedPurchaser**: Allows a buyer to delegate an address to buy a token on their behalf.  This would allow
 * @dev a warm burner wallet to purchase tokens and allow them to be received in a cold wallet, for example.
 * @dev **marketplace**: The address designated to receive marketplace fees, if applicable.
 * @dev **marketplaceFeeNumerator**: Marketplace fee percentage.  Denominator is 10,000.
 * @dev 0.5% fee numerator is 50, 1% fee numerator is 100, 10% fee numerator is 1,000 and so on.
 * @dev **maxRoyaltyFeeNumerator**: Maximum approved royalty fee percentage.  Denominator is 10,000.
 * @dev 0.5% fee numerator is 50, 1% fee numerator is 100, 10% fee numerator is 1,000 and so on.
 * @dev Marketplaces are responsible to query EIP-2981 royalty info from the NFT contract when presenting this
 * @dev for signature.
 * @dev **listingNonce**: The nonce the seller signed in the listing.
 * @dev **offerNonce**: The nonce the buyer signed in the offer.
 * @dev **listingMinPrice**: The minimum price the seller signed off on, in wei.  Buyer can buy above, 
 * @dev but not below the seller-approved minimum price.
 * @dev **offerPrice**: The sale price of the matched order, in wei.  Buyer signs off on the final offer price.
 * @dev **listingExpiration**: The timestamp at which the listing expires.
 * @dev **offerExpiration**: The timestamp at which the offer expires.
 * @dev **tokenId**: The id of the token being sold.  For ERC-721 tokens, this is the specific NFT token id.  
 * @dev For ERC-1155 tokens, this denotes the token type id.
 * @dev **amount**: The number of tokens being sold.  For ERC-721 tokens, this must always be `1`.
 * @dev For ERC-1155 tokens where balances are transferred, this must be greater than or equal to `1`.
 */
struct MatchedOrder {
    bool sellerAcceptedOffer;
    bool collectionLevelOffer;
    TokenProtocols protocol;
    address paymentCoin;
    address tokenAddress;
    address seller;
    address privateBuyer;
    address buyer;
    address delegatedPurchaser;
    address marketplace;
    uint256 marketplaceFeeNumerator;
    uint256 maxRoyaltyFeeNumerator;
    uint256 listingNonce;
    uint256 offerNonce;
    uint256 listingMinPrice;
    uint256 offerPrice;
    uint256 listingExpiration;
    uint256 offerExpiration;
    uint256 tokenId;
    uint256 amount;
}

/**
 * @dev This struct is used as input to `buyBundledListing` calls after an exchange matches a buyer and seller.
 * @dev Wraps `MatchedOrderBundleBase` and adds seller, listing nonce and listing expiration.
 *
 * @dev **bundleBase**: Includes all fields from `MatchedOrderBundleBase`.
 * @dev **seller**: The seller/current owner of all the tokens in a bundled listing.
 * @dev **listingNonce**: The nonce the seller signed in the listing. Only one nonce is required approving the sale
 * @dev of multiple tokens from one collection.
 * @dev **listingExpiration**: The timestamp at which the listing expires.
 */
struct MatchedOrderBundleExtended {
    MatchedOrderBundleBase bundleBase; 
    address seller;
    uint256 listingNonce;
    uint256 listingExpiration;
}

/**
 * @dev This struct is used as input to `sweepCollection` calls after an exchange matches multiple individual listings
 * @dev with a single buyer.
 *
 * @dev **protocol**: 0 for ERC-721 or 1 for ERC-1155.  See `TokenProtocols`.
 * @dev **paymentCoin**: `address(0)` denotes native currency sale.  Otherwise ERC-20 payment coin address.
 * @dev **tokenAddress**: The smart contract address of the ERC-721 or ERC-1155 token being sold.
 * @dev **privateBuyer**: `address(0)` denotes a listing available to any buyer.  Otherwise, this denotes the privately
 * @dev designated buyer.
 * @dev **buyer**: The buyer/new owner of the token.
 * @dev **delegatedPurchaser**: Allows a buyer to delegate an address to buy a token on their behalf.  This would allow
 * @dev a warm burner wallet to purchase tokens and allow them to be received in a cold wallet, for example.
 * @dev **marketplace**: The address designated to receive marketplace fees, if applicable.
 * @dev **marketplaceFeeNumerator**: Marketplace fee percentage.  Denominator is 10,000.
 * @dev 0.5% fee numerator is 50, 1% fee numerator is 100, 10% fee numerator is 1,000 and so on.
 * @dev **offerNonce**: The nonce the buyer signed in the offer.  Only one nonce is required approving the purchase
 * @dev of multiple tokens from one collection.
 * @dev **offerPrice**: The sale price of the entire order, in wei.  Buyer signs off on the final offer price.
 * @dev **offerExpiration**: The timestamp at which the offer expires.
 */
struct MatchedOrderBundleBase {
    TokenProtocols protocol;
    address paymentCoin;
    address tokenAddress;
    address privateBuyer;
    address buyer;
    address delegatedPurchaser;
    address marketplace;
    uint256 marketplaceFeeNumerator;
    uint256 offerNonce;
    uint256 offerPrice;
    uint256 offerExpiration;
}

/**
 * @dev This struct is used as input to `sweepCollection` and `buyBundledListing` calls.
 * @dev These fields are required per individual item listed.
 *
 * @dev **tokenId**: The id of the token being sold.  For ERC-721 tokens, this is the specific NFT token id.  
 * @dev For ERC-1155 tokens, this denotes the token type id.
 * @dev **amount**: The number of tokens being sold.  For ERC-721 tokens, this must always be `1`.
 * @dev For ERC-1155 tokens where balances are transferred, this must be greater than or equal to `1`.
 * @dev **maxRoyaltyFeeNumerator**: Maximum approved royalty fee percentage.  Denominator is 10,000.
 * @dev 0.5% fee numerator is 50, 1% fee numerator is 100, 10% fee numerator is 1,000 and so on.
 * @dev Marketplaces are responsible to query EIP-2981 royalty info from the NFT contract when presenting this
 * @dev for signature.
 * @dev **itemPrice**: The exact price the seller signed off on for an individual item, in wei. 
 * @dev Purchase price for the item must be exactly the listing item price.
 * @dev **listingNonce**: The nonce the seller signed in the listing for an individual item.  This should be set
 * @dev for collection sweep transactions, but it should be zero for bundled listings, as the listing nonce is global
 * @dev in that case.
 * @dev **listingExpiration**: The timestamp at which an individual listing expires. This should be set
 * @dev for collection sweep transactions, but it should be zero for bundled listings, as the listing nonce is global
 * @dev in that case.
 * @dev **seller**: The seller/current owner of the token. This should be set
 * @dev for collection sweep transactions, but it should be zero for bundled listings, as the listing nonce is global
 * @dev in that case.
 */
struct BundledItem {
    uint256 tokenId;
    uint256 amount;
    uint256 maxRoyaltyFeeNumerator;
    uint256 itemPrice;
    uint256 listingNonce;
    uint256 listingExpiration;
    address seller;
}

/**
 * @dev This struct is used to define the marketplace behavior and constraints, giving creators flexibility to define
 *      marketplace behavior(s).
 *
 * @dev **enforceExchangeWhitelist**: Requires `buy` calls from smart contracts to be whitelisted.
 * @dev **enforcePaymentMethodWhitelist**: Requires ERC-20 payment coins for `buy` calls to be whitelisted as an 
 * @dev approved payment method.
 * @dev **enforcePricingConstraints**: Allows the creator to specify exactly one approved payment method, a minimum
 * @dev floor price and a maximum ceiling price.  When true, this value supercedes `enforcePaymentMethodWhitelist`.
 * @dev **disablePrivateListings**: Disables private sales.
 * @dev **disableDelegatedPurchases**: Disables purchases by delegated accounts on behalf of buyers.
 * @dev **disableEIP1271Signatures**: Disables sales and purchases using multi-sig wallets that implement EIP-1271.
 * @dev Enforces that buyers and sellers are EOAs.
 * @dev **disableExchangeWhitelistEOABypass**: Has no effect when `enforceExchangeWhitelist` is false.
 * @dev When exchange whitelist is enforced, this disables calls from EOAs, effectively requiring purchases to be
 * @dev composed by whitelisted 3rd party exchange contracts.
 * @dev **pushPaymentGasLimit**: This is the amount of gas to forward when pushing native payments.
 * @dev At the time this contract was written, 2300 gas is the recommended amount, but should costs of EVM opcodes
 * @dev change in the future, this field can be used to increase or decrease the amount of forwarded gas.  Care should
 * @dev be taken to ensure not enough gas is forwarded to result in possible re-entrancy.
 * @dev **policyOwner**: The account that has access to modify a security policy or update the exchange whitelist
 * @dev or approved payment list for the security policy.
 */
struct SecurityPolicy {
    bool enforceExchangeWhitelist;
    bool enforcePaymentMethodWhitelist;
    bool enforcePricingConstraints;
    bool disablePrivateListings;
    bool disableDelegatedPurchases;
    bool disableEIP1271Signatures;
    bool disableExchangeWhitelistEOABypass;
    uint32 pushPaymentGasLimit;
    address policyOwner;
}

/**
 * @dev This struct is used to define pricing constraints for a collection or individual token.
 *
 * @dev **isEnabled**: When true, this indicates that pricing constraints are set for the collection or token.
 * @dev **isImmutable**: When true, this indicates that pricing constraints are immutable and cannot be changed.
 * @dev **floorPrice**: The minimum price for a token or collection.  This is only enforced when 
 * @dev `enforcePricingConstraints` is `true`.
 * @dev **ceilingPrice**: The maximum price for a token or collection.  This is only enforced when
 * @dev `enforcePricingConstraints` is `true`.
 */
struct PricingBounds {
    bool isEnabled;
    bool isImmutable;
    uint256 floorPrice;
    uint256 ceilingPrice;
}

/** 
 * @dev Internal contract use only - this is not a public-facing struct
 */
struct SplitProceeds {
    address royaltyRecipient;
    uint256 royaltyProceeds;
    uint256 marketplaceProceeds;
    uint256 sellerProceeds;
}

/** 
 * @dev Internal contract use only - this is not a public-facing struct
 */
struct Accumulator {
    uint256[] tokenIds;
    uint256[] amounts;
    uint256[] salePrices;
    uint256[] maxRoyaltyFeeNumerators;
    address[] sellers;
    uint256 sumListingPrices;
}

/** 
 * @dev Internal contract use only - this is not a public-facing struct
 */
struct AccumulatorHashes {
    bytes32 tokenIdsKeccakHash;
    bytes32 amountsKeccakHash;
    bytes32 maxRoyaltyFeeNumeratorsKeccakHash;
    bytes32 itemPricesKeccakHash;
}

/** 
 * @dev Internal contract use only - this is not a public-facing struct
 */
struct PayoutsAccumulator {
    address lastSeller;
    address lastMarketplace;
    address lastRoyaltyRecipient;
    uint256 accumulatedSellerProceeds;
    uint256 accumulatedMarketplaceProceeds;
    uint256 accumulatedRoyaltyProceeds;
}

/**
 * @dev Internal contract use only - this is not a public-facing struct
 */
struct ComputeAndDistributeProceedsArgs {
    uint256 pushPaymentGasLimit;
    address purchaser;
    IERC20 paymentCoin;
    function(address,address,IERC20,uint256,uint256) funcPayout;
    function(address,address,address,uint256,uint256) returns (bool) funcDispenseToken;
}

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

pragma solidity ^0.8.0;

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

File 20 of 23 : Context.sol
// 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;
    }
}

File 21 of 23 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 22 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

        (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");

        (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");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 23 of 23 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

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

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

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

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

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

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

Settings
{
  "remappings": [
    "@ensdomains/=node_modules/@ensdomains/",
    "@limitbreak/=node_modules/@limitbreak/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "forge-std/=lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "@rari-capital/solmate/=node_modules/@rari-capital/solmate/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 600
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"defaultContractOwner_","type":"address"},{"internalType":"uint32","name":"defaultPushPaymentGasLimit_","type":"uint32"},{"internalType":"address[]","name":"defaultPaymentMethods","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"PaymentProcessor__AddressCannotBeZero","type":"error"},{"inputs":[],"name":"PaymentProcessor__AmountForERC1155SalesGreaterThanZero","type":"error"},{"inputs":[],"name":"PaymentProcessor__AmountForERC721SalesMustEqualOne","type":"error"},{"inputs":[],"name":"PaymentProcessor__BundledOfferPriceMustEqualSumOfAllListingPrices","type":"error"},{"inputs":[],"name":"PaymentProcessor__BuyerDidNotAuthorizePurchase","type":"error"},{"inputs":[],"name":"PaymentProcessor__BuyerMustBeDesignatedPrivateBuyer","type":"error"},{"inputs":[],"name":"PaymentProcessor__CallerDoesNotOwnSecurityPolicy","type":"error"},{"inputs":[],"name":"PaymentProcessor__CallerIsNotTheDelegatedPurchaser","type":"error"},{"inputs":[],"name":"PaymentProcessor__CallerIsNotWhitelistedMarketplace","type":"error"},{"inputs":[],"name":"PaymentProcessor__CallerMustHaveElevatedPermissionsForSpecifiedNFT","type":"error"},{"inputs":[],"name":"PaymentProcessor__CannotIncludeNativeFundsWhenPaymentMethodIsAnERC20Coin","type":"error"},{"inputs":[],"name":"PaymentProcessor__CeilingPriceMustBeGreaterThanFloorPrice","type":"error"},{"inputs":[],"name":"PaymentProcessor__CoinDoesNotImplementDecimalsAndLikelyIsNotAnERC20Token","type":"error"},{"inputs":[],"name":"PaymentProcessor__CoinIsApproved","type":"error"},{"inputs":[],"name":"PaymentProcessor__CoinIsNotApproved","type":"error"},{"inputs":[],"name":"PaymentProcessor__CollectionLevelOrItemLevelOffersCanOnlyBeMadeUsingERC20PaymentMethods","type":"error"},{"inputs":[],"name":"PaymentProcessor__DispensingTokenWasUnsuccessful","type":"error"},{"inputs":[],"name":"PaymentProcessor__EIP1271SignatureInvalid","type":"error"},{"inputs":[],"name":"PaymentProcessor__EIP1271SignaturesAreDisabled","type":"error"},{"inputs":[],"name":"PaymentProcessor__ExchangeIsNotWhitelisted","type":"error"},{"inputs":[],"name":"PaymentProcessor__ExchangeIsWhitelisted","type":"error"},{"inputs":[],"name":"PaymentProcessor__FailedToTransferProceeds","type":"error"},{"inputs":[],"name":"PaymentProcessor__InputArrayLengthCannotBeZero","type":"error"},{"inputs":[],"name":"PaymentProcessor__InputArrayLengthMismatch","type":"error"},{"inputs":[],"name":"PaymentProcessor__MarketplaceAndRoyaltyFeesWillExceedSalePrice","type":"error"},{"inputs":[],"name":"PaymentProcessor__NativeCurrencyIsNotAnApprovedPaymentMethod","type":"error"},{"inputs":[],"name":"PaymentProcessor__OfferHasExpired","type":"error"},{"inputs":[],"name":"PaymentProcessor__OfferPriceMustEqualSalePrice","type":"error"},{"inputs":[],"name":"PaymentProcessor__OnchainRoyaltiesExceedMaximumApprovedRoyaltyFee","type":"error"},{"inputs":[],"name":"PaymentProcessor__OverpaidNativeFunds","type":"error"},{"inputs":[],"name":"PaymentProcessor__PaymentCoinIsNotAnApprovedPaymentMethod","type":"error"},{"inputs":[],"name":"PaymentProcessor__PricingBoundsAreImmutable","type":"error"},{"inputs":[],"name":"PaymentProcessor__RanOutOfNativeFunds","type":"error"},{"inputs":[],"name":"PaymentProcessor__SaleHasExpired","type":"error"},{"inputs":[],"name":"PaymentProcessor__SalePriceAboveMaximumCeiling","type":"error"},{"inputs":[],"name":"PaymentProcessor__SalePriceBelowMinimumFloor","type":"error"},{"inputs":[],"name":"PaymentProcessor__SalePriceBelowSellerApprovedMinimum","type":"error"},{"inputs":[],"name":"PaymentProcessor__SecurityPolicyDoesNotExist","type":"error"},{"inputs":[],"name":"PaymentProcessor__SecurityPolicyOwnershipCannotBeTransferredToZeroAddress","type":"error"},{"inputs":[],"name":"PaymentProcessor__SellerDidNotAuthorizeSale","type":"error"},{"inputs":[],"name":"PaymentProcessor__SignatureAlreadyUsedOrRevoked","type":"error"},{"inputs":[],"name":"PaymentProcessor__TokenSecurityPolicyDoesNotAllowDelegatedPurchases","type":"error"},{"inputs":[],"name":"PaymentProcessor__TokenSecurityPolicyDoesNotAllowEOACallers","type":"error"},{"inputs":[],"name":"PaymentProcessor__TokenSecurityPolicyDoesNotAllowPrivateListings","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"bool[]","name":"unsuccessfulFills","type":"bool[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"salePrices","type":"uint256[]"}],"name":"BuyBundledListingERC1155","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"bool[]","name":"unsuccessfulFills","type":"bool[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"salePrices","type":"uint256[]"}],"name":"BuyBundledListingERC721","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"BuySingleListing","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"enforceExchangeWhitelist","type":"bool"},{"indexed":false,"internalType":"bool","name":"enforcePaymentMethodWhitelist","type":"bool"},{"indexed":false,"internalType":"bool","name":"enforcePricingConstraints","type":"bool"},{"indexed":false,"internalType":"bool","name":"disablePrivateListings","type":"bool"},{"indexed":false,"internalType":"bool","name":"disableDelegatedPurchases","type":"bool"},{"indexed":false,"internalType":"bool","name":"disableEIP1271Signatures","type":"bool"},{"indexed":false,"internalType":"bool","name":"disableExchangeWhitelistEOABypass","type":"bool"},{"indexed":false,"internalType":"uint32","name":"pushPaymentGasLimit","type":"uint32"},{"indexed":false,"internalType":"string","name":"policyName","type":"string"}],"name":"CreatedOrUpdatedSecurityPolicy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"indexed":true,"internalType":"address","name":"exchange","type":"address"}],"name":"ExchangeAddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"indexed":true,"internalType":"address","name":"exchange","type":"address"}],"name":"ExchangeRemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MasterNonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":false,"internalType":"bool","name":"wasCancellation","type":"bool"}],"name":"NonceInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coin","type":"address"}],"name":"PaymentMethodAddedToWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"indexed":true,"internalType":"address","name":"coin","type":"address"}],"name":"PaymentMethodRemovedFromWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"SecurityPolicyOwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"bool[]","name":"unsuccessfulFills","type":"bool[]"},{"indexed":false,"internalType":"address[]","name":"sellers","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"salePrices","type":"uint256[]"}],"name":"SweepCollectionERC1155","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"marketplace","type":"address"},{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"bool[]","name":"unsuccessfulFills","type":"bool[]"},{"indexed":false,"internalType":"address[]","name":"sellers","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"salePrices","type":"uint256[]"}],"name":"SweepCollectionERC721","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"floorPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ceilingPrice","type":"uint256"}],"name":"UpdatedCollectionLevelPricingBoundaries","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"address","name":"paymentCoin","type":"address"}],"name":"UpdatedCollectionPaymentCoin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"securityPolicyId","type":"uint256"}],"name":"UpdatedCollectionSecurityPolicy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"floorPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ceilingPrice","type":"uint256"}],"name":"UpdatedTokenLevelPricingBoundaries","type":"event"},{"inputs":[],"name":"BUNDLED_OFFER_APPROVAL_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BUNDLED_SALE_APPROVAL_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLLECTION_OFFER_APPROVAL_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_SECURITY_POLICY_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OFFER_APPROVAL_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SALE_APPROVAL_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"sellerAcceptedOffer","type":"bool"},{"internalType":"bool","name":"collectionLevelOffer","type":"bool"},{"internalType":"enum TokenProtocols","name":"protocol","type":"uint8"},{"internalType":"address","name":"paymentCoin","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"privateBuyer","type":"address"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"delegatedPurchaser","type":"address"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"maxRoyaltyFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"listingNonce","type":"uint256"},{"internalType":"uint256","name":"offerNonce","type":"uint256"},{"internalType":"uint256","name":"listingMinPrice","type":"uint256"},{"internalType":"uint256","name":"offerPrice","type":"uint256"},{"internalType":"uint256","name":"listingExpiration","type":"uint256"},{"internalType":"uint256","name":"offerExpiration","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct MatchedOrder[]","name":"saleDetailsArray","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA[]","name":"signedListings","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA[]","name":"signedOffers","type":"tuple[]"}],"name":"buyBatchOfListings","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signedListing","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signedOffer","type":"tuple"},{"components":[{"components":[{"internalType":"enum TokenProtocols","name":"protocol","type":"uint8"},{"internalType":"address","name":"paymentCoin","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"privateBuyer","type":"address"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"delegatedPurchaser","type":"address"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"offerNonce","type":"uint256"},{"internalType":"uint256","name":"offerPrice","type":"uint256"},{"internalType":"uint256","name":"offerExpiration","type":"uint256"}],"internalType":"struct MatchedOrderBundleBase","name":"bundleBase","type":"tuple"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"listingNonce","type":"uint256"},{"internalType":"uint256","name":"listingExpiration","type":"uint256"}],"internalType":"struct MatchedOrderBundleExtended","name":"bundleDetails","type":"tuple"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxRoyaltyFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"itemPrice","type":"uint256"},{"internalType":"uint256","name":"listingNonce","type":"uint256"},{"internalType":"uint256","name":"listingExpiration","type":"uint256"},{"internalType":"address","name":"seller","type":"address"}],"internalType":"struct BundledItem[]","name":"bundleItems","type":"tuple[]"}],"name":"buyBundledListing","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"sellerAcceptedOffer","type":"bool"},{"internalType":"bool","name":"collectionLevelOffer","type":"bool"},{"internalType":"enum TokenProtocols","name":"protocol","type":"uint8"},{"internalType":"address","name":"paymentCoin","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"privateBuyer","type":"address"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"delegatedPurchaser","type":"address"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"maxRoyaltyFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"listingNonce","type":"uint256"},{"internalType":"uint256","name":"offerNonce","type":"uint256"},{"internalType":"uint256","name":"listingMinPrice","type":"uint256"},{"internalType":"uint256","name":"offerPrice","type":"uint256"},{"internalType":"uint256","name":"listingExpiration","type":"uint256"},{"internalType":"uint256","name":"offerExpiration","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct MatchedOrder","name":"saleDetails","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signedListing","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signedOffer","type":"tuple"}],"name":"buySingleListing","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"collectionPaymentCoins","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enforceExchangeWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePaymentMethodWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePricingConstraints","type":"bool"},{"internalType":"bool","name":"disablePrivateListings","type":"bool"},{"internalType":"bool","name":"disableDelegatedPurchases","type":"bool"},{"internalType":"bool","name":"disableEIP1271Signatures","type":"bool"},{"internalType":"bool","name":"disableExchangeWhitelistEOABypass","type":"bool"},{"internalType":"uint32","name":"pushPaymentGasLimit","type":"uint32"},{"internalType":"string","name":"registryName","type":"string"}],"name":"createSecurityPolicy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCeilingPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getFloorPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"}],"name":"getSecurityPolicy","outputs":[{"components":[{"internalType":"bool","name":"enforceExchangeWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePaymentMethodWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePricingConstraints","type":"bool"},{"internalType":"bool","name":"disablePrivateListings","type":"bool"},{"internalType":"bool","name":"disableDelegatedPurchases","type":"bool"},{"internalType":"bool","name":"disableEIP1271Signatures","type":"bool"},{"internalType":"bool","name":"disableExchangeWhitelistEOABypass","type":"bool"},{"internalType":"uint32","name":"pushPaymentGasLimit","type":"uint32"},{"internalType":"address","name":"policyOwner","type":"address"}],"internalType":"struct SecurityPolicy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collectionAddress","type":"address"}],"name":"getTokenSecurityPolicyId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"isCollectionPricingImmutable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"coin","type":"address"}],"name":"isPaymentMethodApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"isTokenPricingImmutable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"masterNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"}],"name":"renounceSecurityPolicyOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeMasterNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"revokeSingleNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"coin","type":"address"}],"name":"setCollectionPaymentCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isImmutable","type":"bool"},{"internalType":"uint256","name":"floorPrice","type":"uint256"},{"internalType":"uint256","name":"ceilingPrice","type":"uint256"}],"internalType":"struct PricingBounds","name":"pricingBounds","type":"tuple"}],"name":"setCollectionPricingBounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"securityPolicyId","type":"uint256"}],"name":"setCollectionSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isImmutable","type":"bool"},{"internalType":"uint256","name":"floorPrice","type":"uint256"},{"internalType":"uint256","name":"ceilingPrice","type":"uint256"}],"internalType":"struct PricingBounds[]","name":"pricingBounds","type":"tuple[]"}],"name":"setTokenPricingBounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA","name":"signedOffer","type":"tuple"},{"components":[{"internalType":"enum TokenProtocols","name":"protocol","type":"uint8"},{"internalType":"address","name":"paymentCoin","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"privateBuyer","type":"address"},{"internalType":"address","name":"buyer","type":"address"},{"internalType":"address","name":"delegatedPurchaser","type":"address"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"offerNonce","type":"uint256"},{"internalType":"uint256","name":"offerPrice","type":"uint256"},{"internalType":"uint256","name":"offerExpiration","type":"uint256"}],"internalType":"struct MatchedOrderBundleBase","name":"bundleDetails","type":"tuple"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"maxRoyaltyFeeNumerator","type":"uint256"},{"internalType":"uint256","name":"itemPrice","type":"uint256"},{"internalType":"uint256","name":"listingNonce","type":"uint256"},{"internalType":"uint256","name":"listingExpiration","type":"uint256"},{"internalType":"address","name":"seller","type":"address"}],"internalType":"struct BundledItem[]","name":"bundleItems","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct SignatureECDSA[]","name":"signedListings","type":"tuple[]"}],"name":"sweepCollection","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferSecurityPolicyOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"unwhitelistExchange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"coin","type":"address"}],"name":"unwhitelistPaymentMethod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"bool","name":"enforceExchangeWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePaymentMethodWhitelist","type":"bool"},{"internalType":"bool","name":"enforcePricingConstraints","type":"bool"},{"internalType":"bool","name":"disablePrivateListings","type":"bool"},{"internalType":"bool","name":"disableDelegatedPurchases","type":"bool"},{"internalType":"bool","name":"disableEIP1271Signatures","type":"bool"},{"internalType":"bool","name":"disableExchangeWhitelistEOABypass","type":"bool"},{"internalType":"uint32","name":"pushPaymentGasLimit","type":"uint32"},{"internalType":"string","name":"registryName","type":"string"}],"name":"updateSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"account","type":"address"}],"name":"whitelistExchange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"securityPolicyId","type":"uint256"},{"internalType":"address","name":"coin","type":"address"}],"name":"whitelistPaymentMethod","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101406040523480156200001257600080fd5b5060405162006621380380620066218339810160408190526200003591620004ba565b604080518082018252601081526f2830bcb6b2b73a283937b1b2b9b9b7b960811b6020808301918252835180850190945260018452603160f81b908401528151902060e08190527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66101008190524660a0529192917f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6200011b8184846040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b6080523060c05261012052506200013e9250620001389150503390565b62000437565b6000805460ff60a01b19168155604080516101208101825282815260016020808301828152838501868152606085018781526080860188815260a0870189815260c088018a815263ffffffff808e1660e08b019081526101008b81018e81528e80526005909a529a517f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc805499519851975196519551945192519a516001600160a01b03166b01000000000000000000000002600160581b600160f81b03199b9094166701000000000000000263ffffffff60381b199315156601000000000000029390931664ffffffffff60301b19951515650100000000000260ff60281b19971515640100000000029790971661ffff60201b1998151563010000000263ff000000199a151562010000029a909a1663ffff0000199b1515909f0261ff00199415159490941661ffff19909c169b909b1792909217989098169b909b1795909517939093169590951717939093169590951794909417919091161790915590517ffa0f19ecb97e973eefa78c4ef4f6be467d4e0d320b88fa6b3e785f09df7089f6916200037291849190829081908190819081908c90971515885295151560208801529315156040870152911515606086015215156080850152151560a0840152151560c083015263ffffffff1660e082015261012061010082018190526017908201527f44454641554c5420534543555249545920504f4c4943590000000000000000006101408201526101600190565b60405180910390a260005b8151811015620004225760008282815181106200039e576200039e620005be565b6020908102919091018101516001600160a01b03811660008181527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec9093526040808420805460ff191660011790555191935091907fbb1b20966aa1c5d6ce073b9c8bf92e61bc7637cfa60464b83d2be54b7fe11eb3908290a3506001016200037d565b506200042e8362000437565b505050620005d4565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200049f57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080600060608486031215620004d057600080fd5b620004db8462000487565b925060208085015163ffffffff81168114620004f657600080fd5b60408601519093506001600160401b03808211156200051457600080fd5b818701915087601f8301126200052957600080fd5b8151818111156200053e576200053e620004a4565b8060051b604051601f19603f83011681018181108582111715620005665762000566620004a4565b60405291825284820192508381018501918a8311156200058557600080fd5b938501935b82851015620005ae576200059e8562000487565b845293850193928501926200058a565b8096505050505050509250925092565b634e487b7160e01b600052603260045260246000fd5b60805160a05160c05160e0516101005161012051615ffd620006246000396000613a9801526000613ada01526000613ab901526000613a1d01526000613a4701526000613a710152615ffd6000f3fe6080604052600436106102dc5760003560e01c80636c2be897116101845780639627a039116100d6578063dbcbf11b1161008a578063ed24911d11610064578063ed24911d146109b8578063f2e69c42146109cd578063f2fde38b14610a1857600080fd5b8063dbcbf11b14610858578063e67feac814610983578063ec72573f1461099857600080fd5b8063d3055dde116100bb578063d3055dde1461080f578063d3a5e4a114610822578063d73792a91461084257600080fd5b80639627a039146107dc578063c519e3d7146107fc57600080fd5b80637996eef0116101385780637d26279c116101125780637d26279c146107965780638456cb59146107a95780638da5cb5b146107be57600080fd5b80637996eef0146106fc5780637a2170d51461071c5780637d22c35c1461075057600080fd5b8063715018a611610169578063715018a61461066d578063753d130914610682578063755205e8146106b657600080fd5b80636c2be897146106195780636e80a2591461064d57600080fd5b80632ff3449f1161023d5780634faee3fe116101f15780635ed1f9bb116101cb5780635ed1f9bb146105945780635f3e9f42146105a7578063666c2334146105e557600080fd5b80634faee3fe146104f15780635731737c146105275780635c975abb1461057557600080fd5b8063414ab72711610222578063414ab72714610484578063420dab43146104a457806345253c53146104c457600080fd5b80632ff3449f1461044f5780633f4ba83a1461046f57600080fd5b80631af161cb1161029457806326c6ac301161027957806326c6ac30146103ef57806326ed4aa11461040f5780632f3ba8021461042f57600080fd5b80631af161cb146103ba578063226d4adb146103da57600080fd5b8063138315a3116102c5578063138315a31461033857806316ea5ca8146103585780631a2125cf1461037857600080fd5b806301ffc9a7146102e1578063096ff95d14610316575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614e44565b610a38565b60405190151581526020015b60405180910390f35b34801561032257600080fd5b50610336610331366004614ecb565b610a6f565b005b34801561034457600080fd5b50610336610353366004614f7f565b610c1f565b34801561036457600080fd5b50610336610373366004614faf565b610cb9565b34801561038457600080fd5b506103ac7f80244acca7a02d7199149a3038653fc8cb10ca984341ec429a626fab631e166281565b60405190815260200161030d565b3480156103c657600080fd5b506103366103d5366004614fdb565b610d2c565b3480156103e657600080fd5b50610336610d3a565b3480156103fb57600080fd5b5061033661040a366004614faf565b610d8a565b34801561041b57600080fd5b506103ac61042a366004614faf565b610d9c565b34801561043b57600080fd5b5061033661044a366004614f7f565b610db2565b34801561045b57600080fd5b5061033661046a366004614ff4565b610e4c565b34801561047b57600080fd5b50610336610f31565b34801561049057600080fd5b5061033661049f366004614f7f565b610f43565b3480156104b057600080fd5b506103366104bf3660046150a4565b611008565b3480156104d057600080fd5b506103ac6104df366004615186565b60066020526000908152604090205481565b3480156104fd57600080fd5b506103ac61050c366004615186565b6001600160a01b031660009081526002602052604090205490565b34801561053357600080fd5b5061055d610542366004615186565b6008602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161030d565b34801561058157600080fd5b50600054600160a01b900460ff16610301565b6103366105a23660046151e8565b611031565b3480156105b357600080fd5b506103016105c2366004615186565b6001600160a01b0316600090815260096020526040902054610100900460ff1690565b3480156105f157600080fd5b506103ac7f2008a1ab898fdaa2d8f178bc39e807035d2d6e330dac5e42e913ca727ab5603881565b34801561062557600080fd5b506103ac7f0bc3075778b80a2341ce445063e81924b88d61eb5f21c815e8f9cc824af096d081565b34801561065957600080fd5b506103ac6106683660046152b1565b6111f4565b34801561067957600080fd5b50610336611223565b34801561068e57600080fd5b506103ac7f126520d0bca0cfa7e5852d004cc4335723ce67c638cbd55cd530fe992a089e7b81565b3480156106c257600080fd5b506103016106d1366004614f7f565b60009182526004602090815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561070857600080fd5b506103ac610717366004614faf565b611235565b34801561072857600080fd5b506103ac7fd3f4273db8ff5262b6bc5f6ee07d139463b4f826cce90c05165f63062f3686dc81565b34801561075c57600080fd5b5061030161076b366004614f7f565b60009182526003602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6103366107a43660046155fe565b61124b565b3480156107b557600080fd5b5061033661127c565b3480156107ca57600080fd5b506000546001600160a01b031661055d565b3480156107e857600080fd5b506103366107f7366004614f7f565b61128c565b61033661080a36600461574e565b61132a565b61033661081d366004615801565b61166c565b34801561082e57600080fd5b5061033661083d366004614f7f565b61199c565b34801561084e57600080fd5b506103ac61271081565b34801561086457600080fd5b50610976610873366004614fdb565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250600090815260056020908152604091829020825161012081018452905460ff80821615158352610100808304821615159484019490945262010000820481161515948301949094526301000000810484161515606083015264010000000081048416151560808301526501000000000081048416151560a083015266010000000000008104909316151560c0820152600160381b830463ffffffff1660e0820152600160581b9092046001600160a01b03169082015290565b60405161030d9190615878565b34801561098f57600080fd5b506103ac600081565b3480156109a457600080fd5b506103366109b3366004615927565b6119d1565b3480156109c457600080fd5b506103ac611a3e565b3480156109d957600080fd5b506103016109e8366004614faf565b6001600160a01b03919091166000908152600a602090815260408083209383529290522054610100900460ff1690565b348015610a2457600080fd5b50610336610a33366004615186565b611a4d565b60006001600160e01b0319821663306d7a2160e11b1480610a6957506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a7885611ac8565b828114610a985760405163b62503e360e01b815260040160405180910390fd5b82610ab65760405163db560cb560e01b815260040160405180910390fd5b6001600160a01b0385166000908152600a6020526040812090805b85811015610c1557868682818110610aeb57610aeb615955565b9050602002013591506000858583818110610b0857610b08615955565b905060800201803603810190610b1e919061596b565b600084815260208690526040902054909150610100900460ff1615610b565760405163793c666f60e01b815260040160405180910390fd5b806060015181604001511115610b7f5760405163420a69a160e01b815260040160405180910390fd5b60008381526020858152604091829020835181548584015115156101000261ff00199215159290921661ffff199091161717815583830151600182018190556060850151600290920182905583519081529182015284916001600160a01b038c16917f38d88037c7f872f6e5d89332cdae804370cd604776bfcabf8da1f2e11945e271910160405180910390a350600101610ad1565b5050505050505050565b610c2882611c0f565b60008281526003602090815260408083206001600160a01b0385168452918290529091205460ff16610c6d5760405163a935ea0b60e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191690555185917f0aa5e1c56725fc01d0a61fc7302ff0201516b9af2b7261b4ecbea2f74611b5d191a3505050565b610cc282611ac8565b600154811115610ce557604051631797d38360e21b815260040160405180910390fd5b6001600160a01b038216600081815260026020526040808220849055518392917f8a2e423ccab4754dc61747d26d19bc14c55577d5fcc54b4a67d9b82a016b61df91a35050565b610d37816000611c56565b50565b3360008181526006602052604080822054905190917fb06d2760711c1c15c05bc011b1009a36c0713c6d63567c267678c3a382188b6191a333600090815260066020526040902080546001019055565b610d978233836001611ce0565b505050565b600080610da98484611e0f565b95945050505050565b610dbb82611c0f565b60008281526004602090815260408083206001600160a01b0385168452918290529091205460ff16610e005760405163ced71fff60e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191690555185917f24dced5d5e85a1733ad613a53ada041ecc410cca5ee598e3115b67d4a2525e3891a3505050565b610e5582611ac8565b6001600160a01b038216600090815260096020526040902054610100900460ff1615610e945760405163793c666f60e01b815260040160405180910390fd5b806060013581604001351115610ebd5760405163420a69a160e01b815260040160405180910390fd5b6001600160a01b03821660009081526009602052604090208190610ee182826159ee565b505060408051818301358152606083013560208201526001600160a01b038416917fdd61e240b8302b21ad48e3bec0f6e9538c9e4cfffdfde6d604963069d7e23c34910160405180910390a25050565b610f39611f06565b610f41611f60565b565b610f4c82611c0f565b6001600160a01b038116610f7357604051637a79ae6b60e11b815260040160405180910390fd5b60008281526003602090815260408083206001600160a01b0385168452918290529091205460ff1615610fb95760405163467d57a760e11b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191660011790555185917f3286c4e8704920b56173a2f9884345d5f5b90893a15dce75abc157df4081af5f91a3505050565b6110118b611c0f565b6110248b8b8b8b8b8b8b8b8b8b8b611fb5565b5050505050505050505050565b61103961219c565b84831415806110485750848114155b156110665760405163b62503e360e01b815260040160405180910390fd5b846110845760405163db560cb560e01b815260040160405180910390fd5b3461108d614d56565b6040805160608082018352600080835260208084018290528385018290528451928301855281835282018190529281018390529091805b8a8110156111d4578b8b828181106110de576110de615955565b905061028002018036038101906110f59190615a49565b945089898281811061110957611109615955565b90506060020180360381019061111f9190615a66565b935087878281811061113357611133615955565b9050606002018036038101906111499190615a66565b6060860151909350600092506001600160a01b03166111be57846101e0015191508186101561118b5760405163386ad99760e11b815260040160405180910390fd5b818603955061119c828686866121f6565b6111b95760405163f40863ff60e01b815260040160405180910390fd5b6111cc565b6111ca828686866121f6565b505b6001016110c4565b508415611024576040516315a53e4560e31b815260040160405180910390fd5b60018054810190819055600090611214818d8d8d8d8d8d8d8d8d8d611fb5565b9b9a5050505050505050505050565b61122b611f06565b610f4160006128e6565b6000806112428484611e0f565b50949350505050565b61125361219c565b61125f348484846121f6565b610d975760405163f40863ff60e01b815260040160405180910390fd5b611284611f06565b610f41612943565b61129582611c0f565b60008281526004602090815260408083206001600160a01b0385168452918290529091205460ff16156112db57604051637f622a5960e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191660011790555185917fbb1b20966aa1c5d6ce073b9c8bf92e61bc7637cfa60464b83d2be54b7fe11eb391a3505050565b61133261219c565b806113505760405163db560cb560e01b815260040160405180910390fd5b82516040908101516001600160a01b0316600090815260026020908152828220548083526005825283832084516001808252818701909652919490939282015b604080516060810182526000808252602080830182905292820152825260001990920191018161139057905050905087816000815181106113d3576113d3615955565b60200260200101819052506000806114416000858a8a8a808060200260200160405190810160405280939291908181526020016000905b828210156114365761142760e08302860136819003810190615a82565b8152602001906001019061140a565b505050505087612986565b9150915061145685858a60000151858d6132a0565b6040805160a08082019092528554600160381b900463ffffffff1681528951909101516000916115249160208201906001600160a01b03161561149e578b5160a001516114a5565b8b51608001515b6001600160a01b0390811682528c516020908101518216818401528d51015160409092019116156114d8576135a56114dc565b6135b15b67ffffffffffffffff16815260200160018c5151600181111561150157611501615b1a565b1461150e576135bc611512565b61363c5b67ffffffffffffffff16905283613692565b90506001895151600181111561153c5761153c615b1a565b14156115d6578860000151602001516001600160a01b03168960000151604001516001600160a01b03168a6000015160c001516001600160a01b03167f4b761d38cae19a364a5d44d2c4a5cdd41113f9e4d64ae2e21b766d072705b9318c60000151608001518d602001518689600001518a602001518b604001516040516115c996959493929190615b9d565b60405180910390a4611024565b8860000151602001516001600160a01b03168960000151604001516001600160a01b03168a6000015160c001516001600160a01b03167ff5960c81abf2cbc811a3b86b2b2c0338bfd5c47ad8815c941f9d59665a8d458b8c60000151608001518d602001518689600001518a60400151604051611657959493929190615c10565b60405180910390a45050505050505050505050565b61167461219c565b8281146116945760405163b62503e360e01b815260040160405180910390fd5b826116b25760405163db560cb560e01b815260040160405180910390fd5b6000806116e787604001516001600160a01b031660009081526002602090815260408083205480845260059092529091209091565b915091506000806117cc60018460405180608001604052808d815260200160006001600160a01b031681526020016000815260200160008152508b8b808060200260200160405190810160405280939291908181526020016000905b8282101561176f5761176060e08302860136819003810190615a82565b81526020019060010190611743565b50505050508a8a808060200260200160405190810160405280939291908181526020016000905b828210156117c2576117b360608302860136819003810190615a66565b81526020019060010190611796565b5050505050612986565b915091506117dd84848b858e6132a0565b6040805160a08082019092528454600160381b900463ffffffff168152908a01516000916118979160208201906001600160a01b031615611822578c60a00151611828565b8c608001515b6001600160a01b031681526020018c602001516001600160a01b0316815260200160006001600160a01b03168d602001516001600160a01b03161461186f576135a5611873565b6135b15b67ffffffffffffffff16815260200160018d51600181111561150157611501615b1a565b905060018a5160018111156118ae576118ae615b1a565b141561192b5789602001516001600160a01b03168a604001516001600160a01b03168b60c001516001600160a01b03167f35cd37c73a78d0322074e1324a7d5d4cf5c7ff21f3265d03f4d085c532c6f0198d6080015185886080015189600001518a602001518b604001516040516115c996959493929190615ca7565b89602001516001600160a01b03168a604001516001600160a01b03168b60c001516001600160a01b03167f8435e05433e0d3a3fe612b10c36f6623deec79239f76721a154687fef0ca46a18d6080015185886080015189600001518a60400151604051611657959493929190615cef565b6001600160a01b0381166119c357604051632949de9560e01b815260040160405180910390fd5b6119cd8282611c56565b5050565b6119da82611ac8565b6001600160a01b03828116600081815260086020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169486169485179055517f53ab061e9517daf6849d4bde07950e3d199f73115c2e4842a8b20a62e83abd1c9190a35050565b6000611a48613a10565b905090565b611a55611f06565b6001600160a01b038116611abf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610d37816128e6565b336001600160a01b0382161480611bf157816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1257600080fd5b505afa925050508015611b42575060408051601f3d908101601f19168201909252611b3f91810190615d37565b60015b611b4b57611b59565b6001600160a01b0316331490505b80611bf1576001600160a01b0382166391d148546000336040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260440160206040518083038186803b158015611bb557600080fd5b505afa925050508015611be5575060408051601f3d908101601f19168201909252611be291810190615d54565b60015b611bee57611bf1565b90505b806119cd576040516380a6c4af60e01b815260040160405180910390fd5b600081815260056020526040902054600160581b90046001600160a01b0316336001600160a01b031614610d3757604051638d1a2f3760e01b815260040160405180910390fd5b611c5f82611c0f565b60008281526005602052604080822080546001600160a01b03858116600160581b8181027fff0000000000000000000000000000000000000000ffffffffffffffffffffff851617855594519395949092041692909183917f195d9a13f822aeb682fa730ba46c3e3e6103134a536f98e5c40c81cc004f0a8491a350505050565b6040516bffffffffffffffffffffffff19606086811b8216602084015285901b16603482015260009081906007908290604801604051602081830303815290604052805190602001208152602001908152602001600020905060006101008581611d4c57611d4c615d71565b0460008181526020849052604090205490915060ff861690600181831c81161415611d8a5760405163015236d560e61b815260040160405180910390fd5b60009283526020849052604092839020600190921b179055516001600160a01b03808816919087169086907f61b992b9cb8061087d0e50532a8ba94e22379c7edd39cdb465536ef827dc1be790611de690881515815260200190565b60405180910390a4505050506001600160a01b0316600090815260066020526040902054919050565b6001600160a01b0382166000908152600a6020908152604080832084845282528083208151608081018352815460ff8082161580158452610100909204161515948201949094526001820154928101929092526002015460608201528291611e8557806040015181606001519250925050611eff565b6001600160a01b0385166000908152600960209081526040918290208251608081018452815460ff808216158015845261010090920416151593820193909352600182015493810193909352600201546060830152611ef35780604001518160600151935093505050611eff565b50600060001992509250505b9250929050565b6000546001600160a01b03163314610f415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611ab6565b611f68613afe565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6040518061012001604052808b151581526020018a15158152602001891515815260200188151581526020018715158152602001861515815260200185151581526020018463ffffffff16815260200161200c3390565b6001600160a01b0390811690915260008d8152600560209081526040918290208451815492860151868501516060880151608089015160a08a015160c08b015160e08c01516101009c8d015161ffff19909a1697151561ff00191697909717951515909b029490941763ffff00001916620100009315159390930263ff0000001916929092176301000000911515919091021765ffff0000000019166401000000009115159190910265ff00000000001916176501000000000091151591909102176affffffffff00000000000019166601000000000000961515969096026affffffff00000000000000191695909517600160381b63ffffffff90961695909502949094177fff0000000000000000000000000000000000000000ffffffffffffffffffffff16600160581b919093160291909117909155518b907ffa0f19ecb97e973eefa78c4ef4f6be467d4e0d320b88fa6b3e785f09df7089f690612187908d908d908d908d908d908d908d908d908d908d90615d87565b60405180910390a25050505050505050505050565b600054600160a01b900460ff1615610f415760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611ab6565b6080808401516001600160a01b0390811660009081526002602090815260408083205480845260058352818420825161012081018452905460ff80821615158352610100808304821615159684019690965262010000820481161515948301949094526301000000810484161515606080840191909152640100000000820485161515988301989098526501000000000081048416151560a083015266010000000000008104909316151560c082015263ffffffff600160381b84041660e0820152600160581b90920485169282019290925293870151919390929091166123395786866101e00151146122fd57604051630db5f82b60e21b815260040160405180910390fd5b855180612316575060a08601516001600160a01b031632145b1561233457604051632d8457d960e21b815260040160405180910390fd5b612375565b861561235857604051635d6c7e8160e01b815260040160405180910390fd5b612375828260200151836040015189608001518a60600151613b57565b60018660400151600181111561238d5761238d615b1a565b14156123bb576102608601516123b6576040516326db27f160e01b815260040160405180910390fd5b6123e1565b6001866102600151146123e157604051636d9e53cd60e11b815260040160405180910390fd5b8561020001514211156124075760405163099465a960e41b815260040160405180910390fd5b85610220015142111561242d5760405163026de79960e21b815260040160405180910390fd5b856101c00151866101e00151101561245857604051636769dcf160e11b815260040160405180910390fd5b6127108661016001518761014001516124719190615e1e565b1115612490576040516332a7479560e21b815260040160405180910390fd5b60c08601516001600160a01b031615612500578560c001516001600160a01b03168660e001516001600160a01b0316146124dd5760405163185ff71160e21b815260040160405180910390fd5b8060600151156125005760405163646c1dcd60e11b815260040160405180910390fd5b6101008601516001600160a01b03161561256e576101008601516001600160a01b0316336001600160a01b03161461254b576040516390158e4760e01b815260040160405180910390fd5b80608001511561256e576040516358f8e8a560e01b815260040160405180910390fd5b8060a00151156125d25760a08601516001600160a01b03163b156125a55760405163321e0c1560e11b815260040160405180910390fd5b60e08601516001600160a01b03163b156125d25760405163321e0c1560e11b815260040160405180910390fd5b8051156126635733321461261f57600082815260036020908152604080832033845290915290205460ff1661261a576040516329837f1160e21b815260040160405180910390fd5b612663565b8060c001511561266357600082815260036020908152604080832033845290915290205460ff1661266357604051631d4ca04b60e11b815260040160405180910390fd5b8060400151156126dc5760608601516001600160a01b03166126bd5760808601516001600160a01b0390811660009081526008602052604090205416156126bd576040516305a3b2ed60e41b815260040160405180910390fd5b6126dc8660800151876102400151886102600151896101e00151613be8565b6126e68686613c52565b8560200151156126ff576126fa8685613e48565b612709565b6127098685613fef565b604080516001808252818301909252600091816020015b612728614d56565b815260200190600190039081612720579050509050868160008151811061275157612751615955565b602002602001018190525060006128066040518060a001604052808560e0015163ffffffff16815260200160006001600160a01b03168b61010001516001600160a01b0316146127a6578a61010001516127ac565b8a60e001515b6001600160a01b03908116825260608c018051821660208401525160409092019116156127db576135a56127df565b6135b15b67ffffffffffffffff16815260200160018b60400151600181111561150157611501615b1a565b90508060008151811061281b5761281b615955565b602002602001015115945084156128da5787606001516001600160a01b031688608001516001600160a01b03168961012001516001600160a01b03167f7ed668b30822ae5c7db7b4a32f84e6645250bb6db0d1fc73eeb484c5b34b1d1b8b60e001518c60a001518d61024001518e61026001518f6101e001516040516128d19594939291906001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b60405180910390a45b50505050949350505050565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61294b61219c565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611f983390565b6129bf6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001600081525090565b6060835167ffffffffffffffff8111156129db576129db61538c565b604051908082528060200260200182016040528015612a1457816020015b612a01614d56565b8152602001906001900390816129f95790505b5090506040518060c00160405280855167ffffffffffffffff811115612a3c57612a3c61538c565b604051908082528060200260200182016040528015612a65578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612a8557612a8561538c565b604051908082528060200260200182016040528015612aae578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612ace57612ace61538c565b604051908082528060200260200182016040528015612af7578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612b1757612b1761538c565b604051908082528060200260200182016040528015612b40578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612b6057612b6061538c565b604051908082528060200260200182016040528015612b89578160200160208202803683370190505b5081526020016000815250915060005b84518110156130c8576020860151604087015160608801518a15612c1857878481518110612bc957612bc9615955565b602002602001015160c001519250878481518110612be957612be9615955565b6020026020010151608001519150878481518110612c0957612c09615955565b602002602001015160a0015190505b60408051610280810182526000808252602082018190528b515190928201906001811115612c4857612c48615b1a565b81526020018b60000151602001516001600160a01b031681526020018b60000151604001516001600160a01b03168152602001856001600160a01b031681526020018b60000151606001516001600160a01b031681526020018b60000151608001516001600160a01b031681526020018b6000015160a001516001600160a01b031681526020018b6000015160c001516001600160a01b031681526020018b6000015160e0015181526020018a8781518110612d0657612d06615955565b60200260200101516040015181526020018481526020018b60000151610100015181526020018a8781518110612d3e57612d3e615955565b60200260200101516060015181526020018a8781518110612d6157612d61615955565b60200260200101516060015181526020018381526020018b60000151610140015181526020018a8781518110612d9957612d99615955565b60200260200101516000015181526020018a8781518110612dbc57612dbc615955565b602002602001015160200151815250905080868681518110612de057612de0615955565b602002602001018190525080610240015187600001518681518110612e0757612e07615955565b60200260200101818152505080610260015187602001518681518110612e2f57612e2f615955565b602002602001018181525050806101c0015187604001518681518110612e5757612e57615955565b60200260200101818152505080610160015187606001518681518110612e7f57612e7f615955565b6020026020010181815250508060a0015187608001518681518110612ea657612ea6615955565b60200260200101906001600160a01b031690816001600160a01b031681525050806101c001518760a001818151612edd9190615e1e565b905250600181604001516001811115612ef857612ef8615b1a565b1415612f2657610260810151612f21576040516326db27f160e01b815260040160405180910390fd5b612f4c565b600181610260015114612f4c57604051636d9e53cd60e11b815260040160405180910390fd5b612710816101600151826101400151612f659190615e1e565b1115612f84576040516332a7479560e21b815260040160405180910390fd5b8a5462010000900460ff1615612fb357612fb38160800151826102400151836102600151846101e00151613be8565b8b156130b957806102000151421115612fdf5760405163099465a960e41b815260040160405180910390fd5b60c08101516001600160a01b031615613056578060c001516001600160a01b03168160e001516001600160a01b03161461302c5760405163185ff71160e21b815260040160405180910390fd5b8a546301000000900460ff16156130565760405163646c1dcd60e11b815260040160405180910390fd5b8a5465010000000000900460ff16156130965760a08101516001600160a01b03163b156130965760405163321e0c1560e11b815260040160405180910390fd5b6130b9818987815181106130ac576130ac615955565b6020026020010151613c52565b84600101945050505050612b99565b50866132965784606001514211156130f35760405163099465a960e41b815260040160405180910390fd5b8451606001516001600160a01b03161561316957845160608101516080909101516001600160a01b0390811691161461313f5760405163185ff71160e21b815260040160405180910390fd5b85546301000000900460ff16156131695760405163646c1dcd60e11b815260040160405180910390fd5b855465010000000000900460ff16156131a95760208501516001600160a01b03163b156131a95760405163321e0c1560e11b815260040160405180910390fd5b613296604051806080016040528084600001516040516020016131cc9190615e36565b60405160208183030381529060405280519060200120815260200184602001516040516020016131fc9190615e36565b604051602081830303815290604052805190602001208152602001846060015160405160200161322c9190615e36565b604051602081830303815290604052805190602001208152602001846040015160405160200161325c9190615e36565b60405160208183030381529060405280519060200120815250868560008151811061328957613289615955565b60200260200101516140c9565b9550959350505050565b60208301516001600160a01b0316156133015734156132d257604051635d6c7e8160e01b815260040160405180910390fd5b8354604084015160208501516132fc92889260ff6101008304811693620100009093041691613b57565b613375565b826101200151341461332657604051630db5f82b60e21b815260040160405180910390fd5b835462010000900460ff1615613375576040808401516001600160a01b039081166000908152600860205291909120541615613375576040516305a3b2ed60e41b815260040160405180910390fd5b82610140015142111561339b5760405163026de79960e21b815260040160405180910390fd5b60a08301516001600160a01b03161561340f5760a08301516001600160a01b0316336001600160a01b0316146133e4576040516390158e4760e01b815260040160405180910390fd5b8354640100000000900460ff161561340f576040516358f8e8a560e01b815260040160405180910390fd5b835465010000000000900460ff161561344f5760808301516001600160a01b03163b1561344f5760405163321e0c1560e11b815260040160405180910390fd5b835460ff16156134ed5733321461349f57600085815260036020908152604080832033845290915290205460ff1661349a576040516329837f1160e21b815260040160405180910390fd5b6134ed565b83546601000000000000900460ff16156134ed57600085815260036020908152604080832033845290915290205460ff166134ed57604051631d4ca04b60e11b815260040160405180910390fd5b8261012001518260a001511461351657604051637867d96760e11b815260040160405180910390fd5b815160405161359e9161352b91602001615e36565b6040516020818303038152906040528051906020012083602001516040516020016135569190615e36565b6040516020818303038152906040528051906020012084604001516040516020016135819190615e36565b604051602081830303815290604052805190602001208685614282565b5050505050565b61359e83858785614436565b61359e8583836144a5565b6040516323b872dd60e01b81526001600160a01b038681166004830152858116602483015260448201849052600091908516906323b872dd906064015b600060405180830381600087803b15801561361357600080fd5b505af1925050508015613624575060015b61363057506000610da9565b50600195945050505050565b604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018490526064820183905260a06084830152600060a48301819052919085169063f242432a9060c4016135f9565b6060815167ffffffffffffffff8111156136ae576136ae61538c565b6040519080825280602002602001820160405280156136d7578160200160208202803683370190505b506040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529192505b835181101561396f57600084828151811061372a5761372a615955565b6020026020010151905060006137618260a001518360e0015184608001518561024001518661026001518c6080015163ffffffff16565b9050806137bc5760408701516001600160a01b03166137935760405163f40863ff60e01b815260040160405180910390fd5b60018584815181106137a7576137a7615955565b91151560209283029190910190910152613965565b60006137e9836101e0015184608001518561024001518661012001518761014001518861016001516144d1565b905084604001516001600160a01b031681600001516001600160a01b0316146138575760a08501511561383f5761383f856040015189602001518a604001518860a001518c600001518d6060015163ffffffff16565b80516001600160a01b03166040860152600060a08601525b84602001516001600160a01b03168361012001516001600160a01b0316146138c8576080850151156138ac576138ac856020015189602001518a6040015188608001518c600001518d6060015163ffffffff16565b6101208301516001600160a01b03166020860152600060808601525b84600001516001600160a01b03168360a001516001600160a01b0316146139345760608501511561391c5761391c856000015189602001518a6040015188606001518c600001518d6060015163ffffffff16565b60a08301516001600160a01b03168552600060608601525b602081015160a086018051909101905260408101516080860180519091019052606090810151908501805190910190525b505060010161370d565b5060a0810151156139a3576139a38160400151856020015186604001518460a001518860000151896060015163ffffffff16565b6080810151156139d6576139d681602001518560200151866040015184608001518860000151896060015163ffffffff16565b606081015115613a0957613a0981600001518560200151866040015184606001518860000151896060015163ffffffff16565b5092915050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015613a6957507f000000000000000000000000000000000000000000000000000000000000000046145b15613a9357507f000000000000000000000000000000000000000000000000000000000000000090565b611a487f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000614681565b600054600160a01b900460ff16610f415760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611ab6565b8215613b9f576001600160a01b03828116600090815260086020526040902054811690821614613b9a576040516355ce006f60e11b815260040160405180910390fd5b61359e565b831561359e5760008581526004602090815260408083206001600160a01b038516845290915290205460ff1661359e576040516355ce006f60e11b815260040160405180910390fd5b6000613bf48383615e6c565b9050600080613c038787611e0f565b9150915081831015613c285760405163024c625160e61b815260040160405180910390fd5b80831115613c4957604051639837ddd760e01b815260040160405180910390fd5b50505050505050565b6000613dd57fd3f4273db8ff5262b6bc5f6ee07d139463b4f826cce90c05165f63062f3686dc60001b84604001516001811115613c9157613c91615b1a565b855161012087015161014088015161016089015160c08a0151604051613cfa979695949392919060200196875260ff95909516602087015292151560408601526001600160a01b039182166060860152608085015260a08401919091521660c082015260e00190565b60408051601f1981840301815291905260a085015160808601516102408701516102608801516101c08901516102008a01516101808b01516101208c0151613d459088836000611ce0565b6060808e0151604080516001600160a01b039b8c166020820152998b16908a015290880196909652608087019490945260a086019290925260c085015260e084015261010083015291909116610120820152610140015b60408051601f1981840301815290829052613dba9291602001615eba565b604051602081830303815290604052805190602001206146cb565b60a08401519091506001600160a01b03163b15613dfb57610d978360a001518284614719565b613e1381836000015184602001518560400151614833565b6001600160a01b03168360a001516001600160a01b031614610d97576040516312a0f2db60e11b815260040160405180910390fd5b6000613f7c7f0bc3075778b80a2341ce445063e81924b88d61eb5f21c815e8f9cc824af096d060001b84604001516001811115613e8757613e87615b1a565b6020808701516101208801516101408901516101008a015160e08b015160808c01516102608d01516101e08e0151604051613f159b9a9901998a5260ff9890981660208a015295151560408901526001600160a01b039485166060890152608088019390935290831660a0870152821660c08601521660e08401526101008301526101208201526101400190565b604051602081830303815290604052846102200151856101a00151613f4b8761012001518860e00151896101a001516000611ce0565b6060808901516040805160208101969096528501939093528301526001600160a01b0316608082015260a001613d9c565b60e08401519091506001600160a01b03163b15613fa257610d978360e001518284614719565b613fba81836000015184602001518560400151614833565b6001600160a01b03168360e001516001600160a01b031614610d97576040516320af217960e01b815260040160405180910390fd5b6000613f7c7f2008a1ab898fdaa2d8f178bc39e807035d2d6e330dac5e42e913ca727ab5603860001b8460400151600181111561402e5761402e615b1a565b8561012001518661014001518761010001518860e0015189608001518a61024001518b61026001518c6101e00151604051602001613f159a99989796959493929190998a5260ff9890981660208a01526001600160a01b0396871660408a01526060890195909552928516608088015290841660a087015290921660c085015260e08401919091526101008301526101208201526101400190565b815151600090614204907f80244acca7a02d7199149a3038653fc8cb10ca984341ec429a626fab631e166290600181111561410657614106615b1a565b855160c081015160e082015160608301516020808b0151604095860151955161416e98979691920196875260ff9590951660208701526001600160a01b039384166040870152606086019290925282166080850152811660a08401521660c082015260e00190565b60408051601f19818403018152918152606086015190860151865160c00151602088015161419f9190836000611ce0565b87516020908101518a518b8301516040808e015160608f01519151613d9c9998979691929101978852602088019690965260408701949094526001600160a01b03929092166060860152608085015260a084015260c083015260e08201526101000190565b60208401519091506001600160a01b03163b1561422f5761422a83602001518284614719565b61427c565b61424781836000015184602001518560400151614833565b6001600160a01b031683602001516001600160a01b03161461427c576040516312a0f2db60e11b815260040160405180910390fd5b50505050565b81516000906143b6907f126520d0bca0cfa7e5852d004cc4335723ce67c638cbd55cd530fe992a089e7b9060018111156142be576142be615b1a565b8560c001518660e001518760a00151886080015189604001518a610120015160405160200161433698979695949392919097885260ff9690961660208801526001600160a01b03948516604088015260608701939093529083166080860152821660a08501521660c083015260e08201526101000190565b60405160208183030381529060405284610140015185610100015161436b8760c0015188608001518961010001516000611ce0565b60208881015160408051928301959095529381019290925260608201526001600160a01b03909116608082015260a0810189905260c0810188905260e0810187905261010001613d9c565b60808401519091506001600160a01b03163b156143e1576143dc83608001518284614719565b61442e565b6143f981836000015184602001518560400151614833565b6001600160a01b031683608001516001600160a01b03161461442e576040516320af217960e01b815260040160405180910390fd5b505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905261427c90859061485b565b6000806000806000868887f190508061427c5760405163364cc69f60e11b815260040160405180910390fd5b614505604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6060810187905260405163152a902d60e11b815260048101869052602481018890526001600160a01b03871690632a55205a90604401604080518083038186803b15801561455257600080fd5b505afa925050508015614582575060408051601f3d908101601f1916820190925261457f91810190615ee9565b60015b6145bc573d8080156145b0576040519150601f19603f3d011682016040523d82523d6000602084013e6145b5565b606091505b505061462d565b6001600160a01b0382166145ce575060005b801561462a576127106145e1858b615f17565b6145eb9190615e6c565b81111561460b576040516306f6f23d60e21b815260040160405180910390fd5b6001600160a01b03821683526020830181905260608301805182900390525b50505b6001600160a01b038416614642576000614659565b61271061464f8489615f17565b6146599190615e6c565b60408201819052156146775760408101516060820180519190910390525b9695505050505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090505b9392505050565b6000610a696146d8613a10565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000836001600160a01b0316631626ba7e8484602001518560400151866000015160405160200161478293929190928352602083019190915260f81b7fff0000000000000000000000000000000000000000000000000000000000000016604082015260410190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016147ae929190615f62565b60206040518083038186803b1580156147c657600080fd5b505afa9250505080156147f6575060408051601f3d908101601f191682019092526147f391810190615f7b565b60015b6147ff57614815565b6001600160e01b031916630b135d3f60e11b1490505b8061427c576040516307c1d80160e51b815260040160405180910390fd5b60008060006148448787878761492d565b9150915061485181614a1a565b5095945050505050565b60006148b0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614bd59092919063ffffffff16565b805190915015610d9757808060200190518101906148ce9190615d54565b610d975760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611ab6565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156149645750600090506003614a11565b8460ff16601b1415801561497c57508460ff16601c14155b1561498d5750600090506004614a11565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156149e1573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614a0a57600060019250925050614a11565b9150600090505b94509492505050565b6000816004811115614a2e57614a2e615b1a565b1415614a375750565b6001816004811115614a4b57614a4b615b1a565b1415614a995760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401611ab6565b6002816004811115614aad57614aad615b1a565b1415614afb5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611ab6565b6003816004811115614b0f57614b0f615b1a565b1415614b685760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401611ab6565b6004816004811115614b7c57614b7c615b1a565b1415610d375760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401611ab6565b6060614be48484600085614bec565b949350505050565b606082471015614c4d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611ab6565b6001600160a01b0385163b614ca45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ab6565b600080866001600160a01b03168587604051614cc09190615f98565b60006040518083038185875af1925050503d8060008114614cfd576040519150601f19603f3d011682016040523d82523d6000602084013e614d02565b606091505b5091509150614d12828286614d1d565b979650505050505050565b60608315614d2c5750816146c4565b825115614d3c5782518084602001fd5b8160405162461bcd60e51b8152600401611ab69190615fb4565b60408051610280810182526000808252602082018190529091820190815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160e01b031981168114610d3757600080fd5b600060208284031215614e5657600080fd5b81356146c481614e2e565b6001600160a01b0381168114610d3757600080fd5b8035614e8181614e61565b919050565b60008083601f840112614e9857600080fd5b50813567ffffffffffffffff811115614eb057600080fd5b6020830191508360208260071b8501011115611eff57600080fd5b600080600080600060608688031215614ee357600080fd5b8535614eee81614e61565b9450602086013567ffffffffffffffff80821115614f0b57600080fd5b818801915088601f830112614f1f57600080fd5b813581811115614f2e57600080fd5b8960208260051b8501011115614f4357600080fd5b602083019650809550506040880135915080821115614f6157600080fd5b50614f6e88828901614e86565b969995985093965092949392505050565b60008060408385031215614f9257600080fd5b823591506020830135614fa481614e61565b809150509250929050565b60008060408385031215614fc257600080fd5b8235614fcd81614e61565b946020939093013593505050565b600060208284031215614fed57600080fd5b5035919050565b60008082840360a081121561500857600080fd5b833561501381614e61565b92506080601f198201121561502757600080fd5b506020830190509250929050565b8015158114610d3757600080fd5b8035614e8181615035565b803563ffffffff81168114614e8157600080fd5b60008083601f84011261507457600080fd5b50813567ffffffffffffffff81111561508c57600080fd5b602083019150836020828501011115611eff57600080fd5b60008060008060008060008060008060006101408c8e0312156150c657600080fd5b8b359a5060208c01356150d881615035565b995060408c01356150e881615035565b985060608c01356150f881615035565b975060808c013561510881615035565b965060a08c013561511881615035565b955061512660c08d01615043565b945061513460e08d01615043565b93506151436101008d0161504e565b92506101208c013567ffffffffffffffff81111561516057600080fd5b61516c8e828f01615062565b915080935050809150509295989b509295989b9093969950565b60006020828403121561519857600080fd5b81356146c481614e61565b60008083601f8401126151b557600080fd5b50813567ffffffffffffffff8111156151cd57600080fd5b602083019150836020606083028501011115611eff57600080fd5b6000806000806000806060878903121561520157600080fd5b863567ffffffffffffffff8082111561521957600080fd5b818901915089601f83011261522d57600080fd5b81358181111561523c57600080fd5b8a60206102808302850101111561525257600080fd5b60209283019850965090880135908082111561526d57600080fd5b6152798a838b016151a3565b9096509450604089013591508082111561529257600080fd5b5061529f89828a016151a3565b979a9699509497509295939492505050565b6000806000806000806000806000806101208b8d0312156152d157600080fd5b8a356152dc81615035565b995060208b01356152ec81615035565b985060408b01356152fc81615035565b975060608b013561530c81615035565b965060808b013561531c81615035565b955060a08b013561532c81615035565b945060c08b013561533c81615035565b935061534a60e08c0161504e565b92506101008b013567ffffffffffffffff81111561536757600080fd5b6153738d828e01615062565b915080935050809150509295989b9194979a5092959850565b634e487b7160e01b600052604160045260246000fd5b604051610280810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b60405290565b604051610160810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b803560028110614e8157600080fd5b6000610280828403121561545f57600080fd5b6154676153a2565b905061547282615043565b815261548060208301615043565b60208201526154916040830161543d565b60408201526154a260608301614e76565b60608201526154b360808301614e76565b60808201526154c460a08301614e76565b60a08201526154d560c08301614e76565b60c08201526154e660e08301614e76565b60e08201526101006154f9818401614e76565b9082015261012061550b838201614e76565b908201526101408281013590820152610160808301359082015261018080830135908201526101a080830135908201526101c080830135908201526101e080830135908201526102008083013590820152610220808301359082015261024080830135908201526102609182013591810191909152919050565b60006060828403121561559757600080fd5b6040516060810181811067ffffffffffffffff821117156155c857634e487b7160e01b600052604160045260246000fd5b604052905080823560ff811681146155df57600080fd5b8082525060208301356020820152604083013560408201525092915050565b6000806000610340848603121561561457600080fd5b61561e858561544c565b925061562e856102808601615585565b915061563e856102e08601615585565b90509250925092565b6000610160828403121561565a57600080fd5b6156626153da565b905061566d8261543d565b815261567b60208301614e76565b602082015261568c60408301614e76565b604082015261569d60608301614e76565b60608201526156ae60808301614e76565b60808201526156bf60a08301614e76565b60a08201526156d060c08301614e76565b60c082015260e082013560e082015261010080830135818301525061012080830135818301525061014080830135818301525092915050565b60008083601f84011261571b57600080fd5b50813567ffffffffffffffff81111561573357600080fd5b60208301915083602060e083028501011115611eff57600080fd5b60008060008060008587036102a081121561576857600080fd5b6157728888615585565b95506157818860608901615585565b94506101c060bf198201121561579657600080fd5b5061579f61540c565b6157ac8860c08901615647565b81526102208701356157bd81614e61565b602082015261024087013560408201526102608701356060820152925061028086013567ffffffffffffffff8111156157f557600080fd5b614f6e88828901615709565b600080600080600080610200878903121561581b57600080fd5b6158258888615585565b95506158348860608901615647565b94506101c087013567ffffffffffffffff8082111561585257600080fd5b61585e8a838b01615709565b90965094506101e089013591508082111561529257600080fd5b60006101208201905082511515825260208301511515602083015260408301516158a6604084018215159052565b5060608301516158ba606084018215159052565b5060808301516158ce608084018215159052565b5060a08301516158e260a084018215159052565b5060c08301516158f660c084018215159052565b5060e083015161590e60e084018263ffffffff169052565b50610100928301516001600160a01b0316919092015290565b6000806040838503121561593a57600080fd5b823561594581614e61565b91506020830135614fa481614e61565b634e487b7160e01b600052603260045260246000fd5b60006080828403121561597d57600080fd5b6040516080810181811067ffffffffffffffff821117156159ae57634e487b7160e01b600052604160045260246000fd5b60405282356159bc81615035565b815260208301356159cc81615035565b6020820152604083810135908201526060928301359281019290925250919050565b81356159f981615035565b815460ff19811691151560ff1691821783556020840135615a1981615035565b61ffff199190911690911790151560081b61ff001617815560408201356001820155606090910135600290910155565b60006102808284031215615a5c57600080fd5b6146c4838361544c565b600060608284031215615a7857600080fd5b6146c48383615585565b600060e08284031215615a9457600080fd5b60405160e0810181811067ffffffffffffffff82111715615ac557634e487b7160e01b600052604160045260246000fd5b8060405250823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c0830135615b0e81614e61565b60c08201529392505050565b634e487b7160e01b600052602160045260246000fd5b600081518084526020808501945080840160005b83811015615b62578151151587529582019590820190600101615b44565b509495945050505050565b600081518084526020808501945080840160005b83811015615b6257815187529582019590820190600101615b81565b60006001600160a01b03808916835280881660208401525060c06040830152615bc960c0830187615b30565b8281036060840152615bdb8187615b6d565b90508281036080840152615bef8186615b6d565b905082810360a0840152615c038185615b6d565b9998505050505050505050565b60006001600160a01b03808816835280871660208401525060a06040830152615c3c60a0830186615b30565b8281036060840152615c4e8186615b6d565b90508281036080840152615c628185615b6d565b98975050505050505050565b600081518084526020808501945080840160005b83811015615b625781516001600160a01b031687529582019590820190600101615c82565b6001600160a01b038716815260c060208201526000615cc960c0830188615b30565b8281036040840152615cdb8188615c6e565b90508281036060840152615bdb8187615b6d565b6001600160a01b038616815260a060208201526000615d1160a0830187615b30565b8281036040840152615d238187615c6e565b90508281036060840152615c4e8186615b6d565b600060208284031215615d4957600080fd5b81516146c481614e61565b600060208284031215615d6657600080fd5b81516146c481615035565b634e487b7160e01b600052601260045260246000fd5b60006101208c151583528b151560208401528a151560408401528915156060840152881515608084015287151560a084015286151560c084015263ffffffff861660e0840152806101008401528381840152506101408385828501376000838501820152601f909301601f19169091019091019a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115615e3157615e31615e08565b500190565b815160009082906020808601845b83811015615e6057815185529382019390820190600101615e44565b50929695505050505050565b600082615e8957634e487b7160e01b600052601260045260246000fd5b500490565b60005b83811015615ea9578181015183820152602001615e91565b8381111561427c5750506000910152565b60008351615ecc818460208801615e8e565b835190830190615ee0818360208801615e8e565b01949350505050565b60008060408385031215615efc57600080fd5b8251615f0781614e61565b6020939093015192949293505050565b6000816000190483118215151615615f3157615f31615e08565b500290565b60008151808452615f4e816020860160208601615e8e565b601f01601f19169290920160200192915050565b828152604060208201526000614be46040830184615f36565b600060208284031215615f8d57600080fd5b81516146c481614e2e565b60008251615faa818460208701615e8e565b9190910192915050565b6020815260006146c46020830184615f3656fea2646970667358221220208eba2a424cf9d450353832333fa1255369096c9b3808d5d1a44f0d6978725064736f6c63430008090033000000000000000000000000abf94c0771b66bdc2b57238603d19c292c4ba8c00000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000006b175474e89094c44da98b954eedeac495271d0f

Deployed Bytecode

0x6080604052600436106102dc5760003560e01c80636c2be897116101845780639627a039116100d6578063dbcbf11b1161008a578063ed24911d11610064578063ed24911d146109b8578063f2e69c42146109cd578063f2fde38b14610a1857600080fd5b8063dbcbf11b14610858578063e67feac814610983578063ec72573f1461099857600080fd5b8063d3055dde116100bb578063d3055dde1461080f578063d3a5e4a114610822578063d73792a91461084257600080fd5b80639627a039146107dc578063c519e3d7146107fc57600080fd5b80637996eef0116101385780637d26279c116101125780637d26279c146107965780638456cb59146107a95780638da5cb5b146107be57600080fd5b80637996eef0146106fc5780637a2170d51461071c5780637d22c35c1461075057600080fd5b8063715018a611610169578063715018a61461066d578063753d130914610682578063755205e8146106b657600080fd5b80636c2be897146106195780636e80a2591461064d57600080fd5b80632ff3449f1161023d5780634faee3fe116101f15780635ed1f9bb116101cb5780635ed1f9bb146105945780635f3e9f42146105a7578063666c2334146105e557600080fd5b80634faee3fe146104f15780635731737c146105275780635c975abb1461057557600080fd5b8063414ab72711610222578063414ab72714610484578063420dab43146104a457806345253c53146104c457600080fd5b80632ff3449f1461044f5780633f4ba83a1461046f57600080fd5b80631af161cb1161029457806326c6ac301161027957806326c6ac30146103ef57806326ed4aa11461040f5780632f3ba8021461042f57600080fd5b80631af161cb146103ba578063226d4adb146103da57600080fd5b8063138315a3116102c5578063138315a31461033857806316ea5ca8146103585780631a2125cf1461037857600080fd5b806301ffc9a7146102e1578063096ff95d14610316575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614e44565b610a38565b60405190151581526020015b60405180910390f35b34801561032257600080fd5b50610336610331366004614ecb565b610a6f565b005b34801561034457600080fd5b50610336610353366004614f7f565b610c1f565b34801561036457600080fd5b50610336610373366004614faf565b610cb9565b34801561038457600080fd5b506103ac7f80244acca7a02d7199149a3038653fc8cb10ca984341ec429a626fab631e166281565b60405190815260200161030d565b3480156103c657600080fd5b506103366103d5366004614fdb565b610d2c565b3480156103e657600080fd5b50610336610d3a565b3480156103fb57600080fd5b5061033661040a366004614faf565b610d8a565b34801561041b57600080fd5b506103ac61042a366004614faf565b610d9c565b34801561043b57600080fd5b5061033661044a366004614f7f565b610db2565b34801561045b57600080fd5b5061033661046a366004614ff4565b610e4c565b34801561047b57600080fd5b50610336610f31565b34801561049057600080fd5b5061033661049f366004614f7f565b610f43565b3480156104b057600080fd5b506103366104bf3660046150a4565b611008565b3480156104d057600080fd5b506103ac6104df366004615186565b60066020526000908152604090205481565b3480156104fd57600080fd5b506103ac61050c366004615186565b6001600160a01b031660009081526002602052604090205490565b34801561053357600080fd5b5061055d610542366004615186565b6008602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161030d565b34801561058157600080fd5b50600054600160a01b900460ff16610301565b6103366105a23660046151e8565b611031565b3480156105b357600080fd5b506103016105c2366004615186565b6001600160a01b0316600090815260096020526040902054610100900460ff1690565b3480156105f157600080fd5b506103ac7f2008a1ab898fdaa2d8f178bc39e807035d2d6e330dac5e42e913ca727ab5603881565b34801561062557600080fd5b506103ac7f0bc3075778b80a2341ce445063e81924b88d61eb5f21c815e8f9cc824af096d081565b34801561065957600080fd5b506103ac6106683660046152b1565b6111f4565b34801561067957600080fd5b50610336611223565b34801561068e57600080fd5b506103ac7f126520d0bca0cfa7e5852d004cc4335723ce67c638cbd55cd530fe992a089e7b81565b3480156106c257600080fd5b506103016106d1366004614f7f565b60009182526004602090815260408084206001600160a01b0393909316845291905290205460ff1690565b34801561070857600080fd5b506103ac610717366004614faf565b611235565b34801561072857600080fd5b506103ac7fd3f4273db8ff5262b6bc5f6ee07d139463b4f826cce90c05165f63062f3686dc81565b34801561075c57600080fd5b5061030161076b366004614f7f565b60009182526003602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6103366107a43660046155fe565b61124b565b3480156107b557600080fd5b5061033661127c565b3480156107ca57600080fd5b506000546001600160a01b031661055d565b3480156107e857600080fd5b506103366107f7366004614f7f565b61128c565b61033661080a36600461574e565b61132a565b61033661081d366004615801565b61166c565b34801561082e57600080fd5b5061033661083d366004614f7f565b61199c565b34801561084e57600080fd5b506103ac61271081565b34801561086457600080fd5b50610976610873366004614fdb565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250600090815260056020908152604091829020825161012081018452905460ff80821615158352610100808304821615159484019490945262010000820481161515948301949094526301000000810484161515606083015264010000000081048416151560808301526501000000000081048416151560a083015266010000000000008104909316151560c0820152600160381b830463ffffffff1660e0820152600160581b9092046001600160a01b03169082015290565b60405161030d9190615878565b34801561098f57600080fd5b506103ac600081565b3480156109a457600080fd5b506103366109b3366004615927565b6119d1565b3480156109c457600080fd5b506103ac611a3e565b3480156109d957600080fd5b506103016109e8366004614faf565b6001600160a01b03919091166000908152600a602090815260408083209383529290522054610100900460ff1690565b348015610a2457600080fd5b50610336610a33366004615186565b611a4d565b60006001600160e01b0319821663306d7a2160e11b1480610a6957506301ffc9a760e01b6001600160e01b03198316145b92915050565b610a7885611ac8565b828114610a985760405163b62503e360e01b815260040160405180910390fd5b82610ab65760405163db560cb560e01b815260040160405180910390fd5b6001600160a01b0385166000908152600a6020526040812090805b85811015610c1557868682818110610aeb57610aeb615955565b9050602002013591506000858583818110610b0857610b08615955565b905060800201803603810190610b1e919061596b565b600084815260208690526040902054909150610100900460ff1615610b565760405163793c666f60e01b815260040160405180910390fd5b806060015181604001511115610b7f5760405163420a69a160e01b815260040160405180910390fd5b60008381526020858152604091829020835181548584015115156101000261ff00199215159290921661ffff199091161717815583830151600182018190556060850151600290920182905583519081529182015284916001600160a01b038c16917f38d88037c7f872f6e5d89332cdae804370cd604776bfcabf8da1f2e11945e271910160405180910390a350600101610ad1565b5050505050505050565b610c2882611c0f565b60008281526003602090815260408083206001600160a01b0385168452918290529091205460ff16610c6d5760405163a935ea0b60e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191690555185917f0aa5e1c56725fc01d0a61fc7302ff0201516b9af2b7261b4ecbea2f74611b5d191a3505050565b610cc282611ac8565b600154811115610ce557604051631797d38360e21b815260040160405180910390fd5b6001600160a01b038216600081815260026020526040808220849055518392917f8a2e423ccab4754dc61747d26d19bc14c55577d5fcc54b4a67d9b82a016b61df91a35050565b610d37816000611c56565b50565b3360008181526006602052604080822054905190917fb06d2760711c1c15c05bc011b1009a36c0713c6d63567c267678c3a382188b6191a333600090815260066020526040902080546001019055565b610d978233836001611ce0565b505050565b600080610da98484611e0f565b95945050505050565b610dbb82611c0f565b60008281526004602090815260408083206001600160a01b0385168452918290529091205460ff16610e005760405163ced71fff60e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191690555185917f24dced5d5e85a1733ad613a53ada041ecc410cca5ee598e3115b67d4a2525e3891a3505050565b610e5582611ac8565b6001600160a01b038216600090815260096020526040902054610100900460ff1615610e945760405163793c666f60e01b815260040160405180910390fd5b806060013581604001351115610ebd5760405163420a69a160e01b815260040160405180910390fd5b6001600160a01b03821660009081526009602052604090208190610ee182826159ee565b505060408051818301358152606083013560208201526001600160a01b038416917fdd61e240b8302b21ad48e3bec0f6e9538c9e4cfffdfde6d604963069d7e23c34910160405180910390a25050565b610f39611f06565b610f41611f60565b565b610f4c82611c0f565b6001600160a01b038116610f7357604051637a79ae6b60e11b815260040160405180910390fd5b60008281526003602090815260408083206001600160a01b0385168452918290529091205460ff1615610fb95760405163467d57a760e11b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191660011790555185917f3286c4e8704920b56173a2f9884345d5f5b90893a15dce75abc157df4081af5f91a3505050565b6110118b611c0f565b6110248b8b8b8b8b8b8b8b8b8b8b611fb5565b5050505050505050505050565b61103961219c565b84831415806110485750848114155b156110665760405163b62503e360e01b815260040160405180910390fd5b846110845760405163db560cb560e01b815260040160405180910390fd5b3461108d614d56565b6040805160608082018352600080835260208084018290528385018290528451928301855281835282018190529281018390529091805b8a8110156111d4578b8b828181106110de576110de615955565b905061028002018036038101906110f59190615a49565b945089898281811061110957611109615955565b90506060020180360381019061111f9190615a66565b935087878281811061113357611133615955565b9050606002018036038101906111499190615a66565b6060860151909350600092506001600160a01b03166111be57846101e0015191508186101561118b5760405163386ad99760e11b815260040160405180910390fd5b818603955061119c828686866121f6565b6111b95760405163f40863ff60e01b815260040160405180910390fd5b6111cc565b6111ca828686866121f6565b505b6001016110c4565b508415611024576040516315a53e4560e31b815260040160405180910390fd5b60018054810190819055600090611214818d8d8d8d8d8d8d8d8d8d611fb5565b9b9a5050505050505050505050565b61122b611f06565b610f4160006128e6565b6000806112428484611e0f565b50949350505050565b61125361219c565b61125f348484846121f6565b610d975760405163f40863ff60e01b815260040160405180910390fd5b611284611f06565b610f41612943565b61129582611c0f565b60008281526004602090815260408083206001600160a01b0385168452918290529091205460ff16156112db57604051637f622a5960e01b815260040160405180910390fd5b6001600160a01b038216600081815260208390526040808220805460ff191660011790555185917fbb1b20966aa1c5d6ce073b9c8bf92e61bc7637cfa60464b83d2be54b7fe11eb391a3505050565b61133261219c565b806113505760405163db560cb560e01b815260040160405180910390fd5b82516040908101516001600160a01b0316600090815260026020908152828220548083526005825283832084516001808252818701909652919490939282015b604080516060810182526000808252602080830182905292820152825260001990920191018161139057905050905087816000815181106113d3576113d3615955565b60200260200101819052506000806114416000858a8a8a808060200260200160405190810160405280939291908181526020016000905b828210156114365761142760e08302860136819003810190615a82565b8152602001906001019061140a565b505050505087612986565b9150915061145685858a60000151858d6132a0565b6040805160a08082019092528554600160381b900463ffffffff1681528951909101516000916115249160208201906001600160a01b03161561149e578b5160a001516114a5565b8b51608001515b6001600160a01b0390811682528c516020908101518216818401528d51015160409092019116156114d8576135a56114dc565b6135b15b67ffffffffffffffff16815260200160018c5151600181111561150157611501615b1a565b1461150e576135bc611512565b61363c5b67ffffffffffffffff16905283613692565b90506001895151600181111561153c5761153c615b1a565b14156115d6578860000151602001516001600160a01b03168960000151604001516001600160a01b03168a6000015160c001516001600160a01b03167f4b761d38cae19a364a5d44d2c4a5cdd41113f9e4d64ae2e21b766d072705b9318c60000151608001518d602001518689600001518a602001518b604001516040516115c996959493929190615b9d565b60405180910390a4611024565b8860000151602001516001600160a01b03168960000151604001516001600160a01b03168a6000015160c001516001600160a01b03167ff5960c81abf2cbc811a3b86b2b2c0338bfd5c47ad8815c941f9d59665a8d458b8c60000151608001518d602001518689600001518a60400151604051611657959493929190615c10565b60405180910390a45050505050505050505050565b61167461219c565b8281146116945760405163b62503e360e01b815260040160405180910390fd5b826116b25760405163db560cb560e01b815260040160405180910390fd5b6000806116e787604001516001600160a01b031660009081526002602090815260408083205480845260059092529091209091565b915091506000806117cc60018460405180608001604052808d815260200160006001600160a01b031681526020016000815260200160008152508b8b808060200260200160405190810160405280939291908181526020016000905b8282101561176f5761176060e08302860136819003810190615a82565b81526020019060010190611743565b50505050508a8a808060200260200160405190810160405280939291908181526020016000905b828210156117c2576117b360608302860136819003810190615a66565b81526020019060010190611796565b5050505050612986565b915091506117dd84848b858e6132a0565b6040805160a08082019092528454600160381b900463ffffffff168152908a01516000916118979160208201906001600160a01b031615611822578c60a00151611828565b8c608001515b6001600160a01b031681526020018c602001516001600160a01b0316815260200160006001600160a01b03168d602001516001600160a01b03161461186f576135a5611873565b6135b15b67ffffffffffffffff16815260200160018d51600181111561150157611501615b1a565b905060018a5160018111156118ae576118ae615b1a565b141561192b5789602001516001600160a01b03168a604001516001600160a01b03168b60c001516001600160a01b03167f35cd37c73a78d0322074e1324a7d5d4cf5c7ff21f3265d03f4d085c532c6f0198d6080015185886080015189600001518a602001518b604001516040516115c996959493929190615ca7565b89602001516001600160a01b03168a604001516001600160a01b03168b60c001516001600160a01b03167f8435e05433e0d3a3fe612b10c36f6623deec79239f76721a154687fef0ca46a18d6080015185886080015189600001518a60400151604051611657959493929190615cef565b6001600160a01b0381166119c357604051632949de9560e01b815260040160405180910390fd5b6119cd8282611c56565b5050565b6119da82611ac8565b6001600160a01b03828116600081815260086020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169486169485179055517f53ab061e9517daf6849d4bde07950e3d199f73115c2e4842a8b20a62e83abd1c9190a35050565b6000611a48613a10565b905090565b611a55611f06565b6001600160a01b038116611abf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610d37816128e6565b336001600160a01b0382161480611bf157816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b1257600080fd5b505afa925050508015611b42575060408051601f3d908101601f19168201909252611b3f91810190615d37565b60015b611b4b57611b59565b6001600160a01b0316331490505b80611bf1576001600160a01b0382166391d148546000336040516001600160e01b031960e085901b16815260048101929092526001600160a01b0316602482015260440160206040518083038186803b158015611bb557600080fd5b505afa925050508015611be5575060408051601f3d908101601f19168201909252611be291810190615d54565b60015b611bee57611bf1565b90505b806119cd576040516380a6c4af60e01b815260040160405180910390fd5b600081815260056020526040902054600160581b90046001600160a01b0316336001600160a01b031614610d3757604051638d1a2f3760e01b815260040160405180910390fd5b611c5f82611c0f565b60008281526005602052604080822080546001600160a01b03858116600160581b8181027fff0000000000000000000000000000000000000000ffffffffffffffffffffff851617855594519395949092041692909183917f195d9a13f822aeb682fa730ba46c3e3e6103134a536f98e5c40c81cc004f0a8491a350505050565b6040516bffffffffffffffffffffffff19606086811b8216602084015285901b16603482015260009081906007908290604801604051602081830303815290604052805190602001208152602001908152602001600020905060006101008581611d4c57611d4c615d71565b0460008181526020849052604090205490915060ff861690600181831c81161415611d8a5760405163015236d560e61b815260040160405180910390fd5b60009283526020849052604092839020600190921b179055516001600160a01b03808816919087169086907f61b992b9cb8061087d0e50532a8ba94e22379c7edd39cdb465536ef827dc1be790611de690881515815260200190565b60405180910390a4505050506001600160a01b0316600090815260066020526040902054919050565b6001600160a01b0382166000908152600a6020908152604080832084845282528083208151608081018352815460ff8082161580158452610100909204161515948201949094526001820154928101929092526002015460608201528291611e8557806040015181606001519250925050611eff565b6001600160a01b0385166000908152600960209081526040918290208251608081018452815460ff808216158015845261010090920416151593820193909352600182015493810193909352600201546060830152611ef35780604001518160600151935093505050611eff565b50600060001992509250505b9250929050565b6000546001600160a01b03163314610f415760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611ab6565b611f68613afe565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6040518061012001604052808b151581526020018a15158152602001891515815260200188151581526020018715158152602001861515815260200185151581526020018463ffffffff16815260200161200c3390565b6001600160a01b0390811690915260008d8152600560209081526040918290208451815492860151868501516060880151608089015160a08a015160c08b015160e08c01516101009c8d015161ffff19909a1697151561ff00191697909717951515909b029490941763ffff00001916620100009315159390930263ff0000001916929092176301000000911515919091021765ffff0000000019166401000000009115159190910265ff00000000001916176501000000000091151591909102176affffffffff00000000000019166601000000000000961515969096026affffffff00000000000000191695909517600160381b63ffffffff90961695909502949094177fff0000000000000000000000000000000000000000ffffffffffffffffffffff16600160581b919093160291909117909155518b907ffa0f19ecb97e973eefa78c4ef4f6be467d4e0d320b88fa6b3e785f09df7089f690612187908d908d908d908d908d908d908d908d908d908d90615d87565b60405180910390a25050505050505050505050565b600054600160a01b900460ff1615610f415760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401611ab6565b6080808401516001600160a01b0390811660009081526002602090815260408083205480845260058352818420825161012081018452905460ff80821615158352610100808304821615159684019690965262010000820481161515948301949094526301000000810484161515606080840191909152640100000000820485161515988301989098526501000000000081048416151560a083015266010000000000008104909316151560c082015263ffffffff600160381b84041660e0820152600160581b90920485169282019290925293870151919390929091166123395786866101e00151146122fd57604051630db5f82b60e21b815260040160405180910390fd5b855180612316575060a08601516001600160a01b031632145b1561233457604051632d8457d960e21b815260040160405180910390fd5b612375565b861561235857604051635d6c7e8160e01b815260040160405180910390fd5b612375828260200151836040015189608001518a60600151613b57565b60018660400151600181111561238d5761238d615b1a565b14156123bb576102608601516123b6576040516326db27f160e01b815260040160405180910390fd5b6123e1565b6001866102600151146123e157604051636d9e53cd60e11b815260040160405180910390fd5b8561020001514211156124075760405163099465a960e41b815260040160405180910390fd5b85610220015142111561242d5760405163026de79960e21b815260040160405180910390fd5b856101c00151866101e00151101561245857604051636769dcf160e11b815260040160405180910390fd5b6127108661016001518761014001516124719190615e1e565b1115612490576040516332a7479560e21b815260040160405180910390fd5b60c08601516001600160a01b031615612500578560c001516001600160a01b03168660e001516001600160a01b0316146124dd5760405163185ff71160e21b815260040160405180910390fd5b8060600151156125005760405163646c1dcd60e11b815260040160405180910390fd5b6101008601516001600160a01b03161561256e576101008601516001600160a01b0316336001600160a01b03161461254b576040516390158e4760e01b815260040160405180910390fd5b80608001511561256e576040516358f8e8a560e01b815260040160405180910390fd5b8060a00151156125d25760a08601516001600160a01b03163b156125a55760405163321e0c1560e11b815260040160405180910390fd5b60e08601516001600160a01b03163b156125d25760405163321e0c1560e11b815260040160405180910390fd5b8051156126635733321461261f57600082815260036020908152604080832033845290915290205460ff1661261a576040516329837f1160e21b815260040160405180910390fd5b612663565b8060c001511561266357600082815260036020908152604080832033845290915290205460ff1661266357604051631d4ca04b60e11b815260040160405180910390fd5b8060400151156126dc5760608601516001600160a01b03166126bd5760808601516001600160a01b0390811660009081526008602052604090205416156126bd576040516305a3b2ed60e41b815260040160405180910390fd5b6126dc8660800151876102400151886102600151896101e00151613be8565b6126e68686613c52565b8560200151156126ff576126fa8685613e48565b612709565b6127098685613fef565b604080516001808252818301909252600091816020015b612728614d56565b815260200190600190039081612720579050509050868160008151811061275157612751615955565b602002602001018190525060006128066040518060a001604052808560e0015163ffffffff16815260200160006001600160a01b03168b61010001516001600160a01b0316146127a6578a61010001516127ac565b8a60e001515b6001600160a01b03908116825260608c018051821660208401525160409092019116156127db576135a56127df565b6135b15b67ffffffffffffffff16815260200160018b60400151600181111561150157611501615b1a565b90508060008151811061281b5761281b615955565b602002602001015115945084156128da5787606001516001600160a01b031688608001516001600160a01b03168961012001516001600160a01b03167f7ed668b30822ae5c7db7b4a32f84e6645250bb6db0d1fc73eeb484c5b34b1d1b8b60e001518c60a001518d61024001518e61026001518f6101e001516040516128d19594939291906001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b60405180910390a45b50505050949350505050565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b61294b61219c565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611f983390565b6129bf6040518060c001604052806060815260200160608152602001606081526020016060815260200160608152602001600081525090565b6060835167ffffffffffffffff8111156129db576129db61538c565b604051908082528060200260200182016040528015612a1457816020015b612a01614d56565b8152602001906001900390816129f95790505b5090506040518060c00160405280855167ffffffffffffffff811115612a3c57612a3c61538c565b604051908082528060200260200182016040528015612a65578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612a8557612a8561538c565b604051908082528060200260200182016040528015612aae578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612ace57612ace61538c565b604051908082528060200260200182016040528015612af7578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612b1757612b1761538c565b604051908082528060200260200182016040528015612b40578160200160208202803683370190505b508152602001855167ffffffffffffffff811115612b6057612b6061538c565b604051908082528060200260200182016040528015612b89578160200160208202803683370190505b5081526020016000815250915060005b84518110156130c8576020860151604087015160608801518a15612c1857878481518110612bc957612bc9615955565b602002602001015160c001519250878481518110612be957612be9615955565b6020026020010151608001519150878481518110612c0957612c09615955565b602002602001015160a0015190505b60408051610280810182526000808252602082018190528b515190928201906001811115612c4857612c48615b1a565b81526020018b60000151602001516001600160a01b031681526020018b60000151604001516001600160a01b03168152602001856001600160a01b031681526020018b60000151606001516001600160a01b031681526020018b60000151608001516001600160a01b031681526020018b6000015160a001516001600160a01b031681526020018b6000015160c001516001600160a01b031681526020018b6000015160e0015181526020018a8781518110612d0657612d06615955565b60200260200101516040015181526020018481526020018b60000151610100015181526020018a8781518110612d3e57612d3e615955565b60200260200101516060015181526020018a8781518110612d6157612d61615955565b60200260200101516060015181526020018381526020018b60000151610140015181526020018a8781518110612d9957612d99615955565b60200260200101516000015181526020018a8781518110612dbc57612dbc615955565b602002602001015160200151815250905080868681518110612de057612de0615955565b602002602001018190525080610240015187600001518681518110612e0757612e07615955565b60200260200101818152505080610260015187602001518681518110612e2f57612e2f615955565b602002602001018181525050806101c0015187604001518681518110612e5757612e57615955565b60200260200101818152505080610160015187606001518681518110612e7f57612e7f615955565b6020026020010181815250508060a0015187608001518681518110612ea657612ea6615955565b60200260200101906001600160a01b031690816001600160a01b031681525050806101c001518760a001818151612edd9190615e1e565b905250600181604001516001811115612ef857612ef8615b1a565b1415612f2657610260810151612f21576040516326db27f160e01b815260040160405180910390fd5b612f4c565b600181610260015114612f4c57604051636d9e53cd60e11b815260040160405180910390fd5b612710816101600151826101400151612f659190615e1e565b1115612f84576040516332a7479560e21b815260040160405180910390fd5b8a5462010000900460ff1615612fb357612fb38160800151826102400151836102600151846101e00151613be8565b8b156130b957806102000151421115612fdf5760405163099465a960e41b815260040160405180910390fd5b60c08101516001600160a01b031615613056578060c001516001600160a01b03168160e001516001600160a01b03161461302c5760405163185ff71160e21b815260040160405180910390fd5b8a546301000000900460ff16156130565760405163646c1dcd60e11b815260040160405180910390fd5b8a5465010000000000900460ff16156130965760a08101516001600160a01b03163b156130965760405163321e0c1560e11b815260040160405180910390fd5b6130b9818987815181106130ac576130ac615955565b6020026020010151613c52565b84600101945050505050612b99565b50866132965784606001514211156130f35760405163099465a960e41b815260040160405180910390fd5b8451606001516001600160a01b03161561316957845160608101516080909101516001600160a01b0390811691161461313f5760405163185ff71160e21b815260040160405180910390fd5b85546301000000900460ff16156131695760405163646c1dcd60e11b815260040160405180910390fd5b855465010000000000900460ff16156131a95760208501516001600160a01b03163b156131a95760405163321e0c1560e11b815260040160405180910390fd5b613296604051806080016040528084600001516040516020016131cc9190615e36565b60405160208183030381529060405280519060200120815260200184602001516040516020016131fc9190615e36565b604051602081830303815290604052805190602001208152602001846060015160405160200161322c9190615e36565b604051602081830303815290604052805190602001208152602001846040015160405160200161325c9190615e36565b60405160208183030381529060405280519060200120815250868560008151811061328957613289615955565b60200260200101516140c9565b9550959350505050565b60208301516001600160a01b0316156133015734156132d257604051635d6c7e8160e01b815260040160405180910390fd5b8354604084015160208501516132fc92889260ff6101008304811693620100009093041691613b57565b613375565b826101200151341461332657604051630db5f82b60e21b815260040160405180910390fd5b835462010000900460ff1615613375576040808401516001600160a01b039081166000908152600860205291909120541615613375576040516305a3b2ed60e41b815260040160405180910390fd5b82610140015142111561339b5760405163026de79960e21b815260040160405180910390fd5b60a08301516001600160a01b03161561340f5760a08301516001600160a01b0316336001600160a01b0316146133e4576040516390158e4760e01b815260040160405180910390fd5b8354640100000000900460ff161561340f576040516358f8e8a560e01b815260040160405180910390fd5b835465010000000000900460ff161561344f5760808301516001600160a01b03163b1561344f5760405163321e0c1560e11b815260040160405180910390fd5b835460ff16156134ed5733321461349f57600085815260036020908152604080832033845290915290205460ff1661349a576040516329837f1160e21b815260040160405180910390fd5b6134ed565b83546601000000000000900460ff16156134ed57600085815260036020908152604080832033845290915290205460ff166134ed57604051631d4ca04b60e11b815260040160405180910390fd5b8261012001518260a001511461351657604051637867d96760e11b815260040160405180910390fd5b815160405161359e9161352b91602001615e36565b6040516020818303038152906040528051906020012083602001516040516020016135569190615e36565b6040516020818303038152906040528051906020012084604001516040516020016135819190615e36565b604051602081830303815290604052805190602001208685614282565b5050505050565b61359e83858785614436565b61359e8583836144a5565b6040516323b872dd60e01b81526001600160a01b038681166004830152858116602483015260448201849052600091908516906323b872dd906064015b600060405180830381600087803b15801561361357600080fd5b505af1925050508015613624575060015b61363057506000610da9565b50600195945050505050565b604051637921219560e11b81526001600160a01b0386811660048301528581166024830152604482018490526064820183905260a06084830152600060a48301819052919085169063f242432a9060c4016135f9565b6060815167ffffffffffffffff8111156136ae576136ae61538c565b6040519080825280602002602001820160405280156136d7578160200160208202803683370190505b506040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529192505b835181101561396f57600084828151811061372a5761372a615955565b6020026020010151905060006137618260a001518360e0015184608001518561024001518661026001518c6080015163ffffffff16565b9050806137bc5760408701516001600160a01b03166137935760405163f40863ff60e01b815260040160405180910390fd5b60018584815181106137a7576137a7615955565b91151560209283029190910190910152613965565b60006137e9836101e0015184608001518561024001518661012001518761014001518861016001516144d1565b905084604001516001600160a01b031681600001516001600160a01b0316146138575760a08501511561383f5761383f856040015189602001518a604001518860a001518c600001518d6060015163ffffffff16565b80516001600160a01b03166040860152600060a08601525b84602001516001600160a01b03168361012001516001600160a01b0316146138c8576080850151156138ac576138ac856020015189602001518a6040015188608001518c600001518d6060015163ffffffff16565b6101208301516001600160a01b03166020860152600060808601525b84600001516001600160a01b03168360a001516001600160a01b0316146139345760608501511561391c5761391c856000015189602001518a6040015188606001518c600001518d6060015163ffffffff16565b60a08301516001600160a01b03168552600060608601525b602081015160a086018051909101905260408101516080860180519091019052606090810151908501805190910190525b505060010161370d565b5060a0810151156139a3576139a38160400151856020015186604001518460a001518860000151896060015163ffffffff16565b6080810151156139d6576139d681602001518560200151866040015184608001518860000151896060015163ffffffff16565b606081015115613a0957613a0981600001518560200151866040015184606001518860000151896060015163ffffffff16565b5092915050565b6000306001600160a01b037f000000000000000000000000009a1dc9f1a6e2134ad4236fcd75b1ae6285850716148015613a6957507f000000000000000000000000000000000000000000000000000000000000000146145b15613a9357507f768bdd21a17ade31eba72fa420f228a30bac37d0579f0e58707baa9a2334444c90565b611a487f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7fdab569368da3525b394950b18252b2a008851cf1162b59295579c87c377905267fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6614681565b600054600160a01b900460ff16610f415760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401611ab6565b8215613b9f576001600160a01b03828116600090815260086020526040902054811690821614613b9a576040516355ce006f60e11b815260040160405180910390fd5b61359e565b831561359e5760008581526004602090815260408083206001600160a01b038516845290915290205460ff1661359e576040516355ce006f60e11b815260040160405180910390fd5b6000613bf48383615e6c565b9050600080613c038787611e0f565b9150915081831015613c285760405163024c625160e61b815260040160405180910390fd5b80831115613c4957604051639837ddd760e01b815260040160405180910390fd5b50505050505050565b6000613dd57fd3f4273db8ff5262b6bc5f6ee07d139463b4f826cce90c05165f63062f3686dc60001b84604001516001811115613c9157613c91615b1a565b855161012087015161014088015161016089015160c08a0151604051613cfa979695949392919060200196875260ff95909516602087015292151560408601526001600160a01b039182166060860152608085015260a08401919091521660c082015260e00190565b60408051601f1981840301815291905260a085015160808601516102408701516102608801516101c08901516102008a01516101808b01516101208c0151613d459088836000611ce0565b6060808e0151604080516001600160a01b039b8c166020820152998b16908a015290880196909652608087019490945260a086019290925260c085015260e084015261010083015291909116610120820152610140015b60408051601f1981840301815290829052613dba9291602001615eba565b604051602081830303815290604052805190602001206146cb565b60a08401519091506001600160a01b03163b15613dfb57610d978360a001518284614719565b613e1381836000015184602001518560400151614833565b6001600160a01b03168360a001516001600160a01b031614610d97576040516312a0f2db60e11b815260040160405180910390fd5b6000613f7c7f0bc3075778b80a2341ce445063e81924b88d61eb5f21c815e8f9cc824af096d060001b84604001516001811115613e8757613e87615b1a565b6020808701516101208801516101408901516101008a015160e08b015160808c01516102608d01516101e08e0151604051613f159b9a9901998a5260ff9890981660208a015295151560408901526001600160a01b039485166060890152608088019390935290831660a0870152821660c08601521660e08401526101008301526101208201526101400190565b604051602081830303815290604052846102200151856101a00151613f4b8761012001518860e00151896101a001516000611ce0565b6060808901516040805160208101969096528501939093528301526001600160a01b0316608082015260a001613d9c565b60e08401519091506001600160a01b03163b15613fa257610d978360e001518284614719565b613fba81836000015184602001518560400151614833565b6001600160a01b03168360e001516001600160a01b031614610d97576040516320af217960e01b815260040160405180910390fd5b6000613f7c7f2008a1ab898fdaa2d8f178bc39e807035d2d6e330dac5e42e913ca727ab5603860001b8460400151600181111561402e5761402e615b1a565b8561012001518661014001518761010001518860e0015189608001518a61024001518b61026001518c6101e00151604051602001613f159a99989796959493929190998a5260ff9890981660208a01526001600160a01b0396871660408a01526060890195909552928516608088015290841660a087015290921660c085015260e08401919091526101008301526101208201526101400190565b815151600090614204907f80244acca7a02d7199149a3038653fc8cb10ca984341ec429a626fab631e166290600181111561410657614106615b1a565b855160c081015160e082015160608301516020808b0151604095860151955161416e98979691920196875260ff9590951660208701526001600160a01b039384166040870152606086019290925282166080850152811660a08401521660c082015260e00190565b60408051601f19818403018152918152606086015190860151865160c00151602088015161419f9190836000611ce0565b87516020908101518a518b8301516040808e015160608f01519151613d9c9998979691929101978852602088019690965260408701949094526001600160a01b03929092166060860152608085015260a084015260c083015260e08201526101000190565b60208401519091506001600160a01b03163b1561422f5761422a83602001518284614719565b61427c565b61424781836000015184602001518560400151614833565b6001600160a01b031683602001516001600160a01b03161461427c576040516312a0f2db60e11b815260040160405180910390fd5b50505050565b81516000906143b6907f126520d0bca0cfa7e5852d004cc4335723ce67c638cbd55cd530fe992a089e7b9060018111156142be576142be615b1a565b8560c001518660e001518760a00151886080015189604001518a610120015160405160200161433698979695949392919097885260ff9690961660208801526001600160a01b03948516604088015260608701939093529083166080860152821660a08501521660c083015260e08201526101000190565b60405160208183030381529060405284610140015185610100015161436b8760c0015188608001518961010001516000611ce0565b60208881015160408051928301959095529381019290925260608201526001600160a01b03909116608082015260a0810189905260c0810188905260e0810187905261010001613d9c565b60808401519091506001600160a01b03163b156143e1576143dc83608001518284614719565b61442e565b6143f981836000015184602001518560400151614833565b6001600160a01b031683608001516001600160a01b03161461442e576040516320af217960e01b815260040160405180910390fd5b505050505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b17905261427c90859061485b565b6000806000806000868887f190508061427c5760405163364cc69f60e11b815260040160405180910390fd5b614505604051806080016040528060006001600160a01b031681526020016000815260200160008152602001600081525090565b6060810187905260405163152a902d60e11b815260048101869052602481018890526001600160a01b03871690632a55205a90604401604080518083038186803b15801561455257600080fd5b505afa925050508015614582575060408051601f3d908101601f1916820190925261457f91810190615ee9565b60015b6145bc573d8080156145b0576040519150601f19603f3d011682016040523d82523d6000602084013e6145b5565b606091505b505061462d565b6001600160a01b0382166145ce575060005b801561462a576127106145e1858b615f17565b6145eb9190615e6c565b81111561460b576040516306f6f23d60e21b815260040160405180910390fd5b6001600160a01b03821683526020830181905260608301805182900390525b50505b6001600160a01b038416614642576000614659565b61271061464f8489615f17565b6146599190615e6c565b60408201819052156146775760408101516060820180519190910390525b9695505050505050565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090505b9392505050565b6000610a696146d8613a10565b8360405161190160f01b6020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b6000836001600160a01b0316631626ba7e8484602001518560400151866000015160405160200161478293929190928352602083019190915260f81b7fff0000000000000000000000000000000000000000000000000000000000000016604082015260410190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016147ae929190615f62565b60206040518083038186803b1580156147c657600080fd5b505afa9250505080156147f6575060408051601f3d908101601f191682019092526147f391810190615f7b565b60015b6147ff57614815565b6001600160e01b031916630b135d3f60e11b1490505b8061427c576040516307c1d80160e51b815260040160405180910390fd5b60008060006148448787878761492d565b9150915061485181614a1a565b5095945050505050565b60006148b0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614bd59092919063ffffffff16565b805190915015610d9757808060200190518101906148ce9190615d54565b610d975760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401611ab6565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156149645750600090506003614a11565b8460ff16601b1415801561497c57508460ff16601c14155b1561498d5750600090506004614a11565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156149e1573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116614a0a57600060019250925050614a11565b9150600090505b94509492505050565b6000816004811115614a2e57614a2e615b1a565b1415614a375750565b6001816004811115614a4b57614a4b615b1a565b1415614a995760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401611ab6565b6002816004811115614aad57614aad615b1a565b1415614afb5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611ab6565b6003816004811115614b0f57614b0f615b1a565b1415614b685760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401611ab6565b6004816004811115614b7c57614b7c615b1a565b1415610d375760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401611ab6565b6060614be48484600085614bec565b949350505050565b606082471015614c4d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611ab6565b6001600160a01b0385163b614ca45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611ab6565b600080866001600160a01b03168587604051614cc09190615f98565b60006040518083038185875af1925050503d8060008114614cfd576040519150601f19603f3d011682016040523d82523d6000602084013e614d02565b606091505b5091509150614d12828286614d1d565b979650505050505050565b60608315614d2c5750816146c4565b825115614d3c5782518084602001fd5b8160405162461bcd60e51b8152600401611ab69190615fb4565b60408051610280810182526000808252602082018190529091820190815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6001600160e01b031981168114610d3757600080fd5b600060208284031215614e5657600080fd5b81356146c481614e2e565b6001600160a01b0381168114610d3757600080fd5b8035614e8181614e61565b919050565b60008083601f840112614e9857600080fd5b50813567ffffffffffffffff811115614eb057600080fd5b6020830191508360208260071b8501011115611eff57600080fd5b600080600080600060608688031215614ee357600080fd5b8535614eee81614e61565b9450602086013567ffffffffffffffff80821115614f0b57600080fd5b818801915088601f830112614f1f57600080fd5b813581811115614f2e57600080fd5b8960208260051b8501011115614f4357600080fd5b602083019650809550506040880135915080821115614f6157600080fd5b50614f6e88828901614e86565b969995985093965092949392505050565b60008060408385031215614f9257600080fd5b823591506020830135614fa481614e61565b809150509250929050565b60008060408385031215614fc257600080fd5b8235614fcd81614e61565b946020939093013593505050565b600060208284031215614fed57600080fd5b5035919050565b60008082840360a081121561500857600080fd5b833561501381614e61565b92506080601f198201121561502757600080fd5b506020830190509250929050565b8015158114610d3757600080fd5b8035614e8181615035565b803563ffffffff81168114614e8157600080fd5b60008083601f84011261507457600080fd5b50813567ffffffffffffffff81111561508c57600080fd5b602083019150836020828501011115611eff57600080fd5b60008060008060008060008060008060006101408c8e0312156150c657600080fd5b8b359a5060208c01356150d881615035565b995060408c01356150e881615035565b985060608c01356150f881615035565b975060808c013561510881615035565b965060a08c013561511881615035565b955061512660c08d01615043565b945061513460e08d01615043565b93506151436101008d0161504e565b92506101208c013567ffffffffffffffff81111561516057600080fd5b61516c8e828f01615062565b915080935050809150509295989b509295989b9093969950565b60006020828403121561519857600080fd5b81356146c481614e61565b60008083601f8401126151b557600080fd5b50813567ffffffffffffffff8111156151cd57600080fd5b602083019150836020606083028501011115611eff57600080fd5b6000806000806000806060878903121561520157600080fd5b863567ffffffffffffffff8082111561521957600080fd5b818901915089601f83011261522d57600080fd5b81358181111561523c57600080fd5b8a60206102808302850101111561525257600080fd5b60209283019850965090880135908082111561526d57600080fd5b6152798a838b016151a3565b9096509450604089013591508082111561529257600080fd5b5061529f89828a016151a3565b979a9699509497509295939492505050565b6000806000806000806000806000806101208b8d0312156152d157600080fd5b8a356152dc81615035565b995060208b01356152ec81615035565b985060408b01356152fc81615035565b975060608b013561530c81615035565b965060808b013561531c81615035565b955060a08b013561532c81615035565b945060c08b013561533c81615035565b935061534a60e08c0161504e565b92506101008b013567ffffffffffffffff81111561536757600080fd5b6153738d828e01615062565b915080935050809150509295989b9194979a5092959850565b634e487b7160e01b600052604160045260246000fd5b604051610280810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b60405290565b604051610160810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff811182821017156153d457634e487b7160e01b600052604160045260246000fd5b803560028110614e8157600080fd5b6000610280828403121561545f57600080fd5b6154676153a2565b905061547282615043565b815261548060208301615043565b60208201526154916040830161543d565b60408201526154a260608301614e76565b60608201526154b360808301614e76565b60808201526154c460a08301614e76565b60a08201526154d560c08301614e76565b60c08201526154e660e08301614e76565b60e08201526101006154f9818401614e76565b9082015261012061550b838201614e76565b908201526101408281013590820152610160808301359082015261018080830135908201526101a080830135908201526101c080830135908201526101e080830135908201526102008083013590820152610220808301359082015261024080830135908201526102609182013591810191909152919050565b60006060828403121561559757600080fd5b6040516060810181811067ffffffffffffffff821117156155c857634e487b7160e01b600052604160045260246000fd5b604052905080823560ff811681146155df57600080fd5b8082525060208301356020820152604083013560408201525092915050565b6000806000610340848603121561561457600080fd5b61561e858561544c565b925061562e856102808601615585565b915061563e856102e08601615585565b90509250925092565b6000610160828403121561565a57600080fd5b6156626153da565b905061566d8261543d565b815261567b60208301614e76565b602082015261568c60408301614e76565b604082015261569d60608301614e76565b60608201526156ae60808301614e76565b60808201526156bf60a08301614e76565b60a08201526156d060c08301614e76565b60c082015260e082013560e082015261010080830135818301525061012080830135818301525061014080830135818301525092915050565b60008083601f84011261571b57600080fd5b50813567ffffffffffffffff81111561573357600080fd5b60208301915083602060e083028501011115611eff57600080fd5b60008060008060008587036102a081121561576857600080fd5b6157728888615585565b95506157818860608901615585565b94506101c060bf198201121561579657600080fd5b5061579f61540c565b6157ac8860c08901615647565b81526102208701356157bd81614e61565b602082015261024087013560408201526102608701356060820152925061028086013567ffffffffffffffff8111156157f557600080fd5b614f6e88828901615709565b600080600080600080610200878903121561581b57600080fd5b6158258888615585565b95506158348860608901615647565b94506101c087013567ffffffffffffffff8082111561585257600080fd5b61585e8a838b01615709565b90965094506101e089013591508082111561529257600080fd5b60006101208201905082511515825260208301511515602083015260408301516158a6604084018215159052565b5060608301516158ba606084018215159052565b5060808301516158ce608084018215159052565b5060a08301516158e260a084018215159052565b5060c08301516158f660c084018215159052565b5060e083015161590e60e084018263ffffffff169052565b50610100928301516001600160a01b0316919092015290565b6000806040838503121561593a57600080fd5b823561594581614e61565b91506020830135614fa481614e61565b634e487b7160e01b600052603260045260246000fd5b60006080828403121561597d57600080fd5b6040516080810181811067ffffffffffffffff821117156159ae57634e487b7160e01b600052604160045260246000fd5b60405282356159bc81615035565b815260208301356159cc81615035565b6020820152604083810135908201526060928301359281019290925250919050565b81356159f981615035565b815460ff19811691151560ff1691821783556020840135615a1981615035565b61ffff199190911690911790151560081b61ff001617815560408201356001820155606090910135600290910155565b60006102808284031215615a5c57600080fd5b6146c4838361544c565b600060608284031215615a7857600080fd5b6146c48383615585565b600060e08284031215615a9457600080fd5b60405160e0810181811067ffffffffffffffff82111715615ac557634e487b7160e01b600052604160045260246000fd5b8060405250823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c0830135615b0e81614e61565b60c08201529392505050565b634e487b7160e01b600052602160045260246000fd5b600081518084526020808501945080840160005b83811015615b62578151151587529582019590820190600101615b44565b509495945050505050565b600081518084526020808501945080840160005b83811015615b6257815187529582019590820190600101615b81565b60006001600160a01b03808916835280881660208401525060c06040830152615bc960c0830187615b30565b8281036060840152615bdb8187615b6d565b90508281036080840152615bef8186615b6d565b905082810360a0840152615c038185615b6d565b9998505050505050505050565b60006001600160a01b03808816835280871660208401525060a06040830152615c3c60a0830186615b30565b8281036060840152615c4e8186615b6d565b90508281036080840152615c628185615b6d565b98975050505050505050565b600081518084526020808501945080840160005b83811015615b625781516001600160a01b031687529582019590820190600101615c82565b6001600160a01b038716815260c060208201526000615cc960c0830188615b30565b8281036040840152615cdb8188615c6e565b90508281036060840152615bdb8187615b6d565b6001600160a01b038616815260a060208201526000615d1160a0830187615b30565b8281036040840152615d238187615c6e565b90508281036060840152615c4e8186615b6d565b600060208284031215615d4957600080fd5b81516146c481614e61565b600060208284031215615d6657600080fd5b81516146c481615035565b634e487b7160e01b600052601260045260246000fd5b60006101208c151583528b151560208401528a151560408401528915156060840152881515608084015287151560a084015286151560c084015263ffffffff861660e0840152806101008401528381840152506101408385828501376000838501820152601f909301601f19169091019091019a9950505050505050505050565b634e487b7160e01b600052601160045260246000fd5b60008219821115615e3157615e31615e08565b500190565b815160009082906020808601845b83811015615e6057815185529382019390820190600101615e44565b50929695505050505050565b600082615e8957634e487b7160e01b600052601260045260246000fd5b500490565b60005b83811015615ea9578181015183820152602001615e91565b8381111561427c5750506000910152565b60008351615ecc818460208801615e8e565b835190830190615ee0818360208801615e8e565b01949350505050565b60008060408385031215615efc57600080fd5b8251615f0781614e61565b6020939093015192949293505050565b6000816000190483118215151615615f3157615f31615e08565b500290565b60008151808452615f4e816020860160208601615e8e565b601f01601f19169290920160200192915050565b828152604060208201526000614be46040830184615f36565b600060208284031215615f8d57600080fd5b81516146c481614e2e565b60008251615faa818460208701615e8e565b9190910192915050565b6020815260006146c46020830184615f3656fea2646970667358221220208eba2a424cf9d450353832333fa1255369096c9b3808d5d1a44f0d6978725064736f6c63430008090033

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

000000000000000000000000abf94c0771b66bdc2b57238603d19c292c4ba8c00000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000006b175474e89094c44da98b954eedeac495271d0f

-----Decoded View---------------
Arg [0] : defaultContractOwner_ (address): 0xaBF94C0771b66bDc2B57238603d19c292C4ba8C0
Arg [1] : defaultPushPaymentGasLimit_ (uint32): 8000
Arg [2] : defaultPaymentMethods (address[]): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0xdAC17F958D2ee523a2206206994597C13D831ec7,0x6B175474E89094C44Da98b954EedeAC495271d0F

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000abf94c0771b66bdc2b57238603d19c292c4ba8c0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000001f40
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [4] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [5] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [6] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [7] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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