ETH Price: $3,350.25 (-0.95%)
Gas: 10 Gwei

Contract

0x0000000000E655fAe4d56241588680F86E3b2377
 

Overview

ETH Balance

1 wei

Eth Value

Less Than $0.01 (@ $3,350.25/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Execute Multiple...201751822024-06-26 10:11:356 hrs ago1719396695IN
LooksRare: Exchange V2
0.0749 ETH0.00392084.23344489
Increment Bid As...201747972024-06-26 8:54:238 hrs ago1719392063IN
LooksRare: Exchange V2
0 ETH0.0003144.60566499
Execute Taker Bi...201745112024-06-26 7:56:478 hrs ago1719388607IN
LooksRare: Exchange V2
0.0019 ETH0.000268521.82081361
Cancel Order Non...201739992024-06-26 6:13:3510 hrs ago1719382415IN
LooksRare: Exchange V2
0 ETH0.000097872.10533851
Execute Taker Bi...201738182024-06-26 5:37:2311 hrs ago1719380243IN
LooksRare: Exchange V2
0.01 ETH0.000620313.41408057
Cancel Order Non...201725832024-06-26 1:29:2315 hrs ago1719365363IN
LooksRare: Exchange V2
0 ETH0.000132932.8595128
Cancel Order Non...201715622024-06-25 22:04:2318 hrs ago1719353063IN
LooksRare: Exchange V2
0 ETH0.000213884.6019818
Execute Multiple...201712362024-06-25 20:59:1119 hrs ago1719349151IN
LooksRare: Exchange V2
0.1609 ETH0.004201644
Execute Taker Bi...201656892024-06-25 2:23:1138 hrs ago1719282191IN
LooksRare: Exchange V2
0.0176 ETH0.000790334.2241933
Execute Taker Bi...201656712024-06-25 2:19:3538 hrs ago1719281975IN
LooksRare: Exchange V2
0.0175 ETH0.000514133.60734876
Execute Taker Bi...201646582024-06-24 22:55:3542 hrs ago1719269735IN
LooksRare: Exchange V2
0.089 ETH0.000499083.396963
Execute Taker Bi...201615172024-06-24 12:23:232 days ago1719231803IN
LooksRare: Exchange V2
0.2 ETH0.000911756.90831776
Execute Taker Bi...201591512024-06-24 4:27:112 days ago1719203231IN
LooksRare: Exchange V2
0.08 ETH0.000495452.73024497
Execute Taker As...201590462024-06-24 4:05:592 days ago1719201959IN
LooksRare: Exchange V2
0 ETH0.000530852.8323927
Cancel Order Non...201579492024-06-24 0:24:472 days ago1719188687IN
LooksRare: Exchange V2
0 ETH0.000056352.11968596
Cancel Order Non...201579462024-06-24 0:24:112 days ago1719188651IN
LooksRare: Exchange V2
0 ETH0.000084751.82321536
Cancel Order Non...201571152024-06-23 21:37:112 days ago1719178631IN
LooksRare: Exchange V2
0 ETH0.000131272.82389033
Cancel Order Non...201571102024-06-23 21:36:112 days ago1719178571IN
LooksRare: Exchange V2
0 ETH0.000134612.89564391
Cancel Order Non...201571042024-06-23 21:34:592 days ago1719178499IN
LooksRare: Exchange V2
0 ETH0.000134192.88665003
Cancel Order Non...201570962024-06-23 21:33:232 days ago1719178403IN
LooksRare: Exchange V2
0 ETH0.000149933.22599296
Cancel Order Non...201570892024-06-23 21:31:592 days ago1719178319IN
LooksRare: Exchange V2
0 ETH0.000144333.10484965
Cancel Order Non...201570712024-06-23 21:27:592 days ago1719178079IN
LooksRare: Exchange V2
0 ETH0.000143533.08754087
Cancel Order Non...201570662024-06-23 21:26:592 days ago1719178019IN
LooksRare: Exchange V2
0 ETH0.00013953.00083986
Cancel Order Non...201570462024-06-23 21:22:592 days ago1719177779IN
LooksRare: Exchange V2
0 ETH0.000166143.57398234
Cancel Order Non...201570352024-06-23 21:20:472 days ago1719177647IN
LooksRare: Exchange V2
0 ETH0.000168093.61587681
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.006 ETH
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.035 ETH
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.012 ETH
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.0074 ETH
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.0067 ETH
201751822024-06-26 10:11:356 hrs ago1719396695
LooksRare: Exchange V2
0.0078 ETH
201745112024-06-26 7:56:478 hrs ago1719388607
LooksRare: Exchange V2
0.0019 ETH
201738182024-06-26 5:37:2311 hrs ago1719380243
LooksRare: Exchange V2
0.01 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.022 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.022 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.02 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.02 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.02 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.02 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.02 ETH
201712362024-06-25 20:59:1119 hrs ago1719349151
LooksRare: Exchange V2
0.0169 ETH
201685212024-06-25 11:52:5929 hrs ago1719316379
LooksRare: Exchange V2
0.1434449 ETH
201685212024-06-25 11:52:5929 hrs ago1719316379
LooksRare: Exchange V2
0.1434449 ETH
201656892024-06-25 2:23:1138 hrs ago1719282191
LooksRare: Exchange V2
0.0176 ETH
201656712024-06-25 2:19:3538 hrs ago1719281975
LooksRare: Exchange V2
0.0175 ETH
201654602024-06-25 1:37:1139 hrs ago1719279431
LooksRare: Exchange V2
0.01 ETH
201654602024-06-25 1:37:1139 hrs ago1719279431
LooksRare: Exchange V2
0.01 ETH
201654602024-06-25 1:37:1139 hrs ago1719279431
LooksRare: Exchange V2
0.01 ETH
201654602024-06-25 1:37:1139 hrs ago1719279431
LooksRare: Exchange V2
0.01 ETH
201646582024-06-24 22:55:3542 hrs ago1719269735
LooksRare: Exchange V2
0.089 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LooksRareProtocol

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 888888 runs

Other Settings:
default evmVersion
File 1 of 47 : LooksRareProtocol.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// LooksRare unopinionated libraries
import {SignatureCheckerCalldata} from "@looksrare/contracts-libs/contracts/SignatureCheckerCalldata.sol";
import {LowLevelETHReturnETHIfAnyExceptOneWei} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelETHReturnETHIfAnyExceptOneWei.sol";
import {LowLevelWETH} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelWETH.sol";
import {LowLevelERC20Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC20Transfer.sol";

// OpenZeppelin's library (adjusted) for verifying Merkle proofs
import {MerkleProofCalldataWithNodes} from "./libraries/OpenZeppelin/MerkleProofCalldataWithNodes.sol";

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";

// Interfaces
import {ILooksRareProtocol} from "./interfaces/ILooksRareProtocol.sol";

// Shared errors
import {CallerInvalid, CurrencyInvalid, LengthsInvalid, MerkleProofInvalid, MerkleProofTooLarge, QuoteTypeInvalid} from "./errors/SharedErrors.sol";

// Direct dependencies
import {TransferSelectorNFT} from "./TransferSelectorNFT.sol";
import {BatchOrderTypehashRegistry} from "./BatchOrderTypehashRegistry.sol";

// Constants
import {MAX_CALLDATA_PROOF_LENGTH, ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol";

// Enums
import {QuoteType} from "./enums/QuoteType.sol";

/**
 * @title LooksRareProtocol
 * @notice This contract is the core smart contract of the LooksRare protocol ("v2").
 *         It is the main entry point for users to initiate transactions with taker orders
 *         and manage the cancellation of maker orders, which exist off-chain.
LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRAR'''''''''''''''''''''''''''''''''''OOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKS:.                                        .;OOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOO,.                                            .,KSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRAREL'                ..',;:LOOKS::;,'..                'RARELOOKSRARELOOKSR
LOOKSRARELOOKSRAR.              .,:LOOKSRARELOOKSRARELO:,.              .RELOOKSRARELOOKSR
LOOKSRARELOOKS:.             .;RARELOOKSRARELOOKSRARELOOKSl;.             .:OOKSRARELOOKSR
LOOKSRARELOO;.            .'OKSRARELOOKSRARELOOKSRARELOOKSRARE'.            .;KSRARELOOKSR
LOOKSRAREL,.            .,LOOKSRARELOOK:;;:"""":;;;lELOOKSRARELO,.            .,RARELOOKSR
LOOKSRAR.             .;okLOOKSRAREx:.              .;OOKSRARELOOK;.             .RELOOKSR
LOOKS:.             .:dOOOLOOKSRARE'      .''''..     .OKSRARELOOKSR:.             .LOOKSR
LOx;.             .cKSRARELOOKSRAR'     'LOOKSRAR'     .KSRARELOOKSRARc..            .OKSR
L;.             .cxOKSRARELOOKSRAR.    .LOOKS.RARE'     ;kRARELOOKSRARExc.             .;R
LO'             .;oOKSRARELOOKSRAl.    .LOOKS.RARE.     :kRARELOOKSRAREo;.             'SR
LOOK;.            .,KSRARELOOKSRAx,     .;LOOKSR;.     .oSRARELOOKSRAo,.            .;OKSR
LOOKSk:.            .'RARELOOKSRARd;.      ....       'oOOOOOOOOOOxc'.            .:LOOKSR
LOOKSRARc.             .:dLOOKSRAREko;.            .,lxOOOOOOOOOd:.             .ARELOOKSR
LOOKSRARELo'             .;oOKSRARELOOxoc;,....,;:ldkOOOOOOOOkd;.             'SRARELOOKSR
LOOKSRARELOOd,.            .,lSRARELOOKSRARELOOKSRARELOOKSRkl,.            .,OKSRARELOOKSR
LOOKSRARELOOKSx;.            ..;oxELOOKSRARELOOKSRARELOkxl:..            .:LOOKSRARELOOKSR
LOOKSRARELOOKSRARc.              .':cOKSRARELOOKSRALOc;'.              .ARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELl'                 ...'',,,,''...                 'SRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOo,.                                          .,OKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSx;.                                      .;xOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLO:.                                  .:SRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKl.                              .lOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRo'.                        .'oWENV2?LOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARd;.                    .;xRELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARELO:.                .:kRARELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKl.            .cOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRo'        'oLOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARE,.  .,dRELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR
LOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSRARELOOKSRARELOOKSRLOOKSRARELOOKSRARELOOKSR
 * @author LooksRare protocol team (👀,💎)
 */
contract LooksRareProtocol is
    ILooksRareProtocol,
    TransferSelectorNFT,
    LowLevelETHReturnETHIfAnyExceptOneWei,
    LowLevelWETH,
    LowLevelERC20Transfer,
    BatchOrderTypehashRegistry
{
    using OrderStructs for OrderStructs.Maker;

    /**
     * @notice Wrapped ETH.
     */
    address public immutable WETH;

    /**
     * @notice Current chainId.
     */
    uint256 public chainId;

    /**
     * @notice Current domain separator.
     */
    bytes32 public domainSeparator;

    /**
     * @notice This variable is used as the gas limit for a ETH transfer.
     *         If a standard ETH transfer fails within this gas limit, ETH will get wrapped to WETH
     *         and transferred to the initial recipient.
     */
    uint256 private _gasLimitETHTransfer = 2_300;

    /**
     * @notice Constructor
     * @param _owner Owner address
     * @param _protocolFeeRecipient Protocol fee recipient address
     * @param _transferManager Transfer manager address
     * @param _weth Wrapped ETH address
     */
    constructor(
        address _owner,
        address _protocolFeeRecipient,
        address _transferManager,
        address _weth
    ) TransferSelectorNFT(_owner, _protocolFeeRecipient, _transferManager) {
        _updateDomainSeparator();
        WETH = _weth;
    }

    /**
     * @inheritdoc ILooksRareProtocol
     */
    function executeTakerAsk(
        OrderStructs.Taker calldata takerAsk,
        OrderStructs.Maker calldata makerBid,
        bytes calldata makerSignature,
        OrderStructs.MerkleTree calldata merkleTree,
        address affiliate
    ) external nonReentrant {
        address currency = makerBid.currency;

        // Verify whether the currency is allowed and is not ETH (address(0))
        if (!isCurrencyAllowed[currency] || currency == address(0)) {
            revert CurrencyInvalid();
        }

        address signer = makerBid.signer;
        bytes32 orderHash = makerBid.hash();
        _verifyMerkleProofOrOrderHash(merkleTree, orderHash, makerSignature, signer);

        // Execute the transaction and fetch protocol fee amount
        uint256 totalProtocolFeeAmount = _executeTakerAsk(takerAsk, makerBid, orderHash);

        // Pay protocol fee (and affiliate fee if any)
        _payProtocolFeeAndAffiliateFee(currency, signer, affiliate, totalProtocolFeeAmount);
    }

    /**
     * @inheritdoc ILooksRareProtocol
     */
    function executeTakerBid(
        OrderStructs.Taker calldata takerBid,
        OrderStructs.Maker calldata makerAsk,
        bytes calldata makerSignature,
        OrderStructs.MerkleTree calldata merkleTree,
        address affiliate
    ) external payable nonReentrant {
        address currency = makerAsk.currency;

        // Verify whether the currency is allowed for trading.
        if (!isCurrencyAllowed[currency]) {
            revert CurrencyInvalid();
        }

        bytes32 orderHash = makerAsk.hash();
        _verifyMerkleProofOrOrderHash(merkleTree, orderHash, makerSignature, makerAsk.signer);

        // Execute the transaction and fetch protocol fee amount
        uint256 totalProtocolFeeAmount = _executeTakerBid(takerBid, makerAsk, msg.sender, orderHash);

        // Pay protocol fee amount (and affiliate fee if any)
        _payProtocolFeeAndAffiliateFee(currency, msg.sender, affiliate, totalProtocolFeeAmount);

        // Return ETH if any
        _returnETHIfAnyWithOneWeiLeft();
    }

    /**
     * @inheritdoc ILooksRareProtocol
     */
    function executeMultipleTakerBids(
        OrderStructs.Taker[] calldata takerBids,
        OrderStructs.Maker[] calldata makerAsks,
        bytes[] calldata makerSignatures,
        OrderStructs.MerkleTree[] calldata merkleTrees,
        address affiliate,
        bool isAtomic
    ) external payable nonReentrant {
        uint256 length = takerBids.length;
        if (
            length == 0 ||
            (makerAsks.length ^ length) | (makerSignatures.length ^ length) | (merkleTrees.length ^ length) != 0
        ) {
            revert LengthsInvalid();
        }

        // Verify whether the currency at index = 0 is allowed for trading
        address currency = makerAsks[0].currency;
        if (!isCurrencyAllowed[currency]) {
            revert CurrencyInvalid();
        }

        {
            // Initialize protocol fee amount
            uint256 totalProtocolFeeAmount;

            // If atomic, it uses the executeTakerBid function.
            // If not atomic, it uses a catch/revert pattern with external function.
            if (isAtomic) {
                for (uint256 i; i < length; ) {
                    OrderStructs.Maker calldata makerAsk = makerAsks[i];

                    // Verify the currency is the same
                    if (i != 0) {
                        if (makerAsk.currency != currency) {
                            revert CurrencyInvalid();
                        }
                    }

                    OrderStructs.Taker calldata takerBid = takerBids[i];
                    bytes32 orderHash = makerAsk.hash();

                    {
                        _verifyMerkleProofOrOrderHash(merkleTrees[i], orderHash, makerSignatures[i], makerAsk.signer);

                        // Execute the transaction and add protocol fee
                        totalProtocolFeeAmount += _executeTakerBid(takerBid, makerAsk, msg.sender, orderHash);

                        unchecked {
                            ++i;
                        }
                    }
                }
            } else {
                for (uint256 i; i < length; ) {
                    OrderStructs.Maker calldata makerAsk = makerAsks[i];

                    // Verify the currency is the same
                    if (i != 0) {
                        if (makerAsk.currency != currency) {
                            revert CurrencyInvalid();
                        }
                    }

                    OrderStructs.Taker calldata takerBid = takerBids[i];
                    bytes32 orderHash = makerAsk.hash();

                    {
                        _verifyMerkleProofOrOrderHash(merkleTrees[i], orderHash, makerSignatures[i], makerAsk.signer);

                        try this.restrictedExecuteTakerBid(takerBid, makerAsk, msg.sender, orderHash) returns (
                            uint256 protocolFeeAmount
                        ) {
                            totalProtocolFeeAmount += protocolFeeAmount;
                        } catch {}

                        unchecked {
                            ++i;
                        }
                    }
                }
            }

            // Pay protocol fee (and affiliate fee if any)
            _payProtocolFeeAndAffiliateFee(currency, msg.sender, affiliate, totalProtocolFeeAmount);
        }

        // Return ETH if any
        _returnETHIfAnyWithOneWeiLeft();
    }

    /**
     * @notice This function is used to do a non-atomic matching in the context of a batch taker bid.
     * @param takerBid Taker bid struct
     * @param makerAsk Maker ask struct
     * @param sender Sender address (i.e. the initial msg sender)
     * @param orderHash Hash of the maker ask order
     * @return protocolFeeAmount Protocol fee amount
     * @dev This function is only callable by this contract. It is used for non-atomic batch order matching.
     */
    function restrictedExecuteTakerBid(
        OrderStructs.Taker calldata takerBid,
        OrderStructs.Maker calldata makerAsk,
        address sender,
        bytes32 orderHash
    ) external returns (uint256 protocolFeeAmount) {
        if (msg.sender != address(this)) {
            revert CallerInvalid();
        }

        protocolFeeAmount = _executeTakerBid(takerBid, makerAsk, sender, orderHash);
    }

    /**
     * @notice This function allows the owner to update the domain separator (if possible).
     * @dev Only callable by owner. If there is a fork of the network with a new chainId,
     *      it allows the owner to reset the domain separator for the new chain id.
     */
    function updateDomainSeparator() external onlyOwner {
        if (block.chainid != chainId) {
            _updateDomainSeparator();
            emit NewDomainSeparator();
        } else {
            revert SameDomainSeparator();
        }
    }

    /**
     * @notice This function allows the owner to update the maximum ETH gas limit for a standard transfer.
     * @param newGasLimitETHTransfer New gas limit for ETH transfer
     * @dev Only callable by owner.
     */
    function updateETHGasLimitForTransfer(uint256 newGasLimitETHTransfer) external onlyOwner {
        if (newGasLimitETHTransfer < 2_300) {
            revert NewGasLimitETHTransferTooLow();
        }

        _gasLimitETHTransfer = newGasLimitETHTransfer;

        emit NewGasLimitETHTransfer(newGasLimitETHTransfer);
    }

    /**
     * @notice This function is internal and is used to execute a taker ask (against a maker bid).
     * @param takerAsk Taker ask order struct
     * @param makerBid Maker bid order struct
     * @param orderHash Hash of the maker bid order
     * @return protocolFeeAmount Protocol fee amount
     */
    function _executeTakerAsk(
        OrderStructs.Taker calldata takerAsk,
        OrderStructs.Maker calldata makerBid,
        bytes32 orderHash
    ) internal returns (uint256) {
        if (makerBid.quoteType != QuoteType.Bid) {
            revert QuoteTypeInvalid();
        }

        address signer = makerBid.signer;
        {
            bytes32 userOrderNonceStatus = userOrderNonce[signer][makerBid.orderNonce];
            // Verify nonces
            if (
                userBidAskNonces[signer].bidNonce != makerBid.globalNonce ||
                userSubsetNonce[signer][makerBid.subsetNonce] ||
                (userOrderNonceStatus != bytes32(0) && userOrderNonceStatus != orderHash)
            ) {
                revert NoncesInvalid();
            }
        }

        (
            uint256[] memory itemIds,
            uint256[] memory amounts,
            address[2] memory recipients,
            uint256[3] memory feeAmounts,
            bool isNonceInvalidated
        ) = _executeStrategyForTakerOrder(takerAsk, makerBid, msg.sender);

        // Order nonce status is updated
        _updateUserOrderNonce(isNonceInvalidated, signer, makerBid.orderNonce, orderHash);

        // Taker action goes first
        _transferNFT(makerBid.collection, makerBid.collectionType, msg.sender, signer, itemIds, amounts);

        // Maker action goes second
        _transferToAskRecipientAndCreatorIfAny(recipients, feeAmounts, makerBid.currency, signer);

        emit TakerAsk(
            NonceInvalidationParameters({
                orderHash: orderHash,
                orderNonce: makerBid.orderNonce,
                isNonceInvalidated: isNonceInvalidated
            }),
            msg.sender,
            signer,
            makerBid.strategyId,
            makerBid.currency,
            makerBid.collection,
            itemIds,
            amounts,
            recipients,
            feeAmounts
        );

        // It returns the protocol fee amount
        return feeAmounts[2];
    }

    /**
     * @notice This function is internal and is used to execute a taker bid (against a maker ask).
     * @param takerBid Taker bid order struct
     * @param makerAsk Maker ask order struct
     * @param sender Sender of the transaction (i.e. msg.sender)
     * @param orderHash Hash of the maker ask order
     * @return protocolFeeAmount Protocol fee amount
     */
    function _executeTakerBid(
        OrderStructs.Taker calldata takerBid,
        OrderStructs.Maker calldata makerAsk,
        address sender,
        bytes32 orderHash
    ) internal returns (uint256) {
        if (makerAsk.quoteType != QuoteType.Ask) {
            revert QuoteTypeInvalid();
        }

        address signer = makerAsk.signer;
        {
            // Verify nonces
            bytes32 userOrderNonceStatus = userOrderNonce[signer][makerAsk.orderNonce];

            if (
                userBidAskNonces[signer].askNonce != makerAsk.globalNonce ||
                userSubsetNonce[signer][makerAsk.subsetNonce] ||
                (userOrderNonceStatus != bytes32(0) && userOrderNonceStatus != orderHash)
            ) {
                revert NoncesInvalid();
            }
        }

        (
            uint256[] memory itemIds,
            uint256[] memory amounts,
            address[2] memory recipients,
            uint256[3] memory feeAmounts,
            bool isNonceInvalidated
        ) = _executeStrategyForTakerOrder(takerBid, makerAsk, msg.sender);

        // Order nonce status is updated
        _updateUserOrderNonce(isNonceInvalidated, signer, makerAsk.orderNonce, orderHash);

        // Taker action goes first
        _transferToAskRecipientAndCreatorIfAny(recipients, feeAmounts, makerAsk.currency, sender);

        // Maker action goes second
        _transferNFT(
            makerAsk.collection,
            makerAsk.collectionType,
            signer,
            takerBid.recipient == address(0) ? sender : takerBid.recipient,
            itemIds,
            amounts
        );

        emit TakerBid(
            NonceInvalidationParameters({
                orderHash: orderHash,
                orderNonce: makerAsk.orderNonce,
                isNonceInvalidated: isNonceInvalidated
            }),
            sender,
            takerBid.recipient == address(0) ? sender : takerBid.recipient,
            makerAsk.strategyId,
            makerAsk.currency,
            makerAsk.collection,
            itemIds,
            amounts,
            recipients,
            feeAmounts
        );

        // It returns the protocol fee amount
        return feeAmounts[2];
    }

    /**
     * @notice This function is internal and is used to pay the protocol fee and affiliate fee (if any).
     * @param currency Currency address to transfer (address(0) is ETH)
     * @param bidUser Bid user address
     * @param affiliate Affiliate address (address(0) if none)
     * @param totalProtocolFeeAmount Total protocol fee amount (denominated in the currency)
     */
    function _payProtocolFeeAndAffiliateFee(
        address currency,
        address bidUser,
        address affiliate,
        uint256 totalProtocolFeeAmount
    ) internal {
        if (totalProtocolFeeAmount != 0) {
            if (affiliate != address(0)) {
                // Check whether affiliate program is active and whether to execute a affiliate logic
                // If so, it adjusts the protocol fee downward.
                if (isAffiliateProgramActive) {
                    uint256 totalAffiliateFeeAmount = (totalProtocolFeeAmount * affiliateRates[affiliate]) /
                        ONE_HUNDRED_PERCENT_IN_BP;

                    if (totalAffiliateFeeAmount != 0) {
                        totalProtocolFeeAmount -= totalAffiliateFeeAmount;

                        // If bid user isn't the affiliate, pay the affiliate.
                        // If currency is ETH, funds are returned to sender at the end of the execution.
                        // If currency is ERC20, funds are not transferred from bidder to bidder
                        // (since it uses transferFrom).
                        if (bidUser != affiliate) {
                            _transferFungibleTokens(currency, bidUser, affiliate, totalAffiliateFeeAmount);
                        }

                        emit AffiliatePayment(affiliate, currency, totalAffiliateFeeAmount);
                    }
                }
            }

            // Transfer remaining protocol fee to the protocol fee recipient
            _transferFungibleTokens(currency, bidUser, protocolFeeRecipient, totalProtocolFeeAmount);
        }
    }

    /**
     * @notice This function is internal and is used to transfer fungible tokens.
     * @param currency Currency address
     * @param sender Sender address
     * @param recipient Recipient address
     * @param amount Amount (in fungible tokens)
     */
    function _transferFungibleTokens(address currency, address sender, address recipient, uint256 amount) internal {
        if (currency == address(0)) {
            _transferETHAndWrapIfFailWithGasLimit(WETH, recipient, amount, _gasLimitETHTransfer);
        } else {
            _executeERC20TransferFrom(currency, sender, recipient, amount);
        }
    }

    /**
     * @notice This function is private and used to transfer funds to
     *         (1) creator recipient (if any)
     *         (2) ask recipient.
     * @param recipients Recipient addresses
     * @param feeAmounts Fees
     * @param currency Currency address
     * @param bidUser Bid user address
     * @dev It does not send to the 0-th element in the array since it is the protocol fee,
     *      which is paid later in the execution flow.
     */
    function _transferToAskRecipientAndCreatorIfAny(
        address[2] memory recipients,
        uint256[3] memory feeAmounts,
        address currency,
        address bidUser
    ) private {
        // @dev There is no check for address(0) since the ask recipient can never be address(0)
        // If ask recipient is the maker --> the signer cannot be the null address
        // If ask is the taker --> either it is the sender address or
        // if the recipient (in TakerAsk) is set to address(0), it is adjusted to the original taker address
        uint256 sellerProceed = feeAmounts[0];
        if (sellerProceed != 0) {
            _transferFungibleTokens(currency, bidUser, recipients[0], sellerProceed);
        }

        // @dev There is no check for address(0), if the creator recipient is address(0), the fee is set to 0
        uint256 creatorFeeAmount = feeAmounts[1];
        if (creatorFeeAmount != 0) {
            _transferFungibleTokens(currency, bidUser, recipients[1], creatorFeeAmount);
        }
    }

    /**
     * @notice This function is private and used to compute the domain separator and store the current chain id.
     */
    function _updateDomainSeparator() private {
        domainSeparator = keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256("LooksRareProtocol"),
                keccak256(bytes("2")),
                block.chainid,
                address(this)
            )
        );
        chainId = block.chainid;
    }

    /**
     * @notice This function is internal and is called during the execution of a transaction to decide
     *         how to map the user's order nonce.
     * @param isNonceInvalidated Whether the nonce is being invalidated
     * @param signer Signer address
     * @param orderNonce Maker user order nonce
     * @param orderHash Hash of the order struct
     * @dev If isNonceInvalidated is true, this function invalidates the user order nonce for future execution.
     *      If it is equal to false, this function maps the order hash for this user order nonce
     *      to prevent other order structs sharing the same order nonce to be executed.
     */
    function _updateUserOrderNonce(
        bool isNonceInvalidated,
        address signer,
        uint256 orderNonce,
        bytes32 orderHash
    ) private {
        userOrderNonce[signer][orderNonce] = (isNonceInvalidated ? MAGIC_VALUE_ORDER_NONCE_EXECUTED : orderHash);
    }

    /**
     * @notice This function is private and used to verify the chain id, compute the digest, and verify the signature.
     * @dev If chainId is not equal to the cached chain id, it would revert.
     * @param computedHash Hash of order (maker bid or maker ask) or merkle root
     * @param makerSignature Signature of the maker
     * @param signer Signer address
     */
    function _computeDigestAndVerify(bytes32 computedHash, bytes calldata makerSignature, address signer) private view {
        if (chainId == block.chainid) {
            // \x19\x01 is the standard encoding prefix
            SignatureCheckerCalldata.verify(
                keccak256(abi.encodePacked("\x19\x01", domainSeparator, computedHash)),
                signer,
                makerSignature
            );
        } else {
            revert ChainIdInvalid();
        }
    }

    /**
     * @notice This function is private and called to verify whether the merkle proofs provided for the order hash
     *         are correct or verify the order hash if the order is not part of a merkle tree.
     * @param merkleTree Merkle tree
     * @param orderHash Order hash (can be maker bid hash or maker ask hash)
     * @param signature Maker order signature
     * @param signer Maker address
     * @dev It verifies (1) merkle proof (if necessary) (2) signature is from the expected signer
     */
    function _verifyMerkleProofOrOrderHash(
        OrderStructs.MerkleTree calldata merkleTree,
        bytes32 orderHash,
        bytes calldata signature,
        address signer
    ) private view {
        uint256 proofLength = merkleTree.proof.length;

        if (proofLength != 0) {
            if (proofLength > MAX_CALLDATA_PROOF_LENGTH) {
                revert MerkleProofTooLarge(proofLength);
            }

            if (!MerkleProofCalldataWithNodes.verifyCalldata(merkleTree.proof, merkleTree.root, orderHash)) {
                revert MerkleProofInvalid();
            }

            orderHash = hashBatchOrder(merkleTree.root, proofLength);
        }

        _computeDigestAndVerify(orderHash, signature, signer);
    }
}

File 2 of 47 : AffiliateManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// LooksRare unopinionated libraries
import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol";

// Interfaces
import {IAffiliateManager} from "./interfaces/IAffiliateManager.sol";

// Constants
import {ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol";

/**
 * @title AffiliateManager
 * @notice This contract handles the management of affiliates for the LooksRare protocol.
 * @author LooksRare protocol team (👀,💎)
 */
contract AffiliateManager is IAffiliateManager, OwnableTwoSteps {
    /**
     * @notice Whether the affiliate program is active.
     */
    bool public isAffiliateProgramActive;

    /**
     * @notice Address of the affiliate controller.
     */
    address public affiliateController;

    /**
     * @notice It tracks the affiliate rate (in basis point) for a given affiliate address.
     *         The basis point represents how much of the protocol fee will be shared to the affiliate.
     */
    mapping(address => uint256) public affiliateRates;

    /**
     * @notice Constructor
     * @param _owner Owner address
     */
    constructor(address _owner) OwnableTwoSteps(_owner) {}

    /**
     * @notice This function allows the affiliate controller to update the affiliate rate (in basis point).
     * @param affiliate Affiliate address
     * @param bp Rate (in basis point) to collect (e.g. 100 = 1%) per referred transaction
     */
    function updateAffiliateRate(address affiliate, uint256 bp) external {
        if (msg.sender != affiliateController) {
            revert NotAffiliateController();
        }

        if (bp > ONE_HUNDRED_PERCENT_IN_BP) {
            revert PercentageTooHigh();
        }

        affiliateRates[affiliate] = bp;
        emit NewAffiliateRate(affiliate, bp);
    }

    /**
     * @notice This function allows the owner to update the affiliate controller address.
     * @param newAffiliateController New affiliate controller address
     * @dev Only callable by owner.
     */
    function updateAffiliateController(address newAffiliateController) external onlyOwner {
        affiliateController = newAffiliateController;
        emit NewAffiliateController(newAffiliateController);
    }

    /**
     * @notice This function allows the owner to update the affiliate program status.
     * @param isActive Whether the affiliate program is active
     * @dev Only callable by owner.
     */
    function updateAffiliateProgramStatus(bool isActive) external onlyOwner {
        isAffiliateProgramActive = isActive;
        emit NewAffiliateProgramStatus(isActive);
    }
}

File 3 of 47 : BatchOrderTypehashRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Shared errors
import {MerkleProofTooLarge} from "./errors/SharedErrors.sol";

/**
 * @title BatchOrderTypehashRegistry
 * @notice The contract generates the batch order hash that is used to compute the digest for signature verification.
 * @author LooksRare protocol team (👀,💎)
 */
contract BatchOrderTypehashRegistry {
    /**
     * @notice This function returns the hash of the concatenation of batch order type hash and merkle root.
     * @param root Merkle root
     * @param proofLength Merkle proof length
     * @return batchOrderHash The batch order hash
     */
    function hashBatchOrder(bytes32 root, uint256 proofLength) public pure returns (bytes32 batchOrderHash) {
        batchOrderHash = keccak256(abi.encode(_getBatchOrderTypehash(proofLength), root));
    }

    /**
     * @dev It looks like this for each height
     *      height == 1: BatchOrder(Maker[2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters)
     *      height == 2: BatchOrder(Maker[2][2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters)
     *      height == n: BatchOrder(Maker[2]...[2] tree)Maker(uint8 quoteType,uint256 globalNonce,uint256 subsetNonce,uint256 orderNonce,uint256 strategyId,uint8 collectionType,address collection,address currency,address signer,uint256 startTime,uint256 endTime,uint256 price,uint256[] itemIds,uint256[] amounts,bytes additionalParameters)
     */
    function _getBatchOrderTypehash(uint256 height) internal pure returns (bytes32 typehash) {
        if (height == 1) {
            typehash = hex"9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643";
        } else if (height == 2) {
            typehash = hex"a54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08";
        } else if (height == 3) {
            typehash = hex"93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49";
        } else if (height == 4) {
            typehash = hex"9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b";
        } else if (height == 5) {
            typehash = hex"92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98";
        } else if (height == 6) {
            typehash = hex"ce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8";
        } else if (height == 7) {
            typehash = hex"f7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559";
        } else if (height == 8) {
            typehash = hex"def24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6";
        } else if (height == 9) {
            typehash = hex"4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2";
        } else if (height == 10) {
            typehash = hex"f8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db";
        } else {
            revert MerkleProofTooLarge(height);
        }
    }
}

File 4 of 47 : CurrencyManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Interfaces
import {ICurrencyManager} from "./interfaces/ICurrencyManager.sol";

// Dependencies
import {AffiliateManager} from "./AffiliateManager.sol";

/**
 * @title CurrencyManager
 * @notice This contract manages the list of valid fungible currencies.
 * @author LooksRare protocol team (👀,💎)
 */
contract CurrencyManager is ICurrencyManager, AffiliateManager {
    /**
     * @notice It checks whether the currency is allowed for transacting.
     */
    mapping(address => bool) public isCurrencyAllowed;

    /**
     * @notice Constructor
     * @param _owner Owner address
     */
    constructor(address _owner) AffiliateManager(_owner) {}

    /**
     * @notice This function allows the owner to update the status of a currency.
     * @param currency Currency address (address(0) for ETH)
     * @param isAllowed Whether the currency should be allowed for trading
     * @dev Only callable by owner.
     */
    function updateCurrencyStatus(address currency, bool isAllowed) external onlyOwner {
        isCurrencyAllowed[currency] = isAllowed;
        emit CurrencyStatusUpdated(currency, isAllowed);
    }
}

File 5 of 47 : ExecutionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";

// Interfaces
import {IExecutionManager} from "./interfaces/IExecutionManager.sol";
import {ICreatorFeeManager} from "./interfaces/ICreatorFeeManager.sol";

// Direct dependencies
import {InheritedStrategy} from "./InheritedStrategy.sol";
import {NonceManager} from "./NonceManager.sol";
import {StrategyManager} from "./StrategyManager.sol";

// Assembly
import {NoSelectorForStrategy_error_selector, NoSelectorForStrategy_error_length, OutsideOfTimeRange_error_selector, OutsideOfTimeRange_error_length, Error_selector_offset} from "./constants/AssemblyConstants.sol";

// Constants
import {ONE_HUNDRED_PERCENT_IN_BP} from "./constants/NumericConstants.sol";

// Enums
import {QuoteType} from "./enums/QuoteType.sol";

/**
 * @title ExecutionManager
 * @notice This contract handles the execution and resolution of transactions. A transaction is executed on-chain
 *         when an off-chain maker order is matched by on-chain taker order of a different kind.
 *         For instance, a taker ask is executed against a maker bid (or a taker bid against a maker ask).
 * @author LooksRare protocol team (👀,💎)
 */
contract ExecutionManager is InheritedStrategy, NonceManager, StrategyManager, IExecutionManager {
    /**
     * @notice Protocol fee recipient.
     */
    address public protocolFeeRecipient;

    /**
     * @notice Maximum creator fee (in basis point).
     */
    uint16 public maxCreatorFeeBp = 1_000;

    /**
     * @notice Creator fee manager.
     */
    ICreatorFeeManager public creatorFeeManager;

    /**
     * @notice Constructor
     * @param _owner Owner address
     * @param _protocolFeeRecipient Protocol fee recipient address
     */
    constructor(address _owner, address _protocolFeeRecipient) StrategyManager(_owner) {
        _updateProtocolFeeRecipient(_protocolFeeRecipient);
    }

    /**
     * @notice This function allows the owner to update the creator fee manager address.
     * @param newCreatorFeeManager Address of the creator fee manager
     * @dev Only callable by owner.
     */
    function updateCreatorFeeManager(address newCreatorFeeManager) external onlyOwner {
        creatorFeeManager = ICreatorFeeManager(newCreatorFeeManager);
        emit NewCreatorFeeManager(newCreatorFeeManager);
    }

    /**
     * @notice This function allows the owner to update the maximum creator fee (in basis point).
     * @param newMaxCreatorFeeBp New maximum creator fee (in basis point)
     * @dev The maximum value that can be set is 25%.
     *      Only callable by owner.
     */
    function updateMaxCreatorFeeBp(uint16 newMaxCreatorFeeBp) external onlyOwner {
        if (newMaxCreatorFeeBp > 2_500) {
            revert CreatorFeeBpTooHigh();
        }

        maxCreatorFeeBp = newMaxCreatorFeeBp;

        emit NewMaxCreatorFeeBp(newMaxCreatorFeeBp);
    }

    /**
     * @notice This function allows the owner to update the protocol fee recipient.
     * @param newProtocolFeeRecipient New protocol fee recipient address
     * @dev Only callable by owner.
     */
    function updateProtocolFeeRecipient(address newProtocolFeeRecipient) external onlyOwner {
        _updateProtocolFeeRecipient(newProtocolFeeRecipient);
    }

    /**
     * @notice This function is internal and is used to execute a transaction initiated by a taker order.
     * @param takerOrder Taker order struct (taker specific parameters for the execution)
     * @param makerOrder Maker order struct (maker specific parameter for the execution)
     * @param sender The address that sent the transaction
     * @return itemIds Array of item ids to be traded
     * @return amounts Array of amounts for each item id
     * @return recipients Array of recipient addresses
     * @return feeAmounts Array of fee amounts
     * @return isNonceInvalidated Whether the order's nonce will be invalidated after executing the order
     */
    function _executeStrategyForTakerOrder(
        OrderStructs.Taker calldata takerOrder,
        OrderStructs.Maker calldata makerOrder,
        address sender
    )
        internal
        returns (
            uint256[] memory itemIds,
            uint256[] memory amounts,
            address[2] memory recipients,
            uint256[3] memory feeAmounts,
            bool isNonceInvalidated
        )
    {
        uint256 price;

        // Verify the order validity for timestamps
        _verifyOrderTimestampValidity(makerOrder.startTime, makerOrder.endTime);

        if (makerOrder.strategyId == 0) {
            _verifyItemIdsAndAmountsEqualLengthsAndValidAmounts(makerOrder.amounts, makerOrder.itemIds);
            (price, itemIds, amounts) = (makerOrder.price, makerOrder.itemIds, makerOrder.amounts);
            isNonceInvalidated = true;
        } else {
            if (strategyInfo[makerOrder.strategyId].isActive) {
                /**
                 * @dev This is equivalent to
                 *
                 * if (makerOrder.quoteType == QuoteType.Bid) {
                 *     if (!strategyInfo[makerOrder.strategyId].isMakerBid) {
                 *         revert NoSelectorForStrategy();
                 *     }
                 * } else {
                 *     if (strategyInfo[makerOrder.strategyId].isMakerBid) {
                 *         revert NoSelectorForStrategy();
                 *     }
                 * }
                 *
                 * because one must be 0 and another must be 1 for the function
                 * to not revert.
                 *
                 * Both quoteType (an enum with 2 values) and isMakerBid (a bool)
                 * can only be 0 or 1.
                 */
                QuoteType quoteType = makerOrder.quoteType;
                bool isMakerBid = strategyInfo[makerOrder.strategyId].isMakerBid;
                assembly {
                    if eq(quoteType, isMakerBid) {
                        mstore(0x00, NoSelectorForStrategy_error_selector)
                        revert(Error_selector_offset, NoSelectorForStrategy_error_length)
                    }
                }

                (bool status, bytes memory data) = strategyInfo[makerOrder.strategyId].implementation.call(
                    abi.encodeWithSelector(strategyInfo[makerOrder.strategyId].selector, takerOrder, makerOrder)
                );

                if (!status) {
                    // @dev It forwards the revertion message from the low-level call
                    assembly {
                        revert(add(data, 32), mload(data))
                    }
                }

                (price, itemIds, amounts, isNonceInvalidated) = abi.decode(data, (uint256, uint256[], uint256[], bool));
            } else {
                revert StrategyNotAvailable(makerOrder.strategyId);
            }
        }

        // Creator fee and adjustment of protocol fee
        (recipients[1], feeAmounts[1]) = _getCreatorRecipientAndCalculateFeeAmount(
            makerOrder.collection,
            price,
            itemIds
        );
        if (makerOrder.quoteType == QuoteType.Bid) {
            _setTheRestOfFeeAmountsAndRecipients(
                makerOrder.strategyId,
                price,
                takerOrder.recipient == address(0) ? sender : takerOrder.recipient,
                feeAmounts,
                recipients
            );
        } else {
            _setTheRestOfFeeAmountsAndRecipients(
                makerOrder.strategyId,
                price,
                makerOrder.signer,
                feeAmounts,
                recipients
            );
        }
    }

    /**
     * @notice This private function updates the protocol fee recipient.
     * @param newProtocolFeeRecipient New protocol fee recipient address
     */
    function _updateProtocolFeeRecipient(address newProtocolFeeRecipient) private {
        if (newProtocolFeeRecipient == address(0)) {
            revert NewProtocolFeeRecipientCannotBeNullAddress();
        }

        protocolFeeRecipient = newProtocolFeeRecipient;
        emit NewProtocolFeeRecipient(newProtocolFeeRecipient);
    }

    /**
     * @notice This function is internal and is used to calculate
     *         the protocol fee amount for a set of fee amounts.
     * @param price Transaction price
     * @param strategyId Strategy id
     * @param creatorFeeAmount Creator fee amount
     * @param minTotalFeeAmount Min total fee amount
     * @return protocolFeeAmount Protocol fee amount
     */
    function _calculateProtocolFeeAmount(
        uint256 price,
        uint256 strategyId,
        uint256 creatorFeeAmount,
        uint256 minTotalFeeAmount
    ) private view returns (uint256 protocolFeeAmount) {
        protocolFeeAmount = (price * strategyInfo[strategyId].standardProtocolFeeBp) / ONE_HUNDRED_PERCENT_IN_BP;

        if (protocolFeeAmount + creatorFeeAmount < minTotalFeeAmount) {
            protocolFeeAmount = minTotalFeeAmount - creatorFeeAmount;
        }
    }

    /**
     * @notice This function is internal and is used to get the creator fee address
     *         and calculate the creator fee amount.
     * @param collection Collection address
     * @param price Transaction price
     * @param itemIds Array of item ids
     * @return creator Creator recipient
     * @return creatorFeeAmount Creator fee amount
     */
    function _getCreatorRecipientAndCalculateFeeAmount(
        address collection,
        uint256 price,
        uint256[] memory itemIds
    ) private view returns (address creator, uint256 creatorFeeAmount) {
        if (address(creatorFeeManager) != address(0)) {
            (creator, creatorFeeAmount) = creatorFeeManager.viewCreatorFeeInfo(collection, price, itemIds);

            if (creator == address(0)) {
                // If recipient is null address, creator fee is set to 0
                creatorFeeAmount = 0;
            } else if (creatorFeeAmount * ONE_HUNDRED_PERCENT_IN_BP > (price * uint256(maxCreatorFeeBp))) {
                // If creator fee is higher than tolerated, it reverts
                revert CreatorFeeBpTooHigh();
            }
        }
    }

    /**
     * @dev This function does not need to return feeAmounts and recipients as they are modified
     *      in memory.
     */
    function _setTheRestOfFeeAmountsAndRecipients(
        uint256 strategyId,
        uint256 price,
        address askRecipient,
        uint256[3] memory feeAmounts,
        address[2] memory recipients
    ) private view {
        // Compute minimum total fee amount
        uint256 minTotalFeeAmount = (price * strategyInfo[strategyId].minTotalFeeBp) / ONE_HUNDRED_PERCENT_IN_BP;

        if (feeAmounts[1] == 0) {
            // If creator fee is null, protocol fee is set as the minimum total fee amount
            feeAmounts[2] = minTotalFeeAmount;
            // Net fee amount for seller
            feeAmounts[0] = price - feeAmounts[2];
        } else {
            // If there is a creator fee information, the protocol fee amount can be calculated
            feeAmounts[2] = _calculateProtocolFeeAmount(price, strategyId, feeAmounts[1], minTotalFeeAmount);
            // Net fee amount for seller
            feeAmounts[0] = price - feeAmounts[1] - feeAmounts[2];
        }

        recipients[0] = askRecipient;
    }

    /**
     * @notice This function is internal and is used to verify the validity of an order
     *         in the context of the current block timestamps.
     * @param startTime Start timestamp
     * @param endTime End timestamp
     */
    function _verifyOrderTimestampValidity(uint256 startTime, uint256 endTime) private view {
        // if (startTime > block.timestamp || endTime < block.timestamp) revert OutsideOfTimeRange();
        assembly {
            if or(gt(startTime, timestamp()), lt(endTime, timestamp())) {
                mstore(0x00, OutsideOfTimeRange_error_selector)
                revert(Error_selector_offset, OutsideOfTimeRange_error_length)
            }
        }
    }
}

File 6 of 47 : InheritedStrategy.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";

// Shared errors
import {OrderInvalid} from "./errors/SharedErrors.sol";

// Assembly
import {OrderInvalid_error_selector, OrderInvalid_error_length, Error_selector_offset, OneWord} from "./constants/AssemblyConstants.sol";

/**
 * @title InheritedStrategy
 * @notice This contract handles the verification of parameters for standard transactions.
 *         It does not verify the taker struct's itemIds and amounts array as well as
 *         minPrice (taker ask) / maxPrice (taker bid) because before the taker executes the
 *         transaction and the maker itemIds/amounts/price should have already been confirmed off-chain.
 * @dev A standard transaction (bid or ask) is mapped to strategyId = 0.
 * @author LooksRare protocol team (👀,💎)
 */
contract InheritedStrategy {
    /**
     * @notice This function is internal and is used to validate the parameters for a standard sale strategy
     *         when the standard transaction is initiated by a taker bid.
     * @param amounts Array of amounts
     * @param itemIds Array of item ids
     */
    function _verifyItemIdsAndAmountsEqualLengthsAndValidAmounts(
        uint256[] calldata amounts,
        uint256[] calldata itemIds
    ) internal pure {
        assembly {
            let end
            {
                /*
                 * @dev If A == B, then A XOR B == 0.
                 *
                 * if (amountsLength == 0 || amountsLength != itemIdsLength) {
                 *     revert OrderInvalid();
                 * }
                 */
                let amountsLength := amounts.length
                let itemIdsLength := itemIds.length

                if or(iszero(amountsLength), xor(amountsLength, itemIdsLength)) {
                    mstore(0x00, OrderInvalid_error_selector)
                    revert(Error_selector_offset, OrderInvalid_error_length)
                }

                /**
                 * @dev Shifting left 5 times is equivalent to amountsLength * 32 bytes
                 */
                end := shl(5, amountsLength)
            }

            let amountsOffset := amounts.offset

            for {

            } end {

            } {
                /**
                 * @dev Starting from the end of the array minus 32 bytes to load the last item,
                 *      ending with `end` equal to 0 to load the first item
                 *
                 * uint256 end = amountsLength;
                 *
                 * for (uint256 i = end - 1; i >= 0; i--) {
                 *   uint256 amount = amounts[i];
                 *   if (amount == 0) {
                 *      revert OrderInvalid();
                 *   }
                 * }
                 */
                end := sub(end, OneWord)

                let amount := calldataload(add(amountsOffset, end))

                if iszero(amount) {
                    mstore(0x00, OrderInvalid_error_selector)
                    revert(Error_selector_offset, OrderInvalid_error_length)
                }
            }
        }
    }
}

File 7 of 47 : NonceManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Interfaces and errors
import {INonceManager} from "./interfaces/INonceManager.sol";
import {LengthsInvalid} from "./errors/SharedErrors.sol";

/**
 * @title NonceManager
 * @notice This contract handles the nonce logic that is used for invalidating maker orders that exist off-chain.
 *         The nonce logic revolves around three parts at the user level:
 *         - order nonce (orders sharing an order nonce are conditional, OCO-like)
 *         - subset (orders can be grouped under a same subset)
 *         - bid/ask (all orders can be executed only if the bid/ask nonce matches the user's one on-chain)
 *         Only the order nonce is invalidated at the time of the execution of a maker order that contains it.
 * @author LooksRare protocol team (👀,💎)
 */
contract NonceManager is INonceManager {
    /**
     * @notice Magic value nonce returned if executed (or cancelled).
     */
    bytes32 public constant MAGIC_VALUE_ORDER_NONCE_EXECUTED = keccak256("ORDER_NONCE_EXECUTED");

    /**
     * @notice This tracks the bid and ask nonces for a user address.
     */
    mapping(address => UserBidAskNonces) public userBidAskNonces;

    /**
     * @notice This checks whether the order nonce for a user was executed or cancelled.
     */
    mapping(address => mapping(uint256 => bytes32)) public userOrderNonce;

    /**
     * @notice This checks whether the subset nonce for a user was cancelled.
     */
    mapping(address => mapping(uint256 => bool)) public userSubsetNonce;

    /**
     * @notice This function allows a user to cancel an array of order nonces.
     * @param orderNonces Array of order nonces
     * @dev It does not check the status of the nonces to save gas
     *      and to prevent revertion if one of the orders is filled in the same
     *      block.
     */
    function cancelOrderNonces(uint256[] calldata orderNonces) external {
        uint256 length = orderNonces.length;
        if (length == 0) {
            revert LengthsInvalid();
        }

        for (uint256 i; i < length; ) {
            userOrderNonce[msg.sender][orderNonces[i]] = MAGIC_VALUE_ORDER_NONCE_EXECUTED;
            unchecked {
                ++i;
            }
        }

        emit OrderNoncesCancelled(msg.sender, orderNonces);
    }

    /**
     * @notice This function allows a user to cancel an array of subset nonces.
     * @param subsetNonces Array of subset nonces
     * @dev It does not check the status of the nonces to save gas.
     */
    function cancelSubsetNonces(uint256[] calldata subsetNonces) external {
        uint256 length = subsetNonces.length;

        if (length == 0) {
            revert LengthsInvalid();
        }

        for (uint256 i; i < length; ) {
            userSubsetNonce[msg.sender][subsetNonces[i]] = true;
            unchecked {
                ++i;
            }
        }

        emit SubsetNoncesCancelled(msg.sender, subsetNonces);
    }

    /**
     * @notice This function increments a user's bid/ask nonces.
     * @param bid Whether to increment the user bid nonce
     * @param ask Whether to increment the user ask nonce
     * @dev The logic for computing the quasi-random number is inspired by Seaport v1.2.
     *      The pseudo-randomness allows non-deterministic computation of the next ask/bid nonce.
     *      A deterministic increment would make the cancel-all process non-effective in certain cases
     *      (orders signed with a greater ask/bid nonce).
     *      The same quasi-random number is used for incrementing both the bid and ask nonces if both values
     *      are incremented in the same transaction.
     *      If this function is used twice in the same block, it will return the same quasiRandomNumber
     *      but this will not impact the overall business logic.
     */
    function incrementBidAskNonces(bool bid, bool ask) external {
        // Use second half of the previous block hash as a quasi-random number
        uint256 quasiRandomNumber = uint256(blockhash(block.number - 1) >> 128);
        uint256 newBidNonce = userBidAskNonces[msg.sender].bidNonce;
        uint256 newAskNonce = userBidAskNonces[msg.sender].askNonce;

        if (bid) {
            newBidNonce += quasiRandomNumber;
            userBidAskNonces[msg.sender].bidNonce = newBidNonce;
        }

        if (ask) {
            newAskNonce += quasiRandomNumber;
            userBidAskNonces[msg.sender].askNonce = newAskNonce;
        }

        emit NewBidAskNonces(msg.sender, newBidNonce, newAskNonce);
    }
}

File 8 of 47 : StrategyManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// LooksRare unopinionated libraries
import {CurrencyManager} from "./CurrencyManager.sol";

// Interfaces
import {IStrategy} from "./interfaces/IStrategy.sol";
import {IStrategyManager} from "./interfaces/IStrategyManager.sol";

/**
 * @title StrategyManager
 * @notice This contract handles the addition and the update of execution strategies.
 * @author LooksRare protocol team (👀,💎)
 */
contract StrategyManager is IStrategyManager, CurrencyManager {
    /**
     * @notice This variable keeps the count of how many strategies exist.
     *         It includes strategies that have been removed.
     */
    uint256 private _countStrategies = 1;

    /**
     * @notice This returns the strategy information for a strategy id.
     */
    mapping(uint256 => Strategy) public strategyInfo;

    /**
     * @notice Constructor
     * @param _owner Owner address
     */
    constructor(address _owner) CurrencyManager(_owner) {
        strategyInfo[0] = Strategy({
            isActive: true,
            standardProtocolFeeBp: 50,
            minTotalFeeBp: 50,
            maxProtocolFeeBp: 200,
            selector: bytes4(0),
            isMakerBid: false,
            implementation: address(0)
        });

        emit NewStrategy(0, 50, 50, 200, bytes4(0), false, address(0));
    }

    /**
     * @notice This function allows the owner to add a new execution strategy to the protocol.
     * @param standardProtocolFeeBp Standard protocol fee (in basis point)
     * @param minTotalFeeBp Minimum total fee (in basis point)
     * @param maxProtocolFeeBp Maximum protocol fee (in basis point)
     * @param selector Function selector for the strategy
     * @param isMakerBid Whether the function selector is for maker bid
     * @param implementation Implementation address
     * @dev Strategies have an id that is incremental.
     *      Only callable by owner.
     */
    function addStrategy(
        uint16 standardProtocolFeeBp,
        uint16 minTotalFeeBp,
        uint16 maxProtocolFeeBp,
        bytes4 selector,
        bool isMakerBid,
        address implementation
    ) external onlyOwner {
        if (minTotalFeeBp > maxProtocolFeeBp || standardProtocolFeeBp > minTotalFeeBp || maxProtocolFeeBp > 500) {
            revert StrategyProtocolFeeTooHigh();
        }

        if (selector == bytes4(0)) {
            revert StrategyHasNoSelector();
        }

        if (!IStrategy(implementation).isLooksRareV2Strategy()) {
            revert NotV2Strategy();
        }

        strategyInfo[_countStrategies] = Strategy({
            isActive: true,
            standardProtocolFeeBp: standardProtocolFeeBp,
            minTotalFeeBp: minTotalFeeBp,
            maxProtocolFeeBp: maxProtocolFeeBp,
            selector: selector,
            isMakerBid: isMakerBid,
            implementation: implementation
        });

        emit NewStrategy(
            _countStrategies++,
            standardProtocolFeeBp,
            minTotalFeeBp,
            maxProtocolFeeBp,
            selector,
            isMakerBid,
            implementation
        );
    }

    /**
     * @notice This function allows the owner to update parameters for an existing execution strategy.
     * @param strategyId Strategy id
     * @param isActive Whether the strategy must be active
     * @param newStandardProtocolFee New standard protocol fee (in basis point)
     * @param newMinTotalFee New minimum total fee (in basis point)
     * @dev Only callable by owner.
     */
    function updateStrategy(
        uint256 strategyId,
        bool isActive,
        uint16 newStandardProtocolFee,
        uint16 newMinTotalFee
    ) external onlyOwner {
        if (strategyId >= _countStrategies) {
            revert StrategyNotUsed();
        }

        if (newMinTotalFee > strategyInfo[strategyId].maxProtocolFeeBp || newStandardProtocolFee > newMinTotalFee) {
            revert StrategyProtocolFeeTooHigh();
        }

        strategyInfo[strategyId].isActive = isActive;
        strategyInfo[strategyId].standardProtocolFeeBp = newStandardProtocolFee;
        strategyInfo[strategyId].minTotalFeeBp = newMinTotalFee;

        emit StrategyUpdated(strategyId, isActive, newStandardProtocolFee, newMinTotalFee);
    }
}

File 9 of 47 : TransferManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// LooksRare unopinionated libraries
import {OwnableTwoSteps} from "@looksrare/contracts-libs/contracts/OwnableTwoSteps.sol";
import {LowLevelERC721Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC721Transfer.sol";
import {LowLevelERC1155Transfer} from "@looksrare/contracts-libs/contracts/lowLevelCallers/LowLevelERC1155Transfer.sol";

// Interfaces and errors
import {ITransferManager} from "./interfaces/ITransferManager.sol";
import {AmountInvalid, LengthsInvalid} from "./errors/SharedErrors.sol";

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";

// Enums
import {CollectionType} from "./enums/CollectionType.sol";

/**
 * @title TransferManager
 * @notice This contract provides the transfer functions for ERC721/ERC1155 for contracts that require them.
 *         Collection type "0" refers to ERC721 transfer functions.
 *         Collection type "1" refers to ERC1155 transfer functions.
 * @dev "Safe" transfer functions for ERC721 are not implemented since they come with added gas costs
 *       to verify if the recipient is a contract as it requires verifying the receiver interface is valid.
 * @author LooksRare protocol team (👀,💎)
 */
contract TransferManager is ITransferManager, LowLevelERC721Transfer, LowLevelERC1155Transfer, OwnableTwoSteps {
    /**
     * @notice This returns whether the user has approved the operator address.
     * The first address is the user and the second address is the operator (e.g. LooksRareProtocol).
     */
    mapping(address => mapping(address => bool)) public hasUserApprovedOperator;

    /**
     * @notice This returns whether the operator address is allowed by this contract's owner.
     */
    mapping(address => bool) public isOperatorAllowed;

    /**
     * @notice Constructor
     * @param _owner Owner address
     */
    constructor(address _owner) OwnableTwoSteps(_owner) {}

    /**
     * @notice This function transfers items for a single ERC721 collection.
     * @param collection Collection address
     * @param from Sender address
     * @param to Recipient address
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     */
    function transferItemsERC721(
        address collection,
        address from,
        address to,
        uint256[] calldata itemIds,
        uint256[] calldata amounts
    ) external {
        uint256 length = itemIds.length;
        if (length == 0) {
            revert LengthsInvalid();
        }

        _isOperatorValidForTransfer(from, msg.sender);

        for (uint256 i; i < length; ) {
            if (amounts[i] != 1) {
                revert AmountInvalid();
            }
            _executeERC721TransferFrom(collection, from, to, itemIds[i]);
            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice This function transfers items for a single ERC1155 collection.
     * @param collection Collection address
     * @param from Sender address
     * @param to Recipient address
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     * @dev It does not allow batch transferring if from = msg.sender since native function should be used.
     */
    function transferItemsERC1155(
        address collection,
        address from,
        address to,
        uint256[] calldata itemIds,
        uint256[] calldata amounts
    ) external {
        uint256 length = itemIds.length;

        if (length == 0 || amounts.length != length) {
            revert LengthsInvalid();
        }

        _isOperatorValidForTransfer(from, msg.sender);

        if (length == 1) {
            if (amounts[0] == 0) {
                revert AmountInvalid();
            }
            _executeERC1155SafeTransferFrom(collection, from, to, itemIds[0], amounts[0]);
        } else {
            for (uint256 i; i < length; ) {
                if (amounts[i] == 0) {
                    revert AmountInvalid();
                }

                unchecked {
                    ++i;
                }
            }
            _executeERC1155SafeBatchTransferFrom(collection, from, to, itemIds, amounts);
        }
    }

    /**
     * @notice This function transfers items across an array of collections that can be both ERC721 and ERC1155.
     * @param items Array of BatchTransferItem
     * @param from Sender address
     * @param to Recipient address
     */
    function transferBatchItemsAcrossCollections(
        BatchTransferItem[] calldata items,
        address from,
        address to
    ) external {
        uint256 itemsLength = items.length;

        if (itemsLength == 0) {
            revert LengthsInvalid();
        }

        if (from != msg.sender) {
            _isOperatorValidForTransfer(from, msg.sender);
        }

        for (uint256 i; i < itemsLength; ) {
            uint256[] calldata itemIds = items[i].itemIds;
            uint256 itemIdsLengthForSingleCollection = itemIds.length;
            uint256[] calldata amounts = items[i].amounts;

            if (itemIdsLengthForSingleCollection == 0 || amounts.length != itemIdsLengthForSingleCollection) {
                revert LengthsInvalid();
            }

            CollectionType collectionType = items[i].collectionType;
            if (collectionType == CollectionType.ERC721) {
                for (uint256 j; j < itemIdsLengthForSingleCollection; ) {
                    if (amounts[j] != 1) {
                        revert AmountInvalid();
                    }
                    _executeERC721TransferFrom(items[i].collection, from, to, itemIds[j]);
                    unchecked {
                        ++j;
                    }
                }
            } else if (collectionType == CollectionType.ERC1155) {
                for (uint256 j; j < itemIdsLengthForSingleCollection; ) {
                    if (amounts[j] == 0) {
                        revert AmountInvalid();
                    }

                    unchecked {
                        ++j;
                    }
                }
                _executeERC1155SafeBatchTransferFrom(items[i].collection, from, to, itemIds, amounts);
            }

            unchecked {
                ++i;
            }
        }
    }

    /**
     * @notice This function allows a user to grant approvals for an array of operators.
     *         Users cannot grant approvals if the operator is not allowed by this contract's owner.
     * @param operators Array of operator addresses
     * @dev Each operator address must be globally allowed to be approved.
     */
    function grantApprovals(address[] calldata operators) external {
        uint256 length = operators.length;

        if (length == 0) {
            revert LengthsInvalid();
        }

        for (uint256 i; i < length; ) {
            address operator = operators[i];

            if (!isOperatorAllowed[operator]) {
                revert OperatorNotAllowed();
            }

            if (hasUserApprovedOperator[msg.sender][operator]) {
                revert OperatorAlreadyApprovedByUser();
            }

            hasUserApprovedOperator[msg.sender][operator] = true;

            unchecked {
                ++i;
            }
        }

        emit ApprovalsGranted(msg.sender, operators);
    }

    /**
     * @notice This function allows a user to revoke existing approvals for an array of operators.
     * @param operators Array of operator addresses
     * @dev Each operator address must be approved at the user level to be revoked.
     */
    function revokeApprovals(address[] calldata operators) external {
        uint256 length = operators.length;
        if (length == 0) {
            revert LengthsInvalid();
        }

        for (uint256 i; i < length; ) {
            address operator = operators[i];

            if (!hasUserApprovedOperator[msg.sender][operator]) {
                revert OperatorNotApprovedByUser();
            }

            delete hasUserApprovedOperator[msg.sender][operator];
            unchecked {
                ++i;
            }
        }

        emit ApprovalsRemoved(msg.sender, operators);
    }

    /**
     * @notice This function allows an operator to be added for the shared transfer system.
     *         Once the operator is allowed, users can grant NFT approvals to this operator.
     * @param operator Operator address to allow
     * @dev Only callable by owner.
     */
    function allowOperator(address operator) external onlyOwner {
        if (isOperatorAllowed[operator]) {
            revert OperatorAlreadyAllowed();
        }

        isOperatorAllowed[operator] = true;

        emit OperatorAllowed(operator);
    }

    /**
     * @notice This function allows the user to remove an operator for the shared transfer system.
     * @param operator Operator address to remove
     * @dev Only callable by owner.
     */
    function removeOperator(address operator) external onlyOwner {
        if (!isOperatorAllowed[operator]) {
            revert OperatorNotAllowed();
        }

        delete isOperatorAllowed[operator];

        emit OperatorRemoved(operator);
    }

    /**
     * @notice This function is internal and verifies whether the transfer
     *         (by an operator on behalf of a user) is valid. If not, it reverts.
     * @param user User address
     * @param operator Operator address
     */
    function _isOperatorValidForTransfer(address user, address operator) private view {
        if (isOperatorAllowed[operator] && hasUserApprovedOperator[user][operator]) {
            return;
        }

        revert TransferCallerInvalid();
    }
}

File 10 of 47 : TransferSelectorNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Direct dependencies
import {PackableReentrancyGuard} from "@looksrare/contracts-libs/contracts/PackableReentrancyGuard.sol";
import {ExecutionManager} from "./ExecutionManager.sol";
import {TransferManager} from "./TransferManager.sol";

// Libraries
import {OrderStructs} from "./libraries/OrderStructs.sol";

// Enums
import {CollectionType} from "./enums/CollectionType.sol";

/**
 * @title TransferSelectorNFT
 * @notice This contract handles the logic for transferring non-fungible items.
 * @author LooksRare protocol team (👀,💎)
 */
contract TransferSelectorNFT is ExecutionManager, PackableReentrancyGuard {
    /**
     * @notice Transfer manager for ERC721 and ERC1155.
     */
    TransferManager public immutable transferManager;

    /**
     * @notice Constructor
     * @param _owner Owner address
     * @param _protocolFeeRecipient Protocol fee recipient address
     * @param _transferManager Address of the transfer manager for ERC721/ERC1155
     */
    constructor(
        address _owner,
        address _protocolFeeRecipient,
        address _transferManager
    ) ExecutionManager(_owner, _protocolFeeRecipient) {
        transferManager = TransferManager(_transferManager);
    }

    /**
     * @notice This function is internal and used to transfer non-fungible tokens.
     * @param collection Collection address
     * @param collectionType Collection type (e.g. 0 = ERC721, 1 = ERC1155)
     * @param sender Sender address
     * @param recipient Recipient address
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     */
    function _transferNFT(
        address collection,
        CollectionType collectionType,
        address sender,
        address recipient,
        uint256[] memory itemIds,
        uint256[] memory amounts
    ) internal {
        if (collectionType == CollectionType.ERC721) {
            transferManager.transferItemsERC721(collection, sender, recipient, itemIds, amounts);
        } else if (collectionType == CollectionType.ERC1155) {
            transferManager.transferItemsERC1155(collection, sender, recipient, itemIds, amounts);
        }
    }
}

File 11 of 47 : AssemblyConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/*
 * @dev error OrderInvalid()
 *      Memory layout:
 *        - 0x00: Left-padded selector (data begins at 0x1c)
 *      Revert buffer is memory[0x1c:0x20]
 */
uint256 constant OrderInvalid_error_selector = 0x2e0c0f71;
uint256 constant OrderInvalid_error_length = 0x04;

/*
 *  @dev error CurrencyInvalid()
 *       Memory layout:
 *         - 0x00: Left-padded selector (data begins at 0x1c)
 *       Revert buffer is memory[0x1c:0x20]
 */
uint256 constant CurrencyInvalid_error_selector = 0x4f795487;
uint256 constant CurrencyInvalid_error_length = 0x04;

/*
 * @dev error OutsideOfTimeRange()
 *      Memory layout:
 *        - 0x00: Left-padded selector (data begins at 0x1c)
 *      Revert buffer is memory[0x1c:0x20]
 */
uint256 constant OutsideOfTimeRange_error_selector = 0x7476320f;
uint256 constant OutsideOfTimeRange_error_length = 0x04;

/*
 * @dev error NoSelectorForStrategy()
 *      Memory layout:
 *        - 0x00: Left-padded selector (data begins at 0x1c)
 *      Revert buffer is memory[0x1c:0x20]
 */
uint256 constant NoSelectorForStrategy_error_selector = 0xab984846;
uint256 constant NoSelectorForStrategy_error_length = 0x04;

uint256 constant Error_selector_offset = 0x1c;

uint256 constant OneWord = 0x20;

File 12 of 47 : NumericConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @dev 100% represented in basis point is 10_000.
 */
uint256 constant ONE_HUNDRED_PERCENT_IN_BP = 10_000;

/**
 * @dev The maximum length of a proof for a batch order is 10.
 *      The maximum merkle tree that can used for signing has a height of
 *      2**10 = 1_024.
 */
uint256 constant MAX_CALLDATA_PROOF_LENGTH = 10;

File 13 of 47 : CollectionType.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @notice CollectionType is used in OrderStructs.Maker's collectionType to determine the collection type being traded.
 */
enum CollectionType {
    ERC721,
    ERC1155
}

File 14 of 47 : QuoteType.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @notice QuoteType is used in OrderStructs.Maker's quoteType to determine whether the maker order is a bid or an ask.
 */
enum QuoteType {
    Bid,
    Ask
}

File 15 of 47 : SharedErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @notice It is returned if the amount is invalid.
 *         For ERC721, any number that is not 1. For ERC1155, if amount is 0.
 */
error AmountInvalid();

/**
 * @notice It is returned if the ask price is too high for the bid user.
 */
error AskTooHigh();

/**
 * @notice It is returned if the bid price is too low for the ask user.
 */
error BidTooLow();

/**
 * @notice It is returned if the function cannot be called by the sender.
 */
error CallerInvalid();

/**
 * @notice It is returned if the currency is invalid.
 */
error CurrencyInvalid();

/**
 * @notice The function selector is invalid for this strategy implementation.
 */
error FunctionSelectorInvalid();

/**
 * @notice It is returned if there is either a mismatch or an error in the length of the array(s).
 */
error LengthsInvalid();

/**
 * @notice It is returned if the merkle proof provided is invalid.
 */
error MerkleProofInvalid();

/**
 * @notice It is returned if the length of the merkle proof provided is greater than tolerated.
 * @param length Proof length
 */
error MerkleProofTooLarge(uint256 length);

/**
 * @notice It is returned if the order is permanently invalid.
 *         There may be an issue with the order formatting.
 */
error OrderInvalid();

/**
 * @notice It is returned if the maker quote type is invalid.
 */
error QuoteTypeInvalid();

File 16 of 47 : IAffiliateManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title IAffiliateManager
 * @author LooksRare protocol team (👀,💎)
 */
interface IAffiliateManager {
    /**
     * @notice It is emitted when there is an update of affliate controller.
     * @param affiliateController Address of the new affiliate controller
     */
    event NewAffiliateController(address affiliateController);

    /**
     * @notice It is emitted if the affiliate program is activated or deactivated.
     * @param isActive Whether the affiliate program is active after the update
     */
    event NewAffiliateProgramStatus(bool isActive);

    /**
     * @notice It is emitted if there is a new affiliate and its associated rate (in basis point).
     * @param affiliate Address of the affiliate
     * @param rate Affiliate rate (in basis point)
     */
    event NewAffiliateRate(address affiliate, uint256 rate);

    /**
     * @notice It is returned if the function is called by another address than the affiliate controller.
     */
    error NotAffiliateController();

    /**
     * @notice It is returned if the affiliate controller is trying to set an affiliate rate higher than 10,000.
     */
    error PercentageTooHigh();
}

File 17 of 47 : ICreatorFeeManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Interfaces
import {IRoyaltyFeeRegistry} from "./IRoyaltyFeeRegistry.sol";

/**
 * @title ICreatorFeeManager
 * @author LooksRare protocol team (👀,💎)
 */
interface ICreatorFeeManager {
    /**
     * @notice It is returned if the bundle contains multiple itemIds with different creator fee structure.
     */
    error BundleEIP2981NotAllowed(address collection);

    /**
     * @notice It returns the royalty fee registry address/interface.
     * @return royaltyFeeRegistry Interface of the royalty fee registry
     */
    function royaltyFeeRegistry() external view returns (IRoyaltyFeeRegistry royaltyFeeRegistry);

    /**
     * @notice This function returns the creator address and calculates the creator fee amount.
     * @param collection Collection address
     * @param price Transaction price
     * @param itemIds Array of item ids
     * @return creator Creator address
     * @return creatorFeeAmount Creator fee amount
     */
    function viewCreatorFeeInfo(
        address collection,
        uint256 price,
        uint256[] memory itemIds
    ) external view returns (address creator, uint256 creatorFeeAmount);
}

File 18 of 47 : ICurrencyManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title ICurrencyManager
 * @author LooksRare protocol team (👀,💎)
 */
interface ICurrencyManager {
    /**
     * @notice It is emitted if the currency status in the allowlist is updated.
     * @param currency Currency address (address(0) = ETH)
     * @param isAllowed Whether the currency is allowed
     */
    event CurrencyStatusUpdated(address currency, bool isAllowed);
}

File 19 of 47 : IExecutionManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title IExecutionManager
 * @author LooksRare protocol team (👀,💎)
 */
interface IExecutionManager {
    /**
     * @notice It is issued when there is a new creator fee manager.
     * @param creatorFeeManager Address of the new creator fee manager
     */
    event NewCreatorFeeManager(address creatorFeeManager);

    /**
     * @notice It is issued when there is a new maximum creator fee (in basis point).
     * @param maxCreatorFeeBp New maximum creator fee (in basis point)
     */
    event NewMaxCreatorFeeBp(uint256 maxCreatorFeeBp);

    /**
     * @notice It is issued when there is a new protocol fee recipient address.
     * @param protocolFeeRecipient Address of the new protocol fee recipient
     */
    event NewProtocolFeeRecipient(address protocolFeeRecipient);

    /**
     * @notice It is returned if the creator fee (in basis point) is too high.
     */
    error CreatorFeeBpTooHigh();

    /**
     * @notice It is returned if the new protocol fee recipient is set to address(0).
     */
    error NewProtocolFeeRecipientCannotBeNullAddress();

    /**
     * @notice It is returned if there is no selector for maker ask/bid for a given strategyId,
     *         depending on the quote type.
     */
    error NoSelectorForStrategy();

    /**
     * @notice It is returned if the current block timestamp is not between start and end times in the maker order.
     */
    error OutsideOfTimeRange();

    /**
     * @notice It is returned if the strategy id has no implementation.
     * @dev It is returned if there is no implementation address and the strategyId is strictly greater than 0.
     */
    error StrategyNotAvailable(uint256 strategyId);
}

File 20 of 47 : ILooksRareProtocol.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "../libraries/OrderStructs.sol";

/**
 * @title ILooksRareProtocol
 * @author LooksRare protocol team (👀,💎)
 */
interface ILooksRareProtocol {
    /**
     * @notice This struct contains an order nonce's invalidation status
     *         and the order hash that triggered the status change.
     * @param orderHash Maker order hash
     * @param orderNonce Order nonce
     * @param isNonceInvalidated Whether this transaction invalidated the maker user's order nonce at the protocol level
     */
    struct NonceInvalidationParameters {
        bytes32 orderHash;
        uint256 orderNonce;
        bool isNonceInvalidated;
    }

    /**
     * @notice It is emitted when there is an affiliate fee paid.
     * @param affiliate Affiliate address
     * @param currency Address of the currency
     * @param affiliateFee Affiliate fee (in the currency)
     */
    event AffiliatePayment(address affiliate, address currency, uint256 affiliateFee);

    /**
     * @notice It is emitted if there is a change in the domain separator.
     */
    event NewDomainSeparator();

    /**
     * @notice It is emitted when there is a new gas limit for a ETH transfer (before it is wrapped to WETH).
     * @param gasLimitETHTransfer Gas limit for an ETH transfer
     */
    event NewGasLimitETHTransfer(uint256 gasLimitETHTransfer);

    /**
     * @notice It is emitted when a taker ask transaction is completed.
     * @param nonceInvalidationParameters Struct about nonce invalidation parameters
     * @param askUser Address of the ask user
     * @param bidUser Address of the bid user
     * @param strategyId Id of the strategy
     * @param currency Address of the currency
     * @param collection Address of the collection
     * @param itemIds Array of item ids
     * @param amounts Array of amounts (for item ids)
     * @param feeRecipients Array of fee recipients
     *        feeRecipients[0] User who receives the proceeds of the sale (it can be the taker ask user or different)
     *        feeRecipients[1] Creator fee recipient (if none, address(0))
     * @param feeAmounts Array of fee amounts
     *        feeAmounts[0] Fee amount for the user receiving sale proceeds
     *        feeAmounts[1] Creator fee amount
     *        feeAmounts[2] Protocol fee amount prior to adjustment for a potential affiliate payment
     */
    event TakerAsk(
        NonceInvalidationParameters nonceInvalidationParameters,
        address askUser, // taker (initiates the transaction)
        address bidUser, // maker (receives the NFT)
        uint256 strategyId,
        address currency,
        address collection,
        uint256[] itemIds,
        uint256[] amounts,
        address[2] feeRecipients,
        uint256[3] feeAmounts
    );

    /**
     * @notice It is emitted when a taker bid transaction is completed.
     * @param nonceInvalidationParameters Struct about nonce invalidation parameters
     * @param bidUser Address of the bid user
     * @param bidRecipient Address of the recipient of the bid
     * @param strategyId Id of the strategy
     * @param currency Address of the currency
     * @param collection Address of the collection
     * @param itemIds Array of item ids
     * @param amounts Array of amounts (for item ids)
     * @param feeRecipients Array of fee recipients
     *        feeRecipients[0] User who receives the proceeds of the sale (it is the maker ask user)
     *        feeRecipients[1] Creator fee recipient (if none, address(0))
     * @param feeAmounts Array of fee amounts
     *        feeAmounts[0] Fee amount for the user receiving sale proceeds
     *        feeAmounts[1] Creator fee amount
     *        feeAmounts[2] Protocol fee amount prior to adjustment for a potential affiliate payment
     */
    event TakerBid(
        NonceInvalidationParameters nonceInvalidationParameters,
        address bidUser, // taker (initiates the transaction)
        address bidRecipient, // taker (receives the NFT)
        uint256 strategyId,
        address currency,
        address collection,
        uint256[] itemIds,
        uint256[] amounts,
        address[2] feeRecipients,
        uint256[3] feeAmounts
    );

    /**
     * @notice It is returned if the gas limit for a standard ETH transfer is too low.
     */
    error NewGasLimitETHTransferTooLow();

    /**
     * @notice It is returned if the domain separator cannot be updated (i.e. the chainId is the same).
     */
    error SameDomainSeparator();

    /**
     * @notice It is returned if the domain separator should change.
     */
    error ChainIdInvalid();

    /**
     * @notice It is returned if the nonces are invalid.
     */
    error NoncesInvalid();

    /**
     * @notice This function allows a user to execute a taker ask (against a maker bid).
     * @param takerAsk Taker ask struct
     * @param makerBid Maker bid struct
     * @param makerSignature Maker signature
     * @param merkleTree Merkle tree struct (if the signature contains multiple maker orders)
     * @param affiliate Affiliate address
     */
    function executeTakerAsk(
        OrderStructs.Taker calldata takerAsk,
        OrderStructs.Maker calldata makerBid,
        bytes calldata makerSignature,
        OrderStructs.MerkleTree calldata merkleTree,
        address affiliate
    ) external;

    /**
     * @notice This function allows a user to execute a taker bid (against a maker ask).
     * @param takerBid Taker bid struct
     * @param makerAsk Maker ask struct
     * @param makerSignature Maker signature
     * @param merkleTree Merkle tree struct (if the signature contains multiple maker orders)
     * @param affiliate Affiliate address
     */
    function executeTakerBid(
        OrderStructs.Taker calldata takerBid,
        OrderStructs.Maker calldata makerAsk,
        bytes calldata makerSignature,
        OrderStructs.MerkleTree calldata merkleTree,
        address affiliate
    ) external payable;

    /**
     * @notice This function allows a user to batch buy with an array of taker bids (against an array of maker asks).
     * @param takerBids Array of taker bid structs
     * @param makerAsks Array of maker ask structs
     * @param makerSignatures Array of maker signatures
     * @param merkleTrees Array of merkle tree structs if the signature contains multiple maker orders
     * @param affiliate Affiliate address
     * @param isAtomic Whether the execution should be atomic
     *        i.e. whether it should revert if 1 or more transactions fail
     */
    function executeMultipleTakerBids(
        OrderStructs.Taker[] calldata takerBids,
        OrderStructs.Maker[] calldata makerAsks,
        bytes[] calldata makerSignatures,
        OrderStructs.MerkleTree[] calldata merkleTrees,
        address affiliate,
        bool isAtomic
    ) external payable;
}

File 21 of 47 : INonceManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title INonceManager
 * @author LooksRare protocol team (👀,💎)
 */
interface INonceManager {
    /**
     * @notice This struct contains the global bid and ask nonces of a user.
     * @param bidNonce Bid nonce
     * @param askNonce Ask nonce
     */
    struct UserBidAskNonces {
        uint256 bidNonce;
        uint256 askNonce;
    }

    /**
     * @notice It is emitted when there is an update of the global bid/ask nonces for a user.
     * @param user Address of the user
     * @param bidNonce New bid nonce
     * @param askNonce New ask nonce
     */
    event NewBidAskNonces(address user, uint256 bidNonce, uint256 askNonce);

    /**
     * @notice It is emitted when order nonces are cancelled for a user.
     * @param user Address of the user
     * @param orderNonces Array of order nonces cancelled
     */
    event OrderNoncesCancelled(address user, uint256[] orderNonces);

    /**
     * @notice It is emitted when subset nonces are cancelled for a user.
     * @param user Address of the user
     * @param subsetNonces Array of subset nonces cancelled
     */
    event SubsetNoncesCancelled(address user, uint256[] subsetNonces);
}

File 22 of 47 : IRoyaltyFeeRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title IRoyaltyFeeRegistry
 * @author LooksRare protocol team (👀,💎)
 */
interface IRoyaltyFeeRegistry {
    /**
     * @notice This function returns the royalty information for a collection at a given transaction price.
     * @param collection Collection address
     * @param price Transaction price
     * @return receiver Receiver address
     * @return royaltyFee Royalty fee amount
     */
    function royaltyInfo(
        address collection,
        uint256 price
    ) external view returns (address receiver, uint256 royaltyFee);
}

File 23 of 47 : IStrategy.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "../libraries/OrderStructs.sol";

/**
 * @title IStrategy
 * @author LooksRare protocol team (👀,💎)
 */
interface IStrategy {
    /**
     * @notice Validate *only the maker* order under the context of the chosen strategy. It does not revert if
     *         the maker order is invalid. Instead it returns false and the error's 4 bytes selector.
     * @param makerOrder Maker struct (maker specific parameters for the execution)
     * @param functionSelector Function selector for the strategy
     * @return isValid Whether the maker struct is valid
     * @return errorSelector If isValid is false, it returns the error's 4 bytes selector
     */
    function isMakerOrderValid(
        OrderStructs.Maker calldata makerOrder,
        bytes4 functionSelector
    ) external view returns (bool isValid, bytes4 errorSelector);

    /**
     * @notice This function acts as a safety check for the protocol's owner when adding new execution strategies.
     * @return isStrategy Whether it is a LooksRare V2 protocol strategy
     */
    function isLooksRareV2Strategy() external pure returns (bool isStrategy);
}

File 24 of 47 : IStrategyManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * @title IStrategyManager
 * @author LooksRare protocol team (👀,💎)
 */
interface IStrategyManager {
    /**
     * @notice This struct contains the parameter of an execution strategy.
     * @param strategyId Id of the new strategy
     * @param standardProtocolFeeBp Standard protocol fee (in basis point)
     * @param minTotalFeeBp Minimum total fee (in basis point)
     * @param maxProtocolFeeBp Maximum protocol fee (in basis point)
     * @param selector Function selector for the transaction to be executed
     * @param isMakerBid Whether the strategyId is for maker bid
     * @param implementation Address of the implementation of the strategy
     */
    struct Strategy {
        bool isActive;
        uint16 standardProtocolFeeBp;
        uint16 minTotalFeeBp;
        uint16 maxProtocolFeeBp;
        bytes4 selector;
        bool isMakerBid;
        address implementation;
    }

    /**
     * @notice It is emitted when a new strategy is added.
     * @param strategyId Id of the new strategy
     * @param standardProtocolFeeBp Standard protocol fee (in basis point)
     * @param minTotalFeeBp Minimum total fee (in basis point)
     * @param maxProtocolFeeBp Maximum protocol fee (in basis point)
     * @param selector Function selector for the transaction to be executed
     * @param isMakerBid Whether the strategyId is for maker bid
     * @param implementation Address of the implementation of the strategy
     */
    event NewStrategy(
        uint256 strategyId,
        uint16 standardProtocolFeeBp,
        uint16 minTotalFeeBp,
        uint16 maxProtocolFeeBp,
        bytes4 selector,
        bool isMakerBid,
        address implementation
    );

    /**
     * @notice It is emitted when an existing strategy is updated.
     * @param strategyId Id of the strategy
     * @param isActive Whether the strategy is active (or not) after the update
     * @param standardProtocolFeeBp Standard protocol fee (in basis point)
     * @param minTotalFeeBp Minimum total fee (in basis point)
     */
    event StrategyUpdated(uint256 strategyId, bool isActive, uint16 standardProtocolFeeBp, uint16 minTotalFeeBp);

    /**
     * @notice If the strategy has not set properly its implementation contract.
     * @dev It can only be returned for owner operations.
     */
    error NotV2Strategy();

    /**
     * @notice It is returned if the strategy has no selector.
     * @dev It can only be returned for owner operations.
     */
    error StrategyHasNoSelector();

    /**
     * @notice It is returned if the strategyId is invalid.
     */
    error StrategyNotUsed();

    /**
     * @notice It is returned if the strategy's protocol fee is too high.
     * @dev It can only be returned for owner operations.
     */
    error StrategyProtocolFeeTooHigh();
}

File 25 of 47 : ITransferManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "../libraries/OrderStructs.sol";

// Enums
import {CollectionType} from "../enums/CollectionType.sol";

/**
 * @title ITransferManager
 * @author LooksRare protocol team (👀,💎)
 */
interface ITransferManager {
    /**
     * @notice This struct is only used for transferBatchItemsAcrossCollections.
     * @param collection Collection address
     * @param collectionType 0 for ERC721, 1 for ERC1155
     * @param itemIds Array of item ids to transfer
     * @param amounts Array of amounts to transfer
     */
    struct BatchTransferItem {
        address collection;
        CollectionType collectionType;
        uint256[] itemIds;
        uint256[] amounts;
    }

    /**
     * @notice It is emitted if operators' approvals to transfer NFTs are granted by a user.
     * @param user Address of the user
     * @param operators Array of operator addresses
     */
    event ApprovalsGranted(address user, address[] operators);

    /**
     * @notice It is emitted if operators' approvals to transfer NFTs are revoked by a user.
     * @param user Address of the user
     * @param operators Array of operator addresses
     */
    event ApprovalsRemoved(address user, address[] operators);

    /**
     * @notice It is emitted if a new operator is added to the global allowlist.
     * @param operator Operator address
     */
    event OperatorAllowed(address operator);

    /**
     * @notice It is emitted if an operator is removed from the global allowlist.
     * @param operator Operator address
     */
    event OperatorRemoved(address operator);

    /**
     * @notice It is returned if the operator to approve has already been approved by the user.
     */
    error OperatorAlreadyApprovedByUser();

    /**
     * @notice It is returned if the operator to revoke has not been previously approved by the user.
     */
    error OperatorNotApprovedByUser();

    /**
     * @notice It is returned if the transfer caller is already allowed by the owner.
     * @dev This error can only be returned for owner operations.
     */
    error OperatorAlreadyAllowed();

    /**
     * @notice It is returned if the operator to approve is not in the global allowlist defined by the owner.
     * @dev This error can be returned if the user tries to grant approval to an operator address not in the
     *      allowlist or if the owner tries to remove the operator from the global allowlist.
     */
    error OperatorNotAllowed();

    /**
     * @notice It is returned if the transfer caller is invalid.
     *         For a transfer called to be valid, the operator must be in the global allowlist and
     *         approved by the 'from' user.
     */
    error TransferCallerInvalid();
}

File 26 of 47 : MerkleProofCalldataWithNodes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Libraries
import {OrderStructs} from "../../libraries/OrderStructs.sol";

/**
 * @title MerkleProofCalldataWithNodes
 * @notice This library is adjusted from the work of OpenZeppelin.
 *         It is based on the 4.7.0 (utils/cryptography/MerkleProof.sol).
 * @author OpenZeppelin (adjusted by LooksRare)
 */
library MerkleProofCalldataWithNodes {
    /**
     * @notice This returns true if a `leaf` can be proved to be a part of a Merkle tree defined by `root`.
     *         For this, a `proof` must be provided, containing sibling hashes on the branch from the leaf to the
     *         root of the tree. Each pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verifyCalldata(
        OrderStructs.MerkleTreeNode[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @notice This returns the rebuilt hash obtained by traversing a Merkle tree up from `leaf` using `proof`.
     *         A `proof` is valid if and only if the rebuilt hash matches the root of the tree.
     *         When processing the proof, the pairs of leafs & pre-images are assumed to be sorted.
     */
    function processProofCalldata(
        OrderStructs.MerkleTreeNode[] calldata proof,
        bytes32 leaf
    ) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        uint256 length = proof.length;

        for (uint256 i = 0; i < length; ) {
            if (proof[i].position == OrderStructs.MerkleTreeNodePosition.Left) {
                computedHash = _efficientHash(proof[i].value, computedHash);
            } else {
                computedHash = _efficientHash(computedHash, proof[i].value);
            }
            unchecked {
                ++i;
            }
        }
        return computedHash;
    }

    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 27 of 47 : OrderStructs.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Enums
import {CollectionType} from "../enums/CollectionType.sol";
import {QuoteType} from "../enums/QuoteType.sol";

/**
 * @title OrderStructs
 * @notice This library contains all order struct types for the LooksRare protocol (v2).
 * @author LooksRare protocol team (👀,💎)
 */
library OrderStructs {
    /**
     * 1. Maker struct
     */

    /**
     * @notice Maker is the struct for a maker order.
     * @param quoteType Quote type (i.e. 0 = BID, 1 = ASK)
     * @param globalNonce Global user order nonce for maker orders
     * @param subsetNonce Subset nonce (shared across bid/ask maker orders)
     * @param orderNonce Order nonce (it can be shared across bid/ask maker orders)
     * @param strategyId Strategy id
     * @param collectionType Collection type (i.e. 0 = ERC721, 1 = ERC1155)
     * @param collection Collection address
     * @param currency Currency address (@dev address(0) = ETH)
     * @param signer Signer address
     * @param startTime Start timestamp
     * @param endTime End timestamp
     * @param price Minimum price for maker ask, maximum price for maker bid
     * @param itemIds Array of itemIds
     * @param amounts Array of amounts
     * @param additionalParameters Extra data specific for the order
     */
    struct Maker {
        QuoteType quoteType;
        uint256 globalNonce;
        uint256 subsetNonce;
        uint256 orderNonce;
        uint256 strategyId;
        CollectionType collectionType;
        address collection;
        address currency;
        address signer;
        uint256 startTime;
        uint256 endTime;
        uint256 price;
        uint256[] itemIds;
        uint256[] amounts;
        bytes additionalParameters;
    }

    /**
     * 2. Taker struct
     */

    /**
     * @notice Taker is the struct for a taker ask/bid order. It contains the parameters required for a direct purchase.
     * @dev Taker struct is matched against MakerAsk/MakerBid structs at the protocol level.
     * @param recipient Recipient address (to receive NFTs or non-fungible tokens)
     * @param additionalParameters Extra data specific for the order
     */
    struct Taker {
        address recipient;
        bytes additionalParameters;
    }

    /**
     * 3. Merkle tree struct
     */

    enum MerkleTreeNodePosition { Left, Right }

    /**
     * @notice MerkleTreeNode is a MerkleTree's node.
     * @param value It can be an order hash or a proof
     * @param position The node's position in its branch.
     *                 It can be left or right or none
     *                 (before the tree is sorted).
     */
    struct MerkleTreeNode {
        bytes32 value;
        MerkleTreeNodePosition position;
    }

    /**
     * @notice MerkleTree is the struct for a merkle tree of order hashes.
     * @dev A Merkle tree can be computed with order hashes.
     *      It can contain order hashes from both maker bid and maker ask structs.
     * @param root Merkle root
     * @param proof Array containing the merkle proof
     */
    struct MerkleTree {
        bytes32 root;
        MerkleTreeNode[] proof;
    }

    /**
     * 4. Constants
     */

    /**
     * @notice This is the type hash constant used to compute the maker order hash.
     */
    bytes32 internal constant _MAKER_TYPEHASH =
        keccak256(
            "Maker("
                "uint8 quoteType,"
                "uint256 globalNonce,"
                "uint256 subsetNonce,"
                "uint256 orderNonce,"
                "uint256 strategyId,"
                "uint8 collectionType,"
                "address collection,"
                "address currency,"
                "address signer,"
                "uint256 startTime,"
                "uint256 endTime,"
                "uint256 price,"
                "uint256[] itemIds,"
                "uint256[] amounts,"
                "bytes additionalParameters"
            ")"
        );

    /**
     * 5. Hash functions
     */

    /**
     * @notice This function is used to compute the order hash for a maker struct.
     * @param maker Maker order struct
     * @return makerHash Hash of the maker struct
     */
    function hash(Maker memory maker) internal pure returns (bytes32) {
        // Encoding is done into two parts to avoid stack too deep issues
        return
            keccak256(
                bytes.concat(
                    abi.encode(
                        _MAKER_TYPEHASH,
                        maker.quoteType,
                        maker.globalNonce,
                        maker.subsetNonce,
                        maker.orderNonce,
                        maker.strategyId,
                        maker.collectionType,
                        maker.collection,
                        maker.currency
                    ),
                    abi.encode(
                        maker.signer,
                        maker.startTime,
                        maker.endTime,
                        maker.price,
                        keccak256(abi.encodePacked(maker.itemIds)),
                        keccak256(abi.encodePacked(maker.amounts)),
                        keccak256(maker.additionalParameters)
                    )
                )
            );
    }
}

File 28 of 47 : OwnableTwoSteps.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IOwnableTwoSteps} from "./interfaces/IOwnableTwoSteps.sol";

/**
 * @title OwnableTwoSteps
 * @notice This contract offers transfer of ownership in two steps with potential owner
 *         having to confirm the transaction to become the owner.
 *         Renouncement of the ownership is also a two-step process since the next potential owner is the address(0).
 * @author LooksRare protocol team (👀,💎)
 */
abstract contract OwnableTwoSteps is IOwnableTwoSteps {
    /**
     * @notice Address of the current owner.
     */
    address public owner;

    /**
     * @notice Address of the potential owner.
     */
    address public potentialOwner;

    /**
     * @notice Ownership status.
     */
    Status public ownershipStatus;

    /**
     * @notice Modifier to wrap functions for contracts that inherit this contract.
     */
    modifier onlyOwner() {
        _onlyOwner();
        _;
    }

    /**
     * @notice Constructor
     * @param _owner The contract's owner
     */
    constructor(address _owner) {
        owner = _owner;
        emit NewOwner(_owner);
    }

    /**
     * @notice This function is used to cancel the ownership transfer.
     * @dev This function can be used for both cancelling a transfer to a new owner and
     *      cancelling the renouncement of the ownership.
     */
    function cancelOwnershipTransfer() external onlyOwner {
        Status _ownershipStatus = ownershipStatus;
        if (_ownershipStatus == Status.NoOngoingTransfer) {
            revert NoOngoingTransferInProgress();
        }

        if (_ownershipStatus == Status.TransferInProgress) {
            delete potentialOwner;
        }

        delete ownershipStatus;

        emit CancelOwnershipTransfer();
    }

    /**
     * @notice This function is used to confirm the ownership renouncement.
     */
    function confirmOwnershipRenouncement() external onlyOwner {
        if (ownershipStatus != Status.RenouncementInProgress) {
            revert RenouncementNotInProgress();
        }

        delete owner;
        delete ownershipStatus;

        emit NewOwner(address(0));
    }

    /**
     * @notice This function is used to confirm the ownership transfer.
     * @dev This function can only be called by the current potential owner.
     */
    function confirmOwnershipTransfer() external {
        if (ownershipStatus != Status.TransferInProgress) {
            revert TransferNotInProgress();
        }

        if (msg.sender != potentialOwner) {
            revert WrongPotentialOwner();
        }

        owner = msg.sender;
        delete ownershipStatus;
        delete potentialOwner;

        emit NewOwner(msg.sender);
    }

    /**
     * @notice This function is used to initiate the transfer of ownership to a new owner.
     * @param newPotentialOwner New potential owner address
     */
    function initiateOwnershipTransfer(address newPotentialOwner) external onlyOwner {
        if (ownershipStatus != Status.NoOngoingTransfer) {
            revert TransferAlreadyInProgress();
        }

        ownershipStatus = Status.TransferInProgress;
        potentialOwner = newPotentialOwner;

        /**
         * @dev This function can only be called by the owner, so msg.sender is the owner.
         *      We don't have to SLOAD the owner again.
         */
        emit InitiateOwnershipTransfer(msg.sender, newPotentialOwner);
    }

    /**
     * @notice This function is used to initiate the ownership renouncement.
     */
    function initiateOwnershipRenouncement() external onlyOwner {
        if (ownershipStatus != Status.NoOngoingTransfer) {
            revert TransferAlreadyInProgress();
        }

        ownershipStatus = Status.RenouncementInProgress;

        emit InitiateOwnershipRenouncement();
    }

    function _onlyOwner() private view {
        if (msg.sender != owner) revert NotOwner();
    }
}

File 29 of 47 : PackableReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IReentrancyGuard} from "./interfaces/IReentrancyGuard.sol";

/**
 * @title PackableReentrancyGuard
 * @notice This contract protects against reentrancy attacks.
 *         It is adjusted from OpenZeppelin.
 *         The only difference between this contract and ReentrancyGuard
 *         is that _status is uint8 instead of uint256 so that it can be
 *         packed with other contracts' storage variables.
 * @author LooksRare protocol team (👀,💎)
 */
abstract contract PackableReentrancyGuard is IReentrancyGuard {
    uint8 private _status;

    /**
     * @notice Modifier to wrap functions to prevent reentrancy calls.
     */
    modifier nonReentrant() {
        if (_status == 2) {
            revert ReentrancyFail();
        }

        _status = 2;
        _;
        _status = 1;
    }

    constructor() {
        _status = 1;
    }
}

File 30 of 47 : SignatureCheckerCalldata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IERC1271} from "./interfaces/generic/IERC1271.sol";

// Constants
import {ERC1271_MAGIC_VALUE} from "./constants/StandardConstants.sol";

// Errors
import {SignatureParameterSInvalid, SignatureParameterVInvalid, SignatureERC1271Invalid, SignatureEOAInvalid, NullSignerAddress, SignatureLengthInvalid} from "./errors/SignatureCheckerErrors.sol";

/**
 * @title SignatureCheckerCalldata
 * @notice This library is used to verify signatures for EOAs (with lengths of both 65 and 64 bytes)
 *         and contracts (ERC1271).
 * @author LooksRare protocol team (👀,💎)
 */
library SignatureCheckerCalldata {
    /**
     * @notice This function verifies whether the signer is valid for a hash and raw signature.
     * @param hash Data hash
     * @param signer Signer address (to confirm message validity)
     * @param signature Signature parameters encoded (v, r, s)
     * @dev For EIP-712 signatures, the hash must be the digest (computed with signature hash and domain separator)
     */
    function verify(bytes32 hash, address signer, bytes calldata signature) internal view {
        if (signer.code.length == 0) {
            if (_recoverEOASigner(hash, signature) == signer) return;
            revert SignatureEOAInvalid();
        } else {
            if (IERC1271(signer).isValidSignature(hash, signature) == ERC1271_MAGIC_VALUE) return;
            revert SignatureERC1271Invalid();
        }
    }

    /**
     * @notice This function is internal and splits a signature into r, s, v outputs.
     * @param signature A 64 or 65 bytes signature
     * @return r The r output of the signature
     * @return s The s output of the signature
     * @return v The recovery identifier, must be 27 or 28
     */
    function splitSignature(bytes calldata signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
        uint256 length = signature.length;
        if (length == 65) {
            assembly {
                r := calldataload(signature.offset)
                s := calldataload(add(signature.offset, 0x20))
                v := byte(0, calldataload(add(signature.offset, 0x40)))
            }
        } else if (length == 64) {
            assembly {
                r := calldataload(signature.offset)
                let vs := calldataload(add(signature.offset, 0x20))
                s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                v := add(shr(255, vs), 27)
            }
        } else {
            revert SignatureLengthInvalid(length);
        }

        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            revert SignatureParameterSInvalid();
        }

        if (v != 27 && v != 28) {
            revert SignatureParameterVInvalid(v);
        }
    }

    /**
     * @notice This function is private and recovers the signer of a signature (for EOA only).
     * @param hash Hash of the signed message
     * @param signature Bytes containing the signature (64 or 65 bytes)
     * @return signer The address that signed the signature
     */
    function _recoverEOASigner(bytes32 hash, bytes calldata signature) private pure returns (address signer) {
        (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);

        // If the signature is valid (and not malleable), return the signer's address
        signer = ecrecover(hash, v, r, s);

        if (signer == address(0)) {
            revert NullSignerAddress();
        }
    }
}

File 31 of 47 : AssemblyConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/*
 * @dev error ETHTransferFail()
 *      Memory layout:
 *        - 0x00: Left-padded selector (data begins at 0x1c)
 *      Revert buffer is memory[0x1c:0x20]
 */
uint256 constant ETHTransferFail_error_selector = 0x07246cf4;
uint256 constant ETHTransferFail_error_length = 0x04;
uint256 constant Error_selector_offset = 0x1c;

File 32 of 47 : StandardConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @dev ERC1271's magic value (bytes4(keccak256("isValidSignature(bytes32,bytes)"))
 */
bytes4 constant ERC1271_MAGIC_VALUE = 0x1626ba7e;

File 33 of 47 : GenericErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @notice It is emitted if the call recipient is not a contract.
 */
error NotAContract();

File 34 of 47 : LowLevelErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @notice It is emitted if the ETH transfer fails.
 */
error ETHTransferFail();

/**
 * @notice It is emitted if the ERC20 approval fails.
 */
error ERC20ApprovalFail();

/**
 * @notice It is emitted if the ERC20 transfer fails.
 */
error ERC20TransferFail();

/**
 * @notice It is emitted if the ERC20 transferFrom fails.
 */
error ERC20TransferFromFail();

/**
 * @notice It is emitted if the ERC721 transferFrom fails.
 */
error ERC721TransferFromFail();

/**
 * @notice It is emitted if the ERC1155 safeTransferFrom fails.
 */
error ERC1155SafeTransferFromFail();

/**
 * @notice It is emitted if the ERC1155 safeBatchTransferFrom fails.
 */
error ERC1155SafeBatchTransferFromFail();

File 35 of 47 : SignatureCheckerErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @notice It is emitted if the signer is null.
 */
error NullSignerAddress();

/**
 * @notice It is emitted if the signature is invalid for an EOA (the address recovered is not the expected one).
 */
error SignatureEOAInvalid();

/**
 * @notice It is emitted if the signature is invalid for a ERC1271 contract signer.
 */
error SignatureERC1271Invalid();

/**
 * @notice It is emitted if the signature's length is neither 64 nor 65 bytes.
 */
error SignatureLengthInvalid(uint256 length);

/**
 * @notice It is emitted if the signature is invalid due to S parameter.
 */
error SignatureParameterSInvalid();

/**
 * @notice It is emitted if the signature is invalid due to V parameter.
 */
error SignatureParameterVInvalid(uint8 v);

File 36 of 47 : IOwnableTwoSteps.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @title IOwnableTwoSteps
 * @author LooksRare protocol team (👀,💎)
 */
interface IOwnableTwoSteps {
    /**
     * @notice This enum keeps track of the ownership status.
     * @param NoOngoingTransfer The default status when the owner is set
     * @param TransferInProgress The status when a transfer to a new owner is initialized
     * @param RenouncementInProgress The status when a transfer to address(0) is initialized
     */
    enum Status {
        NoOngoingTransfer,
        TransferInProgress,
        RenouncementInProgress
    }

    /**
     * @notice This is returned when there is no transfer of ownership in progress.
     */
    error NoOngoingTransferInProgress();

    /**
     * @notice This is returned when the caller is not the owner.
     */
    error NotOwner();

    /**
     * @notice This is returned when there is no renouncement in progress but
     *         the owner tries to validate the ownership renouncement.
     */
    error RenouncementNotInProgress();

    /**
     * @notice This is returned when the transfer is already in progress but the owner tries
     *         initiate a new ownership transfer.
     */
    error TransferAlreadyInProgress();

    /**
     * @notice This is returned when there is no ownership transfer in progress but the
     *         ownership change tries to be approved.
     */
    error TransferNotInProgress();

    /**
     * @notice This is returned when the ownership transfer is attempted to be validated by the
     *         a caller that is not the potential owner.
     */
    error WrongPotentialOwner();

    /**
     * @notice This is emitted if the ownership transfer is cancelled.
     */
    event CancelOwnershipTransfer();

    /**
     * @notice This is emitted if the ownership renouncement is initiated.
     */
    event InitiateOwnershipRenouncement();

    /**
     * @notice This is emitted if the ownership transfer is initiated.
     * @param previousOwner Previous/current owner
     * @param potentialOwner Potential/future owner
     */
    event InitiateOwnershipTransfer(address previousOwner, address potentialOwner);

    /**
     * @notice This is emitted when there is a new owner.
     */
    event NewOwner(address newOwner);
}

File 37 of 47 : IReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

/**
 * @title IReentrancyGuard
 * @author LooksRare protocol team (👀,💎)
 */
interface IReentrancyGuard {
    /**
     * @notice This is returned when there is a reentrant call.
     */
    error ReentrancyFail();
}

File 38 of 47 : IERC1155.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC1155 {
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

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

    event URI(string value, uint256 indexed id);

    function balanceOf(address account, uint256 id) external view returns (uint256);

    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    function setApprovalForAll(address operator, bool approved) external;

    function isApprovedForAll(address account, address operator) external view returns (bool);

    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 39 of 47 : IERC1271.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC1271 {
    function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue);
}

File 40 of 47 : IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);

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

    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 41 of 47 : IERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IERC721 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

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

    function balanceOf(address owner) external view returns (uint256 balance);

    function ownerOf(uint256 tokenId) external view returns (address owner);

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    function transferFrom(address from, address to, uint256 tokenId) external;

    function approve(address to, uint256 tokenId) external;

    function setApprovalForAll(address operator, bool _approved) external;

    function getApproved(uint256 tokenId) external view returns (address operator);

    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 42 of 47 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.5.0;

interface IWETH {
    function deposit() external payable;

    function transfer(address dst, uint256 wad) external returns (bool);

    function withdraw(uint256 wad) external;
}

File 43 of 47 : LowLevelERC1155Transfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IERC1155} from "../interfaces/generic/IERC1155.sol";

// Errors
import {ERC1155SafeTransferFromFail, ERC1155SafeBatchTransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";

/**
 * @title LowLevelERC1155Transfer
 * @notice This contract contains low-level calls to transfer ERC1155 tokens.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelERC1155Transfer {
    /**
     * @notice Execute ERC1155 safeTransferFrom
     * @param collection Address of the collection
     * @param from Address of the sender
     * @param to Address of the recipient
     * @param tokenId tokenId to transfer
     * @param amount Amount to transfer
     */
    function _executeERC1155SafeTransferFrom(
        address collection,
        address from,
        address to,
        uint256 tokenId,
        uint256 amount
    ) internal {
        if (collection.code.length == 0) {
            revert NotAContract();
        }

        (bool status, ) = collection.call(abi.encodeCall(IERC1155.safeTransferFrom, (from, to, tokenId, amount, "")));

        if (!status) {
            revert ERC1155SafeTransferFromFail();
        }
    }

    /**
     * @notice Execute ERC1155 safeBatchTransferFrom
     * @param collection Address of the collection
     * @param from Address of the sender
     * @param to Address of the recipient
     * @param tokenIds Array of tokenIds to transfer
     * @param amounts Array of amounts to transfer
     */
    function _executeERC1155SafeBatchTransferFrom(
        address collection,
        address from,
        address to,
        uint256[] calldata tokenIds,
        uint256[] calldata amounts
    ) internal {
        if (collection.code.length == 0) {
            revert NotAContract();
        }

        (bool status, ) = collection.call(
            abi.encodeCall(IERC1155.safeBatchTransferFrom, (from, to, tokenIds, amounts, ""))
        );

        if (!status) {
            revert ERC1155SafeBatchTransferFromFail();
        }
    }
}

File 44 of 47 : LowLevelERC20Transfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IERC20} from "../interfaces/generic/IERC20.sol";

// Errors
import {ERC20TransferFail, ERC20TransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";

/**
 * @title LowLevelERC20Transfer
 * @notice This contract contains low-level calls to transfer ERC20 tokens.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelERC20Transfer {
    /**
     * @notice Execute ERC20 transferFrom
     * @param currency Currency address
     * @param from Sender address
     * @param to Recipient address
     * @param amount Amount to transfer
     */
    function _executeERC20TransferFrom(address currency, address from, address to, uint256 amount) internal {
        if (currency.code.length == 0) {
            revert NotAContract();
        }

        (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transferFrom, (from, to, amount)));

        if (!status) {
            revert ERC20TransferFromFail();
        }

        if (data.length > 0) {
            if (!abi.decode(data, (bool))) {
                revert ERC20TransferFromFail();
            }
        }
    }

    /**
     * @notice Execute ERC20 (direct) transfer
     * @param currency Currency address
     * @param to Recipient address
     * @param amount Amount to transfer
     */
    function _executeERC20DirectTransfer(address currency, address to, uint256 amount) internal {
        if (currency.code.length == 0) {
            revert NotAContract();
        }

        (bool status, bytes memory data) = currency.call(abi.encodeCall(IERC20.transfer, (to, amount)));

        if (!status) {
            revert ERC20TransferFail();
        }

        if (data.length > 0) {
            if (!abi.decode(data, (bool))) {
                revert ERC20TransferFail();
            }
        }
    }
}

File 45 of 47 : LowLevelERC721Transfer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IERC721} from "../interfaces/generic/IERC721.sol";

// Errors
import {ERC721TransferFromFail} from "../errors/LowLevelErrors.sol";
import {NotAContract} from "../errors/GenericErrors.sol";

/**
 * @title LowLevelERC721Transfer
 * @notice This contract contains low-level calls to transfer ERC721 tokens.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelERC721Transfer {
    /**
     * @notice Execute ERC721 transferFrom
     * @param collection Address of the collection
     * @param from Address of the sender
     * @param to Address of the recipient
     * @param tokenId tokenId to transfer
     */
    function _executeERC721TransferFrom(address collection, address from, address to, uint256 tokenId) internal {
        if (collection.code.length == 0) {
            revert NotAContract();
        }

        (bool status, ) = collection.call(abi.encodeCall(IERC721.transferFrom, (from, to, tokenId)));

        if (!status) {
            revert ERC721TransferFromFail();
        }
    }
}

File 46 of 47 : LowLevelETHReturnETHIfAnyExceptOneWei.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Assembly constants
import {ETHTransferFail_error_selector, ETHTransferFail_error_length, Error_selector_offset} from "../constants/AssemblyConstants.sol";

/**
 * @title LowLevelETHReturnETHIfAnyExceptOneWei
 * @notice This contract contains a function to return all ETH except 1 wei held.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelETHReturnETHIfAnyExceptOneWei {
    /**
     * @notice It returns ETH to the original sender if any is left in the payable call
     *         but this leaves 1 wei of ETH in the contract.
     * @dev It does not revert if self balance is equal to 1 or 0.
     */
    function _returnETHIfAnyWithOneWeiLeft() internal {
        assembly {
            let selfBalance := selfbalance()
            if gt(selfBalance, 1) {
                let status := call(gas(), caller(), sub(selfBalance, 1), 0, 0, 0, 0)
                if iszero(status) {
                    mstore(0x00, ETHTransferFail_error_selector)
                    revert(Error_selector_offset, ETHTransferFail_error_length)
                }
            }
        }
    }
}

File 47 of 47 : LowLevelWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

// Interfaces
import {IWETH} from "../interfaces/generic/IWETH.sol";

/**
 * @title LowLevelWETH
 * @notice This contract contains a function to transfer ETH with an option to wrap to WETH.
 *         If the ETH transfer fails within a gas limit, the amount in ETH is wrapped to WETH and then transferred.
 * @author LooksRare protocol team (👀,💎)
 */
contract LowLevelWETH {
    /**
     * @notice It transfers ETH to a recipient with a specified gas limit.
     *         If the original transfers fails, it wraps to WETH and transfers the WETH to recipient.
     * @param _WETH WETH address
     * @param _to Recipient address
     * @param _amount Amount to transfer
     * @param _gasLimit Gas limit to perform the ETH transfer
     */
    function _transferETHAndWrapIfFailWithGasLimit(
        address _WETH,
        address _to,
        uint256 _amount,
        uint256 _gasLimit
    ) internal {
        bool status;

        assembly {
            status := call(_gasLimit, _to, _amount, 0, 0, 0, 0)
        }

        if (!status) {
            IWETH(_WETH).deposit{value: _amount}();
            IWETH(_WETH).transfer(_to, _amount);
        }
    }
}

Settings
{
  "remappings": [
    "@chainlink/=node_modules/@chainlink/",
    "@ensdomains/=node_modules/@ensdomains/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@looksrare/=node_modules/@looksrare/",
    "@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/",
    "murky/=lib/murky/src/",
    "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
    "solmate/=node_modules/solmate/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 888888
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_protocolFeeRecipient","type":"address"},{"internalType":"address","name":"_transferManager","type":"address"},{"internalType":"address","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CallerInvalid","type":"error"},{"inputs":[],"name":"ChainIdInvalid","type":"error"},{"inputs":[],"name":"CreatorFeeBpTooHigh","type":"error"},{"inputs":[],"name":"CurrencyInvalid","type":"error"},{"inputs":[],"name":"ERC20TransferFromFail","type":"error"},{"inputs":[],"name":"LengthsInvalid","type":"error"},{"inputs":[],"name":"MerkleProofInvalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"MerkleProofTooLarge","type":"error"},{"inputs":[],"name":"NewGasLimitETHTransferTooLow","type":"error"},{"inputs":[],"name":"NewProtocolFeeRecipientCannotBeNullAddress","type":"error"},{"inputs":[],"name":"NoOngoingTransferInProgress","type":"error"},{"inputs":[],"name":"NoSelectorForStrategy","type":"error"},{"inputs":[],"name":"NoncesInvalid","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"NotAffiliateController","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotV2Strategy","type":"error"},{"inputs":[],"name":"NullSignerAddress","type":"error"},{"inputs":[],"name":"OutsideOfTimeRange","type":"error"},{"inputs":[],"name":"PercentageTooHigh","type":"error"},{"inputs":[],"name":"QuoteTypeInvalid","type":"error"},{"inputs":[],"name":"ReentrancyFail","type":"error"},{"inputs":[],"name":"RenouncementNotInProgress","type":"error"},{"inputs":[],"name":"SameDomainSeparator","type":"error"},{"inputs":[],"name":"SignatureEOAInvalid","type":"error"},{"inputs":[],"name":"SignatureERC1271Invalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"SignatureLengthInvalid","type":"error"},{"inputs":[],"name":"SignatureParameterSInvalid","type":"error"},{"inputs":[{"internalType":"uint8","name":"v","type":"uint8"}],"name":"SignatureParameterVInvalid","type":"error"},{"inputs":[],"name":"StrategyHasNoSelector","type":"error"},{"inputs":[{"internalType":"uint256","name":"strategyId","type":"uint256"}],"name":"StrategyNotAvailable","type":"error"},{"inputs":[],"name":"StrategyNotUsed","type":"error"},{"inputs":[],"name":"StrategyProtocolFeeTooHigh","type":"error"},{"inputs":[],"name":"TransferAlreadyInProgress","type":"error"},{"inputs":[],"name":"TransferNotInProgress","type":"error"},{"inputs":[],"name":"WrongPotentialOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"uint256","name":"affiliateFee","type":"uint256"}],"name":"AffiliatePayment","type":"event"},{"anonymous":false,"inputs":[],"name":"CancelOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"CurrencyStatusUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"InitiateOwnershipRenouncement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"potentialOwner","type":"address"}],"name":"InitiateOwnershipTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliateController","type":"address"}],"name":"NewAffiliateController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"}],"name":"NewAffiliateProgramStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"affiliate","type":"address"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"NewAffiliateRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"bidNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"askNonce","type":"uint256"}],"name":"NewBidAskNonces","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"creatorFeeManager","type":"address"}],"name":"NewCreatorFeeManager","type":"event"},{"anonymous":false,"inputs":[],"name":"NewDomainSeparator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasLimitETHTransfer","type":"uint256"}],"name":"NewGasLimitETHTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxCreatorFeeBp","type":"uint256"}],"name":"NewMaxCreatorFeeBp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"protocolFeeRecipient","type":"address"}],"name":"NewProtocolFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"isMakerBid","type":"bool"},{"indexed":false,"internalType":"address","name":"implementation","type":"address"}],"name":"NewStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"orderNonces","type":"uint256[]"}],"name":"OrderNoncesCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isActive","type":"bool"},{"indexed":false,"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"}],"name":"StrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"subsetNonces","type":"uint256[]"}],"name":"SubsetNoncesCancelled","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"bool","name":"isNonceInvalidated","type":"bool"}],"indexed":false,"internalType":"struct ILooksRareProtocol.NonceInvalidationParameters","name":"nonceInvalidationParameters","type":"tuple"},{"indexed":false,"internalType":"address","name":"askUser","type":"address"},{"indexed":false,"internalType":"address","name":"bidUser","type":"address"},{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"address[2]","name":"feeRecipients","type":"address[2]"},{"indexed":false,"internalType":"uint256[3]","name":"feeAmounts","type":"uint256[3]"}],"name":"TakerAsk","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"bool","name":"isNonceInvalidated","type":"bool"}],"indexed":false,"internalType":"struct ILooksRareProtocol.NonceInvalidationParameters","name":"nonceInvalidationParameters","type":"tuple"},{"indexed":false,"internalType":"address","name":"bidUser","type":"address"},{"indexed":false,"internalType":"address","name":"bidRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"strategyId","type":"uint256"},{"indexed":false,"internalType":"address","name":"currency","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"address[2]","name":"feeRecipients","type":"address[2]"},{"indexed":false,"internalType":"uint256[3]","name":"feeAmounts","type":"uint256[3]"}],"name":"TakerBid","type":"event"},{"inputs":[],"name":"MAGIC_VALUE_ORDER_NONCE_EXECUTED","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bool","name":"isMakerBid","type":"bool"},{"internalType":"address","name":"implementation","type":"address"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"affiliateController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"affiliateRates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderNonces","type":"uint256[]"}],"name":"cancelOrderNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"subsetNonces","type":"uint256[]"}],"name":"cancelSubsetNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"confirmOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creatorFeeManager","outputs":[{"internalType":"contract ICreatorFeeManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker[]","name":"takerBids","type":"tuple[]"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker[]","name":"makerAsks","type":"tuple[]"},{"internalType":"bytes[]","name":"makerSignatures","type":"bytes[]"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree[]","name":"merkleTrees","type":"tuple[]"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bool","name":"isAtomic","type":"bool"}],"name":"executeMultipleTakerBids","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerAsk","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerBid","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree","name":"merkleTree","type":"tuple"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"executeTakerAsk","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerBid","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerAsk","type":"tuple"},{"internalType":"bytes","name":"makerSignature","type":"bytes"},{"components":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"value","type":"bytes32"},{"internalType":"enum OrderStructs.MerkleTreeNodePosition","name":"position","type":"uint8"}],"internalType":"struct OrderStructs.MerkleTreeNode[]","name":"proof","type":"tuple[]"}],"internalType":"struct OrderStructs.MerkleTree","name":"merkleTree","type":"tuple"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"executeTakerBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"uint256","name":"proofLength","type":"uint256"}],"name":"hashBatchOrder","outputs":[{"internalType":"bytes32","name":"batchOrderHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bool","name":"bid","type":"bool"},{"internalType":"bool","name":"ask","type":"bool"}],"name":"incrementBidAskNonces","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateOwnershipRenouncement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPotentialOwner","type":"address"}],"name":"initiateOwnershipTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAffiliateProgramActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isCurrencyAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxCreatorFeeBp","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipStatus","outputs":[{"internalType":"enum IOwnableTwoSteps.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"potentialOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Taker","name":"takerBid","type":"tuple"},{"components":[{"internalType":"enum QuoteType","name":"quoteType","type":"uint8"},{"internalType":"uint256","name":"globalNonce","type":"uint256"},{"internalType":"uint256","name":"subsetNonce","type":"uint256"},{"internalType":"uint256","name":"orderNonce","type":"uint256"},{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"enum CollectionType","name":"collectionType","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256[]","name":"itemIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"additionalParameters","type":"bytes"}],"internalType":"struct OrderStructs.Maker","name":"makerAsk","type":"tuple"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"restrictedExecuteTakerBid","outputs":[{"internalType":"uint256","name":"protocolFeeAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"strategyInfo","outputs":[{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint16","name":"standardProtocolFeeBp","type":"uint16"},{"internalType":"uint16","name":"minTotalFeeBp","type":"uint16"},{"internalType":"uint16","name":"maxProtocolFeeBp","type":"uint16"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bool","name":"isMakerBid","type":"bool"},{"internalType":"address","name":"implementation","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferManager","outputs":[{"internalType":"contract TransferManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAffiliateController","type":"address"}],"name":"updateAffiliateController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isActive","type":"bool"}],"name":"updateAffiliateProgramStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"uint256","name":"bp","type":"uint256"}],"name":"updateAffiliateRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCreatorFeeManager","type":"address"}],"name":"updateCreatorFeeManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"currency","type":"address"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"updateCurrencyStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasLimitETHTransfer","type":"uint256"}],"name":"updateETHGasLimitForTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newMaxCreatorFeeBp","type":"uint16"}],"name":"updateMaxCreatorFeeBp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeeRecipient","type":"address"}],"name":"updateProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"strategyId","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"uint16","name":"newStandardProtocolFee","type":"uint16"},{"internalType":"uint16","name":"newMinTotalFee","type":"uint16"}],"name":"updateStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBidAskNonces","outputs":[{"internalType":"uint256","name":"bidNonce","type":"uint256"},{"internalType":"uint256","name":"askNonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userOrderNonce","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userSubsetNonce","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60c06040526001600855600a805461ffff60a01b1916607d60a31b1790556108fc600e553480156200003057600080fd5b5060405162005dc838038062005dc8833981016040819052620000539162000417565b600380546001600160a01b0319166001600160a01b0386169081179091556040519081528490849084908390839082908190819081907f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc9060200160405180910390a150506040805160e08082018352600182526032602080840182815284860183815260c86060870181815260006080890181815260a08a0182815260c08b01838152838052600990985299517fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b805497519651945192519b5198516001600160a01b03166c01000000000000000000000000026001600160601b039915156b0100000000000000000000000260ff60581b199d909c1c670100000000000000029c909c1664ffffffffff60381b1961ffff948516650100000000000261ffff60281b199786166301000000029790971666ffffffff00000019999095166101000262ffff00199415159490941662ffffff19909a1699909917929092179690961691909117929092179490941617959095179290921694909417905592517f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a29450620002719391829184908190819096875261ffff958616602088015293851660408701529190931660608501526001600160e01b031992909216608084015290151560a08301526001600160a01b031660c082015260e00190565b60405180910390a15062000285816200037e565b5050600b805460ff60a01b1916600160a01b1790556001600160a01b03166080525062000368905060408051808201825260018152601960f91b60209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6001600160a01b031660a0525062000474915050565b6001600160a01b038116620003a657604051630f966bcb60e41b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0383169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb109060200160405180910390a150565b80516001600160a01b03811681146200041257600080fd5b919050565b600080600080608085870312156200042e57600080fd5b6200043985620003fa565b93506200044960208601620003fa565b92506200045960408601620003fa565b91506200046960608601620003fa565b905092959194509250565b60805160a051615919620004af600039600081816107ee0152613a2501526000818161045d015281816138c4015261398e01526159196000f3fe6080604052600436106102dc5760003560e01c8063838b8f5c11610184578063ae1cce5a116100d6578063d5b010f51161008a578063ea179b7611610064578063ea179b7614610a05578063f4288a2114610a40578063f698da2514610a5357600080fd5b8063d5b010f5146109a5578063d5b7f065146109c5578063e72853e1146109e557600080fd5b8063bb91c339116100bb578063bb91c33914610850578063c0b6f56114610965578063d5a06adf1461098557600080fd5b8063ae1cce5a14610810578063b647a4041461083057600080fd5b806391be136011610138578063a02bab5711610112578063a02bab5714610773578063a39bf29f14610793578063ad5c4648146107dc57600080fd5b806391be13601461071d578063974e7c9f1461073d5780639a8a05921461075d57600080fd5b806386c076421161016957806386c07642146106bb57806389ccfe89146106db5780638da5cb5b146106f057600080fd5b8063838b8f5c1461067b5780638585ae03146106a857600080fd5b80634cbac9dc1161023d57806367d9dd79116101f15780637762df25116101cb5780637762df251461060157806379ed31d41461062e5780637a7d88511461064e57600080fd5b806367d9dd79146105735780636e90c014146105a65780637200b829146105ec57600080fd5b80635a195d19116102225780635a195d19146104f15780635b6ac0111461053157806364df049e1461054657600080fd5b80634cbac9dc146104a457806354878876146104d157600080fd5b80632bb5a9e611610294578063463357ec11610279578063463357ec146103f757806346b625bc1461042b57806346ea25521461044b57600080fd5b80632bb5a9e6146103a35780633e567539146103e257600080fd5b80631df47f80116102c55780631df47f801461032357806320cd05c71461034357806323452b9c1461038e57600080fd5b8063134849a6146102e15780631d3c426814610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614520565b610a69565b005b34801561030f57600080fd5b5061030161031e3660046145a8565b610b63565b34801561032f57600080fd5b5061030161033e3660046145e1565b610bfa565b34801561034f57600080fd5b5061037b61035e366004614605565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561039a57600080fd5b50610301610c0e565b3480156103af57600080fd5b506004546103d59074010000000000000000000000000000000000000000900460ff1681565b6040516103859190614660565b3480156103ee57600080fd5b50610301610d15565b34801561040357600080fd5b5061037b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db81565b34801561043757600080fd5b5061030161044636600461468c565b610e0c565b34801561045757600080fd5b5061047f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610385565b3480156104b057600080fd5b5060055461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104dd57600080fd5b506103016104ec3660046146a7565b610ed6565b3480156104fd57600080fd5b5061052161050c3660046145e1565b60076020526000908152604090205460ff1681565b6040519015158152602001610385565b34801561053d57600080fd5b50610301610f58565b34801561055257600080fd5b50600a5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b50600454610521907501000000000000000000000000000000000000000000900460ff1681565b3480156105b257600080fd5b50600a546105d99074010000000000000000000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610385565b3480156105f857600080fd5b50610301611032565b34801561060d57600080fd5b5060045461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561063a57600080fd5b50610301610649366004614520565b611170565b34801561065a57600080fd5b5061037b6106693660046145e1565b60066020526000908152604090205481565b34801561068757600080fd5b50600b5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b6103016106b63660046146ef565b611250565b3480156106c757600080fd5b5061037b6106d63660046147df565b6113fc565b3480156106e757600080fd5b50610301611439565b3480156106fc57600080fd5b5060035461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561072957600080fd5b5061030161073836600461482f565b611583565b34801561074957600080fd5b506103016107583660046148ab565b611996565b34801561076957600080fd5b5061037b600c5481565b34801561077f57600080fd5b5061030161078e3660046145e1565b611a0f565b34801561079f57600080fd5b506107c76107ae3660046145e1565b6000602081905290815260409020805460019091015482565b60408051928352602083019190915201610385565b3480156107e857600080fd5b5061047f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561081c57600080fd5b5061030161082b366004614605565b611a8a565b34801561083c57600080fd5b5061030161084b3660046145e1565b611b75565b34801561085c57600080fd5b506108ec61086b3660046148ab565b60096020526000908152604090205460ff8082169161ffff61010082048116926301000000830482169265010000000000810490921691670100000000000000810460e01b916b0100000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009091041687565b60408051971515885261ffff9687166020890152948616948701949094529390911660608501527fffffffff0000000000000000000000000000000000000000000000000000000016608084015290151560a083015273ffffffffffffffffffffffffffffffffffffffff1660c082015260e001610385565b34801561097157600080fd5b506103016109803660046145e1565b611bf0565b34801561099157600080fd5b506103016109a03660046148c4565b611cf2565b3480156109b157600080fd5b506103016109c0366004614913565b611e89565b3480156109d157600080fd5b5061037b6109e0366004614931565b611f4b565b3480156109f157600080fd5b50610301610a003660046146ef565b611f9b565b348015610a1157600080fd5b50610521610a20366004614605565b600260209081526000928352604080842090915290825290205460ff1681565b610301610a4e3660046149af565b612160565b348015610a5f57600080fd5b5061037b600d5481565b806000819003610aa5576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b2257336000908152600260205260408120600191868685818110610ad457610ad4614a94565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610aa8565b507fe8036d6fb143373f3ff63e551373f5fffe4267f6809bf6d3934014a18a9b38f6338484604051610b5693929190614b0e565b60405180910390a1505050565b610b6b61266e565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527fba28eda47a2e15b1dd3269e6d82f66730d20a5661aa40e9faf9f311c7872a54391015b60405180910390a15050565b610c0261266e565b610c0b816126bf565b50565b610c1661266e565b60045474010000000000000000000000000000000000000000900460ff166000816002811115610c4857610c48614631565b03610c7f576040517fccf69db700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002811115610c9357610c93614631565b03610cc157600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556040517f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae390600090a150565b610d1d61266e565b600260045474010000000000000000000000000000000000000000900460ff166002811115610d4e57610d4e614631565b14610d85576040517f045c512200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc906020015b60405180910390a1565b610e1461266e565b6109c48161ffff161115610e54576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000061ffff8416908102919091179091556040519081527fcaba16bb74e50491b14ebf4755083b43aaf56a765134681af613a2ef8d732f4f906020015b60405180910390a150565b610ede61266e565b600480548215157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9091161790556040517fdca612ba3556b7c2603089071be1feb2404df55dcabceee9d5fd852fdb39bc3490610ecb90831515815260200190565b610f6061266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115610f9157610f91614631565b14610fc8576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556040517f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec90600090a1565b600160045474010000000000000000000000000000000000000000900460ff16600281111561106357611063614631565b1461109a576040517f5e4f282600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045473ffffffffffffffffffffffffffffffffffffffff1633146110eb576040517fafdcfb9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633908117909155600480547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556040519081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602001610e02565b8060008190036111ac576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561121c573360009081526001602052604081207f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db918686858181106111fa576111fa614a94565b60209081029290920135835250810191909152604001600020556001016111af565b507f0560c6093fba8a508d0e6ea3b4d7260d7afa9b152731f03a2d05dfe39b0ec425338484604051610b5693929190614b0e565b600b5474010000000000000000000000000000000000000000900460ff166002036112a7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560006112f9610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff1661135b576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061136e61136988614d1b565b61277f565b905061138e848288886113896101208d016101008e016145e1565b612934565b600061139c898933856129ff565b90506113aa83338684612d14565b6113b2612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050565b600061140782612ea1565b604080516020810192909252810184905260600160405160208183030381529060405280519060200120905092915050565b61144161266e565b600c54461461154f57611524604080518082018252600181527f320000000000000000000000000000000000000000000000000000000000000060209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6040517f5b2d1f36cd3ec425baab07b99853532e2ba6387a472ddbff437c5cc96f2f20ca90600090a1565b6040517fa69915e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61158b61266e565b8361ffff168561ffff1611806115a857508461ffff168661ffff16115b806115b857506101f48461ffff16115b156115ef576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff000000000000000000000000000000000000000000000000000000008316611648576040517fc2d0709200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166345b2b3816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190614e57565b6116ed576040517fef8c37d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e080820183526001825261ffff808a1660208085019182528a83168587019081528a8416606087019081527fffffffff000000000000000000000000000000000000000000000000000000008b16608088019081528a151560a0890190815273ffffffffffffffffffffffffffffffffffffffff808c1660c08b0190815260088054600090815260099098529b87209a518b549851965195519451935191519092166c01000000000000000000000000026bffffffffffffffffffffffff9115156b010000000000000000000000027fffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff94909b1c67010000000000000002939093167fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff948a1665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffff968b16630100000002969096167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff97909a16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff931515939093167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009099169890981791909117949094169690961791909117169290921793909317161790915581547f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a292909161191483614ea3565b909155506040805191825261ffff898116602084015288811683830152871660608301527fffffffff000000000000000000000000000000000000000000000000000000008616608083015284151560a083015273ffffffffffffffffffffffffffffffffffffffff841660c0830152519081900360e00190a1505050505050565b61199e61266e565b6108fc8110156119da576040517fad6d14d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527ffc3a20d07f3d5bcc0b01a52011f630765611323fa9afa69f63ba2aa19f7364b690602001610ecb565b611a1761266e565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa92d85531a006d07fd0df4c61259b6dc18e4f492857e2454e5a20ee5e55cddcc90602001610ecb565b60055473ffffffffffffffffffffffffffffffffffffffff163314611adb576040517f9f63004300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612710811115611b17576040517f2242dac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815260066020908152604091829020849055815192835282018390527fa16126d9473196242b0784325b30642b89f34442dd178a852f5b88ee483a30d89101610bee565b611b7d61266e565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa7014d98341b07b23615cb6b4da7cca2a381932b46fb39ca4b8c3875c53aa76490602001610ecb565b611bf861266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115611c2957611c29614631565b14611c60576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffff000000000000000000000000000000000000000000909116811774010000000000000000000000000000000000000000179091556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef9101610ecb565b611cfa61266e565b6008548410611d35576040517fbd7056c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526009602052604090205461ffff6501000000000090910481169082161180611d6957508061ffff168261ffff16115b15611da0576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020908152604091829020805461ffff858116630100000081027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff92891661010081027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff8c15159081167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009097169690961717939093161790935584518981529384019190915282840152606082015290517f3b25bf77fa688236b850bf89c87e353098688237aa18dc42593aff0f6387aea99181900360800190a150505050565b60006080611e98600143614edb565b3360009081526020819052604090208054600190910154914090921c92508415611edb57611ec68383614ef4565b33600090815260208190526040902081905591505b8315611f0357611eeb8382614ef4565b33600090815260208190526040902060010181905590505b60408051338152602081018490529081018290527fb738dd6073fae1a7128e3fcc6b4ca6e1356b7232f87cc98f8a2857bcd83dfc449060600160405180910390a15050505050565b6000333014611f86576040517fa78d09b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f92858585856129ff565b95945050505050565b600b5474010000000000000000000000000000000000000000900460ff16600203611ff2576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556000612044610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff161580612090575073ffffffffffffffffffffffffffffffffffffffff8116155b156120c7576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120db610120880161010089016145e1565b905060006120eb61136989614d1b565b90506120fa8582898986612934565b60006121078a8a846130b3565b905061211584848784612d14565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b600b5474010000000000000000000000000000000000000000900460ff166002036121b7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790558880158061220d5750878118868218178482181715155b15612244576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008989600081811061225957612259614a94565b905060200281019061226b9190614f07565b61227d9061010081019060e0016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff166122df576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156124555760005b8381101561244f57368c8c8381811061230557612305614a94565b90506020028101906123179190614f07565b905081156123945773ffffffffffffffffffffffffffffffffffffffff8416612347610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612394576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f848181106123a7576123a7614a94565b90506020028101906123b99190614f45565b905060006123c961136984614d1b565b90506124298b8b868181106123e0576123e0614a94565b90506020028101906123f29190614f45565b828f8f8881811061240557612405614a94565b90506020028101906124179190614f79565b61138961012089016101008a016145e1565b612435828433846129ff565b61243f9086614ef4565b94508360010193505050506122ea565b5061260c565b60005b8381101561260a57368c8c8381811061247357612473614a94565b90506020028101906124859190614f07565b905081156125025773ffffffffffffffffffffffffffffffffffffffff84166124b5610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612502576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f8481811061251557612515614a94565b90506020028101906125279190614f45565b9050600061253761136984614d1b565b905061254e8b8b868181106123e0576123e0614a94565b6040517fd5b7f065000000000000000000000000000000000000000000000000000000008152309063d5b7f065906125909085908790339087906004016152be565b6020604051808303816000875af19250505080156125e9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e69181019061530d565b60015b156125fc576125f88187614ef4565b9550505b836001019350505050612458565b505b61261882338784612d14565b50612621612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611581576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661270c576040517ff966bcb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb1090602001610ecb565b60007e3c1bce41a2de73dfe64d6eeb2b3d7f15f1c0c382d9d963c2c6daeb75f0e539826000015183602001518460400151856060015186608001518760a001518860c001518960e001516040516020016127e199989796959493929190615326565b60405160208183030381529060405282610100015183610120015184610140015185610160015186610180015160405160200161281e9190615396565b60405160208183030381529060405280519060200120876101a0015160405160200161284a9190615396565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101c08c015180519083012073ffffffffffffffffffffffffffffffffffffffff90991691840191909152908201959095526060810193909352608083019190915260a082015260c081019190915260e081019190915261010001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261291792916020016153fc565b604051602081830303815290604052805190602001209050919050565b60006129436020870187615411565b91505080156129eb57600a81111561298f576040517febbd838a000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6129a761299f6020880188615411565b88358861330b565b6129dd576040517fc8ac23c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129e88635826113fc565b94505b6129f785858585613323565b505050505050565b60006001612a106020860186615479565b6001811115612a2157612a21614631565b14612a58576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a6c610120860161010087016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020818152604080842060608c013585528252808420549484528382529092200154929350909190870135141580612af5575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832089820135845290915290205460ff165b80612b0a57508015801590612b0a5750838114155b15612b41576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000806000806000612b558b8b336133c3565b94509450945094509450612b6f81878c606001358b6137d2565b612b8b8383612b856101008e0160e08f016145e1565b8c61383a565b612c16612b9e60e08c0160c08d016145e1565b612bae60c08d0160a08e01615479565b88600073ffffffffffffffffffffffffffffffffffffffff168f6000016020810190612bda91906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612c0d578e6000016020810190612c0891906145e1565b612c0f565b8c5b898961386e565b7f3ee3de4684413690dee6fff1a0a4f92916a1b97d1c5a83cdf24671844306b2e360405180606001604052808a81526020018c6060013581526020018315158152508a600073ffffffffffffffffffffffffffffffffffffffff168e6000016020810190612c8491906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612cb157612cac60208f018f6145e1565b612cb3565b8b5b8d608001358e60e0016020810190612ccb91906145e1565b8f60c0016020810190612cde91906145e1565b8b8b8b8b604051612cf89a9998979695949392919061552d565b60405180910390a150604001519450505050505b949350505050565b8015612e6d5773ffffffffffffffffffffffffffffffffffffffff821615612e46576004547501000000000000000000000000000000000000000000900460ff1615612e465773ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604081205461271090612d8e9084615624565b612d98919061563b565b90508015612e4457612daa8183614edb565b91508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612deb57612deb85858584613a05565b6040805173ffffffffffffffffffffffffffffffffffffffff8086168252871660208201529081018290527f49e92b6b3114f7e128555cd58c568f7c2e0e56fe9b4c46b6125bc308184623b39060600160405180910390a15b505b600a54612e6d908590859073ffffffffffffffffffffffffffffffffffffffff1684613a05565b50505050565b476001811115610c0b5760008060008060018503335af180612e9d576307246cf46000526004601cfd5b5050565b600081600103612ed257507f9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643919050565b81600203612f0157507fa54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08919050565b81600303612f3057507f93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49919050565b81600403612f5f57507f9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b919050565b81600503612f8e57507f92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98919050565b81600603612fbd57507fce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8919050565b81600703612fec57507ff7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559919050565b8160080361301b57507fdef24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6919050565b8160090361304a57507f4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2919050565b81600a0361307957507ff8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db919050565b6040517febbd838a00000000000000000000000000000000000000000000000000000000815260048101839052602401612986565b919050565b6000806130c36020850185615479565b60018111156130d4576130d4614631565b1461310b576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061311f610120850161010086016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020908152604080832060608a01358452825280832054938352828252909120549293509091908601351415806131a7575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832088820135845290915290205460ff165b806131bc575080158015906131bc5750838114155b156131f3576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008060008060006132078a8a336133c3565b9450945094509450945061322181878b606001358b6137d2565b61324d61323460e08b0160c08c016145e1565b61324460c08c0160a08d01615479565b3389898961386e565b61326983836132636101008d0160e08e016145e1565b8961383a565b7f9aaa45d6db2ef74ead0751ea9113263d1dec1b50cea05f0ca2002cb8063564a460405180606001604052808a81526020018b60600135815260200183151581525033888c608001358d60e00160208101906132c591906145e1565b8e60c00160208101906132d891906145e1565b8b8b8b8b6040516132f29a9998979695949392919061552d565b60405180910390a1506040015198975050505050505050565b600082613319868685613a5a565b1495945050505050565b46600c540361339157600d546040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810185905261338c9060620160405160208183030381529060405280519060200120828585613b25565b612e6d565b6040517f6fd794c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060806133ce614498565b6133d66144b6565b6000806133ed886101200135896101400135613ca5565b87608001356000036134bf5761341d61340a6101a08a018a615676565b6134186101808c018c615676565b613cbf565b6101608801356134316101808a018a615676565b61343f6101a08c018c615676565b8383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080870282810182019093528682529498509596509394938693869350839250850190849080828437600092019190915250959c50919a50600197509495506136f3945050505050565b608088013560009081526009602052604090205460ff16156136bb5760006134ea60208a018a615479565b60808a01356000908152600960205260409020549091506b010000000000000000000000900460ff168082036135285763ab9848466000526004601cfd5b600080600960008d608001358152602001908152602001600020600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600960008e60800135815260200190815260200160002060000160079054906101000a900460e01b8e8e6040516024016135b79291906156de565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516136409190615703565b6000604051808303816000865af19150503d806000811461367d576040519150601f19603f3d011682016040523d82523d6000602084013e613682565b606091505b50915091508161369457805160208201fd5b808060200190518101906136a8919061576a565b919c509a50965094506136f39350505050565b6040517fd73c2c6a00000000000000000000000000000000000000000000000000000000815260808901356004820152602401612986565b61370d61370660e08a0160c08b016145e1565b8288613d0d565b60208581019190915273ffffffffffffffffffffffffffffffffffffffff9190911681860152600090613742908a018a615479565b600181111561375357613753614631565b036137ab576137a6608089013582600061377060208e018e6145e1565b73ffffffffffffffffffffffffffffffffffffffff161461379d5761379860208d018d6145e1565b61379f565b895b8688613e67565b6137c6565b6137c660808901358261379f6101208c016101008d016145e1565b50939792965093509350565b836137dd57806137ff565b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db5b73ffffffffffffffffffffffffffffffffffffffff909316600090815260016020908152604080832094835293905291909120919091555050565b825180156138565761385683838760005b602002015184613a05565b602084015180156129f7576129f7848488600161384b565b600085600181111561388257613882614631565b03613938576040517fa7bc96d300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a7bc96d39061390190899088908890889088906004016157ea565b600060405180830381600087803b15801561391b57600080fd5b505af115801561392f573d6000803e3d6000fd5b505050506129f7565b600185600181111561394c5761394c614631565b036129f7576040517fa0a406c600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063a0a406c6906139cb90899088908890889088906004016157ea565b600060405180830381600087803b1580156139e557600080fd5b505af11580156139f9573d6000803e3d6000fd5b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416613a4e5761338c7f00000000000000000000000000000000000000000000000000000000000000008383600e54613f17565b612e6d8484848461402c565b60008183825b81811015613b1a576000878783818110613a7c57613a7c614a94565b9050604002016020016020810190613a949190615479565b6001811115613aa557613aa5614631565b03613ae057613ad9878783818110613abf57613abf614a94565b905060400201600001358460009182526020526040902090565b9250613b12565b613b0f83888884818110613af657613af6614a94565b9050604002016000013560009182526020526040902090565b92505b600101613a60565b509095945050505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003613bb3578273ffffffffffffffffffffffffffffffffffffffff16613b66858484614207565b73ffffffffffffffffffffffffffffffffffffffff1614612e6d576040517fd1085d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff851690631626ba7e90613c0b90889087908790600401615849565b602060405180830381865afa158015613c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4c9190615863565b7fffffffff000000000000000000000000000000000000000000000000000000001614612e6d576040517ff6cd0e2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4281104283111715612e9d57637476320f6000526004601cfd5b6000838280821882151715613cdc57632e0c0f716000526004601cfd5b5060051b9050845b81156129f7576020820391508181013580613d0757632e0c0f716000526004601cfd5b50613ce4565b600b54600090819073ffffffffffffffffffffffffffffffffffffffff1615613e5f57600b546040517f70c1092100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906370c1092190613d8a90889088908890600401615880565b6040805180830381865afa158015613da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dca91906158b5565b909250905073ffffffffffffffffffffffffffffffffffffffff8216613df257506000613e5f565b600a54613e1b9074010000000000000000000000000000000000000000900461ffff1685615624565b613e2761271083615624565b1115613e5f576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60008581526009602052604081205461271090613e8f906301000000900461ffff1687615624565b613e99919061563b565b6020840151909150600003613ec05760408301819052613eb98186614edb565b8352613ef6565b613ed385878560016020020151846142f4565b604084018190526020840151613ee99087614edb565b613ef39190614edb565b83525b5073ffffffffffffffffffffffffffffffffffffffff909216909152505050565b6000806000806000868887f1905080614025578473ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f7257600080fd5b505af1158015613f86573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018890528916935063a9059cbb925060440190506020604051808303816000875af1158015614001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f79190614e57565b5050505050565b8373ffffffffffffffffffffffffffffffffffffffff163b60000361407d576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff84811660248301528381166044830152606482018390526000918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052516141389190615703565b6000604051808303816000865af19150503d8060008114614175576040519150601f19603f3d011682016040523d82523d6000602084013e61417a565b606091505b5091509150816141b6576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051156129f757808060200190518101906141d19190614e57565b6129f7576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806142178686614341565b6040805160008152602081018083528c905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015614272573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff84166142ea576040517ff05a20c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050509392505050565b6000838152600960205260408120546127109061431a90610100900461ffff1687615624565b614324919061563b565b9050816143318483614ef4565b1015612d0c57611f928383614edb565b60008080836041819003614369578535935060208601359250604086013560001a91506143e2565b806040036143ad57853593507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6020870135908116935060ff1c601b0191506143e2565b6040517fd42b4bbd00000000000000000000000000000000000000000000000000000000815260048101829052602401612986565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561443c576040517fc185125200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff16601b1415801561445457508160ff16601c14155b15614490576040517f417893a400000000000000000000000000000000000000000000000000000000815260ff83166004820152602401612986565b509250925092565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60008083601f8401126144e657600080fd5b50813567ffffffffffffffff8111156144fe57600080fd5b6020830191508360208260051b850101111561451957600080fd5b9250929050565b6000806020838503121561453357600080fd5b823567ffffffffffffffff81111561454a57600080fd5b614556858286016144d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c0b57600080fd5b80356130ae81614562565b8015158114610c0b57600080fd5b80356130ae8161458f565b600080604083850312156145bb57600080fd5b82356145c681614562565b915060208301356145d68161458f565b809150509250929050565b6000602082840312156145f357600080fd5b81356145fe81614562565b9392505050565b6000806040838503121561461857600080fd5b823561462381614562565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061467457614674614631565b91905290565b803561ffff811681146130ae57600080fd5b60006020828403121561469e57600080fd5b6145fe8261467a565b6000602082840312156146b957600080fd5b81356145fe8161458f565b6000604082840312156146d657600080fd5b50919050565b60006101e082840312156146d657600080fd5b60008060008060008060a0878903121561470857600080fd5b863567ffffffffffffffff8082111561472057600080fd5b61472c8a838b016146c4565b9750602089013591508082111561474257600080fd5b61474e8a838b016146dc565b9650604089013591508082111561476457600080fd5b818901915089601f83011261477857600080fd5b81358181111561478757600080fd5b8a602082850101111561479957600080fd5b6020830196508095505060608901359150808211156147b757600080fd5b506147c489828a016146c4565b9250506147d360808801614584565b90509295509295509295565b600080604083850312156147f257600080fd5b50508035926020909101359150565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610c0b57600080fd5b60008060008060008060c0878903121561484857600080fd5b6148518761467a565b955061485f6020880161467a565b945061486d6040880161467a565b9350606087013561487d81614801565b9250608087013561488d8161458f565b915060a087013561489d81614562565b809150509295509295509295565b6000602082840312156148bd57600080fd5b5035919050565b600080600080608085870312156148da57600080fd5b8435935060208501356148ec8161458f565b92506148fa6040860161467a565b91506149086060860161467a565b905092959194509250565b6000806040838503121561492657600080fd5b82356145c68161458f565b6000806000806080858703121561494757600080fd5b843567ffffffffffffffff8082111561495f57600080fd5b61496b888389016146c4565b9550602087013591508082111561498157600080fd5b5061498e878288016146dc565b935050604085013561499f81614562565b9396929550929360600135925050565b60008060008060008060008060008060c08b8d0312156149ce57600080fd5b8a3567ffffffffffffffff808211156149e657600080fd5b6149f28e838f016144d4565b909c509a5060208d0135915080821115614a0b57600080fd5b614a178e838f016144d4565b909a50985060408d0135915080821115614a3057600080fd5b614a3c8e838f016144d4565b909850965060608d0135915080821115614a5557600080fd5b50614a628d828e016144d4565b9095509350614a75905060808c01614584565b9150614a8360a08c0161459d565b90509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614af557600080fd5b8260051b80836020870137939093016020019392505050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611f92604083018486614ac3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715614b9157614b91614b3e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614bde57614bde614b3e565b604052919050565b60028110610c0b57600080fd5b80356130ae81614be6565b600067ffffffffffffffff821115614c1857614c18614b3e565b5060051b60200190565b600082601f830112614c3357600080fd5b81356020614c48614c4383614bfe565b614b97565b82815260059290921b84018101918181019086841115614c6757600080fd5b8286015b84811015614c825780358352918301918301614c6b565b509695505050505050565b600082601f830112614c9e57600080fd5b813567ffffffffffffffff811115614cb857614cb8614b3e565b614ce960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b97565b818152846020838601011115614cfe57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101e08236031215614d2e57600080fd5b614d36614b6d565b614d3f83614bf3565b815260208301356020820152604083013560408201526060830135606082015260808301356080820152614d7560a08401614bf3565b60a0820152614d8660c08401614584565b60c0820152614d9760e08401614584565b60e0820152610100614daa818501614584565b908201526101208381013590820152610140808401359082015261016080840135908201526101808084013567ffffffffffffffff80821115614dec57600080fd5b614df836838801614c22565b838501526101a0925082860135915080821115614e1457600080fd5b614e2036838801614c22565b838501526101c0925082860135915080821115614e3c57600080fd5b50614e4936828701614c8d565b918301919091525092915050565b600060208284031215614e6957600080fd5b81516145fe8161458f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ed457614ed4614e74565b5060010190565b81810381811115614eee57614eee614e74565b92915050565b80820180821115614eee57614eee614e74565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe21833603018112614f3b57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614f3b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614fae57600080fd5b83018035915067ffffffffffffffff821115614fc957600080fd5b60200191503681900382131561451957600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261501357600080fd5b830160208101925035905067ffffffffffffffff81111561503357600080fd5b80360382131561451957600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000813561509881614562565b73ffffffffffffffffffffffffffffffffffffffff1683526150bd6020830183614fde565b60406020860152611f92604086018284615042565b60028110610c0b57610c0b614631565b6150eb816150d2565b9052565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261512457600080fd5b830160208101925035905067ffffffffffffffff81111561514457600080fd5b8060051b360382131561451957600080fd5b60006101e061516d8461516885614bf3565b6150e2565b602083013560208501526040830135604085015260608301356060850152608083013560808501526151a160a08401614bf3565b6151ae60a08601826150e2565b506151bb60c08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660c08501526151e260e08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660e085015261010061520b848201614584565b73ffffffffffffffffffffffffffffffffffffffff1690850152610120838101359085015261014080840135908501526101608084013590850152610180615255818501856150ef565b83838801526152678488018284614ac3565b93505050506101a061527b818501856150ef565b8684038388015261528d848284614ac3565b93505050506101c06152a181850185614fde565b868403838801526152b3848284615042565b979650505050505050565b6080815260006152d1608083018761508b565b82810360208401526152e38187615156565b73ffffffffffffffffffffffffffffffffffffffff95909516604084015250506060015292915050565b60006020828403121561531f57600080fd5b5051919050565b89815261012081016153378a6150d2565b8960208301528860408301528760608301528660808301528560a083015261535e856150d2565b60c082019490945273ffffffffffffffffffffffffffffffffffffffff92831660e08201529116610100909101529695505050505050565b815160009082906020808601845b838110156153c0578151855293820193908201906001016153a4565b50929695505050505050565b6000815160005b818110156153ed57602081850181015186830152016153d3565b50600093019283525090919050565b6000612d0c61540b83866153cc565b846153cc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261544657600080fd5b83018035915067ffffffffffffffff82111561546157600080fd5b6020019150600681901b360382131561451957600080fd5b60006020828403121561548b57600080fd5b81356145fe81614be6565b600081518084526020808501945080840160005b838110156154c6578151875295820195908201906001016154aa565b509495945050505050565b8060005b6002811015612e6d57815173ffffffffffffffffffffffffffffffffffffffff168452602093840193909101906001016154d5565b8060005b6003811015612e6d57815184526020938401939091019060010161550e565b60006101e08c51835260208d0151602084015260408d01511515604084015261556e606084018d73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff8b1660808401528960a08401526155b260c084018a73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff881660e0840152806101008401526155e181840188615496565b90508281036101208401526155f68187615496565b9150506156076101408301856154d1565b61561561018083018461550a565b9b9a5050505050505050505050565b8082028115828204841417614eee57614eee614e74565b600082615671577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126156ab57600080fd5b83018035915067ffffffffffffffff8211156156c657600080fd5b6020019150600581901b360382131561451957600080fd5b6040815260006156f1604083018561508b565b8281036020840152611f928185615156565b60006145fe82846153cc565b600082601f83011261572057600080fd5b81516020615730614c4383614bfe565b82815260059290921b8401810191818101908684111561574f57600080fd5b8286015b84811015614c825780518352918301918301615753565b6000806000806080858703121561578057600080fd5b84519350602085015167ffffffffffffffff8082111561579f57600080fd5b6157ab8883890161570f565b945060408701519150808211156157c157600080fd5b506157ce8782880161570f565b92505060608501516157df8161458f565b939692955090935050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060a0606083015261582b60a0830185615496565b828103608084015261583d8185615496565b98975050505050505050565b838152604060208201526000611f92604083018486615042565b60006020828403121561587557600080fd5b81516145fe81614801565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611f926060830184615496565b600080604083850312156158c857600080fd5b82516158d381614562565b602093909301519294929350505056fea2646970667358221220fda1aa391f9a90a5fa9e8cc21d3b32dd6362514c3103bfd1a99529e079bcb58264736f6c634300081100330000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x6080604052600436106102dc5760003560e01c8063838b8f5c11610184578063ae1cce5a116100d6578063d5b010f51161008a578063ea179b7611610064578063ea179b7614610a05578063f4288a2114610a40578063f698da2514610a5357600080fd5b8063d5b010f5146109a5578063d5b7f065146109c5578063e72853e1146109e557600080fd5b8063bb91c339116100bb578063bb91c33914610850578063c0b6f56114610965578063d5a06adf1461098557600080fd5b8063ae1cce5a14610810578063b647a4041461083057600080fd5b806391be136011610138578063a02bab5711610112578063a02bab5714610773578063a39bf29f14610793578063ad5c4648146107dc57600080fd5b806391be13601461071d578063974e7c9f1461073d5780639a8a05921461075d57600080fd5b806386c076421161016957806386c07642146106bb57806389ccfe89146106db5780638da5cb5b146106f057600080fd5b8063838b8f5c1461067b5780638585ae03146106a857600080fd5b80634cbac9dc1161023d57806367d9dd79116101f15780637762df25116101cb5780637762df251461060157806379ed31d41461062e5780637a7d88511461064e57600080fd5b806367d9dd79146105735780636e90c014146105a65780637200b829146105ec57600080fd5b80635a195d19116102225780635a195d19146104f15780635b6ac0111461053157806364df049e1461054657600080fd5b80634cbac9dc146104a457806354878876146104d157600080fd5b80632bb5a9e611610294578063463357ec11610279578063463357ec146103f757806346b625bc1461042b57806346ea25521461044b57600080fd5b80632bb5a9e6146103a35780633e567539146103e257600080fd5b80631df47f80116102c55780631df47f801461032357806320cd05c71461034357806323452b9c1461038e57600080fd5b8063134849a6146102e15780631d3c426814610303575b600080fd5b3480156102ed57600080fd5b506103016102fc366004614520565b610a69565b005b34801561030f57600080fd5b5061030161031e3660046145a8565b610b63565b34801561032f57600080fd5b5061030161033e3660046145e1565b610bfa565b34801561034f57600080fd5b5061037b61035e366004614605565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561039a57600080fd5b50610301610c0e565b3480156103af57600080fd5b506004546103d59074010000000000000000000000000000000000000000900460ff1681565b6040516103859190614660565b3480156103ee57600080fd5b50610301610d15565b34801561040357600080fd5b5061037b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db81565b34801561043757600080fd5b5061030161044636600461468c565b610e0c565b34801561045757600080fd5b5061047f7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610385565b3480156104b057600080fd5b5060055461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104dd57600080fd5b506103016104ec3660046146a7565b610ed6565b3480156104fd57600080fd5b5061052161050c3660046145e1565b60076020526000908152604090205460ff1681565b6040519015158152602001610385565b34801561053d57600080fd5b50610301610f58565b34801561055257600080fd5b50600a5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561057f57600080fd5b50600454610521907501000000000000000000000000000000000000000000900460ff1681565b3480156105b257600080fd5b50600a546105d99074010000000000000000000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610385565b3480156105f857600080fd5b50610301611032565b34801561060d57600080fd5b5060045461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561063a57600080fd5b50610301610649366004614520565b611170565b34801561065a57600080fd5b5061037b6106693660046145e1565b60066020526000908152604090205481565b34801561068757600080fd5b50600b5461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b6103016106b63660046146ef565b611250565b3480156106c757600080fd5b5061037b6106d63660046147df565b6113fc565b3480156106e757600080fd5b50610301611439565b3480156106fc57600080fd5b5060035461047f9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561072957600080fd5b5061030161073836600461482f565b611583565b34801561074957600080fd5b506103016107583660046148ab565b611996565b34801561076957600080fd5b5061037b600c5481565b34801561077f57600080fd5b5061030161078e3660046145e1565b611a0f565b34801561079f57600080fd5b506107c76107ae3660046145e1565b6000602081905290815260409020805460019091015482565b60408051928352602083019190915201610385565b3480156107e857600080fd5b5061047f7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561081c57600080fd5b5061030161082b366004614605565b611a8a565b34801561083c57600080fd5b5061030161084b3660046145e1565b611b75565b34801561085c57600080fd5b506108ec61086b3660046148ab565b60096020526000908152604090205460ff8082169161ffff61010082048116926301000000830482169265010000000000810490921691670100000000000000810460e01b916b0100000000000000000000008204169073ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009091041687565b60408051971515885261ffff9687166020890152948616948701949094529390911660608501527fffffffff0000000000000000000000000000000000000000000000000000000016608084015290151560a083015273ffffffffffffffffffffffffffffffffffffffff1660c082015260e001610385565b34801561097157600080fd5b506103016109803660046145e1565b611bf0565b34801561099157600080fd5b506103016109a03660046148c4565b611cf2565b3480156109b157600080fd5b506103016109c0366004614913565b611e89565b3480156109d157600080fd5b5061037b6109e0366004614931565b611f4b565b3480156109f157600080fd5b50610301610a003660046146ef565b611f9b565b348015610a1157600080fd5b50610521610a20366004614605565b600260209081526000928352604080842090915290825290205460ff1681565b610301610a4e3660046149af565b612160565b348015610a5f57600080fd5b5061037b600d5481565b806000819003610aa5576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610b2257336000908152600260205260408120600191868685818110610ad457610ad4614a94565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610aa8565b507fe8036d6fb143373f3ff63e551373f5fffe4267f6809bf6d3934014a18a9b38f6338484604051610b5693929190614b0e565b60405180910390a1505050565b610b6b61266e565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168515159081179091558251938452908301527fba28eda47a2e15b1dd3269e6d82f66730d20a5661aa40e9faf9f311c7872a54391015b60405180910390a15050565b610c0261266e565b610c0b816126bf565b50565b610c1661266e565b60045474010000000000000000000000000000000000000000900460ff166000816002811115610c4857610c48614631565b03610c7f576040517fccf69db700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001816002811115610c9357610c93614631565b03610cc157600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556040517f8eca980489e87f7dba4f26917aa4bfc906eb3f2b4f7b4b9fd0ff2b8bb3e21ae390600090a150565b610d1d61266e565b600260045474010000000000000000000000000000000000000000900460ff166002811115610d4e57610d4e614631565b14610d85576040517f045c512200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055604051600081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc906020015b60405180910390a1565b610e1461266e565b6109c48161ffff161115610e54576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000061ffff8416908102919091179091556040519081527fcaba16bb74e50491b14ebf4755083b43aaf56a765134681af613a2ef8d732f4f906020015b60405180910390a150565b610ede61266e565b600480548215157501000000000000000000000000000000000000000000027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff9091161790556040517fdca612ba3556b7c2603089071be1feb2404df55dcabceee9d5fd852fdb39bc3490610ecb90831515815260200190565b610f6061266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115610f9157610f91614631565b14610fc8576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556040517f3ff05a45e46337fa1cbf20996d2eeb927280bce099f37252bcca1040609604ec90600090a1565b600160045474010000000000000000000000000000000000000000900460ff16600281111561106357611063614631565b1461109a576040517f5e4f282600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60045473ffffffffffffffffffffffffffffffffffffffff1633146110eb576040517fafdcfb9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633908117909155600480547fffffffffffffffffffffff0000000000000000000000000000000000000000001690556040519081527f3edd90e7770f06fafde38004653b33870066c33bfc923ff6102acd601f85dfbc90602001610e02565b8060008190036111ac576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561121c573360009081526001602052604081207f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db918686858181106111fa576111fa614a94565b60209081029290920135835250810191909152604001600020556001016111af565b507f0560c6093fba8a508d0e6ea3b4d7260d7afa9b152731f03a2d05dfe39b0ec425338484604051610b5693929190614b0e565b600b5474010000000000000000000000000000000000000000900460ff166002036112a7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560006112f9610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff1661135b576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061136e61136988614d1b565b61277f565b905061138e848288886113896101208d016101008e016145e1565b612934565b600061139c898933856129ff565b90506113aa83338684612d14565b6113b2612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050565b600061140782612ea1565b604080516020810192909252810184905260600160405160208183030381529060405280519060200120905092915050565b61144161266e565b600c54461461154f57611524604080518082018252600181527f320000000000000000000000000000000000000000000000000000000000000060209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818301527f9e6bc51ef68b436657c5fe7a273ea9121a02b234cc81ad1e04892649c9168c6a818401527fad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5606082015246608082018190523060a0808401919091528451808403909101815260c09092019093528051910120600d55600c55565b6040517f5b2d1f36cd3ec425baab07b99853532e2ba6387a472ddbff437c5cc96f2f20ca90600090a1565b6040517fa69915e500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b61158b61266e565b8361ffff168561ffff1611806115a857508461ffff168661ffff16115b806115b857506101f48461ffff16115b156115ef576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffff000000000000000000000000000000000000000000000000000000008316611648576040517fc2d0709200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166345b2b3816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b79190614e57565b6116ed576040517fef8c37d700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e080820183526001825261ffff808a1660208085019182528a83168587019081528a8416606087019081527fffffffff000000000000000000000000000000000000000000000000000000008b16608088019081528a151560a0890190815273ffffffffffffffffffffffffffffffffffffffff808c1660c08b0190815260088054600090815260099098529b87209a518b549851965195519451935191519092166c01000000000000000000000000026bffffffffffffffffffffffff9115156b010000000000000000000000027fffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff94909b1c67010000000000000002939093167fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff948a1665010000000000027fffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffff968b16630100000002969096167fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff97909a16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff931515939093167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009099169890981791909117949094169690961791909117169290921793909317161790915581547f5290475107686ff8d28cd104943b127d453b23622ac55346373fa25c0c8957a292909161191483614ea3565b909155506040805191825261ffff898116602084015288811683830152871660608301527fffffffff000000000000000000000000000000000000000000000000000000008616608083015284151560a083015273ffffffffffffffffffffffffffffffffffffffff841660c0830152519081900360e00190a1505050505050565b61199e61266e565b6108fc8110156119da576040517fad6d14d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600e8190556040518181527ffc3a20d07f3d5bcc0b01a52011f630765611323fa9afa69f63ba2aa19f7364b690602001610ecb565b611a1761266e565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa92d85531a006d07fd0df4c61259b6dc18e4f492857e2454e5a20ee5e55cddcc90602001610ecb565b60055473ffffffffffffffffffffffffffffffffffffffff163314611adb576040517f9f63004300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612710811115611b17576040517f2242dac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600081815260066020908152604091829020849055815192835282018390527fa16126d9473196242b0784325b30642b89f34442dd178a852f5b88ee483a30d89101610bee565b611b7d61266e565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa7014d98341b07b23615cb6b4da7cca2a381932b46fb39ca4b8c3875c53aa76490602001610ecb565b611bf861266e565b600060045474010000000000000000000000000000000000000000900460ff166002811115611c2957611c29614631565b14611c60576040517f74ed79ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffff000000000000000000000000000000000000000000909116811774010000000000000000000000000000000000000000179091556040805133815260208101929092527fb86c75c9bffca616b2d314cc914f7c3f1d174255b16b941c3f3ededee276d5ef9101610ecb565b611cfa61266e565b6008548410611d35576040517fbd7056c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008481526009602052604090205461ffff6501000000000090910481169082161180611d6957508061ffff168261ffff16115b15611da0576040517fb704b7c100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600084815260096020908152604091829020805461ffff858116630100000081027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffff92891661010081027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ff8c15159081167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000009097169690961717939093161790935584518981529384019190915282840152606082015290517f3b25bf77fa688236b850bf89c87e353098688237aa18dc42593aff0f6387aea99181900360800190a150505050565b60006080611e98600143614edb565b3360009081526020819052604090208054600190910154914090921c92508415611edb57611ec68383614ef4565b33600090815260208190526040902081905591505b8315611f0357611eeb8382614ef4565b33600090815260208190526040902060010181905590505b60408051338152602081018490529081018290527fb738dd6073fae1a7128e3fcc6b4ca6e1356b7232f87cc98f8a2857bcd83dfc449060600160405180910390a15050505050565b6000333014611f86576040517fa78d09b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611f92858585856129ff565b95945050505050565b600b5474010000000000000000000000000000000000000000900460ff16600203611ff2576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790556000612044610100870160e088016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff161580612090575073ffffffffffffffffffffffffffffffffffffffff8116155b156120c7576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006120db610120880161010089016145e1565b905060006120eb61136989614d1b565b90506120fa8582898986612934565b60006121078a8a846130b3565b905061211584848784612d14565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555050505050505050565b600b5474010000000000000000000000000000000000000000900460ff166002036121b7576040517f1bbee72600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740200000000000000000000000000000000000000001790558880158061220d5750878118868218178482181715155b15612244576040517f97983bdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008989600081811061225957612259614a94565b905060200281019061226b9190614f07565b61227d9061010081019060e0016145e1565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205490915060ff166122df576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083156124555760005b8381101561244f57368c8c8381811061230557612305614a94565b90506020028101906123179190614f07565b905081156123945773ffffffffffffffffffffffffffffffffffffffff8416612347610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612394576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f848181106123a7576123a7614a94565b90506020028101906123b99190614f45565b905060006123c961136984614d1b565b90506124298b8b868181106123e0576123e0614a94565b90506020028101906123f29190614f45565b828f8f8881811061240557612405614a94565b90506020028101906124179190614f79565b61138961012089016101008a016145e1565b612435828433846129ff565b61243f9086614ef4565b94508360010193505050506122ea565b5061260c565b60005b8381101561260a57368c8c8381811061247357612473614a94565b90506020028101906124859190614f07565b905081156125025773ffffffffffffffffffffffffffffffffffffffff84166124b5610100830160e084016145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612502576040517f4f79548700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b368f8f8481811061251557612515614a94565b90506020028101906125279190614f45565b9050600061253761136984614d1b565b905061254e8b8b868181106123e0576123e0614a94565b6040517fd5b7f065000000000000000000000000000000000000000000000000000000008152309063d5b7f065906125909085908790339087906004016152be565b6020604051808303816000875af19250505080156125e9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526125e69181019061530d565b60015b156125fc576125f88187614ef4565b9550505b836001019350505050612458565b505b61261882338784612d14565b50612621612e73565b5050600b80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905550505050505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611581576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661270c576040517ff966bcb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f8cffb07faa2874440346743bdc0a86b06c3335cc47dc49b327d10e77b73ceb1090602001610ecb565b60007e3c1bce41a2de73dfe64d6eeb2b3d7f15f1c0c382d9d963c2c6daeb75f0e539826000015183602001518460400151856060015186608001518760a001518860c001518960e001516040516020016127e199989796959493929190615326565b60405160208183030381529060405282610100015183610120015184610140015185610160015186610180015160405160200161281e9190615396565b60405160208183030381529060405280519060200120876101a0015160405160200161284a9190615396565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201206101c08c015180519083012073ffffffffffffffffffffffffffffffffffffffff90991691840191909152908201959095526060810193909352608083019190915260a082015260c081019190915260e081019190915261010001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261291792916020016153fc565b604051602081830303815290604052805190602001209050919050565b60006129436020870187615411565b91505080156129eb57600a81111561298f576040517febbd838a000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6129a761299f6020880188615411565b88358861330b565b6129dd576040517fc8ac23c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6129e88635826113fc565b94505b6129f785858585613323565b505050505050565b60006001612a106020860186615479565b6001811115612a2157612a21614631565b14612a58576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612a6c610120860161010087016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020818152604080842060608c013585528252808420549484528382529092200154929350909190870135141580612af5575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832089820135845290915290205460ff165b80612b0a57508015801590612b0a5750838114155b15612b41576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b506000806000806000612b558b8b336133c3565b94509450945094509450612b6f81878c606001358b6137d2565b612b8b8383612b856101008e0160e08f016145e1565b8c61383a565b612c16612b9e60e08c0160c08d016145e1565b612bae60c08d0160a08e01615479565b88600073ffffffffffffffffffffffffffffffffffffffff168f6000016020810190612bda91906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612c0d578e6000016020810190612c0891906145e1565b612c0f565b8c5b898961386e565b7f3ee3de4684413690dee6fff1a0a4f92916a1b97d1c5a83cdf24671844306b2e360405180606001604052808a81526020018c6060013581526020018315158152508a600073ffffffffffffffffffffffffffffffffffffffff168e6000016020810190612c8491906145e1565b73ffffffffffffffffffffffffffffffffffffffff1614612cb157612cac60208f018f6145e1565b612cb3565b8b5b8d608001358e60e0016020810190612ccb91906145e1565b8f60c0016020810190612cde91906145e1565b8b8b8b8b604051612cf89a9998979695949392919061552d565b60405180910390a150604001519450505050505b949350505050565b8015612e6d5773ffffffffffffffffffffffffffffffffffffffff821615612e46576004547501000000000000000000000000000000000000000000900460ff1615612e465773ffffffffffffffffffffffffffffffffffffffff821660009081526006602052604081205461271090612d8e9084615624565b612d98919061563b565b90508015612e4457612daa8183614edb565b91508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614612deb57612deb85858584613a05565b6040805173ffffffffffffffffffffffffffffffffffffffff8086168252871660208201529081018290527f49e92b6b3114f7e128555cd58c568f7c2e0e56fe9b4c46b6125bc308184623b39060600160405180910390a15b505b600a54612e6d908590859073ffffffffffffffffffffffffffffffffffffffff1684613a05565b50505050565b476001811115610c0b5760008060008060018503335af180612e9d576307246cf46000526004601cfd5b5050565b600081600103612ed257507f9661287f7a4aa4867db46a2453ee15bebac4e8fc25667a58718da658f15de643919050565b81600203612f0157507fa54ab330ea9e1dfccee2b86f3666989e7fbd479704416c757c8de8e820142a08919050565b81600303612f3057507f93390f5d45ede9dea305f16aec86b2472af4f823851637f1b7019ad0775cea49919050565b81600403612f5f57507f9dda2c8358da895e43d574bb15954ce5727b22e923a2d8f28261f297bce42f0b919050565b81600503612f8e57507f92dc717124e161262f9d10c7079e7d54dc51271893fba54aa4a0f270fecdcc98919050565b81600603612fbd57507fce02aee5a7a35d40d974463c4c6e5534954fb07a7e7bc966fee268a15337bfd8919050565b81600703612fec57507ff7a65efd167a18f7091b2bb929d687dd94503cf0a43620487055ed7d6b727559919050565b8160080361301b57507fdef24acacad1318b664520f7c10e8bc6d1e7f6f6f7c8b031e70624ceb42266a6919050565b8160090361304a57507f4cb4080dc4e7bae88b4dc4307ad5117fa4f26195998a1b5f40368809d7f4c7f2919050565b81600a0361307957507ff8b1f864164d8d6e0b45f1399bd711223117a4ab0b057a9c2d7779e86a7c88db919050565b6040517febbd838a00000000000000000000000000000000000000000000000000000000815260048101839052602401612986565b919050565b6000806130c36020850185615479565b60018111156130d4576130d4614631565b1461310b576040517fd641ac7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061311f610120850161010086016145e1565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020908152604080832060608a01358452825280832054938352828252909120549293509091908601351415806131a7575073ffffffffffffffffffffffffffffffffffffffff8216600090815260026020908152604080832088820135845290915290205460ff165b806131bc575080158015906131bc5750838114155b156131f3576040517fbc17cfe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060008060008060006132078a8a336133c3565b9450945094509450945061322181878b606001358b6137d2565b61324d61323460e08b0160c08c016145e1565b61324460c08c0160a08d01615479565b3389898961386e565b61326983836132636101008d0160e08e016145e1565b8961383a565b7f9aaa45d6db2ef74ead0751ea9113263d1dec1b50cea05f0ca2002cb8063564a460405180606001604052808a81526020018b60600135815260200183151581525033888c608001358d60e00160208101906132c591906145e1565b8e60c00160208101906132d891906145e1565b8b8b8b8b6040516132f29a9998979695949392919061552d565b60405180910390a1506040015198975050505050505050565b600082613319868685613a5a565b1495945050505050565b46600c540361339157600d546040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101919091526042810185905261338c9060620160405160208183030381529060405280519060200120828585613b25565b612e6d565b6040517f6fd794c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6060806133ce614498565b6133d66144b6565b6000806133ed886101200135896101400135613ca5565b87608001356000036134bf5761341d61340a6101a08a018a615676565b6134186101808c018c615676565b613cbf565b6101608801356134316101808a018a615676565b61343f6101a08c018c615676565b8383808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080870282810182019093528682529498509596509394938693869350839250850190849080828437600092019190915250959c50919a50600197509495506136f3945050505050565b608088013560009081526009602052604090205460ff16156136bb5760006134ea60208a018a615479565b60808a01356000908152600960205260409020549091506b010000000000000000000000900460ff168082036135285763ab9848466000526004601cfd5b600080600960008d608001358152602001908152602001600020600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600960008e60800135815260200190815260200160002060000160079054906101000a900460e01b8e8e6040516024016135b79291906156de565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516136409190615703565b6000604051808303816000865af19150503d806000811461367d576040519150601f19603f3d011682016040523d82523d6000602084013e613682565b606091505b50915091508161369457805160208201fd5b808060200190518101906136a8919061576a565b919c509a50965094506136f39350505050565b6040517fd73c2c6a00000000000000000000000000000000000000000000000000000000815260808901356004820152602401612986565b61370d61370660e08a0160c08b016145e1565b8288613d0d565b60208581019190915273ffffffffffffffffffffffffffffffffffffffff9190911681860152600090613742908a018a615479565b600181111561375357613753614631565b036137ab576137a6608089013582600061377060208e018e6145e1565b73ffffffffffffffffffffffffffffffffffffffff161461379d5761379860208d018d6145e1565b61379f565b895b8688613e67565b6137c6565b6137c660808901358261379f6101208c016101008d016145e1565b50939792965093509350565b836137dd57806137ff565b7f53849a1acec87308423850dccd979fc7a4b74b75a79b19c3b98ec8df38a599db5b73ffffffffffffffffffffffffffffffffffffffff909316600090815260016020908152604080832094835293905291909120919091555050565b825180156138565761385683838760005b602002015184613a05565b602084015180156129f7576129f7848488600161384b565b600085600181111561388257613882614631565b03613938576040517fa7bc96d300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d169063a7bc96d39061390190899088908890889088906004016157ea565b600060405180830381600087803b15801561391b57600080fd5b505af115801561392f573d6000803e3d6000fd5b505050506129f7565b600185600181111561394c5761394c614631565b036129f7576040517fa0a406c600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d169063a0a406c6906139cb90899088908890889088906004016157ea565b600060405180830381600087803b1580156139e557600080fd5b505af11580156139f9573d6000803e3d6000fd5b50505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416613a4e5761338c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28383600e54613f17565b612e6d8484848461402c565b60008183825b81811015613b1a576000878783818110613a7c57613a7c614a94565b9050604002016020016020810190613a949190615479565b6001811115613aa557613aa5614631565b03613ae057613ad9878783818110613abf57613abf614a94565b905060400201600001358460009182526020526040902090565b9250613b12565b613b0f83888884818110613af657613af6614a94565b9050604002016000013560009182526020526040902090565b92505b600101613a60565b509095945050505050565b8273ffffffffffffffffffffffffffffffffffffffff163b600003613bb3578273ffffffffffffffffffffffffffffffffffffffff16613b66858484614207565b73ffffffffffffffffffffffffffffffffffffffff1614612e6d576040517fd1085d1b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff851690631626ba7e90613c0b90889087908790600401615849565b602060405180830381865afa158015613c28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4c9190615863565b7fffffffff000000000000000000000000000000000000000000000000000000001614612e6d576040517ff6cd0e2f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4281104283111715612e9d57637476320f6000526004601cfd5b6000838280821882151715613cdc57632e0c0f716000526004601cfd5b5060051b9050845b81156129f7576020820391508181013580613d0757632e0c0f716000526004601cfd5b50613ce4565b600b54600090819073ffffffffffffffffffffffffffffffffffffffff1615613e5f57600b546040517f70c1092100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906370c1092190613d8a90889088908890600401615880565b6040805180830381865afa158015613da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dca91906158b5565b909250905073ffffffffffffffffffffffffffffffffffffffff8216613df257506000613e5f565b600a54613e1b9074010000000000000000000000000000000000000000900461ffff1685615624565b613e2761271083615624565b1115613e5f576040517f97d7dcfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b935093915050565b60008581526009602052604081205461271090613e8f906301000000900461ffff1687615624565b613e99919061563b565b6020840151909150600003613ec05760408301819052613eb98186614edb565b8352613ef6565b613ed385878560016020020151846142f4565b604084018190526020840151613ee99087614edb565b613ef39190614edb565b83525b5073ffffffffffffffffffffffffffffffffffffffff909216909152505050565b6000806000806000868887f1905080614025578473ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f7257600080fd5b505af1158015613f86573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018890528916935063a9059cbb925060440190506020604051808303816000875af1158015614001573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f79190614e57565b5050505050565b8373ffffffffffffffffffffffffffffffffffffffff163b60000361407d576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405173ffffffffffffffffffffffffffffffffffffffff84811660248301528381166044830152606482018390526000918291871690608401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052516141389190615703565b6000604051808303816000865af19150503d8060008114614175576040519150601f19603f3d011682016040523d82523d6000602084013e61417a565b606091505b5091509150816141b6576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051156129f757808060200190518101906141d19190614e57565b6129f7576040517fe560521300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000806000806142178686614341565b6040805160008152602081018083528c905260ff8316918101919091526060810184905260808101839052929550909350915060019060a0016020604051602081039080840390855afa158015614272573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff84166142ea576040517ff05a20c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050509392505050565b6000838152600960205260408120546127109061431a90610100900461ffff1687615624565b614324919061563b565b9050816143318483614ef4565b1015612d0c57611f928383614edb565b60008080836041819003614369578535935060208601359250604086013560001a91506143e2565b806040036143ad57853593507f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6020870135908116935060ff1c601b0191506143e2565b6040517fd42b4bbd00000000000000000000000000000000000000000000000000000000815260048101829052602401612986565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561443c576040517fc185125200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff16601b1415801561445457508160ff16601c14155b15614490576040517f417893a400000000000000000000000000000000000000000000000000000000815260ff83166004820152602401612986565b509250925092565b60405180604001604052806002906020820280368337509192915050565b60405180606001604052806003906020820280368337509192915050565b60008083601f8401126144e657600080fd5b50813567ffffffffffffffff8111156144fe57600080fd5b6020830191508360208260051b850101111561451957600080fd5b9250929050565b6000806020838503121561453357600080fd5b823567ffffffffffffffff81111561454a57600080fd5b614556858286016144d4565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610c0b57600080fd5b80356130ae81614562565b8015158114610c0b57600080fd5b80356130ae8161458f565b600080604083850312156145bb57600080fd5b82356145c681614562565b915060208301356145d68161458f565b809150509250929050565b6000602082840312156145f357600080fd5b81356145fe81614562565b9392505050565b6000806040838503121561461857600080fd5b823561462381614562565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b602081016003831061467457614674614631565b91905290565b803561ffff811681146130ae57600080fd5b60006020828403121561469e57600080fd5b6145fe8261467a565b6000602082840312156146b957600080fd5b81356145fe8161458f565b6000604082840312156146d657600080fd5b50919050565b60006101e082840312156146d657600080fd5b60008060008060008060a0878903121561470857600080fd5b863567ffffffffffffffff8082111561472057600080fd5b61472c8a838b016146c4565b9750602089013591508082111561474257600080fd5b61474e8a838b016146dc565b9650604089013591508082111561476457600080fd5b818901915089601f83011261477857600080fd5b81358181111561478757600080fd5b8a602082850101111561479957600080fd5b6020830196508095505060608901359150808211156147b757600080fd5b506147c489828a016146c4565b9250506147d360808801614584565b90509295509295509295565b600080604083850312156147f257600080fd5b50508035926020909101359150565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610c0b57600080fd5b60008060008060008060c0878903121561484857600080fd5b6148518761467a565b955061485f6020880161467a565b945061486d6040880161467a565b9350606087013561487d81614801565b9250608087013561488d8161458f565b915060a087013561489d81614562565b809150509295509295509295565b6000602082840312156148bd57600080fd5b5035919050565b600080600080608085870312156148da57600080fd5b8435935060208501356148ec8161458f565b92506148fa6040860161467a565b91506149086060860161467a565b905092959194509250565b6000806040838503121561492657600080fd5b82356145c68161458f565b6000806000806080858703121561494757600080fd5b843567ffffffffffffffff8082111561495f57600080fd5b61496b888389016146c4565b9550602087013591508082111561498157600080fd5b5061498e878288016146dc565b935050604085013561499f81614562565b9396929550929360600135925050565b60008060008060008060008060008060c08b8d0312156149ce57600080fd5b8a3567ffffffffffffffff808211156149e657600080fd5b6149f28e838f016144d4565b909c509a5060208d0135915080821115614a0b57600080fd5b614a178e838f016144d4565b909a50985060408d0135915080821115614a3057600080fd5b614a3c8e838f016144d4565b909850965060608d0135915080821115614a5557600080fd5b50614a628d828e016144d4565b9095509350614a75905060808c01614584565b9150614a8360a08c0161459d565b90509295989b9194979a5092959850565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614af557600080fd5b8260051b80836020870137939093016020019392505050565b73ffffffffffffffffffffffffffffffffffffffff84168152604060208201526000611f92604083018486614ac3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516101e0810167ffffffffffffffff81118282101715614b9157614b91614b3e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614bde57614bde614b3e565b604052919050565b60028110610c0b57600080fd5b80356130ae81614be6565b600067ffffffffffffffff821115614c1857614c18614b3e565b5060051b60200190565b600082601f830112614c3357600080fd5b81356020614c48614c4383614bfe565b614b97565b82815260059290921b84018101918181019086841115614c6757600080fd5b8286015b84811015614c825780358352918301918301614c6b565b509695505050505050565b600082601f830112614c9e57600080fd5b813567ffffffffffffffff811115614cb857614cb8614b3e565b614ce960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614b97565b818152846020838601011115614cfe57600080fd5b816020850160208301376000918101602001919091529392505050565b60006101e08236031215614d2e57600080fd5b614d36614b6d565b614d3f83614bf3565b815260208301356020820152604083013560408201526060830135606082015260808301356080820152614d7560a08401614bf3565b60a0820152614d8660c08401614584565b60c0820152614d9760e08401614584565b60e0820152610100614daa818501614584565b908201526101208381013590820152610140808401359082015261016080840135908201526101808084013567ffffffffffffffff80821115614dec57600080fd5b614df836838801614c22565b838501526101a0925082860135915080821115614e1457600080fd5b614e2036838801614c22565b838501526101c0925082860135915080821115614e3c57600080fd5b50614e4936828701614c8d565b918301919091525092915050565b600060208284031215614e6957600080fd5b81516145fe8161458f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614ed457614ed4614e74565b5060010190565b81810381811115614eee57614eee614e74565b92915050565b80820180821115614eee57614eee614e74565b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe21833603018112614f3b57600080fd5b9190910192915050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112614f3b57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614fae57600080fd5b83018035915067ffffffffffffffff821115614fc957600080fd5b60200191503681900382131561451957600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261501357600080fd5b830160208101925035905067ffffffffffffffff81111561503357600080fd5b80360382131561451957600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000813561509881614562565b73ffffffffffffffffffffffffffffffffffffffff1683526150bd6020830183614fde565b60406020860152611f92604086018284615042565b60028110610c0b57610c0b614631565b6150eb816150d2565b9052565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261512457600080fd5b830160208101925035905067ffffffffffffffff81111561514457600080fd5b8060051b360382131561451957600080fd5b60006101e061516d8461516885614bf3565b6150e2565b602083013560208501526040830135604085015260608301356060850152608083013560808501526151a160a08401614bf3565b6151ae60a08601826150e2565b506151bb60c08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660c08501526151e260e08401614584565b73ffffffffffffffffffffffffffffffffffffffff1660e085015261010061520b848201614584565b73ffffffffffffffffffffffffffffffffffffffff1690850152610120838101359085015261014080840135908501526101608084013590850152610180615255818501856150ef565b83838801526152678488018284614ac3565b93505050506101a061527b818501856150ef565b8684038388015261528d848284614ac3565b93505050506101c06152a181850185614fde565b868403838801526152b3848284615042565b979650505050505050565b6080815260006152d1608083018761508b565b82810360208401526152e38187615156565b73ffffffffffffffffffffffffffffffffffffffff95909516604084015250506060015292915050565b60006020828403121561531f57600080fd5b5051919050565b89815261012081016153378a6150d2565b8960208301528860408301528760608301528660808301528560a083015261535e856150d2565b60c082019490945273ffffffffffffffffffffffffffffffffffffffff92831660e08201529116610100909101529695505050505050565b815160009082906020808601845b838110156153c0578151855293820193908201906001016153a4565b50929695505050505050565b6000815160005b818110156153ed57602081850181015186830152016153d3565b50600093019283525090919050565b6000612d0c61540b83866153cc565b846153cc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261544657600080fd5b83018035915067ffffffffffffffff82111561546157600080fd5b6020019150600681901b360382131561451957600080fd5b60006020828403121561548b57600080fd5b81356145fe81614be6565b600081518084526020808501945080840160005b838110156154c6578151875295820195908201906001016154aa565b509495945050505050565b8060005b6002811015612e6d57815173ffffffffffffffffffffffffffffffffffffffff168452602093840193909101906001016154d5565b8060005b6003811015612e6d57815184526020938401939091019060010161550e565b60006101e08c51835260208d0151602084015260408d01511515604084015261556e606084018d73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff8b1660808401528960a08401526155b260c084018a73ffffffffffffffffffffffffffffffffffffffff169052565b73ffffffffffffffffffffffffffffffffffffffff881660e0840152806101008401526155e181840188615496565b90508281036101208401526155f68187615496565b9150506156076101408301856154d1565b61561561018083018461550a565b9b9a5050505050505050505050565b8082028115828204841417614eee57614eee614e74565b600082615671577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126156ab57600080fd5b83018035915067ffffffffffffffff8211156156c657600080fd5b6020019150600581901b360382131561451957600080fd5b6040815260006156f1604083018561508b565b8281036020840152611f928185615156565b60006145fe82846153cc565b600082601f83011261572057600080fd5b81516020615730614c4383614bfe565b82815260059290921b8401810191818101908684111561574f57600080fd5b8286015b84811015614c825780518352918301918301615753565b6000806000806080858703121561578057600080fd5b84519350602085015167ffffffffffffffff8082111561579f57600080fd5b6157ab8883890161570f565b945060408701519150808211156157c157600080fd5b506157ce8782880161570f565b92505060608501516157df8161458f565b939692955090935050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060a0606083015261582b60a0830185615496565b828103608084015261583d8185615496565b98975050505050505050565b838152604060208201526000611f92604083018486615042565b60006020828403121561587557600080fd5b81516145fe81614801565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000611f926060830184615496565b600080604083850312156158c857600080fd5b82516158d381614562565b602093909301519294929350505056fea2646970667358221220fda1aa391f9a90a5fa9e8cc21d3b32dd6362514c3103bfd1a99529e079bcb58264736f6c63430008110033

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

0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a70000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _owner (address): 0x3ab105F0e4A22ec4A96a9b0Ca90c5C534d21f3a7
Arg [1] : _protocolFeeRecipient (address): 0x5924A28caAF1cc016617874a2f0C3710d881f3c1
Arg [2] : _transferManager (address): 0x000000000060C4Ca14CfC4325359062ace33Fe3D
Arg [3] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000003ab105f0e4a22ec4a96a9b0ca90c5c534d21f3a7
Arg [1] : 0000000000000000000000005924a28caaf1cc016617874a2f0c3710d881f3c1
Arg [2] : 000000000000000000000000000000000060c4ca14cfc4325359062ace33fe3d
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


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.