ETH Price: $2,149.49 (-2.43%)

Contract

0xffDBE663C9ee2A52d4Cb3A1d6387547D890F2Aa3
 

Overview

ETH Balance

0.15 ETH

Eth Value

$322.42 (@ $2,149.49/ETH)

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Delete Order242462932026-01-16 9:08:3562 days ago1768554515IN
0xffDBE663...D890F2Aa3
0 ETH0.0001272.03133626
Create Offer219535192025-03-01 17:29:59383 days ago1740850199IN
0xffDBE663...D890F2Aa3
1 ETH0.000166911.35564046
Fill Order219240372025-02-25 14:48:11387 days ago1740494891IN
0xffDBE663...D890F2Aa3
0.01 ETH0.000563873.62395161
Set Market Fees217950532025-02-07 13:53:11405 days ago1738936391IN
0xffDBE663...D890F2Aa3
0 ETH0.000110843.4667141
Update Order Pri...217535142025-02-01 18:38:59411 days ago1738435139IN
0xffDBE663...D890F2Aa3
0 ETH0.000088042.8658148
Update Order Pri...216920752025-01-24 4:49:35419 days ago1737694175IN
0xffDBE663...D890F2Aa3
0 ETH0.00014724.79320979
Delete Order216649002025-01-20 9:46:47423 days ago1737366407IN
0xffDBE663...D890F2Aa3
0 ETH0.0026347429.48334823
Fill Order216155242025-01-13 12:21:11430 days ago1736770871IN
0xffDBE663...D890F2Aa3
0.01 ETH0.0034980820.81798846
Create Offer213727572024-12-10 14:40:11464 days ago1733841611IN
0xffDBE663...D890F2Aa3
1 ETH0.0081464666.16521692
Create Offer213318092024-12-04 21:25:35470 days ago1733347535IN
0xffDBE663...D890F2Aa3
1 ETH0.0046710237.93788016
Fill Order212916222024-11-29 6:39:59475 days ago1732862399IN
0xffDBE663...D890F2Aa3
0.01 ETH0.001442228.58303169
Fill Order212887912024-11-28 21:10:23476 days ago1732828223IN
0xffDBE663...D890F2Aa3
0.01 ETH0.001558829.2769521
Fill Order212884052024-11-28 19:52:47476 days ago1732823567IN
0xffDBE663...D890F2Aa3
0.01 ETH0.0023367813.90680261
Fill Order212665902024-11-25 18:34:47479 days ago1732559687IN
0xffDBE663...D890F2Aa3
0.01 ETH0.0022817513.57929755
Fill Order212663792024-11-25 17:52:23479 days ago1732557143IN
0xffDBE663...D890F2Aa3
0.01 ETH0.002974317.70084668
Create Offer212414812024-11-22 6:28:11482 days ago1732256891IN
0xffDBE663...D890F2Aa3
0.69 ETH0.001180859.59087006
Create Offer211931082024-11-15 12:30:59489 days ago1731673859IN
0xffDBE663...D890F2Aa3
0.12 ETH0.0021623217.56235086
Delete Order209718442024-10-15 15:25:23520 days ago1729005923IN
0xffDBE663...D890F2Aa3
0 ETH0.0021818432.47573149
Delete Order209649052024-10-14 16:09:59521 days ago1728922199IN
0xffDBE663...D890F2Aa3
0 ETH0.0021739432.35805778
Delete Order209648972024-10-14 16:08:23521 days ago1728922103IN
0xffDBE663...D890F2Aa3
0 ETH0.0022184133.01999967
Create Offer208059462024-09-22 11:53:35543 days ago1727006015IN
0xffDBE663...D890F2Aa3
0.15 ETH0.0021285917.28668802
Delete Order205500862024-08-17 18:19:23579 days ago1723918763IN
0xffDBE663...D890F2Aa3
0 ETH0.000132851.65332104
Delete Offer205070602024-08-11 18:08:35585 days ago1723399715IN
0xffDBE663...D890F2Aa3
0 ETH0.000071141.61807194
Create Offer205010512024-08-10 21:58:11585 days ago1723327091IN
0xffDBE663...D890F2Aa3
0.25 ETH0.000225631.83262548
Create Offer205001482024-08-10 18:56:59586 days ago1723316219IN
0xffDBE663...D890F2Aa3
0.2 ETH0.000240381.95242786
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer219537502025-03-01 18:16:23383 days ago1740852983
0xffDBE663...D890F2Aa3
0.8 ETH
Transfer219537502025-03-01 18:16:23383 days ago1740852983
0xffDBE663...D890F2Aa3
0.1 ETH
Transfer219537502025-03-01 18:16:23383 days ago1740852983
0xffDBE663...D890F2Aa3
0.1 ETH
Transfer219240372025-02-25 14:48:11387 days ago1740494891
0xffDBE663...D890F2Aa3
0.009 ETH
Transfer219240372025-02-25 14:48:11387 days ago1740494891
0xffDBE663...D890F2Aa3
0.001 ETH
Transfer216155242025-01-13 12:21:11430 days ago1736770871
0xffDBE663...D890F2Aa3
0.0085 ETH
Transfer216155242025-01-13 12:21:11430 days ago1736770871
0xffDBE663...D890F2Aa3
0.001 ETH
Transfer216155242025-01-13 12:21:11430 days ago1736770871
0xffDBE663...D890F2Aa3
0.0005 ETH
Transfer213729812024-12-10 15:25:11464 days ago1733844311
0xffDBE663...D890F2Aa3
0.8 ETH
Transfer213729812024-12-10 15:25:11464 days ago1733844311
0xffDBE663...D890F2Aa3
0.05 ETH
Transfer213729812024-12-10 15:25:11464 days ago1733844311
0xffDBE663...D890F2Aa3
0.1 ETH
Transfer213729812024-12-10 15:25:11464 days ago1733844311
0xffDBE663...D890F2Aa3
0.05 ETH
Transfer213318512024-12-04 21:33:59470 days ago1733348039
0xffDBE663...D890F2Aa3
0.85 ETH
Transfer213318512024-12-04 21:33:59470 days ago1733348039
0xffDBE663...D890F2Aa3
0.1 ETH
Transfer213318512024-12-04 21:33:59470 days ago1733348039
0xffDBE663...D890F2Aa3
0.05 ETH
Transfer212916222024-11-29 6:39:59475 days ago1732862399
0xffDBE663...D890F2Aa3
0.0085 ETH
Transfer212916222024-11-29 6:39:59475 days ago1732862399
0xffDBE663...D890F2Aa3
0.001 ETH
Transfer212916222024-11-29 6:39:59475 days ago1732862399
0xffDBE663...D890F2Aa3
0.0005 ETH
Transfer212887912024-11-28 21:10:23476 days ago1732828223
0xffDBE663...D890F2Aa3
0.0085 ETH
Transfer212887912024-11-28 21:10:23476 days ago1732828223
0xffDBE663...D890F2Aa3
0.001 ETH
Transfer212887912024-11-28 21:10:23476 days ago1732828223
0xffDBE663...D890F2Aa3
0.0005 ETH
Transfer212884052024-11-28 19:52:47476 days ago1732823567
0xffDBE663...D890F2Aa3
0.0085 ETH
Transfer212884052024-11-28 19:52:47476 days ago1732823567
0xffDBE663...D890F2Aa3
0.001 ETH
Transfer212884052024-11-28 19:52:47476 days ago1732823567
0xffDBE663...D890F2Aa3
0.0005 ETH
Transfer212665902024-11-25 18:34:47479 days ago1732559687
0xffDBE663...D890F2Aa3
0.0085 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
NinfaMarketplace

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 4194304 runs

Other Settings:
paris EvmVersion
/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

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

import "./utils/Counters.sol";
import "./utils/RoyaltyEngineV1.sol";
import "./access/Ownable.sol";

/**
 *
 * @title NinfaMarketplace                                   *
 *                                                           *
 * @notice On-chain NFT marketplace                          *
 *                                                           *
 * @custom:security-contact tech@ninfa.io                    *
 *
 */

contract NinfaMarketplace is Ownable, RoyaltyEngineV1 {
    /*----------------------------------------------------------*|
    |*  # VARIABLES                                             *|
    |*----------------------------------------------------------*/

    using Counters for Counters.Counter;
    /// @notice Orders counter
    Counters.Counter private _orderCount;
    /// @notice Offers counter
    Counters.Counter private _offerCount;
    /// @notice address of admin multisig contract for receiving fees generated
    /// by the marketplace
    address private _feeRecipient;
    /// @notice Ninfa's external registry, mapping Ninfa's ERC721 sovreign
    /// collection's tokenIds to a boolean value
    /// indicating if the token has been sold on any of Ninfa's contracts, such
    /// as this marketplace or an auction
    /// contract.
    address private immutable _PRIMARY_MARKET_REGISTRY;
    ///@notice constant 10,000 BPS = 100% shares sale price
    uint256 private constant _BPS_DENOMINATOR = 10_000;
    /// @notice Ninfa Marketplace fee percentage on primary sales from orders,
    /// expressed in basis points
    uint256 private _primaryOrdersFee;
    /// @notice Ninfa Marketplace fee percentage on primary sales from offers,
    /// expressed in basis points
    uint256 private _primaryOffersFee;
    /// @notice Ninfa Marketplace fee percentage on all secondary sales,
    /// expressed in basis points
    uint256 private _secondaryMarketFee;
    /// @notice codehash of Ninfa's ERC721 sovreign collection
    bytes32 private _ERC721SovreignV1CodeHash;
    /// @notice `_orderCount` counter to `_Order` struct mapping
    mapping(uint256 => _Order) private _orders;
    /// @notice `_offerCount` counter to `_Offer` struct mapping
    mapping(uint256 => _Offer) public offers;

    /*----------------------------------------------------------*|
    |*  # STRUCTS                                               *|
    |*----------------------------------------------------------*/

    /**
     * @dev the `Order` struct is used both for storing order information, as
     * well as trade information when passed as a
     * function parameter to the private `_trade` function
     * @param tokenId the NFT id, for now we only allow trading NINFA NFT's so
     * no erc721 address is needed
     * @param unitPrice ERC-1155 unit price in ETH, or total price if ERC-721
     * since there is only 1 unit of each token.
     * @dev when the `Order` struct is passed as a function parameter to
     * `_trade`, `unitPrice` always refers to the
     * total price of ERC-1155 tokens, i.e. token value * unit price
     * @param collection address of the ERC721 or ERC1155 contract. Doesn't
     * require any access control besides the
     * @param erc1155Value the NFT amount, _amount == 0 for ERC721 and _amount >
     * 0 for ERC1155
     * @param commissionBps commission amounts, expressed in basis points 0 -
     * 10000
     * @param commissionReceivers receivers of commission on sales (primary AND
     * secondary)
     * @param collection address of the collection being sold
     * @param from always refers to the seller, who either creater an order or
     * is accepting an offer.
     * @param operator address of an authorized operator, such as a gallery
     * managing an artist; the operator is allowed
     * to change or cancel an order they created on the Marketplace.
     * @dev operator address usually also corresponds to the commission receiver
     * in order to receive sale commissions,
     * unless `commissionReceiver` is set to yet another address, e.g. a payment
     * splitter.
     */
    struct _Order {
        uint256 tokenId;
        uint256 unitPrice;
        uint256 erc1155Value;
        address collection;
        address from;
        address operator;
        uint256[] commissionBps;
        address[] commissionReceivers;
    }

    struct _Offer {
        uint256 tokenId;
        uint256 unitPrice;
        uint256 erc1155Value;
        address collection;
        address from; // buyer
    }

    /*----------------------------------------------------------*|
    |*  # EVENTS                                                *|
    |*----------------------------------------------------------*/

    event OrderCreated(uint256 orderId);

    event OrderUpdated(uint256 orderId);

    event OrderDeleted(uint256 orderId);

    event OfferCreated(uint256 offerId);

    event OfferUpdated(uint256 offerId);

    event OfferDeleted(uint256 offerId);

    // we have order/offer id and all the related data stored in db.
    event Trade( // seller
        address indexed collection,
        uint256 indexed tokenId,
        address indexed from,
        uint256 id,
        uint256 price,
        uint256 erc1155Value
    );

    /*----------------------------------------------------------*|
    |*  # ORDERS                                                *|
    |*----------------------------------------------------------*/

    /**
     * @notice create a new order on the marketplace by transfering an NFT to
     * it.
     * @dev Will create a new order by sending tokens with data bytes containing
     * function parameters
     *
     * Require:
     *
     * - can only be called by an NFT smart contract transfering an NFT to the
     * marketplace
     *
     */
    function _createOrder(
        address _operator, //  either the previous owner or operator, i.e.
            // whichever address called safeTransferFrom on
            // the ERC1155 contract
        address _from, // previous owner, i.e. seller
        uint256 _id,
        uint256 _value,
        uint256 _unitPrice,
        uint256[] memory _commissionBps,
        address[] memory _commissionReceivers
    )
        private
    {
        // `_orderCount` starts at 1
        _orderCount.increment();
        uint256 _orderId = _orderCount.current();

        // create order with new `_orderId` in orders mapping
        _orders[_orderId] = _Order(
            _id,
            _unitPrice,
            _value,
            msg.sender, // collection
            _from,
            _operator,
            _commissionBps,
            _commissionReceivers
        );
        emit OrderCreated(_orderId);
    }

    /// @dev only for 1155 for updating the price and LOWER the amount
    function updateOrder(uint256 _erc1155RedeemAmount, uint256 _unitPrice, uint256 _orderId) external {
        lowerOrderErc1155Amount(_orderId, _erc1155RedeemAmount);

        _orders[_orderId].unitPrice = _unitPrice;
    }

    /**
     * @notice cancels order and transfers NFT back to owner
     * @param _orderId the Id of the order
     * @dev delete `_orders[_orderId]` from storage BEFORE making external calls
     * for transfering the NFT back to the
     * seller (check-effects pattern)
     *
     *
     * SHOULD:
     *
     * This function does not check whether the order exists or not
     *
     */
    function deleteOrder(uint256 _orderId) external {
        _Order memory order = _orders[_orderId];
        require(msg.sender == order.operator);

        delete _orders[_orderId];

        _transferNFT(order.collection, address(this), msg.sender, order.tokenId, order.erc1155Value);

        emit OrderDeleted(_orderId);
    }

    /**
     * @param _unitPrice will override the old price, note that it may be 0
     * although this could only mean that a mistake
     * was made
     * @dev this function doesn't enforce a positive value for `_unitPrice` in
     * order to save a little gas for the users.
     * @dev if `_unitPrice` is set to 0, the order will be deleted from the
     * database (not from the smart contract), see
     * {NinfaMarketplace-OrderUpdated} modifier
     */
    function updateOrderPrice(uint256 _orderId, uint256 _unitPrice) external {
        _Order storage order = _orders[_orderId];
        require(msg.sender == order.operator);

        order.unitPrice = _unitPrice;

        emit OrderUpdated(_orderId);
    }

    /**
     * @notice function to lower an order's amount of the ERC-1155 tokenId on
     * sale, doesn't apply to ERC-721 because it
     * is non-fungible
     * @param _erc1155RedeemAmount is the (negative) difference of tokens to be
     * withdrawn by the seller. Should be
     * different from 0, although not strictly required.
     */
    function lowerOrderErc1155Amount(uint256 _orderId, uint256 _erc1155RedeemAmount) public {
        _Order storage order = _orders[_orderId];
        require(msg.sender == order.operator);

        /// @dev warning, make changes to storage BEFORE making external calls
        /// for transfering the NFT back to the
        /// seller (check-effects-interactions pattern)
        order.erc1155Value -= _erc1155RedeemAmount;

        (bool success,) = order.collection.call(
            abi.encodeWithSelector(
                0xf242432a, // bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)'))
                address(this),
                msg.sender,
                order.tokenId,
                _erc1155RedeemAmount,
                ""
            )
        );
        require(success);

        if (order.erc1155Value == 0) {
            delete _orders[_orderId]; // it is not possible to delete using
                // storage pointers
                // https://docs.soliditylang.org/en/develop/types.html#data-location
            emit OrderDeleted(_orderId);
        } else {
            emit OrderUpdated(_orderId);
        }
    }

    function setOrderCommission(
        uint256 _orderId, 
        uint256[] memory _commissionBps, 
        address[] memory _commissionReceivers) external {
        // should we check if the total commission is less than 10000?
        // should revert in trade function anyway
        require(msg.sender == _orders[_orderId].operator);
        _orders[_orderId].commissionBps = _commissionBps;
        _orders[_orderId].commissionReceivers = _commissionReceivers;
        emit OrderUpdated(_orderId);
    }

    /*----------------------------------------------------------*|
    |*  # OFFERS                                                *|
    |*----------------------------------------------------------*/

    /**
     * @dev offers can be made independently of whether the token is on sale or
     * not, the msg.value is used to determine
     * the offer amount, so no function parameter is needed for that
     * @dev there is no require to check that an offer or offer doesn't already
     * exist and if so, that the offer amount
     * is not greater than the order itself, this was omitted in order to save
     * gas; the frontend should check this in
     * order to prevent mistakes from the user
     * @param _collection address of the erc721 implementation contract or proxy
     * contract
     * @param _tokenId the token Id to make an offer to
     * @param _amount the NFT amount, _amount == 0 for ERC721 and _amount > 0
     * for ERC1155
     * @param _from needed in order to integrate Wert payment solution, because
     * in every txn Wert is the `msg.sender`.
     *      using _msgSender does not represent a security risk, on the other
     * hand, it is possible for the buyer to use
     * this parameter simply in order to transfer the NFT to an address other
     * than their own, this can be useful for
     * external contract buying NFTs.
     */
    function createOffer(
        address _collection,
        uint256 _tokenId,
        uint256 _amount,
        address _from,
        uint256 _unitPrice
    )
        external
        payable
    {
        _offerCount.increment(); // start count at 1

        if (_amount == 0) require(msg.value == _unitPrice);
        else require(msg.value == _unitPrice * _amount);

        offers[_offerCount.current()] = _Offer(
            _tokenId, // uint256 tokenId;
            _unitPrice, // uint256 unitPrice;
            _amount, // uint256 amount;
            _collection, // address collection;
            _from // address from;
        );

        emit OfferCreated(_offerCount.current());
    }

    /**
     * @dev cancels offer and refunds ETH back to bidder. When an order gets
     * filled, the offer isn't marked as
     * cancelled, in order to allow users to claim back their money.
     * @param _offerId the Id of the offer.
     */
    function deleteOffer(uint256 _offerId) external {
        // in memory copy needed so that it is possible to delete the struct
        // inside the storage offers mapping, while
        // keeping check effects interact pattern intact
        _Offer memory offer = offers[_offerId];

        uint256 refund;

        if (offer.erc1155Value == 0) {
            refund = offer.unitPrice;
        } else {
            refund = offer.unitPrice * offer.erc1155Value;
        }
        require(msg.sender == offer.from);
        // mark offer as cancelled forever, updating offer price before external
        // call, Checks Effects Interactions
        // pattern
        delete offers[_offerId];
        // transfer the offer amount back to bidder
        _sendValue(offer.from, refund);

        emit OfferDeleted(_offerId);
    }

    /**
     * @dev this is one of two functions called by a buyer in order to modify
     * their offer, there are two functions,
     * `raiseOffer()` and `lowerOffer()`, because they expect different
     * parameters depending on whether the offer is
     * being raised or lowerd.
     *      A `msg.value` is required, this function will add the amount sent to
     * the old offer amount. The frontend
     * needs to calculate the difference between the old and new offer.
     *      E.g. A buyer calls createOffer() and pays 0.1 ETH. The same buyer
     * later wants to raise the offer to 0.3 ETH,
     * therefore they now need to send 0.2 ETH, because 0.1 was was sent before.
     * @dev anyone can call this function, i.e. requiring that caller is offer
     * creator is not needed
     * @param _offerId the id of the offer
     * call this function only if the new total price is greater than the old
     * total price
     */
    function raiseOfferPrice(uint256 _offerId, uint256 _erc1155Value, uint256 _unitPrice) external payable {
        _Offer storage _offer = offers[_offerId];

        require(msg.sender == _offer.from);

        if (_offer.erc1155Value == 0) {
            require(msg.value == _unitPrice - _offer.unitPrice);
        } else {
            require(msg.value == (_unitPrice * _erc1155Value) - (_offer.unitPrice * _offer.erc1155Value));
        }

        _offer.unitPrice = _unitPrice; // transfer extra amount needed on top of
            // older offer
        _offer.erc1155Value = _erc1155Value;

        emit OfferUpdated(_offerId);
    }

    /**
     * @dev this is one of two functions called by a buyer in order to modify
     * their offer, there are two functions,
     * `raiseOffer()` and `lowerOffer()`, because they expect different
     * parameters depending on whether the offer is
     * being raised or lowerd.
     *      In contrast with `raiseOffer()`, instead of `msg.value` this
     * function expects a uint parameter representing
     * the new (lower) offer; the buyer will get refunded the difference.
     *      E.g. A buyer calls createOffer() and pays 0.3 ETH. The same buyer
     * later wants to lower the offer to 0.1 ETH,
     * therefore they will get refunded 0.2 ETH. I.e. The amount expected by the
     * `_newAmount` paramer is 0.1 ETH (1^17).
     * @param _offerId the id of the offer
     */
    function lowerOfferPrice(uint256 _offerId, uint256 _erc1155Amount, uint256 _unitPrice) external {
        _Offer storage _offer = offers[_offerId];

        require(msg.sender == _offer.from, "hwy");

        uint256 refund;

        if (_erc1155Amount == 0) {
            refund = _offer.unitPrice - _unitPrice;
        } else {
            refund = (_offer.unitPrice * _offer.erc1155Value) - (_unitPrice * _erc1155Amount);
            _offer.erc1155Value = _erc1155Amount;
        }

        _offer.unitPrice = _unitPrice; // needed to store result before offer
            // price is updated
        // transfer the difference between old and new lower offer to the user
        _sendValue(msg.sender, refund);

        emit OfferUpdated(_offerId);
    }

    function acceptListedTokenOffer(
        uint256 _orderId,
        uint256 _offerId,
        uint256[] memory _commissionBps,
        address[] memory _commissionReceivers
    )
        external
    {
        _Order memory order = _orders[_orderId];
        _Offer memory offer = offers[_offerId];

        require(order.operator == msg.sender && order.tokenId == offer.tokenId && order.collection == offer.collection);

        delete _orders[_orderId];
        delete offers[_offerId];

        _trade(
            _Order(
                order.tokenId, // uint256 tokenId
                offer.unitPrice, // offer price, not order price
                0,
                order.collection, // address collection
                msg.sender, // seller
                offer.from, // buyer / nft recipient
                _commissionBps, // uint256 commissionBps
                _commissionReceivers
            ),
            _orderId,
            _primaryOffersFee
        );
    }

    /*----------------------------------------------------------*|
    |*  # TRADING                                               *|
    |*----------------------------------------------------------*/

    /**
     * @notice the collector calls this function to buy an NFT at the ask price,
     * only if an order exists
     * @notice if someone has an open offer but calls fillOrder, the offer will
     * remain open, meaning they will need to
     * call cancelOffer() to get a refund. This is unlikely, as users will
     * likely be aware of this and use the refund in
     * order to pay for part of the order.
     * @param _id avoids having to store a mapping to order id like the
     * deprecated `mapping(address => mapping(uint256
     * => uint256)) private _tokenToOrderId` which would have not worked for
     * erc1155 as each token has a supply.
     * _orderId does not constitute a vulnerability as it is user provided,
     * since A) a regular user will go through the
     * frontend which gets orderId from events
     * @param _buyer needed in order to integrate Wert payment solution, because
     * in every txn Wert is the msg.sender,
     * although using msg.sender would cost less gas.
     * using _msgSender does not represent a security risk, on the other hand,
     * it is possible for the buyer to use this
     * parameter simply in order to transfer the NFT to an address other than
     * their own, this can be useful for external
     * contract buying NFTs.
     *  + @param _erc1155Value market order amount (total or partial fill).
     * `_erc1155Value == 0` corresponds to one erc721 tokenId, `_erc1155Value >
     * 0` for erc1155 tokenIds
     *
     * MUST:
     *
     * - `msg.value` must be equal to `_orders[_orderId]der.unitPrice *
     * buyAmount`
     * - `_orders[_orderId].sellAmount >= buyAmount`
     *
     */
    function fillOrder(uint256 _id, address _buyer, uint256 _erc1155Value) external payable {
        _Order memory order = _orders[_id];

        require(msg.value == order.unitPrice * (_erc1155Value == 0 ? 1 : _erc1155Value));

        // subtracting user-suplied `_erc1155Value` from order amount,
        // transaction will revert if underflow, implicitly
        // requiring `_orders[_id]._erc1155Value >= _erc1155Value`
        if (_orders[_id].erc1155Value - _erc1155Value == 0) delete _orders[_id];
        else _orders[_id].erc1155Value -= _erc1155Value;

        _trade(
            _Order(
                order.tokenId, // uint256 tokenId
                msg.value, // price
                _erc1155Value,
                order.collection, // address collection
                order.from, // seller or from
                _buyer, // address buyer used for nft transfer
                order.commissionBps, // uint256 commissionBps
                order.commissionReceivers // address commissionReceiver
            ),
            _id,
            _primaryOrdersFee // uint256 primaryFee
        );
    }

    /**
     *
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been
     * updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param _operator The address which initiated the transfer (i.e.
     * msg.sender)
     * @param _from     The address which previously owned the token
     * @param _tokenId  The ID of the token being transferred
     * @param _value    The amount of tokens being transferred
     * @param _data     Additional data with no specified format
     * @param _data     `uint256 id` corresponding to an order to be updated or
     * an offer to be accepted, if the `id`
     * parameter is 0 create a new order.
     * @param _data     `uint256 unitPrice` is only required for updating an
     * order, i.e. if `unitPrice == 0` `id` an
     * offer id, if `unitPrice > 0` `id` is an order id
     * @return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * if transfer is allowed
     */
    function onERC1155Received(
        address _operator, //  either the previous owner or operator, whoever
            // called safeTransferFrom on the ERC1155
            // contract
        address _from, // previous owner
        uint256 _tokenId,
        uint256 _value,
        bytes memory _data
    )
        external
        returns (bytes4)
    {
        (uint256 id, uint256 unitPrice, uint256[] memory commissionBps, address[] memory commissionReceivers) =
            abi.decode(_data, (uint256, uint256, uint256[], address[]));

        if (unitPrice == 0) {
            /*----------------------------------------------------------*|
            |*  # ACCEPT OFFER                                          *|
            |*----------------------------------------------------------*/
            // if `_value` is more than the amount the following if check will
            // revert due to underflow,
            // intended to stop someone from sending more erc1155 tokens then
            // there are available in the order

            _Offer memory offer = offers[id];

            require(offer.collection == msg.sender && offer.tokenId == _tokenId);

            // subtracting `_value` from offer amount, transaction will revert
            // if underflow, implicitly requiring
            // `offers[id]._erc1155Value >= _value`
            if (offers[id].erc1155Value - _value == 0) delete offers[id];
            else offers[id].erc1155Value -= _value;

            _trade(
                _Order(
                    _tokenId, // uint256 tokenId
                    offer.unitPrice * _value, // uint256 price (unitPrice *
                        // value)
                    _value,
                    msg.sender, // address collection
                    _from, // seller
                    offer.from, // buyer or operator
                    commissionBps, // uint256 commissionBps
                    commissionReceivers // address commissionReceivers
                ),
                id,
                _primaryOffersFee
            );
        } else if (id == 0) {
            /*----------------------------------------------------------*|
            |*  # CREATE ORDER                                          *|
            |*----------------------------------------------------------*/
            // if the order/offer id parameter is 0, create a new order

            _createOrder(_operator, _from, _tokenId, _value, unitPrice, commissionBps, commissionReceivers);
        } else {
            /*----------------------------------------------------------*|
            |*  # UPDATE ORDER                                          *|
            |*----------------------------------------------------------*/
            // if the user supplied a non-zero value for `unitPrice` then the
            // `id` parameter must correspond to an order
            // that needs to be updated
            // the operator, collection and tokenId of the NFT received by the
            // marketplace must match the ones stored at
            // the id provided by the operator
            // in order to avoid operators increasing allowance for orders with
            // different (more valuable) NFTs
            _Order storage order = _orders[id];

            require(order.operator == _operator && order.collection == msg.sender && order.tokenId == _tokenId);
            order.erc1155Value += _value;
            order.unitPrice = unitPrice;

            emit OrderUpdated(id);
        }

        return 0xf23a6e61;
    }

    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this
     * contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the
     * recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with
     * `IERC721.onERC721Received.selector`.
     * @param _operator The address which called `safeTransferFrom` function
     * @param _from The address which previously owned the token
     * @param _tokenId The NFT identifier which is being transferred
     * @param _data Additional data with no specified format
     */
    function onERC721Received(
        address _operator,
        address _from,
        uint256 _tokenId,
        bytes calldata _data
    )
        external
        returns (bytes4)
    {
        (uint256 id, uint256 unitPrice, uint256[] memory commissionBps, address[] memory commissionReceivers) =
            abi.decode(_data, (uint256, uint256, uint256[], address[]));

        if (id == 0) {
            /*----------------------------------------------------------*|
            |*  # CREATE ORDER                                          *|
            |*----------------------------------------------------------*/
            // if the order/offer id parameter is 0, create a new order
            _createOrder(_operator, _from, _tokenId, 0, unitPrice, commissionBps, commissionReceivers);
        } else {
            /*----------------------------------------------------------*|
            |*  # ACCEPT OFFER                                          *|
            |*----------------------------------------------------------*/
            // if `_value` is more than the amount the following if check will
            // revert due to underflow,
            // intended to stop someone from sending more erc1155 tokens then
            // there are available in the order
            _Offer memory offer = offers[id];

            require(offer.collection == msg.sender && offer.tokenId == _tokenId);

            delete offers[id]; // ERC-721 doesn't have any supply therefore the
                // offer may be deleted after accepting the
                // offer

            _trade(
                _Order(
                    _tokenId, // uint256 tokenId
                    offer.unitPrice, // uint256 price
                    0,
                    msg.sender, // address collection
                    _from, // address buyer or from
                    offer.from, // seller
                    commissionBps, // uint256 commissionBps
                    commissionReceivers
                ),
                id,
                _primaryOffersFee //uint256 primaryFee
            );
        }

        return 0x150b7a02;
    }

    /**
     * @dev ERC-721 tokens are transferred to the buyer via `transferFrom`
     * rather than `safeTransferFrom`
     *      i.e. the caller is responsible to confirm that the recipient is
     * capable of receiving ERC721
     */
    function _transferNFT(
        address _collection,
        address _from,
        address _to,
        uint256 _tokenId,
        uint256 _erc1155Value
    )
        private
    {
        bool success;
        if (_erc1155Value == 0) {
            // bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
            (success,) = _collection.call(abi.encodeWithSelector(0x42842e0e, _from, _to, _tokenId));
        } else {
            // bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a
            (success,) = _collection.call(abi.encodeWithSelector(0xf242432a, _from, _to, _tokenId, _erc1155Value, ""));
        }

        require(success);
    }

    function _trade(_Order memory _order, uint256 _id, uint256 _primaryMarketFee) private {
        uint256 marketplaceAmount; // declare `marketplaceAmount`, its value
            // will be calculated based on whether it is a
            // primary or secondary sale
        uint256 sellerAmount = _order.unitPrice; // sellerAmount is set equal to
            // price and reduced at each step by
            // subtracting fees, royalties and commissions, if any.
        address payable[] memory royaltyRecipients; // declare
            // `royaltyRecipients`, its value will be calculated based
            // on whether it is a primary or secondary sale
        uint256[] memory royaltyAmounts; // declare `royaltyAmounts`, its value
            // will be calculated based on whether it
            // is a primary or secondary sale
        bool checkSecondaryMarket = true;

        if (_order.collection.codehash == _ERC721SovreignV1CodeHash) {
            // it's a v1 721 token, check market registry
            (, bytes memory secondaryMarket) = _PRIMARY_MARKET_REGISTRY.call(
                abi.encodeWithSelector(
                    0x7abab711,
                    _order.collection,
                    _order.tokenId
                ) // bytes4(keccak256("secondaryMarketInfo(address,uint256)")) == 0x7abab711
            );

            checkSecondaryMarket = abi.decode(secondaryMarket, (bool));
        }

        /*----------------------------------------------------------*|
        |*  # PAY ROYALTIES                                         *|
        |*----------------------------------------------------------*/
        // > "Marketplaces that support this standard MUST pay royalties no
        // matter where the sale occurred or in what
        // currency" - https://eips.ethereum.org/EIPS/eip-2981.

        /*----------------------------------------------------------*|
        |*  # IF ROYALTIES SUPPORTED                                *|
        |*----------------------------------------------------------*/
        // The collection implements some royalty standard, otherwise the length
        // of the arrays returned would be 0.
        if (checkSecondaryMarket) {
            (royaltyRecipients, royaltyAmounts) = getRoyalty(_order.collection, _order.tokenId, _order.unitPrice);
        }
        
        uint256 royaltyRecipientsLength = royaltyRecipients.length; // assign to
            // memory variable to save gas
        if (royaltyRecipientsLength > 0) {
            if (_secondaryMarketFee > 0) {
                /*----------------------------------------------------------*|
                |*  # PAY MARKETPLACE FEE                                   *|
                |*----------------------------------------------------------*/
                marketplaceAmount = (_order.unitPrice * _secondaryMarketFee) / _BPS_DENOMINATOR;
                // subtracting primary or secondary fee amount from seller
                // amount, this is a security check (will revert
                // on underflow) as well as a variable assignment.
                sellerAmount -= marketplaceAmount; // subtract before external
                    // call
                _sendValue(_feeRecipient, marketplaceAmount);
            }

            do {
                royaltyRecipientsLength--;
                // subtracting royalty amount from seller amount, this is a
                // security check (will revert on
                // underflow) as well as a variable assignment.
                if(royaltyAmounts[royaltyRecipientsLength] > 0){
                    sellerAmount -= royaltyAmounts[royaltyRecipientsLength]; // subtract
                        // before external call
                    _sendValue(royaltyRecipients[royaltyRecipientsLength], royaltyAmounts[royaltyRecipientsLength]);
                }
            } while (royaltyRecipientsLength > 0);
        } else {
            //case primary
            marketplaceAmount = (_order.unitPrice * _primaryMarketFee) / _BPS_DENOMINATOR;
            sellerAmount -= marketplaceAmount; // subtract before external
            // call
            _sendValue(_feeRecipient, marketplaceAmount);
        }

        /*----------------------------------------------------------*|
        |*  # PAY ORDER COMMISSIONS (if any)                        *|
        |*----------------------------------------------------------*/
        uint256 commissionReceiversLength = _order.commissionReceivers.length; // assign
        if (commissionReceiversLength > 0) {
            do {
                commissionReceiversLength--;
                if(_order.commissionBps[commissionReceiversLength] > 0){
                    uint256 commissionAmount = (_order.commissionBps[commissionReceiversLength] * _order.unitPrice) / _BPS_DENOMINATOR; // calculate
                    sellerAmount -= commissionAmount; // subtract before external

                    _sendValue(_order.commissionReceivers[commissionReceiversLength], commissionAmount);
                }
            } while (commissionReceiversLength > 0);
        }

        /*----------------------------------------------------------*|
        |*  # PAY SELLER                                            *|
        |*----------------------------------------------------------*/
        _sendValue(_order.from, sellerAmount);

        /*----------------------------------------------------------*|
        |*  # TRANSFER NFT                                          *|
        |*----------------------------------------------------------*/

        _transferNFT(
            _order.collection,
            address(this),
            _order.operator, // buyer
            _order.tokenId,
            _order.erc1155Value
        );

        emit Trade(
            _order.collection,
            _order.tokenId,
            _order.from, // seller
            _id,
            _order.unitPrice,
            _order.erc1155Value
        );
    }

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

    /*----------------------------------------------------------*|
    |*  # ADMIN FUNCTIONS                                       *|
    |*----------------------------------------------------------*/

    /**
     * @param feeRecipient_ address (multisig) controlled by Ninfa that will
     * receive any market fees
     */
    function setFeeRecipient(address feeRecipient_) external onlyOwner {
        _feeRecipient = feeRecipient_;
    }

    /**
     * @notice sets market sale fees for NINFA_ERC721_V2 communal collection.
     * @param primaryOrdersFee_ fee BPS for primary market orders, set to 500
     * BPS (5% shares) at deployment.
     * @param primaryOffersFee_ fee BPS for primary market offers, set to 500
     * BPS (5% shares) at deployment.
     */
    function setMarketFees(
        uint256 primaryOrdersFee_,
        uint256 primaryOffersFee_,
        uint256 secondaryMarketFee_
    )
        external
        onlyOwner
    {
        _primaryOrdersFee = primaryOrdersFee_;
        _primaryOffersFee = primaryOffersFee_;
        _secondaryMarketFee = secondaryMarketFee_;
    }

    function orders(uint256 _orderId) external view returns (_Order memory) {
        return _orders[_orderId];
    }

    /*----------------------------------------------------------*|
    |*  # VIEW FUNCTIONS                                        *|
    |*----------------------------------------------------------*/

    /**
     * @dev See {IERC165-supportsInterface}.
     * Interface ID for IERC165 == 0x01ffc9a7
     * Return value from `onERC1155Received` call if a contract accepts receipt
     * (i.e
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`).
     * In all other cases the ERC1155TokenReceiver rules MUST be followed as
     * appropriate for the implementation (i.e.
     * safe, custom and/or hybrid).
     * Interface ID for IERC721Receiver. A wallet/broker/auction application
     * MUST implement the wallet interface if it
     * will accept safe transfers.
     */
    function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
        return interfaceId == 0x01ffc9a7 || interfaceId == 0xf23a6e61 || interfaceId == 0x150b7a02;
    }

    /*----------------------------------------------------------*|
    |*  # CONSTRUCTOR                                           *|
    |*----------------------------------------------------------*/

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`
     * @param _royaltyRegistry see https://royaltyregistry.xyz/lookup for public
     * addresses
     */
    constructor(
        address _royaltyRegistry,
        address _primaryMarketRegistry,
        bytes32 ERC721SovreignV1CodeHash
    )
        RoyaltyEngineV1(_royaltyRegistry)
    {
        _PRIMARY_MARKET_REGISTRY = _primaryMarketRegistry;
        _ERC721SovreignV1CodeHash = ERC721SovreignV1CodeHash;
    }
}

/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

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

/**
 *
 * @title Counters                                           *
 *                                                           *
 * @dev Stripped down version of OpenZeppelin Contracts       *
 * v4.4.1 (utils/Counters.sol), identical to                 *
 * CountersUpgradeable.sol being a library. Provides         *
 * counters that can only be incremented.                    *
 * Used to track the total supply of ERC721 ids.             *
 * @dev Include with `using Counters for Counters.Counter;`  *
 *                                                           *
 * @custom:security-contact tech@ninfa.io                    *
 *
 */
/**
 * @title Counters
 * @dev Stripped down version of OpenZeppelin Contracts v4.4.1
 * (utils/Counters.sol), identical to
 * CountersUpgradeable.sol being a library. Provides counters that can only be
 * incremented. Used to track the total
 * supply of ERC721 ids.
 * @dev Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        uint256 _value; // default: 0
    }

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

    /// @dev if implementing ERC721A there could be an overflow risk by removing
    /// overflow protection with `unchecked`,
    /// unless we limit the amount of tokens that can be minted, or require that
    /// totalsupply be less than 2^256 - 1
    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }
}

/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

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

import "./specs/IRoyaltyRegistry.sol";
import "./specs/IRoyaltySplitter.sol";
import "./specs/IManifold.sol";
import "./specs/IRarible.sol";
import "./specs/IFoundation.sol";
import "./specs/ISuperRare.sol";
import "./specs/IEIP2981.sol";
import "./specs/INinfaRoyalty.sol";
import "./specs/IZoraOverride.sol";
import "./specs/IArtBlocksOverride.sol";
import "./specs/IKODAV2Override.sol";

/**
 *
 * @title RoyaltyEngineV1                                    *
 *                                                           *
 * @notice Custom implementation of Manifold RoyaltyEngineV1 *
 *                                                           *
 * @dev > "Marketplaces may choose to directly inherit the   *
 * Royalty Engine to save a bit of gas".                     *
 *                                                           *
 * @dev ERC165 was removed because interface selector will   *
 * be different from Manifold's (0xcb23f816) and this engine *
 * implementation is not meant for used by other contracts   *
 *                                                           *
 * @author Fork of Manifold's RoyaltyRegistryV1              *
 *                                                           *
 * @custom:security-contact tech@ninfa.io                    *
 *
 */

contract RoyaltyEngineV1 {
    /**
     * @dev ROYALTY_REGISTRY could be a hardcoded constant, however using an
     * immutable variable
     * is useful for deploying the engine onto other (test) networks where its
     * address differs from Mainnet
     */
    address internal immutable ROYALTY_REGISTRY;
    address internal constant SUPERRARE_REGISTRY = 0x17B0C8564E53f22364A6C8de6F7ca5CE9BEa4e5D;
    address internal constant SUPERRARE_V1 = 0x41A322b28D0fF354040e2CbC676F0320d8c8850d;
    address internal constant SUPERRARE_V2 = 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0;

    error Unauthorized();
    error InvalidAmount(uint256 amount);
    error LengthMismatch(uint256 recipients, uint256 bps); // only used in
        // RoyaltyEngineV1

    /**
     * Get the royalties for a given token and sale amount.
     *
     * @param tokenAddress - address of token
     * @param tokenId - id of token
     * @param value - sale value of token
     * Returns two arrays, first is the list of royalty recipients, second is
     * the amounts for each recipient.
     */
    function getRoyalty(
        address tokenAddress,
        uint256 tokenId,
        uint256 value
    )
        internal
        returns (address payable[] memory recipients, uint256[] memory amounts)
    {
        /**
         * @dev Control-flow hijack and gas griefing vulnerability within
         * Manifold's RoyaltyEngine, mitigated in
         * https://github.com/manifoldxyz/royalty-registry-solidity/commit/c5ba6db3e04e0b364f7afd7aae853a25542a7439.
         *      "To mitigate the griefing vector and other potential
         * vulnerabilities, limit the gas by default that
         * _getRoyalty is given to at most 50,000 gas, but certainly no more
         * than 100,000 gas."
         *      -
         * https://githubrecord.com/issue/manifoldxyz/royalty-registry-solidity/17/1067105243
         *      However, Ninfa's ERC-2981 implementation (ERC2981N) needs to write to
         * storage upon primary sales, this consumes
         * 800,000 at most gas,
         *      while it only reads from storage upon secondary sales, see
         * {ERC2981N-rotaltyInfo}
         */
        try this._getRoyalty{ gas: 1_000_000 }(tokenAddress, tokenId, value) returns (
            address payable[] memory _recipients, uint256[] memory _amounts
        ) {
            return (_recipients, _amounts);
        } catch {
            revert("Royalty lookup failed");
        }
    }

    /**
     * @dev Get the royalty for a given token
     * @dev the original RoyaltyEngineV1 has been modified by removing the
     * _specCache and the associated code,
     * using try catch statements is very cheap, no need to store `_specCache`
     * mapping, see
     * {RoyaltyEngineV1-_specCache}.
     * - https://www.reddit.com/r/ethdev/comments/szot8r/comment/hy5vsxb/
     * @dev EIP-2981 standard lookup is performed first unlike Manifold's
     * implementation, as it is the most prevalent
     * royalty standard as well as the one being used by Ninfa's collections
     * @return recipients array and amounts array, if no royalty standard has
     * been found, the returned arrays will be
     * empty
     */
    function _getRoyalty(
        address tokenAddress,
        uint256 tokenId,
        uint256 value
    )
        external
        returns (address payable[] memory recipients, uint256[] memory amounts)
    {
        address royaltyAddress = IRoyaltyRegistry(ROYALTY_REGISTRY).getRoyaltyLookupAddress(tokenAddress);

        try INinfaRoyalty(royaltyAddress).ninfaRoyaltyInfo(tokenId, value) returns (
            address payable[] memory recipients_, uint256[] memory bps_
        ) {
            require(recipients_.length == bps_.length);
            return (recipients_, _computeAmounts(value, bps_));
        } catch { }

        try IEIP2981(royaltyAddress).royaltyInfo(tokenId, value) returns (address recipient, uint256 amount) {
            if (amount > value) revert InvalidAmount(amount);
            uint32 recipientSize;
            assembly {
                recipientSize := extcodesize(recipient)
            }
            if (recipientSize > 0) {
                try IRoyaltySplitter(recipient).getRecipients() returns (Recipient[] memory splitRecipients) {
                    recipients = new address payable[](splitRecipients.length);
                    amounts = new uint256[](splitRecipients.length);
                    uint256 sum = 0;
                    uint256 splitRecipientsLength = splitRecipients.length;
                    for (uint256 i = 0; i < splitRecipientsLength;) {
                        Recipient memory splitRecipient = splitRecipients[i];
                        recipients[i] = payable(splitRecipient.recipient);
                        uint256 splitAmount = splitRecipient.bps * amount / 10_000;
                        amounts[i] = splitAmount;
                        sum += splitAmount;
                        unchecked {
                            ++i;
                        }
                    }
                    // sum can be less than amount, otherwise small-value listings can break
                    require(sum <= amount, "Invalid split");

                    return (recipients, amounts);
                } catch {}
            }

            try
                IRoyaltySplitter(royaltyAddress).getRecipients(tokenId)
            returns (Recipient[] memory royaltyInfo) {
                uint256 splitRecipientsLength = royaltyInfo.length;
                recipients = new address payable[](splitRecipientsLength);
                amounts = new uint256[](splitRecipientsLength);
                uint256 sum;

                for (uint256 i; i < splitRecipientsLength; ) {
                    Recipient memory splitRecipient = royaltyInfo[i];
                    recipients[i] = payable(splitRecipient.recipient);
                    uint256 splitAmount = (splitRecipient.bps * amount) / 10000;
                    amounts[i] = splitAmount;
                    sum += splitAmount;
                    unchecked {
                        ++i;
                    }
                }
                // sum can be less than amount, otherwise small-value listings can break
                require(sum <= amount, "Invalid split");

                return (recipients, amounts);
            } catch {
                // Supports EIP2981. Return amounts
                recipients = new address payable[](1);
                amounts = new uint256[](1);
                recipients[0] = payable(recipient);
                amounts[0] = amount;

                return (recipients, amounts);
            }
        } catch { }

        try IManifold(royaltyAddress).getRoyalties(tokenId) returns (
            address payable[] memory recipients_, uint256[] memory bps
        ) {
            // Supports manifold interface.  Compute amounts
            require(recipients_.length == bps.length);
            return (recipients_, _computeAmounts(value, bps));
        } catch { }

        // SuperRare handling
        if (tokenAddress == SUPERRARE_V1 || tokenAddress == SUPERRARE_V2) {
            try ISuperRareRegistry(SUPERRARE_REGISTRY).tokenCreator(tokenAddress, tokenId) returns (
                address payable creator
            ) {
                try ISuperRareRegistry(SUPERRARE_REGISTRY).calculateRoyaltyFee(tokenAddress, tokenId, value) returns (
                    uint256 amount
                ) {
                    recipients = new address payable[](1);
                    amounts = new uint256[](1);
                    recipients[0] = creator;
                    amounts[0] = amount;
                    return (recipients, amounts);
                } catch { }
            } catch { }
        }

        try IRaribleV2(royaltyAddress).getRaribleV2Royalties(tokenId) returns (IRaribleV2.Part[] memory royalties) {
            // Supports rarible v2 interface. Compute amounts
            recipients = new address payable[](royalties.length);
            amounts = new uint256[](royalties.length);
            uint256 totalAmount;
            for (uint256 i = 0; i < royalties.length; i++) {
                recipients[i] = royalties[i].account;
                amounts[i] = (value * royalties[i].value) / 10_000;
                totalAmount += amounts[i];
            }
            if (totalAmount > value) revert InvalidAmount(totalAmount);
            return (recipients, amounts);
        } catch { }
        try IRaribleV1(royaltyAddress).getFeeRecipients(tokenId) returns (address payable[] memory recipients_) {
            // Supports rarible v1 interface. Compute amounts
            recipients_ = IRaribleV1(royaltyAddress).getFeeRecipients(tokenId);
            try IRaribleV1(royaltyAddress).getFeeBps(tokenId) returns (uint256[] memory bps) {
                if (recipients_.length != bps.length) {
                    revert LengthMismatch(recipients_.length, bps.length);
                }
                return (recipients_, _computeAmounts(value, bps));
            } catch { }
        } catch { }
        try IFoundation(royaltyAddress).getFees(tokenId) returns (
            address payable[] memory recipients_, uint256[] memory bps
        ) {
            // Supports foundation interface.  Compute amounts
            if (recipients_.length != bps.length) {
                revert LengthMismatch(recipients_.length, bps.length);
            }
            return (recipients_, _computeAmounts(value, bps));
        } catch { }
        try IZoraOverride(royaltyAddress).convertBidShares(tokenAddress, tokenId) returns (
            address payable[] memory recipients_, uint256[] memory bps
        ) {
            // Support Zora override
            if (recipients_.length != bps.length) {
                revert LengthMismatch(recipients_.length, bps.length);
            }
            return (recipients_, _computeAmounts(value, bps));
        } catch { }
        try IArtBlocksOverride(royaltyAddress).getRoyalties(tokenAddress, tokenId) returns (
            address payable[] memory recipients_, uint256[] memory bps
        ) {
            // Support Art Blocks override
            if (recipients_.length != bps.length) {
                revert LengthMismatch(recipients_.length, bps.length);
            }
            return (recipients_, _computeAmounts(value, bps));
        } catch { }
        try IKODAV2Override(royaltyAddress).getKODAV2RoyaltyInfo(tokenAddress, tokenId, value) returns (
            address payable[] memory _recipients, uint256[] memory _amounts
        ) {
            // Support KODA V2 override
            if (_recipients.length != _amounts.length) {
                revert LengthMismatch(_recipients.length, _amounts.length);
            }
            return (_recipients, _amounts);
        } catch { }

        // No supported royalties configured
        return (recipients, amounts);
    }

    /**
     * Compute royalty amounts
     */
    function _computeAmounts(uint256 value, uint256[] memory bps) private pure returns (uint256[] memory amounts) {
        amounts = new uint256[](bps.length);
        uint256 totalAmount;
        for (uint256 i = 0; i < bps.length; i++) {
            amounts[i] = (value * bps[i]) / 10_000;
            totalAmount += amounts[i];
        }
        if (totalAmount > value) revert InvalidAmount(totalAmount);
        return amounts;
    }

    constructor(address _royaltyRegistry) {
        ROYALTY_REGISTRY = _royaltyRegistry;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

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

    event OwnershipTransferred(address previousOwner, address newOwner);

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

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

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/// @author: manifold.xyz

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

/**
 * @dev Royalty registry interface
 */
interface IRoyaltyRegistry is IERC165 {
    event RoyaltyOverride(address owner, address tokenAddress, address royaltyAddress);

    /**
     * Override the location of where to look up royalty information for a given
     * token contract.
     * Allows for backwards compatibility and implementation of royalty logic
     * for contracts that did not previously
     * support them.
     *
     * @param tokenAddress    - The token address you wish to override
     * @param royaltyAddress  - The royalty override address
     */
    function setRoyaltyLookupAddress(address tokenAddress, address royaltyAddress) external returns (bool);

    /**
     * Returns royalty address location.  Returns the tokenAddress by default,
     * or the override if it exists
     *
     * @param tokenAddress    - The token address you are looking up the royalty
     * for
     */
    function getRoyaltyLookupAddress(address tokenAddress) external view returns (address);

    /**
     * Returns the token address that an overrideAddress is set for.
     * Note: will not be accurate if the override was created before this
     * function was added.
     *
     * @param overrideAddress - The override address you are looking up the
     * token for
     */
    function getOverrideLookupTokenAddress(address overrideAddress) external view returns (address);

    /**
     * Whether or not the message sender can override the royalty address for
     * the given token address
     *
     * @param tokenAddress    - The token address you are looking up the royalty
     * for
     */
    function overrideAllowed(address tokenAddress) external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/// @author: manifold.xyz
struct Recipient {
    address payable recipient;
    uint16 bps;
}

interface IRoyaltySplitter {
    /**
     * @dev Get the splitter recipients;
     */
    function getRecipients() external view returns (Recipient[] memory);

    function getRecipients(
        uint256 tokenId
    ) external view returns (Recipient[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/// @author: manifold.xyz

/**
 * @dev Royalty interface for creator core classes
 */
interface IManifold {
    /**
     * @dev Get royalites of a token.  Returns list of receivers and basisPoints
     *
     *  bytes4(keccak256('getRoyalties(uint256)')) == 0xbb3bafd6
     *
     *  => 0xbb3bafd6 = 0xbb3bafd6
     */
    function getRoyalties(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

interface IRaribleV1 {
    /*
     * bytes4(keccak256('getFeeBps(uint256)')) == 0x0ebd4c7f
     * bytes4(keccak256('getFeeRecipients(uint256)')) == 0xb9c4d9fb
     *
     * => 0x0ebd4c7f ^ 0xb9c4d9fb == 0xb7799584
     */
    function getFeeBps(uint256 id) external view returns (uint256[] memory);

    function getFeeRecipients(uint256 id) external view returns (address payable[] memory);
}

interface IRaribleV2 {
    /*
     *  bytes4(keccak256('getRaribleV2Royalties(uint256)')) == 0xcad96cca
     */
    struct Part {
        address payable account;
        uint96 value;
    }

    function getRaribleV2Royalties(uint256 id) external view returns (Part[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

interface IFoundation {
    /*
     *  bytes4(keccak256('getFees(uint256)')) == 0xd5a06d4c
     *
     *  => 0xd5a06d4c = 0xd5a06d4c
     */
    function getFees(uint256 tokenId) external view returns (address payable[] memory, uint256[] memory);
}

interface IFoundationTreasuryNode {
    function getFoundationTreasury() external view returns (address payable);
}

interface IFoundationTreasury {
    function isAdmin(address account) external view returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

interface ISuperRareRegistry {
    /**
     * @dev Get the royalty fee percentage for a specific ERC721 contract.
     * @param _contractAddress address ERC721Contract address.
     * @param _tokenId uint256 token ID.
     * @return uint8 wei royalty fee.
     */
    function getERC721TokenRoyaltyPercentage(
        address _contractAddress,
        uint256 _tokenId
    )
        external
        view
        returns (uint8);

    /**
     * @dev Utililty function to calculate the royalty fee for a token.
     * @param _contractAddress address ERC721Contract address.
     * @param _tokenId uint256 token ID.
     * @param _amount uint256 wei amount.
     * @return uint256 wei fee.
     */
    function calculateRoyaltyFee(
        address _contractAddress,
        uint256 _tokenId,
        uint256 _amount
    )
        external
        view
        returns (uint256);

    /**
     * @dev Get the token creator which will receive royalties of the given
     * token
     * @param _contractAddress address ERC721Contract address.
     * @param _tokenId uint256 token ID.
     */
    function tokenCreator(address _contractAddress, uint256 _tokenId) external view returns (address payable);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/**
 * EIP-2981
 */
interface IEIP2981 {
    /**
     * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
     *
     * => 0x2a55205a = 0x2a55205a
     */
    function royaltyInfo(uint256 tokenId, uint256 value) external view returns (address, uint256);
}

File 12 of 16 : INinfaRoyalty.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/**
 * EIP-2981
 */
interface INinfaRoyalty {
    /**
     * bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
     *
     * => 0x2a55205a = 0x2a55205a
     */
    function ninfaRoyaltyInfo(
        uint256 tokenId,
        uint256 value
    )
        external
        returns (address payable[] memory, uint256[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/**
 * Paired down version of the Zora Market interface
 */
interface IZoraMarket {
    struct ZoraDecimal {
        uint256 value;
    }

    struct ZoraBidShares {
        // % of sale value that goes to the _previous_ owner of the nft
        ZoraDecimal prevOwner;
        // % of sale value that goes to the original creator of the nft
        ZoraDecimal creator;
        // % of sale value that goes to the seller (current owner) of the nft
        ZoraDecimal owner;
    }

    function bidSharesForToken(uint256 tokenId) external view returns (ZoraBidShares memory);
}

/**
 * Paired down version of the Zora Media interface
 */
interface IZoraMedia {
    /**
     * Auto-generated accessors of public variables
     */
    function marketContract() external view returns (address);

    function previousTokenOwners(uint256 tokenId) external view returns (address);

    function tokenCreators(uint256 tokenId) external view returns (address);

    /**
     * ERC721 function
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);
}

/**
 * Interface for a Zora media override
 */
interface IZoraOverride {
    /**
     * @dev Convert bid share configuration of a Zora Media token into an array
     * of receivers and bps values
     *      Does not support prevOwner and sell-on amounts as that is specific
     * to Zora marketplace implementation
     *      and requires updates on the Zora Media and Marketplace to update the
     * sell-on amounts/previous owner values.
     *      An off-Zora marketplace sale will break the sell-on functionality.
     */
    function convertBidShares(
        address media,
        uint256 tokenId
    )
        external
        view
        returns (address payable[] memory, uint256[] memory);
}

File 14 of 16 : IArtBlocksOverride.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

/**
 *  Interface for an Art Blocks override
 */
interface IArtBlocksOverride {
    /**
     * @dev Get royalites of a token at a given tokenAddress.
     *      Returns array of receivers and basisPoints.
     *
     *  bytes4(keccak256('getRoyalties(address,uint256)')) == 0x9ca7dc7a
     *
     *  => 0x9ca7dc7a = 0x9ca7dc7a
     */
    function getRoyalties(
        address tokenAddress,
        uint256 tokenId
    )
        external
        view
        returns (address payable[] memory, uint256[] memory);
}

// SPDX-License-Identifier: MIT

/// @author: knownorigin.io

pragma solidity 0.8.20;

interface IKODAV2 {
    function editionOfTokenId(uint256 _tokenId) external view returns (uint256 _editionNumber);

    function artistCommission(uint256 _editionNumber)
        external
        view
        returns (address _artistAccount, uint256 _artistCommission);

    function editionOptionalCommission(uint256 _editionNumber)
        external
        view
        returns (uint256 _rate, address _recipient);
}

interface IKODAV2Override {
    /// @notice Emitted when the royalties fee changes
    event CreatorRoyaltiesFeeUpdated(uint256 _oldCreatorRoyaltiesFee, uint256 _newCreatorRoyaltiesFee);

    /// @notice For the given KO NFT and token ID, return the addresses and the
    /// amounts to pay
    function getKODAV2RoyaltyInfo(
        address _tokenAddress,
        uint256 _id,
        uint256 _amount
    )
        external
        view
        returns (address payable[] memory, uint256[] memory);

    /// @notice Allows the owner() to update the creator royalties
    function updateCreatorRoyalties(uint256 _creatorRoyaltiesFee) external;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.20;

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

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "src/=src/",
    "test/=test/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 4194304,
    "details": {
      "constantOptimizer": true,
      "yul": true,
      "yulDetails": {
        "stackAllocation": true,
        "optimizerSteps": "dhfoDgvulfnTUtnIf"
      }
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_royaltyRegistry","type":"address"},{"internalType":"address","name":"_primaryMarketRegistry","type":"address"},{"internalType":"bytes32","name":"ERC721SovreignV1CodeHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InvalidAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"recipients","type":"uint256"},{"internalType":"uint256","name":"bps","type":"uint256"}],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"OfferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"OfferDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"OfferUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OrderDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OrderUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"erc1155Value","type":"uint256"}],"name":"Trade","type":"event"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"_getRoyalty","outputs":[{"internalType":"address payable[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"},{"internalType":"uint256","name":"_offerId","type":"uint256"},{"internalType":"uint256[]","name":"_commissionBps","type":"uint256[]"},{"internalType":"address[]","name":"_commissionReceivers","type":"address[]"}],"name":"acceptListedTokenOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collection","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_unitPrice","type":"uint256"}],"name":"createOffer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offerId","type":"uint256"}],"name":"deleteOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"deleteOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_buyer","type":"address"},{"internalType":"uint256","name":"_erc1155Value","type":"uint256"}],"name":"fillOrder","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offerId","type":"uint256"},{"internalType":"uint256","name":"_erc1155Amount","type":"uint256"},{"internalType":"uint256","name":"_unitPrice","type":"uint256"}],"name":"lowerOfferPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"},{"internalType":"uint256","name":"_erc1155RedeemAmount","type":"uint256"}],"name":"lowerOrderErc1155Amount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"offers","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"unitPrice","type":"uint256"},{"internalType":"uint256","name":"erc1155Value","type":"uint256"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"orders","outputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"unitPrice","type":"uint256"},{"internalType":"uint256","name":"erc1155Value","type":"uint256"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256[]","name":"commissionBps","type":"uint256[]"},{"internalType":"address[]","name":"commissionReceivers","type":"address[]"}],"internalType":"struct NinfaMarketplace._Order","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_offerId","type":"uint256"},{"internalType":"uint256","name":"_erc1155Value","type":"uint256"},{"internalType":"uint256","name":"_unitPrice","type":"uint256"}],"name":"raiseOfferPrice","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"feeRecipient_","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"primaryOrdersFee_","type":"uint256"},{"internalType":"uint256","name":"primaryOffersFee_","type":"uint256"},{"internalType":"uint256","name":"secondaryMarketFee_","type":"uint256"}],"name":"setMarketFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"},{"internalType":"uint256[]","name":"_commissionBps","type":"uint256[]"},{"internalType":"address[]","name":"_commissionReceivers","type":"address[]"}],"name":"setOrderCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_erc1155RedeemAmount","type":"uint256"},{"internalType":"uint256","name":"_unitPrice","type":"uint256"},{"internalType":"uint256","name":"_orderId","type":"uint256"}],"name":"updateOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_orderId","type":"uint256"},{"internalType":"uint256","name":"_unitPrice","type":"uint256"}],"name":"updateOrderPrice","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c06040523462000043576200001f620000186200011d565b9162000172565b6040516142136200026e82396080518161365d015260a05181612cdd015261421390f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200008057604052565b62000048565b906200009d6200009560405190565b92836200005e565b565b6001600160a01b031690565b90565b6001600160a01b0381165b036200004357565b905051906200009d82620000ae565b80620000b9565b905051906200009d82620000d0565b90916060828403126200004357620000ab620001038484620000c1565b93620001138160208601620000c1565b93604001620000d7565b620001406200448180380380620001348162000086565b928339810190620000e6565b909192565b90600019905b9181191691161790565b9062000166620000ab6200016e9290565b825462000145565b9055565b90620001836200009d93926200018e565b60a052600762000155565b620001986200019d565b608052565b6200009d3362000200565b906001600160a01b03906200014b565b620000ab906200009f906001600160a01b031682565b620000ab90620001b8565b620000ab90620001ce565b90620001f8620000ab6200016e92620001d9565b8254620001a8565b6000546001600160a01b0316906200021a816000620001e4565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091620002686200024a60405190565b928392836001600160a01b0391821681529116602082015260400190565b0390a156fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461017257806311a003271461016d578063150b7a021461016857806317a288df146101635780631efeff841461015e5780632b1708b0146101595780632ede65df1461015457806332689eb81461014f5780633596188d1461014a5780635333a0a4146101455780635e9e78d014610140578063715018a61461013b57806374268ff2146101365780637fea43b8146101315780638a72ea6a1461012c5780638b4c042a146101275780638da5cb5b14610122578063a85c38ef1461011d578063c402b96514610118578063e74b981b14610113578063f23a6e611461010e5763f2fde38b0361017757610ca6565b610c87565b610b83565b610b58565b610ae5565b610974565b61095b565b61092a565b6107e9565b6106e5565b6106cd565b6106a9565b61068d565b610611565b6105fd565b6105bd565b6105a9565b610560565b610524565b610308565b610225565b6101cd565b600080fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361017757565b905035906101b48261017c565b565b90602082820312610177576101ca916101a7565b90565b34610177576101fa6101e86101e33660046101b6565b612eaa565b60405191829182901515815260200190565b0390f35b806101a0565b905035906101b4826101fe565b90602082820312610177576101ca91610204565b346101775761023d610238366004610211565b611190565b604051005b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff81166101a0565b905035906101b48261025b565b909182601f830112156101775781359167ffffffffffffffff831161017757602001926001830284011161017757565b90608082820312610177576102c98183610277565b926102d78260208501610277565b926102e58360408301610204565b92606082013567ffffffffffffffff8111610177576103049201610284565b9091565b34610177576101fa61032761031e3660046102b4565b93929092612585565b604051918291827fffffffff00000000000000000000000000000000000000000000000000000000909116815260200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff8211176103c957604052565b61035a565b906101b46103db60405190565b9283610389565b67ffffffffffffffff81116103c95760208091020190565b9092919261040f61040a826103e2565b6103ce565b938185526020808601920283019281841161017757915b8383106104335750505050565b602080916104418486610204565b815201920191610426565b9080601f83011215610177578160206101ca933591016103fa565b9092919261047761040a826103e2565b938185526020808601920283019281841161017757915b83831061049b5750505050565b602080916104a98486610277565b81520192019161048e565b9080601f83011215610177578160206101ca93359101610467565b91606083830312610177576104e48284610204565b92602081013567ffffffffffffffff8111610177578361050591830161044c565b92604082013567ffffffffffffffff8111610177576101ca92016104b4565b346101775761023d6105373660046104cf565b9161160c565b9190604083820312610177576101ca906105578185610204565b93602001610204565b346101775761023d61057336600461053d565b906113ce565b9091606082840312610177576101ca6105928484610204565b936105a08160208601610204565b93604001610204565b61023d6105b7366004610579565b916119fe565b346101775761023d6105d0366004610579565b91610d07565b9091606082840312610177576101ca6105ef8484610204565b936105a08160208601610277565b61023d61060b3660046105d6565b91611df8565b346101775761023d610624366004610579565b91612e43565b906080828203126101775761063f8183610204565b9261064d8260208501610204565b92604081013567ffffffffffffffff8111610177578361066e91830161044c565b92606082013567ffffffffffffffff8111610177576101ca92016104b4565b346101775761023d6106a036600461062a565b92919091611c19565b346101775761023d6106bc36600461053d565b9061127f565b600091031261017757565b34610177576106dd3660046106c2565b61023d612fb4565b346101775761023d6106f8366004610211565b61190e565b9091606082840312610177576101ca6105928484610277565b0190565b9061073a610733610729845190565b8084529260200190565b9260200190565b9060005b81811061074b5750505090565b90919261077e610777600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9460200190565b92910161073e565b90610795610733610729845190565b9060005b8181106107a65750505090565b9091926107bc6107776001928651815260200190565b929101610799565b60408082526101ca9391926107db9184019061071a565b916020818403910152610786565b34610177576108026107fc3660046106fd565b91613648565b906101fa61080f60405190565b928392836107c4565b6101ca6101ca6101ca9290565b9061082f90610818565b600052602052604060002090565b6101ca9081565b6101ca905461083d565b610859906009610825565b61086281610844565b9161086f60018301610844565b9161087c60028201610844565b916101ca60046108a3600385015473ffffffffffffffffffffffffffffffffffffffff1690565b93015473ffffffffffffffffffffffffffffffffffffffff1690565b909594926101b4946108f161090e926108ea6080966108e360a088019c6000890152565b6020870152565b6040850152565b73ffffffffffffffffffffffffffffffffffffffff166060830152565b019073ffffffffffffffffffffffffffffffffffffffff169052565b34610177576101fa610945610940366004610211565b61084e565b9161095295939560405190565b958695866108bf565b346101775761023d61096e366004610579565b91611b57565b34610177576109843660046106c2565b6101fa6109a660005473ffffffffffffffffffffffffffffffffffffffff1690565b6040519182918273ffffffffffffffffffffffffffffffffffffffff909116815260200190565b906109dc610733610729845190565b9060005b8181106109ed5750505090565b909192610a19610777600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9291016109e0565b805182526101ca9160e0610ac36101008301610a4260208601516020860152565b610a5160408601516040860152565b60608581015173ffffffffffffffffffffffffffffffffffffffff169085015260808581015173ffffffffffffffffffffffffffffffffffffffff169085015260a08581015173ffffffffffffffffffffffffffffffffffffffff169085015260c085015184820360c0860152610786565b9201519060e08184039101526109cd565b60208082526101ca92910190610a21565b34610177576101fa610b00610afb366004610211565b612e93565b60405191829182610ad4565b919060a08382031261017757610b228184610277565b92610b308260208301610204565b926101ca610b418460408501610204565b93610b4f8160608601610277565b93608001610204565b61023d610b66366004610b0c565b93929092611741565b90602082820312610177576101ca91610277565b346101775761023d610b96366004610b6f565b612df1565b67ffffffffffffffff81116103c957602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b90826000939282370152565b90929192610bf261040a82610b9b565b93818552602085019082840111610177576101b492610bd6565b9080601f83011215610177578160206101ca93359101610be2565b91909160a08184031261017757610c3e8382610277565b92610c4c8160208401610277565b92610c5a8260408501610204565b92610c688360608301610204565b92608082013567ffffffffffffffff8111610177576101ca9201610c0c565b34610177576101fa610327610c9d366004610c27565b939290926120d1565b346101775761023d610cb9366004610b6f565b613014565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b90610cfc6101ca610d0392610818565b8254610cbe565b9055565b610d216101b493610d1a600193826113ce565b6008610825565b01610cec565b90610d42610d36610729845490565b92600052602060002090565b9060005b818110610d535750505090565b909192610d77610d70600192610d6887610844565b815260200190565b9460010190565b929101610d46565b906101ca91610d27565b906101b4610da392610d9a60405190565b93848092610d7f565b0383610389565b90610db9610d36610729845490565b9060005b818110610dca5750505090565b909192610e12610d70600192610df4875473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101610dbd565b906101ca91610daa565b906101b4610da392610e3560405190565b93848092610e1a565b6101ca6101006103ce565b906101b4610f766007610e5a610e3e565b94610e6b610e6782610844565b8752565b610e81610e7a60018301610844565b6020880152565b610e97610e9060028301610844565b6040880152565b610ed8610ebb600383015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166060880152565b610f19610efc600483015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166080880152565b610f5a610f3d600583015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1660a0880152565b610f70610f6960068301610d89565b60c0880152565b01610e24565b60e0840152565b6101ca90610e49565b1561017757565b91906008610ce2910291610fc07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b9190610fd66101ca610d0393610818565b908354610f8d565b6101b491600091610fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190611024565b9290565b9180830292818404149015171561103757565b610fea565b818110611047575050565b806110556000600193610fde565b0161103c565b909182811061106957505050565b6101b4929061107790610d36565b908101910161103c565b906801000000000000000081116103c9578161109e6101b4935490565b9082815561105b565b60006101b491611081565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b906000036110f2576101b4906110a7565b6110b2565b600060076101b49261110b83808301610fde565b6111188360018301610fde565b6111258360028301610fde565b82600382015582600482015582600582015561114483600683016110e1565b016110e1565b906000036110f2576101b4906110f7565b6102426101ca6101ca9273ffffffffffffffffffffffffffffffffffffffff1690565b6101ca9061115b565b6101ca9061117e565b61123f60086111a76111a28483610825565b610f7d565b61120160006111fc8633956111f76111d961024260a089015173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff89165b14610f86565b610825565b61114a565b606081015173ffffffffffffffffffffffffffffffffffffffff169161122630611187565b6112396040611233855190565b94015190565b9361274e565b61127a7f91635156bba825be2f9a200b140420e4bee0d251f7d43bf956e63f74960030e09161126d60405190565b9182918290815260200190565b0390a1565b906112d99060016112946101ca856008610825565b610d21336111f16112bf610242600586015473ffffffffffffffffffffffffffffffffffffffff1690565b9173ffffffffffffffffffffffffffffffffffffffff1690565b61127a7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b9190820391821161103757565b6113276113216101ca9290565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526101ca9260a082019261138b9190611384906108ea565b6060830152565b60808183039101526000815260200190565b906113aa61040a83610b9b565b918252565b3d156113c9576113be3d61139d565b903d6000602084013e565b606090565b80916114db6008916114d66000806113e96101ca8888610825565b60046114be3392611433611417610242600584015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff86166111f1565b6114af60028201986114566114508261144b8d610844565b611307565b8b610cec565b600383015473ffffffffffffffffffffffffffffffffffffffff169563f242432a9061149561148f8a61148830611187565b9701610844565b92611314565b9461149f60405190565b978896602088019081520161134c565b60208201810382520382610389565b82602082019151925af16114d06113af565b50610f86565b610844565b906000916114ef6114eb84610818565b9190565b036115015761123f926111fc91610825565b50505061127a7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b81519167ffffffffffffffff83116103c95761155d610d366001926115578686611081565b60200190565b92049160005b8381106115705750505050565b60019060206115806101ca865190565b9401938184015501611563565b906101b491611532565b81519167ffffffffffffffff83116103c9576115bc610d366001926115578686611081565b92049160005b8381106115cf5750505050565b60019060206115f56101ca865173ffffffffffffffffffffffffffffffffffffffff1690565b94019381840155016115c2565b906101b491611597565b916007611664846112d9946111f733916116526008936111f16112bf61024260056116378a8a610825565b015473ffffffffffffffffffffffffffffffffffffffff1690565b600661165e8585610825565b0161158d565b01611602565b6101ca60a06103ce565b9073ffffffffffffffffffffffffffffffffffffffff90610ce2565b906116a06101ca610d0392611187565b8254611674565b6101b49190611714906080906004906116c8816116c2875190565b90610cec565b6116da600182016116c2602088015190565b6116ec600282016116c2604088015190565b61171a60038201611714606088015173ffffffffffffffffffffffffffffffffffffffff1690565b90611690565b0192015173ffffffffffffffffffffffffffffffffffffffff1690565b906101b4916116a7565b6117fc94936117c16117de926117a46117f79661179d61175f600290565b996117698b6130ba565b6117966000996117788b610818565b850361182a5761178883346111f1565b61179061166a565b9a8b0152565b6020890152565b6040870152565b73ffffffffffffffffffffffffffffffffffffffff166060850152565b73ffffffffffffffffffffffffffffffffffffffff166080830152565b6117f260096117ec856130a5565b90610825565b611737565b6130a5565b61127a7f682fd9923da5632e7c7702dabcfa626195d5f444833bc25f94e418e258e791869161126d60405190565b61183e346111f16114eb6101ca8988611019565b611788565b906101b46118a3600461185461166a565b94611861610e6782610844565b611870610e7a60018301610844565b61187f610e9060028301610844565b611637610ebb600383015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166080840152565b6101ca90611843565b6000906004906118d98382610fde565b6118e68360018301610fde565b6118f38360028301610fde565b8260038201550155565b906000036110f2576101b4906118c9565b6119aa60096119a56119286119238584610825565b6118c0565b61198b60408201611937815190565b90876000926119486114eb85610818565b036119d85760208501516119869250965b6111f76080339701966111f16112bf6102428a5173ffffffffffffffffffffffffffffffffffffffff1690565b6118fd565b5173ffffffffffffffffffffffffffffffffffffffff1690565b612d86565b61127a7f88686b85d6f2c3ab9a04e4f15a22fcfa025ffd97226dcf0a67cdf682def556769161126d60405190565b6119f8611986926119f26119ed602089015190565b915190565b90611019565b96611959565b9190611a8691611a81611a156101ca866009610825565b91611a41336111f16112bf610242600488015473ffffffffffffffffffffffffffffffffffffffff1690565b60016002840193611a5185610844565b611a5e6114eb6000610818565b03611ab457610d21346111f16114eb6101ca611a7b878701610844565b88611307565b610cec565b61127a7f7eff4a127d11f41398f54211d23467816d498336249c9103adb206d679f0e4829161126d60405190565b611ae8346111f16114eb6101ca611acb8b89611019565b611ae2611ad9898901610844565b6119f28d610844565b90611307565b610d21565b15611af457565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f68777900000000000000000000000000000000000000000000000000000000006044820152606490fd5b0390fd5b91611a8691611b6a6101ca856009610825565b913391611bb1611b94610242600487015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff851614611aed565b611bbb6000610818565b8103611bde5750806001611bd76119a59361144b838801610844565b9401610cec565b9290600182611ae8611bf4836119a59601610844565b96611c13611c0960028501996119f28b610844565b611ae28388611019565b97610cec565b919290926008611c2c6111a28583610825565b906009611c3c6119238883610825565b96611c5e60a085015173ffffffffffffffffffffffffffffffffffffffff1690565b3393908890611c6c866112bf565b1480611ddd575b80611d89575b611c8290610f86565b611c8b91610825565b6000611c969161114a565b611c9f91610825565b6000611caa916118fd565b815195611cb8602082015190565b60609093015160009073ffffffffffffffffffffffffffffffffffffffff1660809092015173ffffffffffffffffffffffffffffffffffffffff1693611cfc610e3e565b98611d0790838b0152565b6020890152611d1590610818565b604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e0830152611d7f6005610844565b906101b4926128ed565b50611c828a611dd56112bf6102426060611db9818d015173ffffffffffffffffffffffffffffffffffffffff1690565b94015173ffffffffffffffffffffffffffffffffffffffff1690565b149050611c79565b5089611df26114eb6101ca60006112338b5190565b14611c73565b90916101ca92600890611e0e6111a28584610825565b91843491611e1d602086015190565b90611e48611e4260009a8b94611e3286610818565b8b03611f72576119f26001610818565b856111f1565b611e618761144b6002611e5b8786610825565b01610844565b611e6d6114eb84610818565b03611f4e57611e7f926111fc91610825565b8583015193611ea5606085015173ffffffffffffffffffffffffffffffffffffffff1690565b90611ec7608086015173ffffffffffffffffffffffffffffffffffffffff1690565b9260c08601519560e0015196611edb610e3e565b998a01526020890152604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e0830152611d7f6004610844565b60029150611f6d92611f5f91610825565b016116c28661144b83610844565b611e7f565b8a90611019565b905051906101b4826101fe565b90929192611f9661040a826103e2565b938185526020808601920283019281841161017757915b838310611fba5750505050565b60208091611fc88486611f79565b815201920191611fad565b9080601f830112156101775781516101ca92602001611f86565b905051906101b48261025b565b9092919261200a61040a826103e2565b938185526020808601920283019281841161017757915b83831061202e5750505050565b6020809161203c8486611fed565b815201920191612021565b9080601f830112156101775781516101ca92602001611ffa565b90608082820312610177576120768183611f79565b926120848260208501611f79565b92604081015167ffffffffffffffff811161017757836120a5918301611fd3565b92606082015167ffffffffffffffff8111610177576101ca9201612047565b9190820180921161103757565b939092906120ee9060206120e3825190565b818301019101612061565b9492959160009491949761210189610818565b82036122895750506009906121196119238884610825565b878961213c606084015173ffffffffffffffffffffffffffffffffffffffff1690565b339590612148876112bf565b1480612272575b61215890610f86565b61216b8561144b6002611e5b8786610825565b6121776114eb84610818565b0361224e576121899261198691610825565b81612195602083015190565b9061219f91611019565b60809091015173ffffffffffffffffffffffffffffffffffffffff16946121c4610e3e565b998a01526020890152604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e08301526122376005610844565b90612241926128ed565b6101ca63f23a6e61611314565b6002915061226d9261225f91610825565b016116c28461144b83610844565b612189565b506121586122808386015190565b8914905061214f565b909495969761229b8195949395610818565b89036122b157506122ac97506124ac565b612241565b6123419750600195965061232b91949250610d21936122d46101ca8b6008610825565b956123166112bf6122fc60058a015473ffffffffffffffffffffffffffffffffffffffff1690565b9273ffffffffffffffffffffffffffffffffffffffff1690565b149182612393575b82612377575b5050610f86565b6116c2600284019161233c83610844565b6120c4565b61236f7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b0390a1612241565b61238b9192506110206114eb918801610844565b143880612324565b91506123b6600387015473ffffffffffffffffffffffffffffffffffffffff1690565b6123bf336112bf565b149161231e565b6101b4919061249c9060e0906007906123e1816116c2875190565b6123f3600182016116c2602088015190565b612405600282016116c2604088015190565b61242d60038201611714606088015173ffffffffffffffffffffffffffffffffffffffff1690565b61245560048201611714608088015173ffffffffffffffffffffffffffffffffffffffff1690565b61247d6005820161171460a088015173ffffffffffffffffffffffffffffffffffffffff1690565b6124956006820161248f60c088015190565b9061158d565b0192015190565b90611602565b906101b4916123c6565b919492959360016124bc816130ba565b6124c5906130a5565b9633916124d0610e3e565b9788526020880152604087015273ffffffffffffffffffffffffffffffffffffffff16606086015273ffffffffffffffffffffffffffffffffffffffff16608085015273ffffffffffffffffffffffffffffffffffffffff1660a084015260c083015260e0820152612543826008610825565b9061254d916124a2565b7f7e82078c35b6665b9d320ebeaa6c266960fad5b802c5558cf7df60c4769af95b9061257860405190565b908152806020810161127a565b9261259d919294612594600090565b5081019061062a565b9491926000949194906125af82610818565b81036125d75750906125c46125ca9792610818565b926124ac565b6101ca63150b7a02611314565b95949350915060096125ec6119238783610825565b928061260f606086015173ffffffffffffffffffffffffffffffffffffffff1690565b339390899061261d866112bf565b14806126fc575b61262d90610f86565b61263691610825565b90612640916118fd565b602084015160809094015173ffffffffffffffffffffffffffffffffffffffff169361266a610e3e565b9861267590838b0152565b602089015261268390610818565b604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e08301526126ed6005610844565b906126f7926128ed565b6125ca565b5061262d8b6127116114eb611020878c015190565b149050612624565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526060810192916101b49160400152565b0152565b906101b4949293600491612760600090565b50600095869561276f87610818565b81036127a557506114be926114af9161278b6342842e0e611314565b9361279560405190565b9687956020870190815201612719565b6114be936114af9261149563f242432a611314565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101b49160200152565b8015156101a0565b905051906101b4826127e4565b90602082820312610177576101ca916127ec565b6101ca612710610818565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612851570490565b612818565b8015611037577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906128b9825190565b8110156128ca576020809102010190565b612881565b9081526060810193926101b492909160409161274a905b6020830152565b909160208201916128fc835190565b908192612907606090565b8060019182936060860194612930865173ffffffffffffffffffffffffffffffffffffffff1690565b3f6129416114eb6101ca6007610844565b14612cd7575b612ca2575b82519687916000986129606114eb8b610818565b1115612c545750506129726006610844565b61297e6114eb89610818565b11612c0a575b83805b612b7e575b505050505b60e083019061299f82515190565b90816129ad6114eb88610818565b11612ac9575b5050506119ed612a51612a56612a51612a71946129ec60808801996119a58b5173ffffffffffffffffffffffffffffffffffffffff1690565b61198b612a0d825173ffffffffffffffffffffffffffffffffffffffff1690565b612a1630611187565b98612a3860a082015173ffffffffffffffffffffffffffffffffffffffff1690565b9a81019a6040612a468d5190565b92019a6112398c5190565b955190565b955173ffffffffffffffffffffffffffffffffffffffff1690565b94612ac4612ab1612aab612aa57f09c7d1ab159dbdc16054d51213cf8ab76b507ff896aca64379b18e54ce7959ef96611187565b96610818565b96611187565b96612abb60405190565b938493846128cf565b0390a4565b9081805b612ad8575b506129b3565b15612b69575b612ae88691612856565b91828960c08801612b01612afd8483516128b0565b5190565b612b0d6114eb8c610818565b11612b1e575b505050919082612acd565b61198b612b59612b52612b44869e956119f26119ed612afd612b619a6119a599516128b0565b612b4c61280d565b90612847565b8094611307565b9b88516128b0565b388981612b13565b612b7286610818565b8111612ade5780612ad2565b15612bf5575b612b8e8791612856565b9081612b9d612afd82866128b0565b612ba96114eb8b610818565b11612bb6575b5084612987565b98612bf0612bcc8792611ae2612afd8e896128b0565b9a6119a5612bea612afd612be361198b858c6128b0565b93896128b0565b91611187565b612baf565b612bfe87610818565b8111612b84578061298c565b612c4f612c2f612c28612b44612c1e8d5190565b6119f26006610844565b809a611307565b986119a560035473ffffffffffffffffffffffffffffffffffffffff1690565b612984565b612b44919950612c9d9450612c7d9350612c769250612c718b5190565b611019565b8097611307565b956119a560035473ffffffffffffffffffffffffffffffffffffffff1690565b612991565b915050612cd0612cc6845173ffffffffffffffffffffffffffffffffffffffff1690565b85518951916131c7565b909161294c565b506000807f00000000000000000000000000000000000000000000000000000000000000006004612d568a6114af8b612d3c612d3688612d30637abab711945173ffffffffffffffffffffffffffffffffffffffff1690565b95015190565b91611314565b92612d4660405190565b95869460208601908152016127ba565b82602082019151925af150612d81612d6c6113af565b6020612d76825190565b8183010191016127f9565b612947565b60006101b492612d9e612d998394611187565b611187565b90612da860405190565b90818003925af16114d06113af565b6101b490612de6612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6111f1336112bf565b6101b4906003611690565b6101b490612db7565b906101b49291612e22612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b49291612e35612e3c926004610cec565b6005610cec565b6006610cec565b906101b49291612dfa565b612e56610e3e565b906000825260208080808080808089016000815201600081520160008152016000815201600081520160608152016060905250565b6101ca612e4e565b6111a26101ca91612ea2612e8b565b506008610825565b612eb76301ffc9a7611314565b7fffffffff00000000000000000000000000000000000000000000000000000000821614908115612f29575b8115612eed575090565b9050612f25612eff63150b7a02611314565b917fffffffff000000000000000000000000000000000000000000000000000000001690565b1490565b9050612f3863f23a6e61611314565b7fffffffff0000000000000000000000000000000000000000000000000000000082161490612ee3565b612f84612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b4612fa2565b6102426101ca6101ca9290565b6101ca90612f8c565b6101b4612faf6000612f99565b613049565b6101b4612f62565b6101b490612fe2612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b490612faf612ff66102426000612f99565b73ffffffffffffffffffffffffffffffffffffffff83161415610f86565b6101b490612fbc565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101b49160209061090e565b60005473ffffffffffffffffffffffffffffffffffffffff169061306e816000611690565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09161127a61309c60405190565b9283928361301d565b60006101ca916130b3600090565b5001610844565b6101b4906116c260006130cd6001610818565b92019161071683610844565b909291926130e961040a826103e2565b938185526020808601920283019281841161017757915b83831061310d5750505050565b6020809161311b8486611fed565b815201920191613100565b9080601f830112156101775781516101ca926020016130d9565b91909160408184031261017757805167ffffffffffffffff8111610177578361316a918301613126565b92602082015167ffffffffffffffff8111610177576101ca9201611fd3565b73ffffffffffffffffffffffffffffffffffffffff90911681526060810193926101b492909160409161274a906128e6565b6040513d6000823e3d90fd5b60009193926131d4606090565b5061320d836131e230611187565b637fea43b86132186131f6620f4240610818565b9561320060405190565b9a8b988997889560e01b90565b855260048501613189565b0393f19182600091829461328b575b506114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f526f79616c7479206c6f6f6b7570206661696c656400000000000000000000006044820152606490fd5b9093506132a9913d8091833e6132a18183610389565b810190613140565b9238613227565b90602082820312610177576101ca91611fed565b9081526040810192916101b49160200152565b9190604083820312610177576101ca906132f18185611fed565b93602001611f79565b6133076101ca6101ca9290565b63ffffffff1690565b61ffff81166101a0565b905051906101b482613310565b9190916040818403126101775761335c61334160406103ce565b93600061334e8285611fed565b90860152602080930161331a565b90830152565b9092919261337261040a826103e2565b93818552604060208601920283019281841161017757915b8383106133975750505050565b60206040916133a68486613327565b81520192019161338a565b9080601f830112156101775781516101ca92602001613362565b9060208282031261017757815167ffffffffffffffff8111610177576101ca92016133b1565b906113aa61040a836103e2565b369037565b906101b4613419613413846133f1565b936103e2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001602084016133fe565b6101ca6101ca6101ca9261ffff1690565b1561345c57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642073706c6974000000000000000000000000000000000000006044820152606490fd5b90602082820312610177576101ca91611f79565b6bffffffffffffffffffffffff81166101a0565b905051906101b4826134cf565b9190916040818403126101775761335c61350a60406103ce565b9360006135178285611fed565b9086015260208093016134e3565b9092919261353561040a826103e2565b93818552604060208601920283019281841161017757915b83831061355a5750505050565b602060409161356984866134f0565b81520192019161354d565b9080601f830112156101775781516101ca92602001613525565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201613574565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146110375760010190565b6101ca6101ca6101ca926bffffffffffffffffffffffff1690565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201613126565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201611fd3565b60609392849291906136996020613681612d997f0000000000000000000000000000000000000000000000000000000000000000611187565b63de5488af9061369060405190565b93849260e01b90565b825273ffffffffffffffffffffffffffffffffffffffff8616600483015260249082905afa8015613b06576136d69160009161416a575b50611187565b906136e082611187565b9163d6a1919a6136f96136f260405190565b9160e01b90565b81526000818061370d868a600484016132c4565b038183885af180600092839261414c575b50613e3f575050632a55205a6137366136f260405190565b81526040818061374a868a600484016132c4565b0381875afa806000928392614119575b50613e8857505063bb3bafd66137726136f260405190565b815260048101869052600081602481875afa806000928392613e6a575b50613e3f5750506137b46102427341a322b28d0ff354040e2cbc676f0320d8c8850d90565b73ffffffffffffffffffffffffffffffffffffffff8516148015613e0c575b613cb5575b63cad96cca6137e96136f260405190565b815260048101869052600081602481875afa60009181613c92575b50613b26575063b9c4d9fb61381860405190565b6138228260e01b90565b815260048101879052600081602481885afa60009181613b0b575b50613a4d575b505063d5a06d4c6138566136f260405190565b815260048101869052600081602481875afa806000928392613a2f575b506139b957505063f662207461388b6136f260405190565b81526000818061389f8989600484016127ba565b0381875afa806000928392613a11575b506139b9575050639ca7dc7a6138c76136f260405190565b8152600081806138db8989600484016127ba565b0381875afa8060009283926139f3575b506139b9575050600093929161320d915061391b63fbda03ab9161390e60405190565b9788968795869560e01b90565b03915afa9081600091829361399c575b506139365750509190565b8051919450915061394b6114eb6101ca865190565b03613954579190565b6139606119ed84925190565b90611b5361396d60405190565b9283927fab8b67c6000000000000000000000000000000000000000000000000000000008452600484016132c4565b9092506139b2913d8091833e6132a18183610389565b913861392b565b9650975050925050506139ca845190565b6139d86114eb6101ca855190565b036139e757906101ca91614188565b506139606119ed845190565b9092613a0992503d8091833e6132a18183610389565b9091386138eb565b9092613a2792503d8091833e6132a18183610389565b9091386138af565b9092613a4592503d8091833e6132a18183610389565b909138613873565b50613a5a6136f260405190565b815260048101869052600081602481875afa908115613b0657600091613ae5575b50630ebd4c7f613a8d6136f260405190565b815260048101879052600081602481885afa60009181613ac2575b5015600003613843579650975050925050506139ca845190565b613ade91923d8091833e613ad68183610389565b810190613622565b9038613aa8565b613b00913d8091833e613af88183610389565b8101906135fc565b38613a7b565b6131bb565b613b1f91923d8091833e613af88183610389565b903861383d565b9750509350505050613b3e613b39845190565b613403565b90613b4a613b39855190565b936000926000613b5981610818565b945b613b666101ca855190565b861015613c3a57613c2e613c3491613c1b613c0e613c03613bfd613bf86020613be48e613bde8d8f838f613bbd90613ba183613bc3956128b0565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b926128b0565b9073ffffffffffffffffffffffffffffffffffffffff169052565b8d6128b0565b5101516bffffffffffffffffffffffff1690565b6135e1565b8a611019565b612b4c612710610818565b613c188a8d6128b0565b52565b613c28612afd898c6128b0565b906120c4565b956135b4565b94613b5b565b9391945050613c47915090565b8111613c5257509190565b611b5390613c5f60405190565b9182917f3728b83d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b613cae91923d8091833e613ca68183610389565b81019061358e565b9038613804565b613cd3612d997317b0c8564e53f22364a6c8de6f7ca5ce9bea4e5d81565b63b85ed7e490613cec613ce560405190565b9260e01b90565b825260208280613d008a8a600484016127ba565b0381845afa60009281613ddc575b50613d1b575b50506137d8565b6020613d309163860110f59061369060405190565b82528180613d43898d8d60048501613189565b03915afa60009181613dac575b5015600003613d14579650975050505050506114eb613d6f6001610818565b91613c18613da6613d88613d8286613403565b95613403565b96613da1600091613bc3613d9b84610818565b896128b0565b610818565b866128b0565b613dce91925060203d8111613dd5575b613dc68183610389565b8101906134bb565b9038613d50565b503d613dbc565b613dfe91935060203d8111613e05575b613df68183610389565b8101906132b0565b9138613d0e565b503d613dec565b5073b932a70a57673d89f4acffbe830e8ed7f75fb9e073ffffffffffffffffffffffffffffffffffffffff8516146137d3565b95509750509150506101ca9250613e65613e57865190565b6111f16114eb6101ca865190565b614188565b9092613e8092503d8091833e6132a18183610389565b90913861378f565b9593965097509250831161410c5760009384918291883b613eb5613eab856132fa565b9163ffffffff1690565b11614029575b613eec9450613ede63fd90e897613ed160405190565b9687948593849360e01b90565b835260048301526024820190565b03915afa849281614005575b50613f3e5750506114eb90613c18613da6613f136001610818565b94613da1613f32613f2c613f2689613403565b98613403565b99611187565b613bc3613d9b84610818565b9290939450613f4b845190565b93613f5585613403565b90613f5f86613403565b96855b88885b881015613fe957613fda88613f659361233c613fe194613c18613fd2613c038e612c718f8f8f91613fc4602092613bc38e613bbd613fa682613fcd996128b0565b519586015173ffffffffffffffffffffffffffffffffffffffff1690565b015161ffff1690565b613444565b9485926128b0565b9760010190565b969050613f62565b5093509550509250613ffe6114eb6114eb9390565b1115613455565b6140229193503d8087833e61401a8183610389565b8101906133cb565b9138613ef8565b9161404d9061403e612d998b97949697611187565b63d78d610b9061369060405190565b825260049082905afa8791816140f0575b50158714614070575092918591613ebb565b95975050505050614082613b39835190565b9361408e613b39845190565b9461409882610818565b936140a1815190565b95855b88885b881015613fe957613fda886140a79361233c6140e894613c18613fd2613c038e612c718f8f8f91613fc4602092613bc38e613bbd613fa682613fcd996128b0565b9690506140a4565b6141059192503d808a833e61401a8183610389565b903861405e565b611b5383613c5f60405190565b90925061413d915060403d8111614145575b6141358183610389565b8101906132d7565b90913861375a565b503d61412b565b909261416292503d8091833e6132a18183610389565b90913861371e565b614182915060203d8111613e0557613df68183610389565b386136d0565b9190614195613b39825190565b926000916141a36000610818565b925b6141b06101ca835190565b8410156141fd576141f16141f7916141e46141da613c036141d4612afd8a896128b0565b88611019565b613c18888b6128b0565b613c28612afd878a6128b0565b936135b4565b926141a5565b93949392506142099050565b8111613c5257509056000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000167a296135c0067903d4c099806405f6c316442e618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461017257806311a003271461016d578063150b7a021461016857806317a288df146101635780631efeff841461015e5780632b1708b0146101595780632ede65df1461015457806332689eb81461014f5780633596188d1461014a5780635333a0a4146101455780635e9e78d014610140578063715018a61461013b57806374268ff2146101365780637fea43b8146101315780638a72ea6a1461012c5780638b4c042a146101275780638da5cb5b14610122578063a85c38ef1461011d578063c402b96514610118578063e74b981b14610113578063f23a6e611461010e5763f2fde38b0361017757610ca6565b610c87565b610b83565b610b58565b610ae5565b610974565b61095b565b61092a565b6107e9565b6106e5565b6106cd565b6106a9565b61068d565b610611565b6105fd565b6105bd565b6105a9565b610560565b610524565b610308565b610225565b6101cd565b600080fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361017757565b905035906101b48261017c565b565b90602082820312610177576101ca916101a7565b90565b34610177576101fa6101e86101e33660046101b6565b612eaa565b60405191829182901515815260200190565b0390f35b806101a0565b905035906101b4826101fe565b90602082820312610177576101ca91610204565b346101775761023d610238366004610211565b611190565b604051005b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff81166101a0565b905035906101b48261025b565b909182601f830112156101775781359167ffffffffffffffff831161017757602001926001830284011161017757565b90608082820312610177576102c98183610277565b926102d78260208501610277565b926102e58360408301610204565b92606082013567ffffffffffffffff8111610177576103049201610284565b9091565b34610177576101fa61032761031e3660046102b4565b93929092612585565b604051918291827fffffffff00000000000000000000000000000000000000000000000000000000909116815260200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff8211176103c957604052565b61035a565b906101b46103db60405190565b9283610389565b67ffffffffffffffff81116103c95760208091020190565b9092919261040f61040a826103e2565b6103ce565b938185526020808601920283019281841161017757915b8383106104335750505050565b602080916104418486610204565b815201920191610426565b9080601f83011215610177578160206101ca933591016103fa565b9092919261047761040a826103e2565b938185526020808601920283019281841161017757915b83831061049b5750505050565b602080916104a98486610277565b81520192019161048e565b9080601f83011215610177578160206101ca93359101610467565b91606083830312610177576104e48284610204565b92602081013567ffffffffffffffff8111610177578361050591830161044c565b92604082013567ffffffffffffffff8111610177576101ca92016104b4565b346101775761023d6105373660046104cf565b9161160c565b9190604083820312610177576101ca906105578185610204565b93602001610204565b346101775761023d61057336600461053d565b906113ce565b9091606082840312610177576101ca6105928484610204565b936105a08160208601610204565b93604001610204565b61023d6105b7366004610579565b916119fe565b346101775761023d6105d0366004610579565b91610d07565b9091606082840312610177576101ca6105ef8484610204565b936105a08160208601610277565b61023d61060b3660046105d6565b91611df8565b346101775761023d610624366004610579565b91612e43565b906080828203126101775761063f8183610204565b9261064d8260208501610204565b92604081013567ffffffffffffffff8111610177578361066e91830161044c565b92606082013567ffffffffffffffff8111610177576101ca92016104b4565b346101775761023d6106a036600461062a565b92919091611c19565b346101775761023d6106bc36600461053d565b9061127f565b600091031261017757565b34610177576106dd3660046106c2565b61023d612fb4565b346101775761023d6106f8366004610211565b61190e565b9091606082840312610177576101ca6105928484610277565b0190565b9061073a610733610729845190565b8084529260200190565b9260200190565b9060005b81811061074b5750505090565b90919261077e610777600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9460200190565b92910161073e565b90610795610733610729845190565b9060005b8181106107a65750505090565b9091926107bc6107776001928651815260200190565b929101610799565b60408082526101ca9391926107db9184019061071a565b916020818403910152610786565b34610177576108026107fc3660046106fd565b91613648565b906101fa61080f60405190565b928392836107c4565b6101ca6101ca6101ca9290565b9061082f90610818565b600052602052604060002090565b6101ca9081565b6101ca905461083d565b610859906009610825565b61086281610844565b9161086f60018301610844565b9161087c60028201610844565b916101ca60046108a3600385015473ffffffffffffffffffffffffffffffffffffffff1690565b93015473ffffffffffffffffffffffffffffffffffffffff1690565b909594926101b4946108f161090e926108ea6080966108e360a088019c6000890152565b6020870152565b6040850152565b73ffffffffffffffffffffffffffffffffffffffff166060830152565b019073ffffffffffffffffffffffffffffffffffffffff169052565b34610177576101fa610945610940366004610211565b61084e565b9161095295939560405190565b958695866108bf565b346101775761023d61096e366004610579565b91611b57565b34610177576109843660046106c2565b6101fa6109a660005473ffffffffffffffffffffffffffffffffffffffff1690565b6040519182918273ffffffffffffffffffffffffffffffffffffffff909116815260200190565b906109dc610733610729845190565b9060005b8181106109ed5750505090565b909192610a19610777600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9291016109e0565b805182526101ca9160e0610ac36101008301610a4260208601516020860152565b610a5160408601516040860152565b60608581015173ffffffffffffffffffffffffffffffffffffffff169085015260808581015173ffffffffffffffffffffffffffffffffffffffff169085015260a08581015173ffffffffffffffffffffffffffffffffffffffff169085015260c085015184820360c0860152610786565b9201519060e08184039101526109cd565b60208082526101ca92910190610a21565b34610177576101fa610b00610afb366004610211565b612e93565b60405191829182610ad4565b919060a08382031261017757610b228184610277565b92610b308260208301610204565b926101ca610b418460408501610204565b93610b4f8160608601610277565b93608001610204565b61023d610b66366004610b0c565b93929092611741565b90602082820312610177576101ca91610277565b346101775761023d610b96366004610b6f565b612df1565b67ffffffffffffffff81116103c957602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b90826000939282370152565b90929192610bf261040a82610b9b565b93818552602085019082840111610177576101b492610bd6565b9080601f83011215610177578160206101ca93359101610be2565b91909160a08184031261017757610c3e8382610277565b92610c4c8160208401610277565b92610c5a8260408501610204565b92610c688360608301610204565b92608082013567ffffffffffffffff8111610177576101ca9201610c0c565b34610177576101fa610327610c9d366004610c27565b939290926120d1565b346101775761023d610cb9366004610b6f565b613014565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b90610cfc6101ca610d0392610818565b8254610cbe565b9055565b610d216101b493610d1a600193826113ce565b6008610825565b01610cec565b90610d42610d36610729845490565b92600052602060002090565b9060005b818110610d535750505090565b909192610d77610d70600192610d6887610844565b815260200190565b9460010190565b929101610d46565b906101ca91610d27565b906101b4610da392610d9a60405190565b93848092610d7f565b0383610389565b90610db9610d36610729845490565b9060005b818110610dca5750505090565b909192610e12610d70600192610df4875473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101610dbd565b906101ca91610daa565b906101b4610da392610e3560405190565b93848092610e1a565b6101ca6101006103ce565b906101b4610f766007610e5a610e3e565b94610e6b610e6782610844565b8752565b610e81610e7a60018301610844565b6020880152565b610e97610e9060028301610844565b6040880152565b610ed8610ebb600383015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166060880152565b610f19610efc600483015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166080880152565b610f5a610f3d600583015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1660a0880152565b610f70610f6960068301610d89565b60c0880152565b01610e24565b60e0840152565b6101ca90610e49565b1561017757565b91906008610ce2910291610fc07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b9190610fd66101ca610d0393610818565b908354610f8d565b6101b491600091610fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190611024565b9290565b9180830292818404149015171561103757565b610fea565b818110611047575050565b806110556000600193610fde565b0161103c565b909182811061106957505050565b6101b4929061107790610d36565b908101910161103c565b906801000000000000000081116103c9578161109e6101b4935490565b9082815561105b565b60006101b491611081565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b906000036110f2576101b4906110a7565b6110b2565b600060076101b49261110b83808301610fde565b6111188360018301610fde565b6111258360028301610fde565b82600382015582600482015582600582015561114483600683016110e1565b016110e1565b906000036110f2576101b4906110f7565b6102426101ca6101ca9273ffffffffffffffffffffffffffffffffffffffff1690565b6101ca9061115b565b6101ca9061117e565b61123f60086111a76111a28483610825565b610f7d565b61120160006111fc8633956111f76111d961024260a089015173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff89165b14610f86565b610825565b61114a565b606081015173ffffffffffffffffffffffffffffffffffffffff169161122630611187565b6112396040611233855190565b94015190565b9361274e565b61127a7f91635156bba825be2f9a200b140420e4bee0d251f7d43bf956e63f74960030e09161126d60405190565b9182918290815260200190565b0390a1565b906112d99060016112946101ca856008610825565b610d21336111f16112bf610242600586015473ffffffffffffffffffffffffffffffffffffffff1690565b9173ffffffffffffffffffffffffffffffffffffffff1690565b61127a7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b9190820391821161103757565b6113276113216101ca9290565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526101ca9260a082019261138b9190611384906108ea565b6060830152565b60808183039101526000815260200190565b906113aa61040a83610b9b565b918252565b3d156113c9576113be3d61139d565b903d6000602084013e565b606090565b80916114db6008916114d66000806113e96101ca8888610825565b60046114be3392611433611417610242600584015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff86166111f1565b6114af60028201986114566114508261144b8d610844565b611307565b8b610cec565b600383015473ffffffffffffffffffffffffffffffffffffffff169563f242432a9061149561148f8a61148830611187565b9701610844565b92611314565b9461149f60405190565b978896602088019081520161134c565b60208201810382520382610389565b82602082019151925af16114d06113af565b50610f86565b610844565b906000916114ef6114eb84610818565b9190565b036115015761123f926111fc91610825565b50505061127a7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b81519167ffffffffffffffff83116103c95761155d610d366001926115578686611081565b60200190565b92049160005b8381106115705750505050565b60019060206115806101ca865190565b9401938184015501611563565b906101b491611532565b81519167ffffffffffffffff83116103c9576115bc610d366001926115578686611081565b92049160005b8381106115cf5750505050565b60019060206115f56101ca865173ffffffffffffffffffffffffffffffffffffffff1690565b94019381840155016115c2565b906101b491611597565b916007611664846112d9946111f733916116526008936111f16112bf61024260056116378a8a610825565b015473ffffffffffffffffffffffffffffffffffffffff1690565b600661165e8585610825565b0161158d565b01611602565b6101ca60a06103ce565b9073ffffffffffffffffffffffffffffffffffffffff90610ce2565b906116a06101ca610d0392611187565b8254611674565b6101b49190611714906080906004906116c8816116c2875190565b90610cec565b6116da600182016116c2602088015190565b6116ec600282016116c2604088015190565b61171a60038201611714606088015173ffffffffffffffffffffffffffffffffffffffff1690565b90611690565b0192015173ffffffffffffffffffffffffffffffffffffffff1690565b906101b4916116a7565b6117fc94936117c16117de926117a46117f79661179d61175f600290565b996117698b6130ba565b6117966000996117788b610818565b850361182a5761178883346111f1565b61179061166a565b9a8b0152565b6020890152565b6040870152565b73ffffffffffffffffffffffffffffffffffffffff166060850152565b73ffffffffffffffffffffffffffffffffffffffff166080830152565b6117f260096117ec856130a5565b90610825565b611737565b6130a5565b61127a7f682fd9923da5632e7c7702dabcfa626195d5f444833bc25f94e418e258e791869161126d60405190565b61183e346111f16114eb6101ca8988611019565b611788565b906101b46118a3600461185461166a565b94611861610e6782610844565b611870610e7a60018301610844565b61187f610e9060028301610844565b611637610ebb600383015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166080840152565b6101ca90611843565b6000906004906118d98382610fde565b6118e68360018301610fde565b6118f38360028301610fde565b8260038201550155565b906000036110f2576101b4906118c9565b6119aa60096119a56119286119238584610825565b6118c0565b61198b60408201611937815190565b90876000926119486114eb85610818565b036119d85760208501516119869250965b6111f76080339701966111f16112bf6102428a5173ffffffffffffffffffffffffffffffffffffffff1690565b6118fd565b5173ffffffffffffffffffffffffffffffffffffffff1690565b612d86565b61127a7f88686b85d6f2c3ab9a04e4f15a22fcfa025ffd97226dcf0a67cdf682def556769161126d60405190565b6119f8611986926119f26119ed602089015190565b915190565b90611019565b96611959565b9190611a8691611a81611a156101ca866009610825565b91611a41336111f16112bf610242600488015473ffffffffffffffffffffffffffffffffffffffff1690565b60016002840193611a5185610844565b611a5e6114eb6000610818565b03611ab457610d21346111f16114eb6101ca611a7b878701610844565b88611307565b610cec565b61127a7f7eff4a127d11f41398f54211d23467816d498336249c9103adb206d679f0e4829161126d60405190565b611ae8346111f16114eb6101ca611acb8b89611019565b611ae2611ad9898901610844565b6119f28d610844565b90611307565b610d21565b15611af457565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f68777900000000000000000000000000000000000000000000000000000000006044820152606490fd5b0390fd5b91611a8691611b6a6101ca856009610825565b913391611bb1611b94610242600487015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff851614611aed565b611bbb6000610818565b8103611bde5750806001611bd76119a59361144b838801610844565b9401610cec565b9290600182611ae8611bf4836119a59601610844565b96611c13611c0960028501996119f28b610844565b611ae28388611019565b97610cec565b919290926008611c2c6111a28583610825565b906009611c3c6119238883610825565b96611c5e60a085015173ffffffffffffffffffffffffffffffffffffffff1690565b3393908890611c6c866112bf565b1480611ddd575b80611d89575b611c8290610f86565b611c8b91610825565b6000611c969161114a565b611c9f91610825565b6000611caa916118fd565b815195611cb8602082015190565b60609093015160009073ffffffffffffffffffffffffffffffffffffffff1660809092015173ffffffffffffffffffffffffffffffffffffffff1693611cfc610e3e565b98611d0790838b0152565b6020890152611d1590610818565b604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e0830152611d7f6005610844565b906101b4926128ed565b50611c828a611dd56112bf6102426060611db9818d015173ffffffffffffffffffffffffffffffffffffffff1690565b94015173ffffffffffffffffffffffffffffffffffffffff1690565b149050611c79565b5089611df26114eb6101ca60006112338b5190565b14611c73565b90916101ca92600890611e0e6111a28584610825565b91843491611e1d602086015190565b90611e48611e4260009a8b94611e3286610818565b8b03611f72576119f26001610818565b856111f1565b611e618761144b6002611e5b8786610825565b01610844565b611e6d6114eb84610818565b03611f4e57611e7f926111fc91610825565b8583015193611ea5606085015173ffffffffffffffffffffffffffffffffffffffff1690565b90611ec7608086015173ffffffffffffffffffffffffffffffffffffffff1690565b9260c08601519560e0015196611edb610e3e565b998a01526020890152604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e0830152611d7f6004610844565b60029150611f6d92611f5f91610825565b016116c28661144b83610844565b611e7f565b8a90611019565b905051906101b4826101fe565b90929192611f9661040a826103e2565b938185526020808601920283019281841161017757915b838310611fba5750505050565b60208091611fc88486611f79565b815201920191611fad565b9080601f830112156101775781516101ca92602001611f86565b905051906101b48261025b565b9092919261200a61040a826103e2565b938185526020808601920283019281841161017757915b83831061202e5750505050565b6020809161203c8486611fed565b815201920191612021565b9080601f830112156101775781516101ca92602001611ffa565b90608082820312610177576120768183611f79565b926120848260208501611f79565b92604081015167ffffffffffffffff811161017757836120a5918301611fd3565b92606082015167ffffffffffffffff8111610177576101ca9201612047565b9190820180921161103757565b939092906120ee9060206120e3825190565b818301019101612061565b9492959160009491949761210189610818565b82036122895750506009906121196119238884610825565b878961213c606084015173ffffffffffffffffffffffffffffffffffffffff1690565b339590612148876112bf565b1480612272575b61215890610f86565b61216b8561144b6002611e5b8786610825565b6121776114eb84610818565b0361224e576121899261198691610825565b81612195602083015190565b9061219f91611019565b60809091015173ffffffffffffffffffffffffffffffffffffffff16946121c4610e3e565b998a01526020890152604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e08301526122376005610844565b90612241926128ed565b6101ca63f23a6e61611314565b6002915061226d9261225f91610825565b016116c28461144b83610844565b612189565b506121586122808386015190565b8914905061214f565b909495969761229b8195949395610818565b89036122b157506122ac97506124ac565b612241565b6123419750600195965061232b91949250610d21936122d46101ca8b6008610825565b956123166112bf6122fc60058a015473ffffffffffffffffffffffffffffffffffffffff1690565b9273ffffffffffffffffffffffffffffffffffffffff1690565b149182612393575b82612377575b5050610f86565b6116c2600284019161233c83610844565b6120c4565b61236f7fb8b459bc0688c37baf5f735d17f1711684bc14ab7db116f88bc18bf409b9309a9161126d60405190565b0390a1612241565b61238b9192506110206114eb918801610844565b143880612324565b91506123b6600387015473ffffffffffffffffffffffffffffffffffffffff1690565b6123bf336112bf565b149161231e565b6101b4919061249c9060e0906007906123e1816116c2875190565b6123f3600182016116c2602088015190565b612405600282016116c2604088015190565b61242d60038201611714606088015173ffffffffffffffffffffffffffffffffffffffff1690565b61245560048201611714608088015173ffffffffffffffffffffffffffffffffffffffff1690565b61247d6005820161171460a088015173ffffffffffffffffffffffffffffffffffffffff1690565b6124956006820161248f60c088015190565b9061158d565b0192015190565b90611602565b906101b4916123c6565b919492959360016124bc816130ba565b6124c5906130a5565b9633916124d0610e3e565b9788526020880152604087015273ffffffffffffffffffffffffffffffffffffffff16606086015273ffffffffffffffffffffffffffffffffffffffff16608085015273ffffffffffffffffffffffffffffffffffffffff1660a084015260c083015260e0820152612543826008610825565b9061254d916124a2565b7f7e82078c35b6665b9d320ebeaa6c266960fad5b802c5558cf7df60c4769af95b9061257860405190565b908152806020810161127a565b9261259d919294612594600090565b5081019061062a565b9491926000949194906125af82610818565b81036125d75750906125c46125ca9792610818565b926124ac565b6101ca63150b7a02611314565b95949350915060096125ec6119238783610825565b928061260f606086015173ffffffffffffffffffffffffffffffffffffffff1690565b339390899061261d866112bf565b14806126fc575b61262d90610f86565b61263691610825565b90612640916118fd565b602084015160809094015173ffffffffffffffffffffffffffffffffffffffff169361266a610e3e565b9861267590838b0152565b602089015261268390610818565b604088015273ffffffffffffffffffffffffffffffffffffffff16606087015273ffffffffffffffffffffffffffffffffffffffff16608086015273ffffffffffffffffffffffffffffffffffffffff1660a085015260c084015260e08301526126ed6005610844565b906126f7926128ed565b6125ca565b5061262d8b6127116114eb611020878c015190565b149050612624565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526060810192916101b49160400152565b0152565b906101b4949293600491612760600090565b50600095869561276f87610818565b81036127a557506114be926114af9161278b6342842e0e611314565b9361279560405190565b9687956020870190815201612719565b6114be936114af9261149563f242432a611314565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101b49160200152565b8015156101a0565b905051906101b4826127e4565b90602082820312610177576101ca916127ec565b6101ca612710610818565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612851570490565b612818565b8015611037577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b906128b9825190565b8110156128ca576020809102010190565b612881565b9081526060810193926101b492909160409161274a905b6020830152565b909160208201916128fc835190565b908192612907606090565b8060019182936060860194612930865173ffffffffffffffffffffffffffffffffffffffff1690565b3f6129416114eb6101ca6007610844565b14612cd7575b612ca2575b82519687916000986129606114eb8b610818565b1115612c545750506129726006610844565b61297e6114eb89610818565b11612c0a575b83805b612b7e575b505050505b60e083019061299f82515190565b90816129ad6114eb88610818565b11612ac9575b5050506119ed612a51612a56612a51612a71946129ec60808801996119a58b5173ffffffffffffffffffffffffffffffffffffffff1690565b61198b612a0d825173ffffffffffffffffffffffffffffffffffffffff1690565b612a1630611187565b98612a3860a082015173ffffffffffffffffffffffffffffffffffffffff1690565b9a81019a6040612a468d5190565b92019a6112398c5190565b955190565b955173ffffffffffffffffffffffffffffffffffffffff1690565b94612ac4612ab1612aab612aa57f09c7d1ab159dbdc16054d51213cf8ab76b507ff896aca64379b18e54ce7959ef96611187565b96610818565b96611187565b96612abb60405190565b938493846128cf565b0390a4565b9081805b612ad8575b506129b3565b15612b69575b612ae88691612856565b91828960c08801612b01612afd8483516128b0565b5190565b612b0d6114eb8c610818565b11612b1e575b505050919082612acd565b61198b612b59612b52612b44869e956119f26119ed612afd612b619a6119a599516128b0565b612b4c61280d565b90612847565b8094611307565b9b88516128b0565b388981612b13565b612b7286610818565b8111612ade5780612ad2565b15612bf5575b612b8e8791612856565b9081612b9d612afd82866128b0565b612ba96114eb8b610818565b11612bb6575b5084612987565b98612bf0612bcc8792611ae2612afd8e896128b0565b9a6119a5612bea612afd612be361198b858c6128b0565b93896128b0565b91611187565b612baf565b612bfe87610818565b8111612b84578061298c565b612c4f612c2f612c28612b44612c1e8d5190565b6119f26006610844565b809a611307565b986119a560035473ffffffffffffffffffffffffffffffffffffffff1690565b612984565b612b44919950612c9d9450612c7d9350612c769250612c718b5190565b611019565b8097611307565b956119a560035473ffffffffffffffffffffffffffffffffffffffff1690565b612991565b915050612cd0612cc6845173ffffffffffffffffffffffffffffffffffffffff1690565b85518951916131c7565b909161294c565b506000807f000000000000000000000000167a296135c0067903d4c099806405f6c316442e6004612d568a6114af8b612d3c612d3688612d30637abab711945173ffffffffffffffffffffffffffffffffffffffff1690565b95015190565b91611314565b92612d4660405190565b95869460208601908152016127ba565b82602082019151925af150612d81612d6c6113af565b6020612d76825190565b8183010191016127f9565b612947565b60006101b492612d9e612d998394611187565b611187565b90612da860405190565b90818003925af16114d06113af565b6101b490612de6612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6111f1336112bf565b6101b4906003611690565b6101b490612db7565b906101b49291612e22612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b49291612e35612e3c926004610cec565b6005610cec565b6006610cec565b906101b49291612dfa565b612e56610e3e565b906000825260208080808080808089016000815201600081520160008152016000815201600081520160608152016060905250565b6101ca612e4e565b6111a26101ca91612ea2612e8b565b506008610825565b612eb76301ffc9a7611314565b7fffffffff00000000000000000000000000000000000000000000000000000000821614908115612f29575b8115612eed575090565b9050612f25612eff63150b7a02611314565b917fffffffff000000000000000000000000000000000000000000000000000000001690565b1490565b9050612f3863f23a6e61611314565b7fffffffff0000000000000000000000000000000000000000000000000000000082161490612ee3565b612f84612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b4612fa2565b6102426101ca6101ca9290565b6101ca90612f8c565b6101b4612faf6000612f99565b613049565b6101b4612f62565b6101b490612fe2612ddd60005473ffffffffffffffffffffffffffffffffffffffff1690565b6101b490612faf612ff66102426000612f99565b73ffffffffffffffffffffffffffffffffffffffff83161415610f86565b6101b490612fbc565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101b49160209061090e565b60005473ffffffffffffffffffffffffffffffffffffffff169061306e816000611690565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09161127a61309c60405190565b9283928361301d565b60006101ca916130b3600090565b5001610844565b6101b4906116c260006130cd6001610818565b92019161071683610844565b909291926130e961040a826103e2565b938185526020808601920283019281841161017757915b83831061310d5750505050565b6020809161311b8486611fed565b815201920191613100565b9080601f830112156101775781516101ca926020016130d9565b91909160408184031261017757805167ffffffffffffffff8111610177578361316a918301613126565b92602082015167ffffffffffffffff8111610177576101ca9201611fd3565b73ffffffffffffffffffffffffffffffffffffffff90911681526060810193926101b492909160409161274a906128e6565b6040513d6000823e3d90fd5b60009193926131d4606090565b5061320d836131e230611187565b637fea43b86132186131f6620f4240610818565b9561320060405190565b9a8b988997889560e01b90565b855260048501613189565b0393f19182600091829461328b575b506114eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f526f79616c7479206c6f6f6b7570206661696c656400000000000000000000006044820152606490fd5b9093506132a9913d8091833e6132a18183610389565b810190613140565b9238613227565b90602082820312610177576101ca91611fed565b9081526040810192916101b49160200152565b9190604083820312610177576101ca906132f18185611fed565b93602001611f79565b6133076101ca6101ca9290565b63ffffffff1690565b61ffff81166101a0565b905051906101b482613310565b9190916040818403126101775761335c61334160406103ce565b93600061334e8285611fed565b90860152602080930161331a565b90830152565b9092919261337261040a826103e2565b93818552604060208601920283019281841161017757915b8383106133975750505050565b60206040916133a68486613327565b81520192019161338a565b9080601f830112156101775781516101ca92602001613362565b9060208282031261017757815167ffffffffffffffff8111610177576101ca92016133b1565b906113aa61040a836103e2565b369037565b906101b4613419613413846133f1565b936103e2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001602084016133fe565b6101ca6101ca6101ca9261ffff1690565b1561345c57565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642073706c6974000000000000000000000000000000000000006044820152606490fd5b90602082820312610177576101ca91611f79565b6bffffffffffffffffffffffff81166101a0565b905051906101b4826134cf565b9190916040818403126101775761335c61350a60406103ce565b9360006135178285611fed565b9086015260208093016134e3565b9092919261353561040a826103e2565b93818552604060208601920283019281841161017757915b83831061355a5750505050565b602060409161356984866134f0565b81520192019161354d565b9080601f830112156101775781516101ca92602001613525565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201613574565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146110375760010190565b6101ca6101ca6101ca926bffffffffffffffffffffffff1690565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201613126565b9060208282031261017757815167ffffffffffffffff8111610177576101ca9201611fd3565b60609392849291906136996020613681612d997f000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d611187565b63de5488af9061369060405190565b93849260e01b90565b825273ffffffffffffffffffffffffffffffffffffffff8616600483015260249082905afa8015613b06576136d69160009161416a575b50611187565b906136e082611187565b9163d6a1919a6136f96136f260405190565b9160e01b90565b81526000818061370d868a600484016132c4565b038183885af180600092839261414c575b50613e3f575050632a55205a6137366136f260405190565b81526040818061374a868a600484016132c4565b0381875afa806000928392614119575b50613e8857505063bb3bafd66137726136f260405190565b815260048101869052600081602481875afa806000928392613e6a575b50613e3f5750506137b46102427341a322b28d0ff354040e2cbc676f0320d8c8850d90565b73ffffffffffffffffffffffffffffffffffffffff8516148015613e0c575b613cb5575b63cad96cca6137e96136f260405190565b815260048101869052600081602481875afa60009181613c92575b50613b26575063b9c4d9fb61381860405190565b6138228260e01b90565b815260048101879052600081602481885afa60009181613b0b575b50613a4d575b505063d5a06d4c6138566136f260405190565b815260048101869052600081602481875afa806000928392613a2f575b506139b957505063f662207461388b6136f260405190565b81526000818061389f8989600484016127ba565b0381875afa806000928392613a11575b506139b9575050639ca7dc7a6138c76136f260405190565b8152600081806138db8989600484016127ba565b0381875afa8060009283926139f3575b506139b9575050600093929161320d915061391b63fbda03ab9161390e60405190565b9788968795869560e01b90565b03915afa9081600091829361399c575b506139365750509190565b8051919450915061394b6114eb6101ca865190565b03613954579190565b6139606119ed84925190565b90611b5361396d60405190565b9283927fab8b67c6000000000000000000000000000000000000000000000000000000008452600484016132c4565b9092506139b2913d8091833e6132a18183610389565b913861392b565b9650975050925050506139ca845190565b6139d86114eb6101ca855190565b036139e757906101ca91614188565b506139606119ed845190565b9092613a0992503d8091833e6132a18183610389565b9091386138eb565b9092613a2792503d8091833e6132a18183610389565b9091386138af565b9092613a4592503d8091833e6132a18183610389565b909138613873565b50613a5a6136f260405190565b815260048101869052600081602481875afa908115613b0657600091613ae5575b50630ebd4c7f613a8d6136f260405190565b815260048101879052600081602481885afa60009181613ac2575b5015600003613843579650975050925050506139ca845190565b613ade91923d8091833e613ad68183610389565b810190613622565b9038613aa8565b613b00913d8091833e613af88183610389565b8101906135fc565b38613a7b565b6131bb565b613b1f91923d8091833e613af88183610389565b903861383d565b9750509350505050613b3e613b39845190565b613403565b90613b4a613b39855190565b936000926000613b5981610818565b945b613b666101ca855190565b861015613c3a57613c2e613c3491613c1b613c0e613c03613bfd613bf86020613be48e613bde8d8f838f613bbd90613ba183613bc3956128b0565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b926128b0565b9073ffffffffffffffffffffffffffffffffffffffff169052565b8d6128b0565b5101516bffffffffffffffffffffffff1690565b6135e1565b8a611019565b612b4c612710610818565b613c188a8d6128b0565b52565b613c28612afd898c6128b0565b906120c4565b956135b4565b94613b5b565b9391945050613c47915090565b8111613c5257509190565b611b5390613c5f60405190565b9182917f3728b83d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b613cae91923d8091833e613ca68183610389565b81019061358e565b9038613804565b613cd3612d997317b0c8564e53f22364a6c8de6f7ca5ce9bea4e5d81565b63b85ed7e490613cec613ce560405190565b9260e01b90565b825260208280613d008a8a600484016127ba565b0381845afa60009281613ddc575b50613d1b575b50506137d8565b6020613d309163860110f59061369060405190565b82528180613d43898d8d60048501613189565b03915afa60009181613dac575b5015600003613d14579650975050505050506114eb613d6f6001610818565b91613c18613da6613d88613d8286613403565b95613403565b96613da1600091613bc3613d9b84610818565b896128b0565b610818565b866128b0565b613dce91925060203d8111613dd5575b613dc68183610389565b8101906134bb565b9038613d50565b503d613dbc565b613dfe91935060203d8111613e05575b613df68183610389565b8101906132b0565b9138613d0e565b503d613dec565b5073b932a70a57673d89f4acffbe830e8ed7f75fb9e073ffffffffffffffffffffffffffffffffffffffff8516146137d3565b95509750509150506101ca9250613e65613e57865190565b6111f16114eb6101ca865190565b614188565b9092613e8092503d8091833e6132a18183610389565b90913861378f565b9593965097509250831161410c5760009384918291883b613eb5613eab856132fa565b9163ffffffff1690565b11614029575b613eec9450613ede63fd90e897613ed160405190565b9687948593849360e01b90565b835260048301526024820190565b03915afa849281614005575b50613f3e5750506114eb90613c18613da6613f136001610818565b94613da1613f32613f2c613f2689613403565b98613403565b99611187565b613bc3613d9b84610818565b9290939450613f4b845190565b93613f5585613403565b90613f5f86613403565b96855b88885b881015613fe957613fda88613f659361233c613fe194613c18613fd2613c038e612c718f8f8f91613fc4602092613bc38e613bbd613fa682613fcd996128b0565b519586015173ffffffffffffffffffffffffffffffffffffffff1690565b015161ffff1690565b613444565b9485926128b0565b9760010190565b969050613f62565b5093509550509250613ffe6114eb6114eb9390565b1115613455565b6140229193503d8087833e61401a8183610389565b8101906133cb565b9138613ef8565b9161404d9061403e612d998b97949697611187565b63d78d610b9061369060405190565b825260049082905afa8791816140f0575b50158714614070575092918591613ebb565b95975050505050614082613b39835190565b9361408e613b39845190565b9461409882610818565b936140a1815190565b95855b88885b881015613fe957613fda886140a79361233c6140e894613c18613fd2613c038e612c718f8f8f91613fc4602092613bc38e613bbd613fa682613fcd996128b0565b9690506140a4565b6141059192503d808a833e61401a8183610389565b903861405e565b611b5383613c5f60405190565b90925061413d915060403d8111614145575b6141358183610389565b8101906132d7565b90913861375a565b503d61412b565b909261416292503d8091833e6132a18183610389565b90913861371e565b614182915060203d8111613e0557613df68183610389565b386136d0565b9190614195613b39825190565b926000916141a36000610818565b925b6141b06101ca835190565b8410156141fd576141f16141f7916141e46141da613c036141d4612afd8a896128b0565b88611019565b613c18888b6128b0565b613c28612afd878a6128b0565b936135b4565b926141a5565b93949392506142099050565b8111613c5257509056

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

000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000167a296135c0067903d4c099806405f6c316442e618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

-----Decoded View---------------
Arg [0] : _royaltyRegistry (address): 0xaD2184FB5DBcfC05d8f056542fB25b04fa32A95D
Arg [1] : _primaryMarketRegistry (address): 0x167A296135c0067903d4C099806405f6c316442E
Arg [2] : ERC721SovreignV1CodeHash (bytes32): 0x618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d
Arg [1] : 000000000000000000000000167a296135c0067903d4c099806405f6c316442e
Arg [2] : 618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487


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

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