ETH Price: $3,327.51 (-1.41%)

Contract

0xFA2238eEb4E2E5612853BF29f925a36f971F9010
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Cancel Auction213866012024-12-12 13:03:5915 days ago1734008639IN
0xFA2238eE...f971F9010
0 ETH0.002227524.31245177
Finalize213777162024-12-11 7:15:4716 days ago1733901347IN
0xFA2238eE...f971F9010
0 ETH0.0017281311.35222852
Bid213765822024-12-11 3:27:4716 days ago1733887667IN
0xFA2238eE...f971F9010
0.647058 ETH0.0007677916.27546284
Bid213765262024-12-11 3:16:3516 days ago1733886995IN
0xFA2238eE...f971F9010
0.616245 ETH0.0007610316.13216282
Bid213764902024-12-11 3:09:1116 days ago1733886551IN
0xFA2238eE...f971F9010
0.5869 ETH0.0006741814.29124244
Bid213764672024-12-11 3:04:3516 days ago1733886275IN
0xFA2238eE...f971F9010
0.553245 ETH0.0006767514.34554047
Bid213764402024-12-11 2:59:1117 days ago1733885951IN
0xFA2238eE...f971F9010
0.5269 ETH0.0007089815.02889039
Bid213764042024-12-11 2:51:5917 days ago1733885519IN
0xFA2238eE...f971F9010
0.49245 ETH0.0007098215.04669157
Bid213763522024-12-11 2:41:3517 days ago1733884895IN
0xFA2238eE...f971F9010
0.469 ETH0.0007540715.98461006
Bid213753742024-12-10 23:25:3517 days ago1733873135IN
0xFA2238eE...f971F9010
0.441 ETH0.000678814.38913878
First Bid213700462024-12-10 5:34:2317 days ago1733808863IN
0xFA2238eE...f971F9010
0.42 ETH0.0009240313.09235827
Update Reserve P...213201232024-12-03 6:15:3524 days ago1733206535IN
0xFA2238eE...f971F9010
0 ETH0.0005792517.5601958
Cancel Auction212945382024-11-29 16:28:1128 days ago1732897691IN
0xFA2238eE...f971F9010
0 ETH0.0022183822.88176317
Cancel Auction212945312024-11-29 16:26:4728 days ago1732897607IN
0xFA2238eE...f971F9010
0 ETH0.0022549823.25928116
Cancel Auction212945212024-11-29 16:24:4728 days ago1732897487IN
0xFA2238eE...f971F9010
0 ETH0.0022668723.38188293
Cancel Auction212429562024-11-22 11:24:5935 days ago1732274699IN
0xFA2238eE...f971F9010
0 ETH0.000744179.54926653
Cancel Auction211984662024-11-16 6:28:4741 days ago1731738527IN
0xFA2238eE...f971F9010
0 ETH0.0012704415.37935116
Update Reserve P...209481402024-10-12 7:49:2376 days ago1728719363IN
0xFA2238eE...f971F9010
0 ETH0.0004479813.58563185
Update Reserve P...209481182024-10-12 7:44:5976 days ago1728719099IN
0xFA2238eE...f971F9010
0 ETH0.0005237415.8830921
Finalize209357972024-10-10 14:26:1178 days ago1728570371IN
0xFA2238eE...f971F9010
0 ETH0.0048617929.30310507
First Bid209285562024-10-09 14:13:1179 days ago1728483191IN
0xFA2238eE...f971F9010
0.2 ETH0.0018580326.32604255
Finalize208947542024-10-04 21:08:5984 days ago1728076139IN
0xFA2238eE...f971F9010
0 ETH0.001505998.6
Set Commissions208929452024-10-04 15:05:5984 days ago1728054359IN
0xFA2238eE...f971F9010
0 ETH0.0005218813.80058329
Set Commissions208929272024-10-04 15:02:2384 days ago1728054143IN
0xFA2238eE...f971F9010
0 ETH0.0004698712.4253336
First Bid208867642024-10-03 18:26:3585 days ago1727979995IN
0xFA2238eE...f971F9010
1 ETH0.0019985728.31731497
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
213777162024-12-11 7:15:4716 days ago1733901347
0xFA2238eE...f971F9010
0.56941104 ETH
213777162024-12-11 7:15:4716 days ago1733901347
0xFA2238eE...f971F9010
0.04529406 ETH
213777162024-12-11 7:15:4716 days ago1733901347
0xFA2238eE...f971F9010
0.0323529 ETH
213765822024-12-11 3:27:4716 days ago1733887667
0xFA2238eE...f971F9010
0.616245 ETH
213765262024-12-11 3:16:3516 days ago1733886995
0xFA2238eE...f971F9010
0.5869 ETH
213764902024-12-11 3:09:1116 days ago1733886551
0xFA2238eE...f971F9010
0.553245 ETH
213764672024-12-11 3:04:3516 days ago1733886275
0xFA2238eE...f971F9010
0.5269 ETH
213764402024-12-11 2:59:1117 days ago1733885951
0xFA2238eE...f971F9010
0.49245 ETH
213764042024-12-11 2:51:5917 days ago1733885519
0xFA2238eE...f971F9010
0.469 ETH
213763522024-12-11 2:41:3517 days ago1733884895
0xFA2238eE...f971F9010
0.441 ETH
213753742024-12-10 23:25:3517 days ago1733873135
0xFA2238eE...f971F9010
0.42 ETH
209357972024-10-10 14:26:1178 days ago1728570371
0xFA2238eE...f971F9010
0.14 ETH
209357972024-10-10 14:26:1178 days ago1728570371
0xFA2238eE...f971F9010
0.03 ETH
209357972024-10-10 14:26:1178 days ago1728570371
0xFA2238eE...f971F9010
0.02 ETH
209357972024-10-10 14:26:1178 days ago1728570371
0xFA2238eE...f971F9010
0.01 ETH
208947542024-10-04 21:08:5984 days ago1728076139
0xFA2238eE...f971F9010
0.7 ETH
208947542024-10-04 21:08:5984 days ago1728076139
0xFA2238eE...f971F9010
0.15 ETH
208947542024-10-04 21:08:5984 days ago1728076139
0xFA2238eE...f971F9010
0.1 ETH
208947542024-10-04 21:08:5984 days ago1728076139
0xFA2238eE...f971F9010
0.05 ETH
208834032024-10-03 7:09:5985 days ago1727939399
0xFA2238eE...f971F9010
0.7 ETH
208834032024-10-03 7:09:5985 days ago1727939399
0xFA2238eE...f971F9010
0.15 ETH
208834032024-10-03 7:09:5985 days ago1727939399
0xFA2238eE...f971F9010
0.1 ETH
208834032024-10-03 7:09:5985 days ago1727939399
0xFA2238eE...f971F9010
0.05 ETH
208834012024-10-03 7:09:3585 days ago1727939375
0xFA2238eE...f971F9010
0.7 ETH
208834012024-10-03 7:09:3585 days ago1727939375
0xFA2238eE...f971F9010
0.15 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NinfaEnglishAuction

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 4194304 runs

Other Settings:
default evmVersion
File 1 of 16 : NinfaEnglishAuction.sol
/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

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

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

/**
 *
 * @title NinfaEnglishAuction                                *
 *                                                           *
 * @notice On-chain english auction                          *
 *                                                           *
 * @custom:security-contact [email protected]                    *
 *
 */

contract NinfaEnglishAuction is Ownable, RoyaltyEngineV1 {
    using Counters for Counters.Counter;

    Counters.Counter private _auctionId;
    /// @notice Ninfa's external registry, mapping Ninfa's ERC721 sovereign
    /// 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 auctions ids mapped to NFT auction data.
     * @dev This is deleted when an auction is finalized or canceled.
     * @dev Visibility needs to be public so that it can be called by a frontend
     * as the auction creation event only
     * emits auction id.
     */
    mapping(uint256 => _Auction) private _auctions;
    /// @notice whitelist of address codehashes of Ninfa's sovreign ERC721
    /// collections, in order to determine if it is a
    /// primary market sale
    bytes32 private _ERC721SovreignV1CodeHash;
    /**
     * @notice _feeRecipient multisig for receiving trading fees
     */
    address payable private _feeRecipient;
    /// @notice factory contract for deploying self-sovereign collections.
    address private _factory;
    address private _whitelist;
    /**
     * @notice How long an auction lasts for once the first bid has been
     * received.
     */
    uint256 private constant _DURATION = 1 days;
    /**
     * @notice The window for auction extensions, any bid placed in the final 15
     * minutes of an auction will reset the
     * time remaining to 15 minutes.
     */
    uint256 private constant _EXTENSION_DURATION = 15 minutes;
    /**
     * @notice the last highest bid is divided by this number in order to obtain
     * the minimum bid increment. E.g.
     * _MIN_BID_RAISE = 10 is 10% increment, 20 is 5%, 2 is 50%. I.e. 100 /
     * _MIN_BID_RAISE. OpenSea uses a fixed 5%
     * increment while SuperRare between 5-10%
     */
    uint256 private constant _MIN_BID_RAISE = 20;
    /// @notice Ninfa Marketplace fee percentage on primary sales, expressed in
    /// basis points
    uint256 private _primaryMarketFee;
    /// @notice Ninfa Marketplace fee percentage on all secondary sales,
    /// expressed in basis points
    uint256 private _secondaryMarketFee;

    /**
     * @notice Stores the auction configuration for a specific NFT.
     * @param operator since the order creator may be a gallery, i.e. the
     * commission receiver itself, they would not be
     * able to cancel or update the order as there would be no way to know if
     * the order creator was the seller or the
     * commissionReceiver,
     * @dev therefore an additional parameter is needed to store the address of
     * `msg.sender`
     * @param end the time at which this auction will not accept any new bids.
     * This is `0` until the first bid is
     * placed.
     * @param bidder highest bidder, needs to be payable in order to receive
     * refund in case of being outbid
     * @param price reserve price, highest bid, and all bids in between
     * @param erc1155Amount 0 for erc721, 1> for erc1155
     */
    struct _Auction {
        address operator;
        address seller;
        address collection;
        address bidder;
        uint256 tokenId;
        uint256 bidPrice;
        uint256 end;
        uint256[] commissionBps;
        address[] commissionReceivers;
    }

    /**
     * @notice Emitted when an NFT is listed for auction.
     * @param auctionId The id of the auction that was created.
     * @dev the only parameter needed is auctionId, the emitted event must
     * trigger the backend to retrieve all auction
     * data from a getter function and store it in DB.
     */
    event AuctionCreated(uint256 auctionId);

    /**
     * @notice Emitted when an auction is cancelled.
     * @dev This is only possible if the auction has not received any bids.
     * @param auctionId The id of the auction that was cancelled.
     */
    event AuctionCanceled(uint256 auctionId);

    /**
     * @notice Emitted when the auction's reserve price is updated.
     * @dev This is only possible if the auction has not received any bids.
     * @param auctionId The id of the auction that was updated.
     */
    event AuctionUpdated(uint256 auctionId);

    /**
     * @notice Emitted when an auction that has already ended is finalized,
     * indicating that the NFT has been transferred and revenue from the sale
     * distributed.
     */
    event AuctionFinalized(uint256 auctionId);

    /**
     * @notice Emitted when a bid is placed.
     * @param auctionId The id of the auction this bid was for.
     */
    event Bid(uint256 auctionId);

    /**
     * @notice ERC721 and ERC1155 collections must be whitelisted.
     * @dev if the collection has not been whitelisted, check if it is one of
     * Ninfa's factory clones (Ninfa's
     * self-sovereign collections)
     * @dev by checking the whitelist first with nested `if`s avoids having to
     * make an external call unnecessarily
     */
    modifier isWhitelisted(address _collection) {
        bytes memory authorized;
            (, authorized) = _factory.staticcall(
                abi.encodeWithSelector(0xf6a3d24e, _collection)
            );
        if (abi.decode(authorized, (bool)) == false) {
            (, authorized) = _whitelist.staticcall(
                abi.encodeWithSelector(0x3af32abf, _collection)
            );
            if (abi.decode(authorized, (bool)) == false) revert Unauthorized();
        }
        _;
    }

    /**
     * @notice Creates an auction for the given NFT. The NFT is held in escrow
     * until the auction is finalized or
     * canceled.
     * @param _id The id of the NFT.
     * @param _reservePrice The initial reserve price for the auction.
     * @dev reserve price may also be 0, clearly a mistake but not strictly
     * required, only done in order to save gas by
     * removing the need for a condition such as `if (_price == 0) revert
     * InvalidAmount(_price)`
     * @param _commissionReceivers address of sale commissions receiver
     * @dev if `msg.sender` is also the `_commissionReceiver`, e.g. if
     * `msg.sender` is a gallery, they must put their
     * own address as the `_commissionReceiver`, and set the `_seller` parameter
     * with the artist's/collector's address.
     * @dev if there is no commission receiver, it must be set to address(0)
     * @dev it is not required for `_commissionReceiver` and `_seller` addresses
     * to be different (in order to save gas),
     * although it would likely be a mistake, it cannot be exploited as the
     * total amount paid out will never exceed the
     * price set for the order. I.e. in the worst case the same address will
     * receive both principal sale profit and
     * commissions.
     */
    function _createAuction(
        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 _reservePrice,
        uint256[] memory _commissionBps,
        address[] memory _commissionReceivers
    )
        private
    {
        _auctionId.increment(); // start counter at 1

        uint256 auctionId_ = _auctionId.current();

        _auctions[auctionId_] = _Auction(
            _operator,
            _from, // auction beneficiary, needs to be payable in order to
                // receive funds from the auction sale
            msg.sender,
            address(0), // bidder is only known once a bid has been placed. //
                // highest bidder, needs to be payable in
                // order to receive refund in case of being outbid
            _id,
            _reservePrice,
            0,
            _commissionBps,
            _commissionReceivers
        );

        emit AuctionCreated(auctionId_);
    }

    /**
     * @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 reservePrice, uint256[] memory commissionBps, address[] memory commissionReceivers) =
            abi.decode(_data, (uint256, uint256[], address[]));

        _createAuction(_operator, _from, _tokenId, reservePrice, commissionBps, commissionReceivers);

        return 0x150b7a02;
    }

    function _transferNFT(address _collection, address _from, address _to, uint256 _tokenId) private {
        (bool success,) = _collection.call(
            abi.encodeWithSelector(
                0x42842e0e, // bytes4(keccak256('safeTransferFrom(address,address,uint256)'))
                    // == 0x42842e0e
                _from,
                _to,
                _tokenId
            )
        );

        require(success);
    }

    function firstBid(uint256 auctionId_) external payable {
        _Auction storage _auction = _auctions[auctionId_];

        // hardcoded 0x0 address in order to avoid reading from storage.
        // there is no need to check whether the auction exists already, because
        // even if someone managed to set end,
        // price and bidder for a (yet) non-existing auction, they would be
        // reser when an auction with the same id gets
        // created
        // the important thing is that no one can reset these variables for
        // auctions that have already started, and
        // can't happen because _auction.bidder would be set after the first bid
        // is placed by calling this function.
        if (
            _auction.bidder != 0x0000000000000000000000000000000000000000 // if
                // auction has started
                || msg.value < _auction.bidPrice
        ) revert Unauthorized();

        // if the auction exists and this is the firsat bid, start the auction
        // timer.
        // On the first bid, set the end to now + duration. `_DURATION` is a
        // constant set to 24hrs therefore the below
        // addition can't overflow.
        unchecked {
            _auction.end = block.timestamp + _DURATION;
            _auction.bidPrice = msg.value; // new highest bid
            _auction.bidder = msg.sender; // new highest bidder
        }

        emit Bid(auctionId_);
    }

    /**
     * @notice Place a bid in an auction.
     * A bidder may place a bid which is at least the amount defined by
     * `getMinBidAmount`.
     * If this is the first bid on the auction, the countdown will begin.
     * If there is already an outstanding bid, the previous bidder will be
     * refunded at this time
     * and if the bid is placed in the final moments of the auction, the
     * countdown may be extended.
     * @dev bids MUST be at least 5% higher than previous bid.
     * @param auctionId_ The id of the auction to bid on.
     * @dev auctionId_ MUST exist, auction MUST have begun and MUST not have
     * ended.
     */
    function bid(uint256 auctionId_) external payable {
        _Auction storage _auction = _auctions[auctionId_];
        // if auction hasn't started or doesn't exist, i.e. no one has called
        // firstBid() yet, _auction.end will still be
        // 0,
        // therefore the following require statement implicitly checks that
        // auction has started and explicitly that it
        // has not ended

        if (
            block.timestamp > _auction.end || _auction.end == 0 // required
                // otherwise calling this function would start
                // a 15 minutes auction rather than 24h
                || msg.value - _auction.bidPrice < _auction.bidPrice / _MIN_BID_RAISE
        ) revert Unauthorized();

        // if there is less than 15 minutes left, increment end time by 15 more.
        // _EXTENSION_DURATION is always set to 15
        // minutes so the below can't overflow.
        // already checking in previous if statement that if `block.timestamp >
        // _auction.end` the tx reverts, meaning
        // that `block.timestamp` must be less than `_auction.end`, i.e. auction
        // hasn't expired,
        // if you combine that with `block.timestamp + _EXTENSION_DURATION >
        // _auction.end` that means that
        // `block.timestamp` must be between `_auction.end` and `_auction.end -
        // 15 minutes`, i.e. it's the last 15
        // minutes of the auction.
        if (block.timestamp + _EXTENSION_DURATION > _auction.end) {
            unchecked {
                _auction.end += _EXTENSION_DURATION;
            }
        }

        // refund the previous bidder
        _sendValue(_auction.bidder, _auction.bidPrice);

        // does not follow check-effects-interactions pattern so that storing
        // previous bidder and amount in memory is
        // not required, however there is no reentrancy exploit in this case;
        // calling back into `bid()` requires that `msg.value` is 5% higher than
        // previous bid, meaning that the extra 5%
        // would not be refunded because storage has not been updated yet
        // besides the bid() function, there is no other function that can be
        // called back into which represents a
        // security risk, namely `createAuction()` and `firstBid()`, i.e.
        // _auction.bidPrice and _auction.bidder are not
        // read by any other function that may be reentered
        _auction.bidPrice = msg.value; // new highest bid
        _auction.bidder = msg.sender; // new highest bidder

        emit Bid(auctionId_);
    }

    /**
     * @notice If an auction has been created but has not yet received bids, the
     * `reservePrice` may be edited by the
     * seller.
     * @param auctionId_ The id of the auction to change.
     * @param _newReservePrice The new reserve price for this auction, may be
     * higher or lower than the previoius price.
     * @dev `_newReservePrice` may be equal to old price
     * (`_auctions[auctionId_].price`); although this doesn't make much
     * sense it isn't a security requirement, hence `require(_auction.bidPrice
     * != _price)` it has been omitted in order
     * to save the user some gas
     * @dev `_newReservePrice` may also be 0, clearly a mistake but not a
     * security requirement,  hence `require(_price >
     * 0)` has been omitted in order to save the user some gas
     */
    function updateReservePrice(uint256 auctionId_, uint256 _newReservePrice) external {
        _Auction storage _auction = _auctions[auctionId_];
        // code duplication because modifiers can't pass variables to functions,
        // meanining that storage pointer cannot
        // be instantiated in modifier
        require(_auction.operator == msg.sender && _auction.end == 0);

        // Update the current reserve price.
        _auction.bidPrice = _newReservePrice;

        emit AuctionUpdated(auctionId_);
    }

    function setCommissions(
        uint256 auctionId_, 
        uint256[] memory _commissionBps, 
        address[] memory _commissionReceivers) external {
        require(msg.sender == _auctions[auctionId_].operator);
        _auctions[auctionId_].commissionBps = _commissionBps;
        _auctions[auctionId_].commissionReceivers = _commissionReceivers;
        emit AuctionUpdated(auctionId_);
    }

    /**
     * @notice If an auction has been created but has not yet received bids, it
     * may be canceled by the seller.
     * @dev The NFT is transferred back to the owner unless there is still a buy
     * price set.
     * @param auctionId_ The id of the auction to cancel.
     */
    function cancelAuction(uint256 auctionId_) external {
        _Auction memory _auction = _auctions[auctionId_];

        require(_auction.operator == msg.sender && _auction.end == 0);

        // Delete the _auction.
        delete _auctions[auctionId_];

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

        emit AuctionCanceled(auctionId_);
    }

    function finalize(uint256 auctionId_) external {
        _Auction memory auction = _auctions[auctionId_];
        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
        // sellerAmount is a security check as well as a variable assignment,
        // because it would revert if there was an
        // underflow
        // sellerAmount may be 0 if royalties are set too high for an external
        // collection. If `royaltyAmount ==
        // (auction.bidPrice - marketplaceAmount)` then `sellerAmount == 0`. if
        // royalties amount exceeds price - fees
        // amount the transaction will revert.
        uint256 sellerAmount = auction.bidPrice;
        uint256 marketplaceAmount;

        // there must be at least one bid higher than the reserve price in order
        // to execute the trade, no bids mean no
        // end time
        if (block.timestamp < auction.end || auction.end == 0) {
            revert Unauthorized();
        }

        // Remove the auction.
        delete _auctions[auctionId_];

        bool checkSecondaryMarket = true;

        if (auction.collection.codehash == _ERC721SovreignV1CodeHash) {
            // it's a v1 721 token, check market registry
            (, bytes memory secondaryMarket) = _PRIMARY_MARKET_REGISTRY.call(
                abi.encodeWithSelector(
                    0x7abab711,
                    auction.collection,
                    auction.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(auction.collection, auction.tokenId, sellerAmount);
        }
        
        uint256 royaltyRecipientsLength = royaltyRecipients.length; // assign to

        if (royaltyRecipientsLength > 0) {
            if (_secondaryMarketFee > 0) {
                /*----------------------------------------------------------*|
                |*  # PAY MARKETPLACE FEE                                   *|
                |*----------------------------------------------------------*/
                marketplaceAmount = (auction.bidPrice * _secondaryMarketFee) / 10_000;
                // 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 = (auction.bidPrice * _primaryMarketFee) / 10_000;
            sellerAmount -= marketplaceAmount; // subtract before external
            // call
            _sendValue(_feeRecipient, marketplaceAmount);
        }

        /**
         *
         * Pay seller commissions *
         *
         */

        uint256 commissionReceiversLength = auction.commissionReceivers.length;

        if (commissionReceiversLength > 0) {
            do {
                commissionReceiversLength--;
                if(auction.commissionBps[commissionReceiversLength] > 0){
                    uint256 commissionAmount = (auction.commissionBps[commissionReceiversLength] * auction.bidPrice) / 10_000; // calculate
    
                    sellerAmount -= commissionAmount; // subtract before external

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

        /**
         *
         * Pay seller *
         *
         */

        _sendValue(auction.seller, sellerAmount);

        // transfer nft to auction winner
        _transferNFT(auction.collection, address(this), auction.bidder, auction.tokenId);

        emit AuctionFinalized(auctionId_);
    }

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

    /**
     * @dev setter function only callable by contract admin used to change the
     * address to which fees are paid
     * @param _newFeeAccount is the address owned by NINFA that will collect
     * sales fees
     */
    function setFeeRecipient(address payable _newFeeAccount) external onlyOwner {
        _feeRecipient = _newFeeAccount;
    }

    function setWhitelist(address whitelist_) external onlyOwner {
        _whitelist = whitelist_;
    }

    /**
     * @notice sets primary sale fees for NINFA_ERC721_V2 communal collection.
     */
    function setMarketFees(uint256 primaryMarketFee_, uint256 secondaryMarketFee_) external onlyOwner {
        _primaryMarketFee = primaryMarketFee_;
        _secondaryMarketFee = secondaryMarketFee_;
    }

    function auctions(uint256 auctionId_) external view returns (_Auction memory) {
        return _auctions[auctionId_];
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
        return
        // Interface ID for IERC165
        interfaceId == 0x01ffc9a7
        // Interface ID for IERC721Receiver. A wallet/broker/auction application
        // MUST implement the wallet interface if
        // it will accept safe transfers.
        || interfaceId == 0x150b7a02;
    }

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

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`
     * @dev after deployment admin needs to manually whitelist collections.
     * @param _royaltyRegistry see https://royaltyregistry.xyz/lookup for public
     * addresses
     */
    constructor(
        address _royaltyRegistry,
        address _primarySalesRegistry,
        address factory_,
        address whitelist_,
        bytes32 ERC721SovreignV1CodeHash
    )
        RoyaltyEngineV1(_royaltyRegistry)
    {
        _PRIMARY_MARKET_REGISTRY = _primarySalesRegistry;
        _factory = factory_;
        _whitelist = whitelist_;
        _ERC721SovreignV1CodeHash = ERC721SovreignV1CodeHash;
    }
}

File 2 of 16 : Counters.sol
/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

// 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 [email protected]                    *
 *
 */
/**
 * @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;
        }
    }
}

File 3 of 16 : RoyaltyEngineV1.sol
/*----------------------------------------------------------*|
|*          ███    ██ ██ ███    ██ ███████  █████           *|
|*          ████   ██ ██ ████   ██ ██      ██   ██          *|
|*          ██ ██  ██ ██ ██ ██  ██ █████   ███████          *|
|*          ██  ██ ██ ██ ██  ██ ██ ██      ██   ██          *|
|*          ██   ████ ██ ██   ████ ██      ██   ██          *|
|*----------------------------------------------------------*/

// 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 [email protected]                    *
 *
 */

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

File 4 of 16 : Ownable.sol
// 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);
    }
}

File 5 of 16 : IRoyaltyRegistry.sol
// 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);
}

File 6 of 16 : IRoyaltySplitter.sol
// 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);
}

File 7 of 16 : IManifold.sol
// 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);
}

File 8 of 16 : IRarible.sol
// 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);
}

File 9 of 16 : IFoundation.sol
// 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);
}

File 10 of 16 : ISuperRare.sol
// 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);
}

File 11 of 16 : IEIP2981.sol
// 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);
}

File 13 of 16 : IZoraOverride.sol
// 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);
}

File 15 of 16 : IKODAV2Override.sol
// 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;
}

File 16 of 16 : IERC165.sol
// 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": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "solmate/=lib/solmate/src/",
    "src/=src/",
    "test/=test/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 4194304,
    "details": {
      "constantOptimizer": true,
      "yul": true,
      "yulDetails": {
        "stackAllocation": true,
        "optimizerSteps": "dhfoDgvulfnTUtnIf"
      }
    }
  },
  "metadata": {
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_royaltyRegistry","type":"address"},{"internalType":"address","name":"_primarySalesRegistry","type":"address"},{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"whitelist_","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":"auctionId","type":"uint256"}],"name":"AuctionCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"AuctionFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"AuctionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"auctionId","type":"uint256"}],"name":"Bid","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"},{"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":"auctionId_","type":"uint256"}],"name":"auctions","outputs":[{"components":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"bidder","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"bidPrice","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256[]","name":"commissionBps","type":"uint256[]"},{"internalType":"address[]","name":"commissionReceivers","type":"address[]"}],"internalType":"struct NinfaEnglishAuction._Auction","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"auctionId_","type":"uint256"}],"name":"bid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"auctionId_","type":"uint256"}],"name":"cancelAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"auctionId_","type":"uint256"}],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"auctionId_","type":"uint256"}],"name":"firstBid","outputs":[],"stateMutability":"payable","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":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"auctionId_","type":"uint256"},{"internalType":"uint256[]","name":"_commissionBps","type":"uint256[]"},{"internalType":"address[]","name":"_commissionReceivers","type":"address[]"}],"name":"setCommissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_newFeeAccount","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"primaryMarketFee_","type":"uint256"},{"internalType":"uint256","name":"secondaryMarketFee_","type":"uint256"}],"name":"setMarketFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whitelist_","type":"address"}],"name":"setWhitelist","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":"auctionId_","type":"uint256"},{"internalType":"uint256","name":"_newReservePrice","type":"uint256"}],"name":"updateReservePrice","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c0604052346200004657620000226200001862000140565b93929092620001ef565b604051613031620002ca823960805181612477015260a05181611b0b015261303190f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b038211176200008357604052565b6200004b565b90620000a06200009860405190565b928362000061565b565b6001600160a01b031690565b90565b6001600160a01b0381165b036200004657565b90505190620000a082620000b1565b80620000bc565b90505190620000a082620000d3565b919060a0838203126200004657620001028184620000c4565b92620001128260208301620000c4565b92620000ae620001268460408501620000c4565b93620001368160608601620000c4565b93608001620000da565b62000163620032fb80380380620001578162000089565b928339810190620000e9565b9091929394565b906001600160a01b03905b9181191691161790565b620000ae90620000a2906001600160a01b031682565b620000ae906200017f565b620000ae9062000195565b90620001bf620000ae620001c792620001a0565b82546200016a565b9055565b906000199062000175565b90620001e7620000ae620001c79290565b8254620001cb565b6200021d92620000a09594926200020a620002159362000225565b60a0526005620001ab565b6006620001ab565b6003620001d6565b6200022f62000234565b608052565b620000a03362000270565b620000ae90620000a2565b620000ae90546200023f565b6001600160a01b0391821681529116602082015260400190565b6200027c60006200024a565b906200028a816000620001ab565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091620002c4620002ba60405190565b9283928362000256565b0390a156fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461011257806305261aea1461010d578063150b7a0214610108578063389273941461010357806338c61759146100fe578063454a2ab3146100f9578063571a26a0146100f4578063715018a6146100ef5780637fea43b8146100ea578063854cff2f146100e55780638da5cb5b146100e057806396b5a755146100db578063cbdfe7cc146100d6578063d8d62599146100d1578063e74b981b146100cc5763f2fde38b03610117576108b1565b610899565b610880565b61069d565b610685565b610643565b61062b565b6105e8565b610527565b6104f5565b610349565b610336565b61031d565b6102a8565b6101c5565b61016d565b600080fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361011757565b905035906101548261011c565b565b906020828203126101175761016a91610147565b90565b346101175761019a610188610183366004610156565b611cd9565b60405191829182901515815260200190565b0390f35b80610140565b905035906101548261019e565b906020828203126101175761016a916101a4565b34610117576101dd6101d83660046101b1565b61175c565b604051005b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff8116610140565b90503590610154826101fb565b909182601f830112156101175781359167ffffffffffffffff831161011757602001926001830284011161011757565b90608082820312610117576102698183610217565b926102778260208501610217565b9261028583604083016101a4565b92606082013567ffffffffffffffff8111610117576102a49201610224565b9091565b346101175761019a6102c76102be366004610254565b93929092610901565b604051918291827fffffffff00000000000000000000000000000000000000000000000000000000909116815260200190565b91906040838203126101175761016a9061031481856101a4565b936020016101a4565b34610117576101dd6103303660046102fa565b90611118565b6101dd6103443660046101b1565b610ea2565b6101dd6103573660046101b1565b61100f565b0190565b9061038061037961036f845190565b8084529260200190565b9260200190565b9060005b8181106103915750505090565b9091926103ae6103a76001928651815260200190565b9460200190565b929101610384565b906103c561037961036f845190565b9060005b8181106103d65750505090565b9091926104026103a7600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9291016103c9565b805173ffffffffffffffffffffffffffffffffffffffff16825261016a916101006104d2610120830160208581015173ffffffffffffffffffffffffffffffffffffffff169085015260408581015173ffffffffffffffffffffffffffffffffffffffff169085015260608581015173ffffffffffffffffffffffffffffffffffffffff16908501526104a260808601516080860152565b6104b160a086015160a0860152565b6104c060c086015160c0860152565b60e085015184820360e0860152610360565b920151906101008184039101526103b6565b602080825261016a9291019061040a565b346101175761019a61051061050b3660046101b1565b611cc2565b604051918291826104e4565b600091031261011757565b346101175761053736600461051c565b6101dd611d7b565b90916060828403126101175761016a6105588484610217565b9361056681602086016101a4565b936040016101a4565b9061057e61037961036f845190565b9060005b81811061058f5750505090565b9091926105bb6103a7600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101610582565b604080825261016a9391926105da9184019061056f565b916020818403910152610360565b34610117576106016105fb36600461053f565b91612462565b9061019a61060e60405190565b928392836105c3565b906020828203126101175761016a91610217565b34610117576101dd61063e366004610617565b611c3e565b346101175761065336600461051c565b61019a61065e611d51565b6040519182918273ffffffffffffffffffffffffffffffffffffffff909116815260200190565b34610117576101dd6106983660046101b1565b6114a8565b34610117576101dd6106b03660046102fa565b90611c6d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff82111761072557604052565b6106b6565b9061015461073760405190565b92836106e5565b67ffffffffffffffff81116107255760208091020190565b9092919261076b6107668261073e565b61072a565b938185526020808601920283019281841161011757915b83831061078f5750505050565b6020809161079d84866101a4565b815201920191610782565b9080601f830112156101175781602061016a93359101610756565b909291926107d36107668261073e565b938185526020808601920283019281841161011757915b8383106107f75750505050565b602080916108058486610217565b8152019201916107ea565b9080601f830112156101175781602061016a933591016107c3565b916060838303126101175761084082846101a4565b92602081013567ffffffffffffffff811161011757836108619183016107a8565b92604082013567ffffffffffffffff81116101175761016a9201610810565b34610117576101dd61089336600461082b565b916111a8565b34610117576101dd6108ac366004610617565b611c1b565b34610117576101dd6108c4366004610617565b611dc4565b6108dc6108d661016a9290565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b919261091c9061092695610913600090565b5081019061082b565b9491929093610d65565b61016a63150b7a026108c9565b6101e261016a61016a9290565b61016a90610933565b61016a61012061072a565b61016a61016a61016a9290565b9061096b90610954565b600052602052604060002090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b9073ffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b6101e261016a61016a9273ffffffffffffffffffffffffffffffffffffffff1690565b61016a906109ca565b61016a906109ed565b90610a0f61016a610a16926109f6565b82546109a8565b9055565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff906109c0565b90610a5261016a610a1692610954565b8254610a1a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810292918115918404141715610a9b57565b610a59565b919060086109c0910291610ad37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b9190610ae961016a610a1693610954565b908354610aa0565b61015491600091610ad8565b818110610b08575050565b80610b166000600193610af1565b01610afd565b9091828110610b2a57505050565b6101549290610b40905b92600052602060002090565b9081019101610afd565b906801000000000000000081116107255781610b67610154935490565b90828155610b1c565b81519167ffffffffffffffff831161072557610b9b610b34600192610b958686610b4a565b60200190565b92049160005b838110610bae5750505050565b6001906020610bbe61016a865190565b9401938184015501610ba1565b9061015491610b70565b81519167ffffffffffffffff831161072557610bfa610b34600192610b958686610b4a565b92049160005b838110610c0d5750505050565b6001906020610c3361016a865173ffffffffffffffffffffffffffffffffffffffff1690565b9401938184015501610c00565b9061015491610bd5565b6101549190610d559061010090600890610c8281610c7c875173ffffffffffffffffffffffffffffffffffffffff1690565b906109ff565b610caa60018201610c7c602088015173ffffffffffffffffffffffffffffffffffffffff1690565b610cd260028201610c7c604088015173ffffffffffffffffffffffffffffffffffffffff1690565b610cfa60038201610c7c606088015173ffffffffffffffffffffffffffffffffffffffff1690565b610d1260048201610d0c608088015190565b90610a42565b610d2460058201610d0c60a088015190565b610d3660068201610d0c60c088015190565b610d4e60078201610d4860e088015190565b90610bcb565b0192015190565b90610c40565b9061015491610c4a565b939194926001610d7481611e51565b610d7d90611e3c565b9560009233610d8b85610940565b91610d94610949565b73ffffffffffffffffffffffffffffffffffffffff909916868a015273ffffffffffffffffffffffffffffffffffffffff16602089015273ffffffffffffffffffffffffffffffffffffffff16604088015273ffffffffffffffffffffffffffffffffffffffff166060870152608086015260a0850152610e1490610954565b60c084015260e0830152610100820152610e2f826002610961565b90610e3991610d5b565b7f7e0e356457a92dacd3760ddf327a24dd226c6ca01b2cc41a7fd6f28469c7ab9b90610e6460405190565b90815280602081015b0390a1565b61016a906101e2565b61016a9054610e72565b61016a9081565b61016a9054610e85565b61016a62015180610954565b610eb061016a826002610961565b60038101610ebd81610e7b565b610edd60005b9173ffffffffffffffffffffffffffffffffffffffff1690565b14158015610f84575b610f5557610f13610f1a92610f09610f004261035c610e96565b60068301610a42565b6005349101610a42565b33906109ff565b610e6d7f7a183e84509e3fe5b0b3aac15347fd1c7d71fd1503001f1a1d7c9658077eb35f91610f4860405190565b9182918290815260200190565b6040517f82b42900000000000000000000000000000000000000000000000000000000008152600490fd5b0390fd5b5034610f9c610f9861016a60058601610e8c565b9190565b10610ee6565b91908203918211610a9b57565b61016a6014610954565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115610ff2570490565b610fb9565b61016a610384610954565b91908201809211610a9b57565b61101d61016a826002610961565b60068101904261102f61016a84610e8c565b811180156110f4575b80156110b6575b610f5557610f1a92611059611052610ff7565b8093611002565b611068610f9861016a84610e8c565b1161109f575b5050610f136003820191611098600561108685610e7b565b92019161109283610e8c565b90611bcc565b3490610a42565b610d0c6110af9261035c83610e8c565b388061106e565b50600582016110ee610f9861016a6110e06110da346110d487610e8c565b90610fa2565b94610e8c565b6110e8610faf565b90610fe8565b1061103f565b506110fe83610e8c565b61110b610f986000610954565b14611038565b1561011757565b9061115590600561112d61016a856002610961565b61113681610e7b565b61113f33610ec3565b1480611183575b61114f90611111565b01610a42565b610e6d7faed3e56ca017d9b02e523c2c7ba81ae5591f43f264dd5d603d70953a12d8079e91610f4860405190565b5061114f61119360068301610e8c565b6111a0610f986000610954565b149050611146565b9160086111f684611155946111f133916111df6002936111d9610ec36101e260006111d38a8a610961565b01610e7b565b14611111565b60076111eb8585610961565b01610bcb565b610961565b01610c40565b9061120b610b3461036f845490565b9060005b81811061121c5750505090565b90919261124061123960019261123187610e8c565b815260200190565b9460010190565b92910161120f565b9061016a916111fc565b9061015461126c9261126360405190565b93848092611248565b03836106e5565b90611282610b3461036f845490565b9060005b8181106112935750505090565b9091926112c66112396001926112a887610e7b565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101611286565b9061016a91611273565b9061015461126c926112e960405190565b938480926112ce565b9061015461140c6008611303610949565b9461132a61131082610e7b565b73ffffffffffffffffffffffffffffffffffffffff168752565b61135661133960018301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166020880152565b61138261136560028301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166040880152565b6113ae61139160038301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166060880152565b6113c46113bd60048301610e8c565b6080880152565b6113da6113d360058301610e8c565b60a0880152565b6113f06113e960068301610e8c565b60c0880152565b6114066113ff60078301611252565b60e0880152565b016112d8565b610100840152565b61016a906112f2565b600061015491610b4a565b90600003611439576101549061141d565b610979565b6000600861015492828082015582600182015582600282015582600382015561146a8360048301610af1565b6114778360058301610af1565b6114848360068301610af1565b6114918360078301611428565b01611428565b90600003611439576101549061143e565b61153e60026114bf6114ba8483610961565b611414565b906115086000611503866114e7865173ffffffffffffffffffffffffffffffffffffffff1690565b3395906114f387610ec3565b148061156c575b6111f190611111565b611497565b604082015173ffffffffffffffffffffffffffffffffffffffff16916115386080611532306109f6565b92015190565b92611630565b610e6d7f28601d865dccc9f113e15a7185c1b38c085d598c71250d3337916a428536d77191610f4860405190565b506111f161157b60c089015190565b611587610f9887610954565b1490506114fa565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526060810192916101549160400152565b0152565b67ffffffffffffffff811161072557602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b9061160c610766836115c4565b918252565b3d1561162b576116203d6115ff565b903d6000602084013e565b606090565b60046116786000949361166961015497879661164f6342842e0e6108c9565b9361165960405190565b968795602087019081520161158f565b602082018103825203826106e5565b82602082019151925af161168a611611565b50611111565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101549160200152565b801515610140565b90505190610154826116ba565b906020828203126101175761016a916116c2565b8015610a9b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90611746825190565b811015611757576020809102010190565b61170e565b600261176b6114ba8383610961565b906060908160a0840161177c815190565b908193611787600090565b5060c087014261179b610f9861016a845190565b10908115611bb5575b50610f55576000611503896117b893610961565b600192839560408801966117e0885173ffffffffffffffffffffffffffffffffffffffff1690565b3f6117f1610f9861016a6003610e8c565b14611b05575b611ad1575b81516000948161180e610f9888610954565b1115611a94575061181f6008610e8c565b61182b610f9887610954565b11611a57575b85805b6119cb575b505050505b61010086019261184d84515190565b908161185b610f9886610954565b11611916575b505050505082916118986118b29261189360206118e897015173ffffffffffffffffffffffffffffffffffffffff1690565b611bcc565b5173ffffffffffffffffffffffffffffffffffffffff1690565b906118bc306109f6565b61153860806118e2606085015173ffffffffffffffffffffffffffffffffffffffff1690565b93015190565b610e6d7f2d7633a748a750b559b97738629efd586b561319b152bb42ba14d590706d31da91610f4860405190565b9081805b611925575b50611861565b156119b6575b61193584916116e3565b918260e08a0161194d61194983835161173d565b5190565b611959610f9889610954565b11611969575b505091908261191a565b976118936118986119a76119a061199561198c611949889f986119af995161173d565b8b515b90610a88565b6110e8612710610954565b8094610fa2565b9a8a5161173d565b388061195f565b6119bf84610954565b811161192b578061191f565b15611a42575b6119db85916116e3565b90816119ea611949828661173d565b6119f6610f9889610954565b11611a03575b5086611834565b97611a3d611a1989926110d46119498d8961173d565b99611893611a37611949611a30611898858c61173d565b938961173d565b916109f6565b6119fc565b611a4b85610954565b81116119d15780611839565b611a8f611a7c611a75611995611a6b885190565b61198f6008610e8c565b8099610fa2565b97611893611a8a6004610e7b565b6109f6565b611831565b9650505050611acc611abe611ab7611995611aad855190565b61198f6007610e8c565b8096610fa2565b94611893611a8a6004610e7b565b61183e565b5050611b0082611af5875173ffffffffffffffffffffffffffffffffffffffff1690565b608089015190611fe1565b6117fc565b506000807f00000000000000000000000000000000000000000000000000000000000000006004611b858c6116698d611b6b611b656080611b5f637abab711945173ffffffffffffffffffffffffffffffffffffffff1690565b95015190565b916108c9565b92611b7560405190565b9586946020860190815201611690565b82602082019151925af150611bb0611b9b611611565b6020611ba5825190565b8183010191016116cf565b6117f7565b519050611bc5610f986000610954565b14386117a4565b600061015492611bdf611a8a83946109f6565b90611be960405190565b90818003925af161168a611611565b61015490611c10611c07611d51565b6111d933610ec3565b6101549060046109ff565b61015490611bf8565b61015490611c33611c07611d51565b6101549060066109ff565b61015490611c24565b9061015491611c57611c07611d51565b90611c66610154926007610a42565b6008610a42565b9061015491611c47565b611c7f610949565b9060008252602080808080808080808a0160008152016000815201600081520160008152016000815201600081520160608152016060905250565b61016a611c77565b6114ba61016a91611cd1611cba565b506002610961565b611ce66301ffc9a76108c9565b7fffffffff00000000000000000000000000000000000000000000000000000000821614908115611d15575090565b9050611d4d611d2763150b7a026108c9565b917fffffffff000000000000000000000000000000000000000000000000000000001690565b1490565b61016a6000610e7b565b611d66611c07611d51565b610154610154611d766000610940565b611dcd565b610154611d5b565b61015490611d92611c07611d51565b61015490611d76611da66101e26000610940565b73ffffffffffffffffffffffffffffffffffffffff83161415611111565b61015490611d83565b611dd76000610e7b565b90611de38160006109ff565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091610e6d611e1160405190565b9283928373ffffffffffffffffffffffffffffffffffffffff91821681529116602082015260400190565b600061016a91611e4a600090565b5001610e8c565b61015490610d0c6000611e646001610954565b92019161035c83610e8c565b90505190610154826101fb565b90929192611e8d6107668261073e565b938185526020808601920283019281841161011757915b838310611eb15750505050565b60208091611ebf8486611e70565b815201920191611ea4565b9080601f8301121561011757815161016a92602001611e7d565b905051906101548261019e565b90929192611f016107668261073e565b938185526020808601920283019281841161011757915b838310611f255750505050565b60208091611f338486611ee4565b815201920191611f18565b9080601f8301121561011757815161016a92602001611ef1565b91909160408184031261011757805167ffffffffffffffff81116101175783611f82918301611eca565b92602082015167ffffffffffffffff81116101175761016a9201611f3e565b73ffffffffffffffffffffffffffffffffffffffff90911681526060810193926101549290916040916115c0906020830152565b6040513d6000823e3d90fd5b6000919392611fee606090565b5061202783611ffc306109f6565b637fea43b8612032612010620f4240610954565b9561201a60405190565b9a8b988997889560e01b90565b855260048501611fa1565b0393f1918260009182946120a5575b50610f98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f526f79616c7479206c6f6f6b7570206661696c656400000000000000000000006044820152606490fd5b9093506120c3913d8091833e6120bb81836106e5565b810190611f58565b9238612041565b906020828203126101175761016a91611e70565b9081526040810192916101549160200152565b91906040838203126101175761016a9061210b8185611e70565b93602001611ee4565b61212161016a61016a9290565b63ffffffff1690565b61ffff8116610140565b905051906101548261212a565b9190916040818403126101175761217661215b604061072a565b9360006121688285611e70565b908601526020809301612134565b90830152565b9092919261218c6107668261073e565b93818552604060208601920283019281841161011757915b8383106121b15750505050565b60206040916121c08486612141565b8152019201916121a4565b9080601f8301121561011757815161016a9260200161217c565b9060208282031261011757815167ffffffffffffffff81116101175761016a92016121cb565b9061160c6107668361073e565b369037565b9061015461223361222d8461220b565b9361073e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00160208401612218565b61016a61016a61016a9261ffff1690565b1561227657565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642073706c6974000000000000000000000000000000000000006044820152606490fd5b906020828203126101175761016a91611ee4565b6bffffffffffffffffffffffff8116610140565b90505190610154826122e9565b91909160408184031261011757612176612324604061072a565b9360006123318285611e70565b9086015260208093016122fd565b9092919261234f6107668261073e565b93818552604060208601920283019281841161011757915b8383106123745750505050565b6020604091612383848661230a565b815201920191612367565b9080601f8301121561011757815161016a9260200161233f565b9060208282031261011757815167ffffffffffffffff81116101175761016a920161238e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a9b5760010190565b61016a61016a61016a926bffffffffffffffffffffffff1690565b9060208282031261011757815167ffffffffffffffff81116101175761016a9201611eca565b9060208282031261011757815167ffffffffffffffff81116101175761016a9201611f3e565b60609392849291906124b3602061249b611a8a7f00000000000000000000000000000000000000000000000000000000000000006109f6565b63de5488af906124aa60405190565b93849260e01b90565b825273ffffffffffffffffffffffffffffffffffffffff8616600483015260249082905afa8015612925576124f091600091612f88575b506109f6565b906124fa826109f6565b9163d6a1919a61251361250c60405190565b9160e01b90565b815260008180612527868a600484016120de565b038183885af1806000928392612f6a575b50612c53575050632a55205a61255061250c60405190565b815260408180612564868a600484016120de565b0381875afa806000928392612f37575b50612c9c57505063bb3bafd661258c61250c60405190565b815260048101869052600081602481875afa806000928392612c7e575b50612c535750506125ce6101e27341a322b28d0ff354040e2cbc676f0320d8c8850d90565b73ffffffffffffffffffffffffffffffffffffffff8516148015612c20575b612ac9575b63cad96cca61260361250c60405190565b815260048101869052600081602481875afa60009181612aa6575b50612945575063b9c4d9fb61263260405190565b61263c8260e01b90565b815260048101879052600081602481885afa6000918161292a575b5061286c575b505063d5a06d4c61267061250c60405190565b815260048101869052600081602481875afa80600092839261284e575b506127d857505063f66220746126a561250c60405190565b8152600081806126b9898960048401611690565b0381875afa806000928392612830575b506127d8575050639ca7dc7a6126e161250c60405190565b8152600081806126f5898960048401611690565b0381875afa806000928392612812575b506127d85750506000939291612027915061273563fbda03ab9161272860405190565b9788968795869560e01b90565b03915afa908160009182936127bb575b506127505750509190565b80519194509150612765610f9861016a865190565b0361276e579190565b61277f61277a84925190565b915190565b90610f8061278c60405190565b9283927fab8b67c6000000000000000000000000000000000000000000000000000000008452600484016120de565b9092506127d1913d8091833e6120bb81836106e5565b9138612745565b9650975050925050506127e9845190565b6127f7610f9861016a855190565b03612806579061016a91612fa6565b5061277f61277a845190565b909261282892503d8091833e6120bb81836106e5565b909138612705565b909261284692503d8091833e6120bb81836106e5565b9091386126c9565b909261286492503d8091833e6120bb81836106e5565b90913861268d565b5061287961250c60405190565b815260048101869052600081602481875afa90811561292557600091612904575b50630ebd4c7f6128ac61250c60405190565b815260048101879052600081602481885afa600091816128e1575b501560000361265d579650975050925050506127e9845190565b6128fd91923d8091833e6128f581836106e5565b81019061243c565b90386128c7565b61291f913d8091833e61291781836106e5565b810190612416565b3861289a565b611fd5565b61293e91923d8091833e61291781836106e5565b9038612657565b975050935050505061295d612958845190565b61221d565b90612969612958855190565b93600092600061297881610954565b945b61298561016a855190565b861015612a4e57612a42612a4891612a2f612a22611995612a1c612a176020612a038e6129fd8d8f838f6129dc906129c0836129e29561173d565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b9261173d565b9073ffffffffffffffffffffffffffffffffffffffff169052565b8d61173d565b5101516bffffffffffffffffffffffff1690565b6123fb565b8a610a88565b612a2c8a8d61173d565b52565b612a3c611949898c61173d565b90611002565b956123ce565b9461297a565b9391945050612a5b915090565b8111612a6657509190565b610f8090612a7360405190565b9182917f3728b83d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b612ac291923d8091833e612aba81836106e5565b8101906123a8565b903861261e565b612ae7611a8a7317b0c8564e53f22364a6c8de6f7ca5ce9bea4e5d81565b63b85ed7e490612b00612af960405190565b9260e01b90565b825260208280612b148a8a60048401611690565b0381845afa60009281612bf0575b50612b2f575b50506125f2565b6020612b449163860110f5906124aa60405190565b82528180612b57898d8d60048501611fa1565b03915afa60009181612bc0575b5015600003612b2857965097505050505050610f98612b836001610954565b91612a2c612bba612b9c612b968661221d565b9561221d565b96612bb56000916129e2612baf84610954565b8961173d565b610954565b8661173d565b612be291925060203d8111612be9575b612bda81836106e5565b8101906122d5565b9038612b64565b503d612bd0565b612c1291935060203d8111612c19575b612c0a81836106e5565b8101906120ca565b9138612b22565b503d612c00565b5073b932a70a57673d89f4acffbe830e8ed7f75fb9e073ffffffffffffffffffffffffffffffffffffffff8516146125ed565b955097505091505061016a9250612c79612c6b865190565b6111d9610f9861016a865190565b612fa6565b9092612c9492503d8091833e6120bb81836106e5565b9091386125a9565b95939650975092508311612f2a5760009384918291883b612cc9612cbf85612114565b9163ffffffff1690565b11612e47575b612d009450612cf263fd90e897612ce560405190565b9687948593849360e01b90565b835260048301526024820190565b03915afa849281612e23575b50612d52575050610f9890612a2c612bba612d276001610954565b94612bb5612d46612d40612d3a8961221d565b9861221d565b996109f6565b6129e2612baf84610954565b9290939450612d5f845190565b93612d698561221d565b90612d738661221d565b96855b88885b881015612e0757612df888612d7993612df3612dff94612a2c612deb6119958e612de68f8f8f91612dd86020926129e28e6129dc612dba82612de19961173d565b519586015173ffffffffffffffffffffffffffffffffffffffff1690565b015161ffff1690565b61225e565b610a88565b94859261173d565b611002565b9760010190565b969050612d76565b5093509550509250612e1c610f98610f989390565b111561226f565b612e409193503d8087833e612e3881836106e5565b8101906121e5565b9138612d0c565b91612e6b90612e5c611a8a8b979496976109f6565b63d78d610b906124aa60405190565b825260049082905afa879181612f0e575b50158714612e8e575092918591612ccf565b95975050505050612ea0612958835190565b93612eac612958845190565b94612eb682610954565b93612ebf815190565b95855b88885b881015612e0757612df888612ec593612df3612f0694612a2c612deb6119958e612de68f8f8f91612dd86020926129e28e6129dc612dba82612de19961173d565b969050612ec2565b612f239192503d808a833e612e3881836106e5565b9038612e7c565b610f8083612a7360405190565b909250612f5b915060403d8111612f63575b612f5381836106e5565b8101906120f1565b909138612574565b503d612f49565b9092612f8092503d8091833e6120bb81836106e5565b909138612538565b612fa0915060203d8111612c1957612c0a81836106e5565b386124ea565b9190612fb3612958825190565b92600091612fc16000610954565b925b612fce61016a835190565b84101561301b5761300f61301591613002612ff8611995612ff26119498a8961173d565b88610a88565b612a2c888b61173d565b612a3c611949878a61173d565b936123ce565b92612fc3565b93949392506130279050565b8111612a6657509056000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000167a296135c0067903d4c099806405f6c316442e00000000000000000000000061b98acbfc23326cfe296f380b5aa3e5adcc5238000000000000000000000000ede30a830c6bd69abb358976b108b3596e5da7c9618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a71461011257806305261aea1461010d578063150b7a0214610108578063389273941461010357806338c61759146100fe578063454a2ab3146100f9578063571a26a0146100f4578063715018a6146100ef5780637fea43b8146100ea578063854cff2f146100e55780638da5cb5b146100e057806396b5a755146100db578063cbdfe7cc146100d6578063d8d62599146100d1578063e74b981b146100cc5763f2fde38b03610117576108b1565b610899565b610880565b61069d565b610685565b610643565b61062b565b6105e8565b610527565b6104f5565b610349565b610336565b61031d565b6102a8565b6101c5565b61016d565b600080fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081165b0361011757565b905035906101548261011c565b565b906020828203126101175761016a91610147565b90565b346101175761019a610188610183366004610156565b611cd9565b60405191829182901515815260200190565b0390f35b80610140565b905035906101548261019e565b906020828203126101175761016a916101a4565b34610117576101dd6101d83660046101b1565b61175c565b604051005b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff8116610140565b90503590610154826101fb565b909182601f830112156101175781359167ffffffffffffffff831161011757602001926001830284011161011757565b90608082820312610117576102698183610217565b926102778260208501610217565b9261028583604083016101a4565b92606082013567ffffffffffffffff8111610117576102a49201610224565b9091565b346101175761019a6102c76102be366004610254565b93929092610901565b604051918291827fffffffff00000000000000000000000000000000000000000000000000000000909116815260200190565b91906040838203126101175761016a9061031481856101a4565b936020016101a4565b34610117576101dd6103303660046102fa565b90611118565b6101dd6103443660046101b1565b610ea2565b6101dd6103573660046101b1565b61100f565b0190565b9061038061037961036f845190565b8084529260200190565b9260200190565b9060005b8181106103915750505090565b9091926103ae6103a76001928651815260200190565b9460200190565b929101610384565b906103c561037961036f845190565b9060005b8181106103d65750505090565b9091926104026103a7600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b9291016103c9565b805173ffffffffffffffffffffffffffffffffffffffff16825261016a916101006104d2610120830160208581015173ffffffffffffffffffffffffffffffffffffffff169085015260408581015173ffffffffffffffffffffffffffffffffffffffff169085015260608581015173ffffffffffffffffffffffffffffffffffffffff16908501526104a260808601516080860152565b6104b160a086015160a0860152565b6104c060c086015160c0860152565b60e085015184820360e0860152610360565b920151906101008184039101526103b6565b602080825261016a9291019061040a565b346101175761019a61051061050b3660046101b1565b611cc2565b604051918291826104e4565b600091031261011757565b346101175761053736600461051c565b6101dd611d7b565b90916060828403126101175761016a6105588484610217565b9361056681602086016101a4565b936040016101a4565b9061057e61037961036f845190565b9060005b81811061058f5750505090565b9091926105bb6103a7600192865173ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101610582565b604080825261016a9391926105da9184019061056f565b916020818403910152610360565b34610117576106016105fb36600461053f565b91612462565b9061019a61060e60405190565b928392836105c3565b906020828203126101175761016a91610217565b34610117576101dd61063e366004610617565b611c3e565b346101175761065336600461051c565b61019a61065e611d51565b6040519182918273ffffffffffffffffffffffffffffffffffffffff909116815260200190565b34610117576101dd6106983660046101b1565b6114a8565b34610117576101dd6106b03660046102fa565b90611c6d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810190811067ffffffffffffffff82111761072557604052565b6106b6565b9061015461073760405190565b92836106e5565b67ffffffffffffffff81116107255760208091020190565b9092919261076b6107668261073e565b61072a565b938185526020808601920283019281841161011757915b83831061078f5750505050565b6020809161079d84866101a4565b815201920191610782565b9080601f830112156101175781602061016a93359101610756565b909291926107d36107668261073e565b938185526020808601920283019281841161011757915b8383106107f75750505050565b602080916108058486610217565b8152019201916107ea565b9080601f830112156101175781602061016a933591016107c3565b916060838303126101175761084082846101a4565b92602081013567ffffffffffffffff811161011757836108619183016107a8565b92604082013567ffffffffffffffff81116101175761016a9201610810565b34610117576101dd61089336600461082b565b916111a8565b34610117576101dd6108ac366004610617565b611c1b565b34610117576101dd6108c4366004610617565b611dc4565b6108dc6108d661016a9290565b60e01b90565b7fffffffff000000000000000000000000000000000000000000000000000000001690565b919261091c9061092695610913600090565b5081019061082b565b9491929093610d65565b61016a63150b7a026108c9565b6101e261016a61016a9290565b61016a90610933565b61016a61012061072a565b61016a61016a61016a9290565b9061096b90610954565b600052602052604060002090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b9073ffffffffffffffffffffffffffffffffffffffff905b9181191691161790565b6101e261016a61016a9273ffffffffffffffffffffffffffffffffffffffff1690565b61016a906109ca565b61016a906109ed565b90610a0f61016a610a16926109f6565b82546109a8565b9055565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff906109c0565b90610a5261016a610a1692610954565b8254610a1a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810292918115918404141715610a9b57565b610a59565b919060086109c0910291610ad37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841b90565b921b90565b9190610ae961016a610a1693610954565b908354610aa0565b61015491600091610ad8565b818110610b08575050565b80610b166000600193610af1565b01610afd565b9091828110610b2a57505050565b6101549290610b40905b92600052602060002090565b9081019101610afd565b906801000000000000000081116107255781610b67610154935490565b90828155610b1c565b81519167ffffffffffffffff831161072557610b9b610b34600192610b958686610b4a565b60200190565b92049160005b838110610bae5750505050565b6001906020610bbe61016a865190565b9401938184015501610ba1565b9061015491610b70565b81519167ffffffffffffffff831161072557610bfa610b34600192610b958686610b4a565b92049160005b838110610c0d5750505050565b6001906020610c3361016a865173ffffffffffffffffffffffffffffffffffffffff1690565b9401938184015501610c00565b9061015491610bd5565b6101549190610d559061010090600890610c8281610c7c875173ffffffffffffffffffffffffffffffffffffffff1690565b906109ff565b610caa60018201610c7c602088015173ffffffffffffffffffffffffffffffffffffffff1690565b610cd260028201610c7c604088015173ffffffffffffffffffffffffffffffffffffffff1690565b610cfa60038201610c7c606088015173ffffffffffffffffffffffffffffffffffffffff1690565b610d1260048201610d0c608088015190565b90610a42565b610d2460058201610d0c60a088015190565b610d3660068201610d0c60c088015190565b610d4e60078201610d4860e088015190565b90610bcb565b0192015190565b90610c40565b9061015491610c4a565b939194926001610d7481611e51565b610d7d90611e3c565b9560009233610d8b85610940565b91610d94610949565b73ffffffffffffffffffffffffffffffffffffffff909916868a015273ffffffffffffffffffffffffffffffffffffffff16602089015273ffffffffffffffffffffffffffffffffffffffff16604088015273ffffffffffffffffffffffffffffffffffffffff166060870152608086015260a0850152610e1490610954565b60c084015260e0830152610100820152610e2f826002610961565b90610e3991610d5b565b7f7e0e356457a92dacd3760ddf327a24dd226c6ca01b2cc41a7fd6f28469c7ab9b90610e6460405190565b90815280602081015b0390a1565b61016a906101e2565b61016a9054610e72565b61016a9081565b61016a9054610e85565b61016a62015180610954565b610eb061016a826002610961565b60038101610ebd81610e7b565b610edd60005b9173ffffffffffffffffffffffffffffffffffffffff1690565b14158015610f84575b610f5557610f13610f1a92610f09610f004261035c610e96565b60068301610a42565b6005349101610a42565b33906109ff565b610e6d7f7a183e84509e3fe5b0b3aac15347fd1c7d71fd1503001f1a1d7c9658077eb35f91610f4860405190565b9182918290815260200190565b6040517f82b42900000000000000000000000000000000000000000000000000000000008152600490fd5b0390fd5b5034610f9c610f9861016a60058601610e8c565b9190565b10610ee6565b91908203918211610a9b57565b61016a6014610954565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115610ff2570490565b610fb9565b61016a610384610954565b91908201809211610a9b57565b61101d61016a826002610961565b60068101904261102f61016a84610e8c565b811180156110f4575b80156110b6575b610f5557610f1a92611059611052610ff7565b8093611002565b611068610f9861016a84610e8c565b1161109f575b5050610f136003820191611098600561108685610e7b565b92019161109283610e8c565b90611bcc565b3490610a42565b610d0c6110af9261035c83610e8c565b388061106e565b50600582016110ee610f9861016a6110e06110da346110d487610e8c565b90610fa2565b94610e8c565b6110e8610faf565b90610fe8565b1061103f565b506110fe83610e8c565b61110b610f986000610954565b14611038565b1561011757565b9061115590600561112d61016a856002610961565b61113681610e7b565b61113f33610ec3565b1480611183575b61114f90611111565b01610a42565b610e6d7faed3e56ca017d9b02e523c2c7ba81ae5591f43f264dd5d603d70953a12d8079e91610f4860405190565b5061114f61119360068301610e8c565b6111a0610f986000610954565b149050611146565b9160086111f684611155946111f133916111df6002936111d9610ec36101e260006111d38a8a610961565b01610e7b565b14611111565b60076111eb8585610961565b01610bcb565b610961565b01610c40565b9061120b610b3461036f845490565b9060005b81811061121c5750505090565b90919261124061123960019261123187610e8c565b815260200190565b9460010190565b92910161120f565b9061016a916111fc565b9061015461126c9261126360405190565b93848092611248565b03836106e5565b90611282610b3461036f845490565b9060005b8181106112935750505090565b9091926112c66112396001926112a887610e7b565b73ffffffffffffffffffffffffffffffffffffffff16815260200190565b929101611286565b9061016a91611273565b9061015461126c926112e960405190565b938480926112ce565b9061015461140c6008611303610949565b9461132a61131082610e7b565b73ffffffffffffffffffffffffffffffffffffffff168752565b61135661133960018301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166020880152565b61138261136560028301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166040880152565b6113ae61139160038301610e7b565b73ffffffffffffffffffffffffffffffffffffffff166060880152565b6113c46113bd60048301610e8c565b6080880152565b6113da6113d360058301610e8c565b60a0880152565b6113f06113e960068301610e8c565b60c0880152565b6114066113ff60078301611252565b60e0880152565b016112d8565b610100840152565b61016a906112f2565b600061015491610b4a565b90600003611439576101549061141d565b610979565b6000600861015492828082015582600182015582600282015582600382015561146a8360048301610af1565b6114778360058301610af1565b6114848360068301610af1565b6114918360078301611428565b01611428565b90600003611439576101549061143e565b61153e60026114bf6114ba8483610961565b611414565b906115086000611503866114e7865173ffffffffffffffffffffffffffffffffffffffff1690565b3395906114f387610ec3565b148061156c575b6111f190611111565b611497565b604082015173ffffffffffffffffffffffffffffffffffffffff16916115386080611532306109f6565b92015190565b92611630565b610e6d7f28601d865dccc9f113e15a7185c1b38c085d598c71250d3337916a428536d77191610f4860405190565b506111f161157b60c089015190565b611587610f9887610954565b1490506114fa565b73ffffffffffffffffffffffffffffffffffffffff9182168152911660208201526060810192916101549160400152565b0152565b67ffffffffffffffff811161072557602090601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160190565b9061160c610766836115c4565b918252565b3d1561162b576116203d6115ff565b903d6000602084013e565b606090565b60046116786000949361166961015497879661164f6342842e0e6108c9565b9361165960405190565b968795602087019081520161158f565b602082018103825203826106e5565b82602082019151925af161168a611611565b50611111565b73ffffffffffffffffffffffffffffffffffffffff90911681526040810192916101549160200152565b801515610140565b90505190610154826116ba565b906020828203126101175761016a916116c2565b8015610a9b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90611746825190565b811015611757576020809102010190565b61170e565b600261176b6114ba8383610961565b906060908160a0840161177c815190565b908193611787600090565b5060c087014261179b610f9861016a845190565b10908115611bb5575b50610f55576000611503896117b893610961565b600192839560408801966117e0885173ffffffffffffffffffffffffffffffffffffffff1690565b3f6117f1610f9861016a6003610e8c565b14611b05575b611ad1575b81516000948161180e610f9888610954565b1115611a94575061181f6008610e8c565b61182b610f9887610954565b11611a57575b85805b6119cb575b505050505b61010086019261184d84515190565b908161185b610f9886610954565b11611916575b505050505082916118986118b29261189360206118e897015173ffffffffffffffffffffffffffffffffffffffff1690565b611bcc565b5173ffffffffffffffffffffffffffffffffffffffff1690565b906118bc306109f6565b61153860806118e2606085015173ffffffffffffffffffffffffffffffffffffffff1690565b93015190565b610e6d7f2d7633a748a750b559b97738629efd586b561319b152bb42ba14d590706d31da91610f4860405190565b9081805b611925575b50611861565b156119b6575b61193584916116e3565b918260e08a0161194d61194983835161173d565b5190565b611959610f9889610954565b11611969575b505091908261191a565b976118936118986119a76119a061199561198c611949889f986119af995161173d565b8b515b90610a88565b6110e8612710610954565b8094610fa2565b9a8a5161173d565b388061195f565b6119bf84610954565b811161192b578061191f565b15611a42575b6119db85916116e3565b90816119ea611949828661173d565b6119f6610f9889610954565b11611a03575b5086611834565b97611a3d611a1989926110d46119498d8961173d565b99611893611a37611949611a30611898858c61173d565b938961173d565b916109f6565b6119fc565b611a4b85610954565b81116119d15780611839565b611a8f611a7c611a75611995611a6b885190565b61198f6008610e8c565b8099610fa2565b97611893611a8a6004610e7b565b6109f6565b611831565b9650505050611acc611abe611ab7611995611aad855190565b61198f6007610e8c565b8096610fa2565b94611893611a8a6004610e7b565b61183e565b5050611b0082611af5875173ffffffffffffffffffffffffffffffffffffffff1690565b608089015190611fe1565b6117fc565b506000807f000000000000000000000000167a296135c0067903d4c099806405f6c316442e6004611b858c6116698d611b6b611b656080611b5f637abab711945173ffffffffffffffffffffffffffffffffffffffff1690565b95015190565b916108c9565b92611b7560405190565b9586946020860190815201611690565b82602082019151925af150611bb0611b9b611611565b6020611ba5825190565b8183010191016116cf565b6117f7565b519050611bc5610f986000610954565b14386117a4565b600061015492611bdf611a8a83946109f6565b90611be960405190565b90818003925af161168a611611565b61015490611c10611c07611d51565b6111d933610ec3565b6101549060046109ff565b61015490611bf8565b61015490611c33611c07611d51565b6101549060066109ff565b61015490611c24565b9061015491611c57611c07611d51565b90611c66610154926007610a42565b6008610a42565b9061015491611c47565b611c7f610949565b9060008252602080808080808080808a0160008152016000815201600081520160008152016000815201600081520160608152016060905250565b61016a611c77565b6114ba61016a91611cd1611cba565b506002610961565b611ce66301ffc9a76108c9565b7fffffffff00000000000000000000000000000000000000000000000000000000821614908115611d15575090565b9050611d4d611d2763150b7a026108c9565b917fffffffff000000000000000000000000000000000000000000000000000000001690565b1490565b61016a6000610e7b565b611d66611c07611d51565b610154610154611d766000610940565b611dcd565b610154611d5b565b61015490611d92611c07611d51565b61015490611d76611da66101e26000610940565b73ffffffffffffffffffffffffffffffffffffffff83161415611111565b61015490611d83565b611dd76000610e7b565b90611de38160006109ff565b7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091610e6d611e1160405190565b9283928373ffffffffffffffffffffffffffffffffffffffff91821681529116602082015260400190565b600061016a91611e4a600090565b5001610e8c565b61015490610d0c6000611e646001610954565b92019161035c83610e8c565b90505190610154826101fb565b90929192611e8d6107668261073e565b938185526020808601920283019281841161011757915b838310611eb15750505050565b60208091611ebf8486611e70565b815201920191611ea4565b9080601f8301121561011757815161016a92602001611e7d565b905051906101548261019e565b90929192611f016107668261073e565b938185526020808601920283019281841161011757915b838310611f255750505050565b60208091611f338486611ee4565b815201920191611f18565b9080601f8301121561011757815161016a92602001611ef1565b91909160408184031261011757805167ffffffffffffffff81116101175783611f82918301611eca565b92602082015167ffffffffffffffff81116101175761016a9201611f3e565b73ffffffffffffffffffffffffffffffffffffffff90911681526060810193926101549290916040916115c0906020830152565b6040513d6000823e3d90fd5b6000919392611fee606090565b5061202783611ffc306109f6565b637fea43b8612032612010620f4240610954565b9561201a60405190565b9a8b988997889560e01b90565b855260048501611fa1565b0393f1918260009182946120a5575b50610f98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f526f79616c7479206c6f6f6b7570206661696c656400000000000000000000006044820152606490fd5b9093506120c3913d8091833e6120bb81836106e5565b810190611f58565b9238612041565b906020828203126101175761016a91611e70565b9081526040810192916101549160200152565b91906040838203126101175761016a9061210b8185611e70565b93602001611ee4565b61212161016a61016a9290565b63ffffffff1690565b61ffff8116610140565b905051906101548261212a565b9190916040818403126101175761217661215b604061072a565b9360006121688285611e70565b908601526020809301612134565b90830152565b9092919261218c6107668261073e565b93818552604060208601920283019281841161011757915b8383106121b15750505050565b60206040916121c08486612141565b8152019201916121a4565b9080601f8301121561011757815161016a9260200161217c565b9060208282031261011757815167ffffffffffffffff81116101175761016a92016121cb565b9061160c6107668361073e565b369037565b9061015461223361222d8461220b565b9361073e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00160208401612218565b61016a61016a61016a9261ffff1690565b1561227657565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c69642073706c6974000000000000000000000000000000000000006044820152606490fd5b906020828203126101175761016a91611ee4565b6bffffffffffffffffffffffff8116610140565b90505190610154826122e9565b91909160408184031261011757612176612324604061072a565b9360006123318285611e70565b9086015260208093016122fd565b9092919261234f6107668261073e565b93818552604060208601920283019281841161011757915b8383106123745750505050565b6020604091612383848661230a565b815201920191612367565b9080601f8301121561011757815161016a9260200161233f565b9060208282031261011757815167ffffffffffffffff81116101175761016a920161238e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a9b5760010190565b61016a61016a61016a926bffffffffffffffffffffffff1690565b9060208282031261011757815167ffffffffffffffff81116101175761016a9201611eca565b9060208282031261011757815167ffffffffffffffff81116101175761016a9201611f3e565b60609392849291906124b3602061249b611a8a7f000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d6109f6565b63de5488af906124aa60405190565b93849260e01b90565b825273ffffffffffffffffffffffffffffffffffffffff8616600483015260249082905afa8015612925576124f091600091612f88575b506109f6565b906124fa826109f6565b9163d6a1919a61251361250c60405190565b9160e01b90565b815260008180612527868a600484016120de565b038183885af1806000928392612f6a575b50612c53575050632a55205a61255061250c60405190565b815260408180612564868a600484016120de565b0381875afa806000928392612f37575b50612c9c57505063bb3bafd661258c61250c60405190565b815260048101869052600081602481875afa806000928392612c7e575b50612c535750506125ce6101e27341a322b28d0ff354040e2cbc676f0320d8c8850d90565b73ffffffffffffffffffffffffffffffffffffffff8516148015612c20575b612ac9575b63cad96cca61260361250c60405190565b815260048101869052600081602481875afa60009181612aa6575b50612945575063b9c4d9fb61263260405190565b61263c8260e01b90565b815260048101879052600081602481885afa6000918161292a575b5061286c575b505063d5a06d4c61267061250c60405190565b815260048101869052600081602481875afa80600092839261284e575b506127d857505063f66220746126a561250c60405190565b8152600081806126b9898960048401611690565b0381875afa806000928392612830575b506127d8575050639ca7dc7a6126e161250c60405190565b8152600081806126f5898960048401611690565b0381875afa806000928392612812575b506127d85750506000939291612027915061273563fbda03ab9161272860405190565b9788968795869560e01b90565b03915afa908160009182936127bb575b506127505750509190565b80519194509150612765610f9861016a865190565b0361276e579190565b61277f61277a84925190565b915190565b90610f8061278c60405190565b9283927fab8b67c6000000000000000000000000000000000000000000000000000000008452600484016120de565b9092506127d1913d8091833e6120bb81836106e5565b9138612745565b9650975050925050506127e9845190565b6127f7610f9861016a855190565b03612806579061016a91612fa6565b5061277f61277a845190565b909261282892503d8091833e6120bb81836106e5565b909138612705565b909261284692503d8091833e6120bb81836106e5565b9091386126c9565b909261286492503d8091833e6120bb81836106e5565b90913861268d565b5061287961250c60405190565b815260048101869052600081602481875afa90811561292557600091612904575b50630ebd4c7f6128ac61250c60405190565b815260048101879052600081602481885afa600091816128e1575b501560000361265d579650975050925050506127e9845190565b6128fd91923d8091833e6128f581836106e5565b81019061243c565b90386128c7565b61291f913d8091833e61291781836106e5565b810190612416565b3861289a565b611fd5565b61293e91923d8091833e61291781836106e5565b9038612657565b975050935050505061295d612958845190565b61221d565b90612969612958855190565b93600092600061297881610954565b945b61298561016a855190565b861015612a4e57612a42612a4891612a2f612a22611995612a1c612a176020612a038e6129fd8d8f838f6129dc906129c0836129e29561173d565b51015173ffffffffffffffffffffffffffffffffffffffff1690565b9261173d565b9073ffffffffffffffffffffffffffffffffffffffff169052565b8d61173d565b5101516bffffffffffffffffffffffff1690565b6123fb565b8a610a88565b612a2c8a8d61173d565b52565b612a3c611949898c61173d565b90611002565b956123ce565b9461297a565b9391945050612a5b915090565b8111612a6657509190565b610f8090612a7360405190565b9182917f3728b83d0000000000000000000000000000000000000000000000000000000083526004830190815260200190565b612ac291923d8091833e612aba81836106e5565b8101906123a8565b903861261e565b612ae7611a8a7317b0c8564e53f22364a6c8de6f7ca5ce9bea4e5d81565b63b85ed7e490612b00612af960405190565b9260e01b90565b825260208280612b148a8a60048401611690565b0381845afa60009281612bf0575b50612b2f575b50506125f2565b6020612b449163860110f5906124aa60405190565b82528180612b57898d8d60048501611fa1565b03915afa60009181612bc0575b5015600003612b2857965097505050505050610f98612b836001610954565b91612a2c612bba612b9c612b968661221d565b9561221d565b96612bb56000916129e2612baf84610954565b8961173d565b610954565b8661173d565b612be291925060203d8111612be9575b612bda81836106e5565b8101906122d5565b9038612b64565b503d612bd0565b612c1291935060203d8111612c19575b612c0a81836106e5565b8101906120ca565b9138612b22565b503d612c00565b5073b932a70a57673d89f4acffbe830e8ed7f75fb9e073ffffffffffffffffffffffffffffffffffffffff8516146125ed565b955097505091505061016a9250612c79612c6b865190565b6111d9610f9861016a865190565b612fa6565b9092612c9492503d8091833e6120bb81836106e5565b9091386125a9565b95939650975092508311612f2a5760009384918291883b612cc9612cbf85612114565b9163ffffffff1690565b11612e47575b612d009450612cf263fd90e897612ce560405190565b9687948593849360e01b90565b835260048301526024820190565b03915afa849281612e23575b50612d52575050610f9890612a2c612bba612d276001610954565b94612bb5612d46612d40612d3a8961221d565b9861221d565b996109f6565b6129e2612baf84610954565b9290939450612d5f845190565b93612d698561221d565b90612d738661221d565b96855b88885b881015612e0757612df888612d7993612df3612dff94612a2c612deb6119958e612de68f8f8f91612dd86020926129e28e6129dc612dba82612de19961173d565b519586015173ffffffffffffffffffffffffffffffffffffffff1690565b015161ffff1690565b61225e565b610a88565b94859261173d565b611002565b9760010190565b969050612d76565b5093509550509250612e1c610f98610f989390565b111561226f565b612e409193503d8087833e612e3881836106e5565b8101906121e5565b9138612d0c565b91612e6b90612e5c611a8a8b979496976109f6565b63d78d610b906124aa60405190565b825260049082905afa879181612f0e575b50158714612e8e575092918591612ccf565b95975050505050612ea0612958835190565b93612eac612958845190565b94612eb682610954565b93612ebf815190565b95855b88885b881015612e0757612df888612ec593612df3612f0694612a2c612deb6119958e612de68f8f8f91612dd86020926129e28e6129dc612dba82612de19961173d565b969050612ec2565b612f239192503d808a833e612e3881836106e5565b9038612e7c565b610f8083612a7360405190565b909250612f5b915060403d8111612f63575b612f5381836106e5565b8101906120f1565b909138612574565b503d612f49565b9092612f8092503d8091833e6120bb81836106e5565b909138612538565b612fa0915060203d8111612c1957612c0a81836106e5565b386124ea565b9190612fb3612958825190565b92600091612fc16000610954565b925b612fce61016a835190565b84101561301b5761300f61301591613002612ff8611995612ff26119498a8961173d565b88610a88565b612a2c888b61173d565b612a3c611949878a61173d565b936123ce565b92612fc3565b93949392506130279050565b8111612a6657509056

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

000000000000000000000000ad2184fb5dbcfc05d8f056542fb25b04fa32a95d000000000000000000000000167a296135c0067903d4c099806405f6c316442e00000000000000000000000061b98acbfc23326cfe296f380b5aa3e5adcc5238000000000000000000000000ede30a830c6bd69abb358976b108b3596e5da7c9618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

-----Decoded View---------------
Arg [0] : _royaltyRegistry (address): 0xaD2184FB5DBcfC05d8f056542fB25b04fa32A95D
Arg [1] : _primarySalesRegistry (address): 0x167A296135c0067903d4C099806405f6c316442E
Arg [2] : factory_ (address): 0x61b98ACbfc23326Cfe296f380B5aa3e5Adcc5238
Arg [3] : whitelist_ (address): 0xEdE30a830C6bD69ABb358976B108b3596e5DA7c9
Arg [4] : ERC721SovreignV1CodeHash (bytes32): 0x618d4f1f0a3a895f9e0af7fba63dbbfdb28ec1fb0650450b40f7fa3df9877487

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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