ETH Price: $1,959.27 (-0.70%)
Gas: 0.03 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw Pending...243925292026-02-05 18:50:3517 days ago1770317435IN
0xD17dcEE0...04cC77B68
0 ETH0.00011493.05212952
Withdraw Pending...243922942026-02-05 18:03:2317 days ago1770314603IN
0xD17dcEE0...04cC77B68
0 ETH0.000101992.40296474
Claim243922792026-02-05 18:00:2317 days ago1770314423IN
0xD17dcEE0...04cC77B68
0 ETH0.000187282.47585141
Claim243922772026-02-05 17:59:5917 days ago1770314399IN
0xD17dcEE0...04cC77B68
0 ETH0.000222422.683881
Claim243922742026-02-05 17:59:2317 days ago1770314363IN
0xD17dcEE0...04cC77B68
0 ETH0.000255392.44017383
Claim243922602026-02-05 17:56:3517 days ago1770314195IN
0xD17dcEE0...04cC77B68
0 ETH0.000215442.59974953
Claim243922272026-02-05 17:49:5917 days ago1770313799IN
0xD17dcEE0...04cC77B68
0 ETH0.000245642.80539447
Claim243922252026-02-05 17:49:3517 days ago1770313775IN
0xD17dcEE0...04cC77B68
0 ETH0.000269932.70007307
Claim243922222026-02-05 17:48:5917 days ago1770313739IN
0xD17dcEE0...04cC77B68
0 ETH0.000225792.25853219
Claim243922162026-02-05 17:47:4717 days ago1770313667IN
0xD17dcEE0...04cC77B68
0 ETH0.000232072.3213586
Claim243922102026-02-05 17:46:3517 days ago1770313595IN
0xD17dcEE0...04cC77B68
0 ETH0.000250132.38991279
Claim243922052026-02-05 17:45:3517 days ago1770313535IN
0xD17dcEE0...04cC77B68
0 ETH0.000437074.27827454
Claim243922022026-02-05 17:44:5917 days ago1770313499IN
0xD17dcEE0...04cC77B68
0 ETH0.00025272.52778084
Claim243921972026-02-05 17:43:5917 days ago1770313439IN
0xD17dcEE0...04cC77B68
0 ETH0.000243762.43825886
Claim243921952026-02-05 17:43:3517 days ago1770313415IN
0xD17dcEE0...04cC77B68
0 ETH0.000250292.5035839
Claim243921932026-02-05 17:43:1117 days ago1770313391IN
0xD17dcEE0...04cC77B68
0 ETH0.000256112.56183003
Claim243921892026-02-05 17:42:2317 days ago1770313343IN
0xD17dcEE0...04cC77B68
0 ETH0.000246852.46916891
Claim243921842026-02-05 17:41:2317 days ago1770313283IN
0xD17dcEE0...04cC77B68
0 ETH0.000222752.12832245
Claim243921652026-02-05 17:37:3517 days ago1770313055IN
0xD17dcEE0...04cC77B68
0 ETH0.000382174.75496013
Claim243921642026-02-05 17:37:2317 days ago1770313043IN
0xD17dcEE0...04cC77B68
0 ETH0.0004614.72960275
Claim243921602026-02-05 17:36:3517 days ago1770312995IN
0xD17dcEE0...04cC77B68
0 ETH0.00026152.68279678
Claim243921602026-02-05 17:36:3517 days ago1770312995IN
0xD17dcEE0...04cC77B68
0 ETH0.000448744.60379678
Claim243921532026-02-05 17:35:1117 days ago1770312911IN
0xD17dcEE0...04cC77B68
0 ETH0.000327713.36213831
Claim243921502026-02-05 17:34:3517 days ago1770312875IN
0xD17dcEE0...04cC77B68
0 ETH0.001523417.90953626
Create Bid243921492026-02-05 17:34:2317 days ago1770312863IN
0xD17dcEE0...04cC77B68
0.65 ETH0.000084362.92591037
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer243925292026-02-05 18:50:3517 days ago1770317435
0xD17dcEE0...04cC77B68
14.9 ETH
Transfer243922942026-02-05 18:03:2317 days ago1770314603
0xD17dcEE0...04cC77B68
0.1 ETH
Transfer243922772026-02-05 17:59:5917 days ago1770314399
0xD17dcEE0...04cC77B68
0.02 ETH
Transfer243922742026-02-05 17:59:2317 days ago1770314363
0xD17dcEE0...04cC77B68
0.02 ETH
Transfer243922602026-02-05 17:56:3517 days ago1770314195
0xD17dcEE0...04cC77B68
0.07 ETH
Transfer243922272026-02-05 17:49:5917 days ago1770313799
0xD17dcEE0...04cC77B68
0.14 ETH
Transfer243922252026-02-05 17:49:3517 days ago1770313775
0xD17dcEE0...04cC77B68
0.185 ETH
Transfer243922222026-02-05 17:48:5917 days ago1770313739
0xD17dcEE0...04cC77B68
0.2 ETH
Transfer243922162026-02-05 17:47:4717 days ago1770313667
0xD17dcEE0...04cC77B68
0.202995 ETH
Transfer243922102026-02-05 17:46:3517 days ago1770313595
0xD17dcEE0...04cC77B68
0.26 ETH
Transfer243922052026-02-05 17:45:3517 days ago1770313535
0xD17dcEE0...04cC77B68
0.3901 ETH
Transfer243922022026-02-05 17:44:5917 days ago1770313499
0xD17dcEE0...04cC77B68
0.4 ETH
Transfer243921972026-02-05 17:43:5917 days ago1770313439
0xD17dcEE0...04cC77B68
0.41 ETH
Transfer243921952026-02-05 17:43:3517 days ago1770313415
0xD17dcEE0...04cC77B68
0.6 ETH
Transfer243921932026-02-05 17:43:1117 days ago1770313391
0xD17dcEE0...04cC77B68
0.699 ETH
Transfer243921892026-02-05 17:42:2317 days ago1770313343
0xD17dcEE0...04cC77B68
0.73 ETH
Transfer243921842026-02-05 17:41:2317 days ago1770313283
0xD17dcEE0...04cC77B68
0.9 ETH
Transfer243921652026-02-05 17:37:3517 days ago1770313055
0xD17dcEE0...04cC77B68
0.2008 ETH
Transfer243921642026-02-05 17:37:2317 days ago1770313043
0xD17dcEE0...04cC77B68
1.269 ETH
Transfer243921602026-02-05 17:36:3517 days ago1770312995
0xD17dcEE0...04cC77B68
0.03 ETH
Transfer243921602026-02-05 17:36:3517 days ago1770312995
0xD17dcEE0...04cC77B68
0.25007 ETH
Transfer243921532026-02-05 17:35:1117 days ago1770312911
0xD17dcEE0...04cC77B68
0.38 ETH
Transfer243921502026-02-05 17:34:3517 days ago1770312875
0xD17dcEE0...04cC77B68
0.09 ETH
Transfer243921482026-02-05 17:34:1117 days ago1770312851
0xD17dcEE0...04cC77B68
0.21 ETH
Transfer243921482026-02-05 17:34:1117 days ago1770312851
0xD17dcEE0...04cC77B68
0.0375 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
TLRankedAuction

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 10000 runs

Other Settings:
prague EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {IERC721} from "@openzeppelin-contracts-5.5.0/token/ERC721/IERC721.sol";
import {Ownable} from "@openzeppelin-contracts-5.5.0/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin-contracts-5.5.0/utils/ReentrancyGuard.sol";

/// @title Transient Ranked Auction
/// @notice Fully onchain ranked auction using a sorted doubly linked list.
///         Supports any number of tokens between 2 and 512 (inclusive).
/// @author mpeyfuss
contract TLRankedAuction is Ownable, ReentrancyGuard {
    /////////////////////////////////////////////////////////////////////
    // Types
    /////////////////////////////////////////////////////////////////////

    enum AuctionState {
        CONFIGURING,
        LIVE,
        SETTLING,
        SETTLED
    }

    struct BidNode {
        uint128 amount;
        uint32 next;
        uint32 prev;
        uint32 rank;
        bool claimed;
    }

    struct BidView {
        uint32 bidId;
        address bidder;
        uint128 amount;
        uint32 next;
        uint32 prev;
        uint32 rank;
        bool claimed;
    }

    /////////////////////////////////////////////////////////////////////
    // Storage
    /////////////////////////////////////////////////////////////////////

    // constants
    uint256 public constant GAS_GRIEFING_LIMIT = 1e5;
    uint256 public constant EXTENSION_TIME = 5 minutes;
    uint256 public constant EXTENSION_HARD_CAP = 2 hours;
    uint128 public constant BASIS = 10_000;
    uint128 public constant CREATE_BID_BPS = 250; // 2.5%
    uint128 public constant INCREASE_BID_BPS = 50; // 0.5%
    uint256 public constant MAX_TOKENS = 512; // upper bound to keep looped external calls manageable

    // immutable storage set on initialization
    IERC721 public immutable NFT_CONTRACT;
    uint128 public immutable START_BID;
    uint32 public immutable NUM_TOKENS; // capped by MAX_TOKENS in the constructor

    // auction state
    AuctionState public state;

    // storage for setting up the auction
    uint64 public openAt;
    uint64 public duration;
    uint64 public hardEndAt;
    uint256[] public prizeTokenIds;

    // storage for bids
    mapping(uint32 => BidNode) private _bids;
    mapping(uint32 => address) private _bidders;
    uint32 public nextBidId = 1;
    uint32 public listSize;
    uint32 public head;
    uint32 public tail;

    // storage for settling the auction
    uint128 public clearingPrice;
    uint32 public lastProcessedId;
    uint32 public nextRank = 1;
    uint32 public nextUnallocatedRank;
    uint256 public pendingProceeds;

    // refund bucket if auto-payout fails
    mapping(address => uint256) public pendingRefunds; // user address => amount of refund they can reclaim

    // nft bucket if transfer on claim fails
    mapping(uint256 => address) public pendingNfts; // token id => user that can reclaim it

    /////////////////////////////////////////////////////////////////////
    // Events
    /////////////////////////////////////////////////////////////////////

    event AuctionConfigured(uint64 openAt, uint64 duration);
    event AuctionExtended(uint64 newDuration);
    event AuctionReset();
    event AuctionSettling(uint256 clearingPrice);
    event AuctionSettled();
    event BidCreated(address indexed bidder, uint32 indexed bidId, uint256 amount);
    event BidIncreased(address indexed bidder, uint32 indexed bidId, uint256 newAmount);
    event BidRanked(uint32 indexed bidId, uint32 rank);
    event BidRemoved(address indexed bidder, uint32 indexed bidId, uint256 amount);
    event PrizeTokenEscrowed(uint256 indexed tokenId);
    event PrizeTokenClaimed(address indexed winner, uint256 indexed tokenId, uint256 refund);
    event PrizeTokenWithdrawn(address indexed recipient, uint256 indexed tokenId);
    event PrizeTokenRescued(address indexed winner, address indexed recipient, uint256 indexed tokenId);
    event PrizeTokenTransferFailed(address indexed winner, uint256 indexed tokenId);
    event RefundQueued(address indexed user, uint256 amount);
    event RefundWithdrawn(address indexed user, address indexed recipient, uint256 amount);

    /////////////////////////////////////////////////////////////////////
    // Errors
    /////////////////////////////////////////////////////////////////////

    error AddMore();
    error AuctionNotEnded();
    error BidClaimed();
    error BidMore();
    error BiddingEnded();
    error BiddingNotOpen();
    error BidsHaveBeenPlaced();
    error DepositAllPrizeTokens();
    error InvalidAddress();
    error InvalidBid();
    error InvalidNftContract();
    error InvalidRank();
    error InvalidStartBid();
    error InvariantBroken();
    error NotAllowed();
    error NotBidder();
    error NothingToWithdraw();
    error ProcessAtLeastOne();
    error TooFewTokens();
    error TooManyTokens();
    error WithdrawalFailed();

    /////////////////////////////////////////////////////////////////////
    // Constructor
    /////////////////////////////////////////////////////////////////////

    constructor(address owner_, address nftContract, uint128 startBid, uint32 numTokens) Ownable(owner_) {
        if (numTokens < 2) revert TooFewTokens();
        if (numTokens > MAX_TOKENS) revert TooManyTokens();
        if (startBid < BASIS) revert InvalidStartBid();
        if (nftContract.code.length == 0) revert InvalidNftContract(); // simple check for code is typically fine
        NFT_CONTRACT = IERC721(nftContract);
        START_BID = startBid;
        NUM_TOKENS = numTokens;
    }

    /////////////////////////////////////////////////////////////////////
    // Bid Functions
    /////////////////////////////////////////////////////////////////////

    /// @notice Function to create a bid, using a hint bid id to lower gas consumption.
    /// @dev If `hintBidId` is invalid, it will walk the entire list. Otherwise, will walk UP or DOWN from the hint.
    function createBid(uint32 hintBidId) external payable nonReentrant {
        // check auction is open
        _checkAuctionOpen();

        // check min bid
        uint128 amount = uint128(msg.value);
        uint128 minBid = _getMinBid();
        if (amount < minBid) revert BidMore();

        // insert bid
        uint32 bidId = nextBidId;
        unchecked {
            nextBidId = bidId + 1;
        }
        _insertBid(hintBidId, bidId, msg.sender, amount);

        // extend duration if needed
        _extendAuctionDuration();

        // remove tail, if needed
        _removeTailAndRefund();

        emit BidCreated(msg.sender, bidId, amount);
    }

    /// @notice Function to add onto a bid, again using a hint bid id for a new insertion point.
    /// @dev Removes the bid from it's current position and then inserts it again using the hint.
    ///      There's no need to remove the tail as we aren't increasing the list size.
    ///      The bid must increase over itself by `INCREASE_BID_BPS` and can extend the auction
    ///      if the position of the bid changes in the list.
    function increaseBid(uint32 bidId, uint32 hintBidId) external payable nonReentrant {
        // check auction is open
        _checkAuctionOpen();

        // ensure bid is a real bid in the list
        if (!_isBidInList(bidId)) revert InvalidBid();

        // cache storage pointer
        BidNode storage bid = _bids[bidId];

        // ensure the bidder is the one calling this function
        address bidder = _bidders[bidId];
        if (msg.sender != bidder) revert NotBidder();

        // cache bid amount
        uint128 bidAmount = bid.amount;

        // make sure enough eth was sent
        if (msg.value < _getMinBidIncrease(bidAmount)) revert AddMore();

        // calculate the new bid amount
        uint128 newBidAmount = bidAmount + uint128(msg.value);

        // cache the old bid pointers
        uint32 oldNextId = bid.next;
        uint32 oldPrevId = bid.prev;

        // pop the bid
        _popBid(bidId);

        // insert bid again
        _insertBid(hintBidId, bidId, bidder, newBidAmount);

        // extend auction duration, only if the bid position has changed
        if (oldNextId != bid.next || oldPrevId != bid.prev) {
            _extendAuctionDuration();
        }

        emit BidIncreased(bidder, bidId, newBidAmount);
    }

    /// @dev Internal helper to ensure the auction is open
    function _checkAuctionOpen() internal view {
        if (state != AuctionState.LIVE) revert NotAllowed();
        if (block.timestamp < uint256(openAt)) revert BiddingNotOpen();
        uint256 endTime = uint256(openAt + duration);
        if (block.timestamp > endTime) revert BiddingEnded();
    }

    /// @dev Internal helper to extend the auction on bid or bid increase, if needed.
    ///      This is an anti-snipe measure and the hard end cap stops a DOS attack.
    function _extendAuctionDuration() internal {
        // check end time
        uint256 endTime = uint256(openAt + duration);
        uint256 timeRemaining = endTime - block.timestamp;
        if (timeRemaining >= EXTENSION_TIME) return;

        // calculate desired end time
        uint256 desiredEndTime = block.timestamp + EXTENSION_TIME;

        // check against the hard cap
        uint256 newEnd = desiredEndTime > hardEndAt ? hardEndAt : desiredEndTime;

        // if doesn't change anything, return
        if (newEnd <= endTime) return;

        // extend duration
        duration = uint64(newEnd) - openAt;
        emit AuctionExtended(duration);
    }

    /// @dev Internal helper function to insert a bid.
    function _insertBid(uint32 hintBidId, uint32 bidId, address bidder, uint128 amount) internal {
        uint32 prevId = _findInsertionSpot(hintBidId, amount);
        uint32 nextId;

        // save new bid
        if (prevId == 0) {
            // new head
            nextId = head;
            head = bidId;
        } else {
            // middle/end insertion
            nextId = _bids[prevId].next;
            _bids[prevId].next = bidId;
        }
        _bids[bidId] = BidNode({amount: amount, next: nextId, prev: prevId, rank: 0, claimed: false});
        _bidders[bidId] = bidder;

        if (nextId == 0) {
            // new tail, no need to make a reverse link to the new bid
            tail = bidId;
        } else {
            // middle insertion so make sure the reverse link to the new bid is set
            _bids[nextId].prev = bidId;
        }

        // increase list size
        unchecked {
            ++listSize;
        }
    }

    /// @dev Internal helper to find the insertion spot
    ///      Returns the bid to insert AFTER
    ///      Returning 0 means new head.
    ///      Returning anything else is the new insertion spot.
    function _findInsertionSpot(uint32 hintBidId, uint128 amount) internal view returns (uint32) {
        uint32 listSize_ = listSize; // cache for gas

        // special case: new head
        if (listSize_ == 0 || amount > _getHeadBid()) return 0;

        // determine start spot
        uint32 current = hintBidId;
        if (current == 0 || !_isBidInList(current)) {
            // invalid bid, start at head
            current = head;
        }

        // walk the list
        if (amount <= _bids[current].amount) {
            // walk down
            for (uint256 i = 0; i < listSize_; ++i) {
                uint32 next = _bids[current].next;
                if (next == 0 || amount > _bids[next].amount) {
                    return current;
                }
                current = next;
            }
        } else {
            // walk up
            for (uint256 i = 0; i < listSize_; ++i) {
                uint32 prev = _bids[current].prev;
                if (prev == 0 || amount <= _bids[prev].amount) {
                    return prev;
                }
                current = prev;
            }
        }

        // if get here, should revert
        revert InvariantBroken();
    }

    /// @dev Internal helper to pop a bid from the list
    function _popBid(uint32 bidId) internal {
        // cache data
        uint32 prevId = _bids[bidId].prev;
        uint32 nextId = _bids[bidId].next;

        // adjust next bid
        if (nextId == 0) {
            // bid was the tail - set new tail
            tail = prevId;
        } else {
            _bids[nextId].prev = prevId;
        }

        // adjust prev bid
        if (prevId == 0) {
            // bid was the head - set new head
            head = nextId;
        } else {
            _bids[prevId].next = nextId;
        }

        // adjust bid pointers
        _bids[bidId].next = 0;
        _bids[bidId].prev = 0;

        // adjust list listSize
        unchecked {
            --listSize;
        }
    }

    /// @dev Internal helper function to remove the tail and refund.
    function _removeTailAndRefund() internal {
        // only remove tail if listSize is greater than the number of tokens
        if (listSize <= NUM_TOKENS) return;

        // get old tail
        uint32 oldTailId = tail;
        BidNode memory oldTail = _bids[oldTailId];
        address oldTailBidder = _bidders[oldTailId];

        // set new tail
        uint32 newTail = oldTail.prev;
        tail = newTail;
        _bids[newTail].next = 0;

        // delete old tail
        delete _bids[oldTailId];
        delete _bidders[oldTailId];
        unchecked {
            --listSize;
        }

        // refund ETH
        _tryRefundEth(oldTailBidder, uint256(oldTail.amount));

        emit BidRemoved(oldTailBidder, oldTailId, oldTail.amount);
    }

    /////////////////////////////////////////////////////////////////////
    // Settlement Functions
    /////////////////////////////////////////////////////////////////////

    /// @notice function to kick off the settlling of the auction
    /// @dev Anyone can call this after the preconditions are met
    ///      The clearing price is the tail bid only if all tokens are allocated.
    ///      Otherwise, the clearing price is the start price. This means that
    ///      the starting price should always be set to something you're okay
    ///      settling at unless you're confident it'll sell out.
    function startSettlingAuction() external nonReentrant {
        if (state != AuctionState.LIVE) revert NotAllowed();
        uint64 endTime = openAt + duration;
        if (block.timestamp <= uint256(endTime)) revert AuctionNotEnded();

        if (listSize == 0) {
            state = AuctionState.SETTLED;
            clearingPrice = START_BID;
            nextUnallocatedRank = 1;

            emit AuctionSettling(clearingPrice);
            emit AuctionSettled();
        } else {
            state = AuctionState.SETTLING;
            clearingPrice = listSize < NUM_TOKENS ? START_BID : _getTailBid();
            unchecked { 
                pendingProceeds = uint256(listSize) * uint256(clearingPrice);
                nextUnallocatedRank = listSize + 1;
            }
            
            emit AuctionSettling(clearingPrice);
        }
    }

    /// @notice Function to batch process ranks of bids.
    /// @dev Walks DOWN the list from the head to the tail and updates `lastProcessedId` to handle batches.
    function processRanks(uint32 numToProcess) external nonReentrant {
        if (state != AuctionState.SETTLING) revert NotAllowed();

        // cap numToProcess
        uint32 alreadyProcessed;
        unchecked {
            alreadyProcessed = nextRank - 1;
        }
        uint32 remaining = listSize > alreadyProcessed ? (listSize - alreadyProcessed) : 0;
        if (numToProcess > remaining) {
            numToProcess = remaining;
        }
        if (numToProcess == 0) revert ProcessAtLeastOne();

        // check that the last processed id has been ranked
        if (lastProcessedId != 0 && _bids[lastProcessedId].rank != (nextRank - 1)) revert InvariantBroken(); // something went wrong if reverts

        // start at head or the bid after the last processed
        uint32 current = lastProcessedId == 0 ? head : _bids[lastProcessedId].next;
        uint32 processedId = lastProcessedId;

        // process ranks
        for (uint256 i = 0; i < numToProcess; ++i) {
            if (current == 0) revert InvariantBroken(); // safety measure to catch regression
            uint32 rank = nextRank;
            unchecked { 
                nextRank = rank + 1;
            }
            _bids[current].rank = rank;
            processedId = current;
            current = _bids[current].next;
            emit BidRanked(processedId, rank);
        }

        // store last processed id once
        lastProcessedId = processedId;

        // settle if at the tail
        if (processedId == tail) {
            // move to next auction state
            state = AuctionState.SETTLED;
            emit AuctionSettled();
        }
    }

    /// @notice Function to claim the result of a bid.
    /// @dev Can be called by anyone but only sends out the NFT & refund to the bidder.
    ///      Auction must be settled in order to call this.
    function claim(uint32 bidId) external nonReentrant {
        if (state != AuctionState.SETTLED) revert NotAllowed();

        // get bid information
        BidNode storage storedBid = _bids[bidId];
        address bidder = _bidders[bidId];

        // check if bid valid or already claimed
        if (storedBid.rank == 0) revert InvalidBid();
        if (storedBid.claimed) revert BidClaimed();

        // mark claimed
        storedBid.claimed = true;

        // claim prize & refund
        uint256 prizeTokenId;
        uint256 refund;
        unchecked {
            prizeTokenId = prizeTokenIds[storedBid.rank - 1]; // minus one since rank is one based, but array is zero based
            refund = uint256(storedBid.amount - clearingPrice);
        }
        if (refund > 0) {
            _tryRefundEth(bidder, refund);
        }
        try NFT_CONTRACT.safeTransferFrom(address(this), bidder, prizeTokenId) {
            // success
            emit PrizeTokenClaimed(bidder, prizeTokenId, refund);
        } catch {
            // flag nft as needing rescuing
            pendingNfts[prizeTokenId] = bidder;
            emit PrizeTokenTransferFailed(bidder, prizeTokenId);
        }
    }

    /// @notice Function to withdraw left over prize tokens after the auction has been settled.
    /// @dev Uses a separate rank counter than what's used during `processRanks` for separation of concerns
    ///      and invariant tracking.
    function withdrawLeftOverPrizeTokens(address tokenRecipient, uint256 numToProcess)
        external
        nonReentrant
        onlyOwner
    {
        if (state != AuctionState.SETTLED) revert NotAllowed();
        if (listSize == NUM_TOKENS) revert NothingToWithdraw();
        if (tokenRecipient == address(0)) revert InvalidAddress();

        // cap numToProcess
        uint32 alreadyProcessed;
        uint32 remaining;
        unchecked {
            alreadyProcessed = nextUnallocatedRank - 1;
            remaining = NUM_TOKENS - alreadyProcessed;
        }
        if (numToProcess > remaining) {
            numToProcess = remaining;
        }
        if (numToProcess == 0) revert ProcessAtLeastOne();

        // withdraw prize tokens
        for (uint256 i = 0; i < numToProcess; ++i) {
            uint32 rank = nextUnallocatedRank;
            uint256 prizeTokenId;
            unchecked { 
                nextUnallocatedRank = rank + 1;
                prizeTokenId = prizeTokenIds[rank - 1]; // rank is ones based
            }
            NFT_CONTRACT.safeTransferFrom(address(this), tokenRecipient, prizeTokenId);

            emit PrizeTokenWithdrawn(tokenRecipient, prizeTokenId);
        }
    }

    /// @notice Function to withdraw pending proceeds.
    /// @dev The owner can withdraw prior to people claiming their winning tokens, but it is safe
    ///      since `pendingProceeds` is calculated before the contract enters the `SETTLING` state.
    function withdrawPendingProceeds(uint256 amount, address payoutAddress) external nonReentrant onlyOwner {
        if (state != AuctionState.SETTLED) revert NotAllowed();
        if (payoutAddress == address(0)) revert InvalidAddress();

        // calculate amount to withdraw
        uint256 amountToWithdraw = amount > pendingProceeds ? pendingProceeds : amount;
        if (amountToWithdraw == 0) revert NothingToWithdraw();

        // effects
        unchecked {
            pendingProceeds -= amountToWithdraw;
        }

        // withdraw
        (bool success,) = payoutAddress.call{value: amountToWithdraw}("");
        if (!success) {
            revert WithdrawalFailed();
        }
    }

    /////////////////////////////////////////////////////////////////////
    // Setup Functions
    /////////////////////////////////////////////////////////////////////

    /// @notice Function to deposit token ids into the contract, in batches if necessary.
    /// @dev The contract must be given approval by the nft owner to escrow the tokens.
    ///      Owner can escrow from any approved token owner; this is an intentional admin workflow.
    ///      The tokens should be deposited in the order in which they should be distributed based on rank.
    ///      i.e. [1,2,3] rather than [3,2,1] if rank one should get token id 1.
    function depositPrizeTokens(address tokenOwner, uint256[] calldata tokenIdsToAdd) external nonReentrant onlyOwner {
        if (state != AuctionState.CONFIGURING) revert NotAllowed();
        if (prizeTokenIds.length + tokenIdsToAdd.length > NUM_TOKENS) revert TooManyTokens();
        if (tokenOwner == address(this)) revert InvalidAddress();

        for (uint256 i = 0; i < tokenIdsToAdd.length; ++i) {
            uint256 prizeTokenId = tokenIdsToAdd[i];
            // effect
            prizeTokenIds.push(prizeTokenId);
            // interaction
            // safe to use just `transferFrom` here as we are escrowing them in this contract
            NFT_CONTRACT.transferFrom(tokenOwner, address(this), prizeTokenId);

            emit PrizeTokenEscrowed(prizeTokenId);
        }
    }

    /// @notice Function for the owner to remove prize tokens if not done in the right order.
    /// @dev Not allowed unless configuring.
    function withdrawPrizeTokens(address tokenRecipient, uint256 numToWithdraw) external nonReentrant onlyOwner {
        if (state != AuctionState.CONFIGURING) revert NotAllowed();
        if (tokenRecipient == address(0)) revert InvalidAddress();
        if (numToWithdraw > prizeTokenIds.length) {
            numToWithdraw = prizeTokenIds.length;
        }

        while (numToWithdraw > 0) {
            uint256 prizeTokenId = prizeTokenIds[prizeTokenIds.length - 1];
            prizeTokenIds.pop();

            NFT_CONTRACT.safeTransferFrom(address(this), tokenRecipient, prizeTokenId);
            emit PrizeTokenWithdrawn(tokenRecipient, prizeTokenId);

            unchecked {
                --numToWithdraw;
            } // safe because we cap it to the length of the array
        }
    }

    /// @notice Function to setup the auction and enable bidding.
    /// @dev Can only be called after the tokens deposited meet the expected number.
    ///      If the order isn't correct, use the `withdrawPrizeTokens` function and deposit again.
    ///      If `openAt_` is less than the current block timestamp, set to the current block timestamp.
    ///      Similarly, if `duration_` is less than `EXTENSION_TIME`, set to `EXTENSION_TIME`
    function setupAuction(uint64 openAt_, uint64 duration_) external nonReentrant onlyOwner {
        if (state != AuctionState.CONFIGURING) revert NotAllowed();
        if (prizeTokenIds.length != NUM_TOKENS) revert DepositAllPrizeTokens();

        state = AuctionState.LIVE;
        if (openAt_ < block.timestamp) {
            openAt_ = uint64(block.timestamp);
        }
        if (duration_ < EXTENSION_TIME) {
            duration_ = uint64(EXTENSION_TIME);
        }
        openAt = openAt_;
        duration = duration_;
        hardEndAt = openAt + duration + uint64(EXTENSION_HARD_CAP);

        emit AuctionConfigured(openAt_, duration_);
    }

    /// @notice Function to reset an auction back to `CONFIGURING` in case of error in setup.
    /// @dev This can only be done before any bid comes in and can only be called by the owner.
    function resetAuction() external nonReentrant onlyOwner {
        if (state != AuctionState.LIVE) revert NotAllowed();
        if (listSize > 0) revert BidsHaveBeenPlaced();

        state = AuctionState.CONFIGURING;
        openAt = 0;
        duration = 0;
        hardEndAt = 0;

        emit AuctionReset();
    }

    /////////////////////////////////////////////////////////////////////
    // Reclaim Functions
    /////////////////////////////////////////////////////////////////////

    /// @notice Function for someone to manually pull a refund that reverted prior.
    function rescueRefund(address recipient) external nonReentrant {
        if (recipient == address(0)) revert InvalidAddress();
        uint256 refund = pendingRefunds[msg.sender];
        if (refund == 0) revert NothingToWithdraw();

        // clear pending refund for msg sender
        pendingRefunds[msg.sender] = 0;

        // refund to the specified recipient
        (bool success,) = recipient.call{value: refund}("");
        if (success) {
            emit RefundWithdrawn(msg.sender, recipient, refund); // emit event based on msg sender
        } else {
            revert WithdrawalFailed();
        }
    }

    /// @notice Function to rescue an nft that failed to transfer on claim.
    /// @dev In practice, this shouldn't happen, but you never know.
    ///      The caller must be the rightful reclaimer, but they can specify a new token recipient.
    function rescueNft(address recipient, uint256 tokenId) external nonReentrant {
        if (recipient == address(0)) revert InvalidAddress();
        address pendingNftOwner = pendingNfts[tokenId];
        if (pendingNftOwner == address(0)) revert NothingToWithdraw();
        if (pendingNftOwner != msg.sender) revert NotAllowed();

        // clear pending nft
        pendingNfts[tokenId] = address(0);

        // send NFT
        NFT_CONTRACT.safeTransferFrom(address(this), recipient, tokenId);

        emit PrizeTokenRescued(msg.sender, recipient, tokenId);
    }

    /////////////////////////////////////////////////////////////////////
    // View Functions
    /////////////////////////////////////////////////////////////////////

    /// @notice Function to get important auction info.
    function getAuctionInfo()
        external
        view
        returns (
            AuctionState state_,
            uint64 openAt_,
            uint64 duration_,
            uint64 hardEndAt_,
            uint128 clearingPrice_,
            uint32 listSize_,
            uint32 head_,
            uint32 tail_
        )
    {
        state_ = state;
        openAt_ = openAt;
        duration_ = duration;
        hardEndAt_ = hardEndAt;
        clearingPrice_ = clearingPrice;
        listSize_ = listSize;
        head_ = head;
        tail_ = tail;
    }

    /// @notice Function to get the minimum bid amount.
    function getMinBid() external view returns (uint128) {
        return _getMinBid();
    }

    /// @notice Function to calculate the minimum bid increase amount.
    function getMinBidIncrease(uint128 amount) external pure returns (uint128) {
        return _getMinBidIncrease(amount);
    }

    /// @notice Function to get the tail bid amount.
    function getTailBid() external view returns (uint128) {
        return _getTailBid();
    }

    /// @notice Function to get the head bid amount.
    function getHeadBid() external view returns (uint128) {
        return _getHeadBid();
    }

    /// @notice Function to get a full bid in detail.
    function getDetailedBid(uint32 bidId) public view returns (BidView memory) {
        BidNode memory storedBid = _bids[bidId];
        address bidder = _bidders[bidId];
        return BidView({
            bidId: bidId,
            bidder: bidder,
            amount: storedBid.amount,
            next: storedBid.next,
            prev: storedBid.prev,
            rank: storedBid.rank,
            claimed: storedBid.claimed
        });
    }

    /// @notice Function to get full bids as an array with pagination.
    function getBids(uint32 startBidId, uint32 limit)
        external
        view
        returns (BidView[] memory bids, uint32 numReturned)
    {
        bids = new BidView[](limit);
        uint32 current = startBidId == 0 ? head : startBidId;
        numReturned = 0;
        for (uint256 i = 0; i < limit; ++i) {
            if (current == 0) break;
            bids[i] = getDetailedBid(current);
            unchecked {
                ++numReturned;
            }
            current = bids[i].next;
        }
    }

    /// @notice Function to get the prize token for a rank.
    function getPrizeTokenIdForRank(uint32 rank) external view returns (uint256) {
        if (rank > NUM_TOKENS || rank == 0) revert InvalidRank();
        unchecked {
            return prizeTokenIds[rank - 1]; // rank is one based
        }
    }

    /////////////////////////////////////////////////////////////////////
    // Helper Functions
    /////////////////////////////////////////////////////////////////////

    /// @dev Helper function to get the minimum bid to be valid on bid creation.
    function _getMinBid() internal view returns (uint128) {
        if (listSize < NUM_TOKENS) {
            // underallocated list has min bid of `START_BID`
            return START_BID;
        } else {
            // fully allocated list has a min bid above tail bid to prevent bid pollution (outbid by 1 wei)
            uint256 tailBid = uint256(_bids[tail].amount);
            return uint128(tailBid + tailBid * CREATE_BID_BPS / BASIS);
        }
    }

    /// @dev Helper function to get the minimum bid increase amount to be valid on bid increase.
    function _getMinBidIncrease(uint128 bidAmount) internal pure returns (uint128) {
        return uint128(uint256(bidAmount) * INCREASE_BID_BPS / BASIS);
    }

    /// @dev Helper function to get the tail bid.
    function _getTailBid() internal view returns (uint128) {
        return _bids[tail].amount;
    }

    /// @dev Helper function to get the head bid.
    function _getHeadBid() internal view returns (uint128) {
        return _bids[head].amount;
    }

    /// @dev Helper function to determine if a bid is in the list
    function _isBidInList(uint32 bidId) internal view returns (bool) {
        // reject if bidder not stored
        if (_bidders[bidId] == address(0)) return false;

        // head & tail are always in the list if they exist
        if (bidId == head || bidId == tail) return true;

        // return true if pointers exist
        return _bids[bidId].prev != 0 || _bids[bidId].next != 0;
    }

    /// @dev Helper function to try to refund eth with gas griefing protection.
    function _tryRefundEth(address to, uint256 refund) internal {
        (bool success,) = to.call{value: refund, gas: GAS_GRIEFING_LIMIT}("");
        if (!success) {
            pendingRefunds[to] += refund;
            emit RefundQueued(to, refund);
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol)

pragma solidity >=0.6.2;

import {IERC165} from "../../utils/introspection/IERC165.sol";

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
 * by the {ReentrancyGuardTransient} variant in v6.0.
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuard {
    using StorageSlot for bytes32;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

Settings
{
  "remappings": [
    "@openzeppelin-contracts-5.5.0/=dependencies/@openzeppelin-contracts-5.5.0/",
    "forge-std-1.11.0/=dependencies/forge-std-1.11.0/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 10000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "prague",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"nftContract","type":"address"},{"internalType":"uint128","name":"startBid","type":"uint128"},{"internalType":"uint32","name":"numTokens","type":"uint32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddMore","type":"error"},{"inputs":[],"name":"AuctionNotEnded","type":"error"},{"inputs":[],"name":"BidClaimed","type":"error"},{"inputs":[],"name":"BidMore","type":"error"},{"inputs":[],"name":"BiddingEnded","type":"error"},{"inputs":[],"name":"BiddingNotOpen","type":"error"},{"inputs":[],"name":"BidsHaveBeenPlaced","type":"error"},{"inputs":[],"name":"DepositAllPrizeTokens","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidBid","type":"error"},{"inputs":[],"name":"InvalidNftContract","type":"error"},{"inputs":[],"name":"InvalidRank","type":"error"},{"inputs":[],"name":"InvalidStartBid","type":"error"},{"inputs":[],"name":"InvariantBroken","type":"error"},{"inputs":[],"name":"NotAllowed","type":"error"},{"inputs":[],"name":"NotBidder","type":"error"},{"inputs":[],"name":"NothingToWithdraw","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ProcessAtLeastOne","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TooFewTokens","type":"error"},{"inputs":[],"name":"TooManyTokens","type":"error"},{"inputs":[],"name":"WithdrawalFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"openAt","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"duration","type":"uint64"}],"name":"AuctionConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"newDuration","type":"uint64"}],"name":"AuctionExtended","type":"event"},{"anonymous":false,"inputs":[],"name":"AuctionReset","type":"event"},{"anonymous":false,"inputs":[],"name":"AuctionSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"clearingPrice","type":"uint256"}],"name":"AuctionSettling","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bidder","type":"address"},{"indexed":true,"internalType":"uint32","name":"bidId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BidCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bidder","type":"address"},{"indexed":true,"internalType":"uint32","name":"bidId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"BidIncreased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"bidId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"rank","type":"uint32"}],"name":"BidRanked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bidder","type":"address"},{"indexed":true,"internalType":"uint32","name":"bidId","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"BidRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"refund","type":"uint256"}],"name":"PrizeTokenClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PrizeTokenEscrowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PrizeTokenRescued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PrizeTokenTransferFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"PrizeTokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RefundWithdrawn","type":"event"},{"inputs":[],"name":"BASIS","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATE_BID_BPS","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTENSION_HARD_CAP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXTENSION_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GAS_GRIEFING_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INCREASE_BID_BPS","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NFT_CONTRACT","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NUM_TOKENS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_BID","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"bidId","type":"uint32"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"clearingPrice","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"hintBidId","type":"uint32"}],"name":"createBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256[]","name":"tokenIdsToAdd","type":"uint256[]"}],"name":"depositPrizeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"duration","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAuctionInfo","outputs":[{"internalType":"enum TLRankedAuction.AuctionState","name":"state_","type":"uint8"},{"internalType":"uint64","name":"openAt_","type":"uint64"},{"internalType":"uint64","name":"duration_","type":"uint64"},{"internalType":"uint64","name":"hardEndAt_","type":"uint64"},{"internalType":"uint128","name":"clearingPrice_","type":"uint128"},{"internalType":"uint32","name":"listSize_","type":"uint32"},{"internalType":"uint32","name":"head_","type":"uint32"},{"internalType":"uint32","name":"tail_","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"startBidId","type":"uint32"},{"internalType":"uint32","name":"limit","type":"uint32"}],"name":"getBids","outputs":[{"components":[{"internalType":"uint32","name":"bidId","type":"uint32"},{"internalType":"address","name":"bidder","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint32","name":"next","type":"uint32"},{"internalType":"uint32","name":"prev","type":"uint32"},{"internalType":"uint32","name":"rank","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"}],"internalType":"struct TLRankedAuction.BidView[]","name":"bids","type":"tuple[]"},{"internalType":"uint32","name":"numReturned","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"bidId","type":"uint32"}],"name":"getDetailedBid","outputs":[{"components":[{"internalType":"uint32","name":"bidId","type":"uint32"},{"internalType":"address","name":"bidder","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint32","name":"next","type":"uint32"},{"internalType":"uint32","name":"prev","type":"uint32"},{"internalType":"uint32","name":"rank","type":"uint32"},{"internalType":"bool","name":"claimed","type":"bool"}],"internalType":"struct TLRankedAuction.BidView","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHeadBid","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinBid","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"}],"name":"getMinBidIncrease","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"rank","type":"uint32"}],"name":"getPrizeTokenIdForRank","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTailBid","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hardEndAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"head","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"bidId","type":"uint32"},{"internalType":"uint32","name":"hintBidId","type":"uint32"}],"name":"increaseBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"lastProcessedId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listSize","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextBidId","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRank","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextUnallocatedRank","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingNfts","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingProceeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pendingRefunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"prizeTokenIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"numToProcess","type":"uint32"}],"name":"processRanks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"rescueRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"openAt_","type":"uint64"},{"internalType":"uint64","name":"duration_","type":"uint64"}],"name":"setupAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startSettlingAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum TLRankedAuction.AuctionState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tail","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenRecipient","type":"address"},{"internalType":"uint256","name":"numToProcess","type":"uint256"}],"name":"withdrawLeftOverPrizeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"payoutAddress","type":"address"}],"name":"withdrawPendingProceeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenRecipient","type":"address"},{"internalType":"uint256","name":"numToWithdraw","type":"uint256"}],"name":"withdrawPrizeTokens","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040526005805463ffffffff191660011790556006805463ffffffff60201b1916640100000000179055348015610036575f5ffd5b50604051614abb380380614abb833981016040819052610055916101eb565b836001600160a01b03811661008357604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b61008c81610181565b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055600263ffffffff821610156100d957604051634c69935360e01b815260040160405180910390fd5b6102008163ffffffff16111561010257604051633a4733d960e11b815260040160405180910390fd5b6127106001600160801b038316101561012e57604051635a9c511160e01b815260040160405180910390fd5b826001600160a01b03163b5f03610158576040516391da300560e01b815260040160405180910390fd5b6001600160a01b039092166080526001600160801b031660a05263ffffffff1660c05250610255565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146101e6575f5ffd5b919050565b5f5f5f5f608085870312156101fe575f5ffd5b610207856101d0565b9350610215602086016101d0565b60408601519093506001600160801b0381168114610231575f5ffd5b606086015190925063ffffffff8116811461024a575f5ffd5b939692955090935050565b60805160a05160c0516147cc6102ef5f395f81816107650152818161187c01528181611cdc01528181611e63015281816120cf01528181612a1801528181612ae6015281816133d7015261392601525f818161032e01528181611baa01528181611d4c015261340b01525f818161064601528181610eeb0152818161173e01528181612236015281816128b40152612c2801526147cc5ff3fe608060405260043610610319575f3560e01c806381cd8d621161019c578063b70ed9f3116100e7578063e343dc2d11610092578063ed042f031161006d578063ed042f0314610be2578063f2fde38b14610c23578063f47c84c514610c42578063fa5703f714610c57575f5ffd5b8063e343dc2d14610b54578063e7dd5d0a14610b70578063e8a60d3214610bba575f5ffd5b8063d94a3505116100c2578063d94a350514610a57578063dc26904914610b19578063e167956b14610b35575f5ffd5b8063b70ed9f3146109ed578063c19d93fb14610a0c578063c1c7033014610a38575f5ffd5b8063972c535611610147578063a68e79b711610122578063a68e79b714610977578063b02de0f4146109a3578063b613b114146109c2575f5ffd5b8063972c5356146108fc5780639c59e8c714610920578063a0e23ebd1461093f575f5ffd5b80638f7dcfa3116101775780638f7dcfa3146108a1578063916a661c146108c957806396c87e70146108dd575f5ffd5b806381cd8d62146108455780638cb39385146108645780638da5cb5b14610878575f5ffd5b80632b8f3689116102675780635681104a116102125780636e2c90e7116101ed5780636e2c90e7146107e9578063715018a6146108085780637bdcd6341461081c5780637d35045314610831575f5ffd5b80635681104a1461079c5780635d56ff48146107b1578063699ced4f146107d5575f5ffd5b806340fa01351161024257806340fa01351461073e5780634149db4814610754578063528cfa9814610787575f5ffd5b80632b8f3689146106c457806331d0cd92146106e357806332a0f2d714610702575f5ffd5b80631abbf0cd116102c75780631fda9a02116102a25780631fda9a0214610635578063267421c51461068d57806328dc501d146106a1575f5ffd5b80631abbf0cd146104845780631b8d6ed4146104975780631ea83a1d14610616575f5ffd5b80630fb5a6b4116102f75780630fb5a6b4146103dd57806313d8c8401461041657806318bff57614610457575f5ffd5b80630253492a1461031d57806303ed26291461037657806304951891146103bc575b5f5ffd5b348015610328575f5ffd5b506103507f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610381575f5ffd5b5060055468010000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16610350565b3480156103c7575f5ffd5b506103db6103d6366004614214565b610c6f565b005b3480156103e8575f5ffd5b506001546103fd9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161036d565b348015610421575f5ffd5b50600554610442906c01000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161036d565b348015610462575f5ffd5b50610476610471366004614234565b61103e565b60405161036d9291906142f6565b6103db610492366004614214565b6112c5565b3480156104a2575f5ffd5b506106096104b1366004614214565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091525063ffffffff9081165f818152600360209081526040808320815160a0808201845291546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048916838701908152600160a01b83048a16848701908152780100000000000000000000000000000000000000000000000084048b1660608087019182527c010000000000000000000000000000000000000000000000000000000090950460ff16151560808088019182528c8c5260048b529a89902054895160e081018b529c8d5273ffffffffffffffffffffffffffffffffffffffff16998c01999099529451909216958901959095529351881690870152915186169385019390935251909316908201529051151560c082015290565b60405161036d9190614354565b348015610621575f5ffd5b506103db610630366004614385565b611411565b348015610640575f5ffd5b506106687f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161036d565b348015610698575f5ffd5b5061035060fa81565b3480156106ac575f5ffd5b506106b6611c2081565b60405190815260200161036d565b3480156106cf575f5ffd5b506103db6106de36600461439e565b6115d0565b3480156106ee575f5ffd5b506103db6106fd3660046143dd565b61180d565b34801561070d575f5ffd5b506005546103509070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1681565b348015610749575f5ffd5b506106b6620186a081565b34801561075f575f5ffd5b506104427f000000000000000000000000000000000000000000000000000000000000000081565b348015610792575f5ffd5b5061035061271081565b3480156107a7575f5ffd5b506106b661012c81565b3480156107bc575f5ffd5b5060065461044290640100000000900463ffffffff1681565b3480156107e0575f5ffd5b506103db611a71565b3480156107f4575f5ffd5b506106b6610803366004614214565b611e60565b348015610813575f5ffd5b506103db611f02565b348015610827575f5ffd5b506106b660075481565b34801561083c575f5ffd5b506103db611f13565b348015610850575f5ffd5b506103db61085f366004614405565b612060565b34801561086f575f5ffd5b506103506122f1565b348015610883575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff16610668565b3480156108ac575f5ffd5b506005546104429068010000000000000000900463ffffffff1681565b3480156108d4575f5ffd5b50610350603281565b3480156108e8575f5ffd5b506103db6108f7366004614214565b6122fa565b348015610907575f5ffd5b5060055461044290640100000000900463ffffffff1681565b34801561092b575f5ffd5b506103db61093a36600461439e565b612730565b34801561094a575f5ffd5b505f546103fd907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b348015610982575f5ffd5b506001546103fd9068010000000000000000900467ffffffffffffffff1681565b3480156109ae575f5ffd5b506106b66109bd366004614486565b612979565b3480156109cd575f5ffd5b506106b66109dc366004614385565b60086020525f908152604090205481565b3480156109f8575f5ffd5b50610350610a0736600461449d565b612998565b348015610a17575f5ffd5b505f54610a2b90600160a01b900460ff1681565b60405161036d9190614532565b348015610a43575f5ffd5b506103db610a5236600461439e565b6129a8565b348015610a62575f5ffd5b50610b055f5460015460055460ff600160a01b8404169367ffffffffffffffff7501000000000000000000000000000000000000000000909404841693838116936801000000000000000090819004909116926fffffffffffffffffffffffffffffffff7001000000000000000000000000000000008204169263ffffffff640100000000830481169383048116926c0100000000000000000000000090041690565b60405161036d989796959493929190614540565b348015610b24575f5ffd5b506005546104429063ffffffff1681565b348015610b40575f5ffd5b506103db610b4f3660046145c8565b612cf9565b348015610b5f575f5ffd5b506006546104429063ffffffff1681565b348015610b7b575f5ffd5b506005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16610350565b348015610bc5575f5ffd5b506006546104429068010000000000000000900463ffffffff1681565b348015610bed575f5ffd5b50610668610bfc366004614486565b60096020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b348015610c2e575f5ffd5b506103db610c3d366004614385565b612ec4565b348015610c4d575f5ffd5b506106b661020081565b6103db610c65366004614234565b612f29565b905090565b610c77613177565b60035f54600160a01b900460ff166003811115610c9657610c966144cc565b14610ccd576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8082165f90815260036020908152604080832060049092528220548154919373ffffffffffffffffffffffffffffffffffffffff909116927801000000000000000000000000000000000000000000000000909204169003610d60576040517fc6388ef700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547c0100000000000000000000000000000000000000000000000000000000900460ff1615610dbc576040517ff91356a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000017808355600280545f928392915f1963ffffffff7801000000000000000000000000000000000000000000000000909304831601909116908110610e4457610e446145e9565b5f9182526020909120015460055485549193506fffffffffffffffffffffffffffffffff7001000000000000000000000000000000009091048116918116919091031690508015610e9957610e9983826131a5565b6040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906342842e0e906064015f604051808303815f87803b158015610f2c575f5ffd5b505af1925050508015610f3d575060015b610fbc575f8281526009602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155905184927fd25a34c2cc093efc542d272b8bd09c2a72770f059f3689157470ffa54e33d92691a361100e565b818373ffffffffffffffffffffffffffffffffffffffff167fbcca8c1b0b7c9cfecbcd6d78d2b7e577c64cc3feaa29bb5352169eac263225ca8360405161100591815260200190565b60405180910390a35b5050505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b60605f8263ffffffff1667ffffffffffffffff81111561106057611060614616565b6040519080825280602002602001820160405280156110c557816020015b6040805160e0810182525f8082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282525f1990920191018161107e5790505b5091505f63ffffffff8516156110db57846110f1565b60055468010000000000000000900463ffffffff165b5f92509050815b8463ffffffff168110156112bc5763ffffffff8216156112bc5761126e826040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091525063ffffffff9081165f818152600360209081526040808320815160a0808201845291546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048916838701908152600160a01b83048a16848701908152780100000000000000000000000000000000000000000000000084048b1660608087019182527c010000000000000000000000000000000000000000000000000000000090950460ff16151560808088019182528c8c5260048b529a89902054895160e081018b529c8d5273ffffffffffffffffffffffffffffffffffffffff16998c01999099529451909216958901959095529351881690870152915186169385019390935251909316908201529051151560c082015290565b848281518110611280576112806145e9565b60200260200101819052508260010192508381815181106112a3576112a36145e9565b60200260200101516060015191508060010190506110f8565b50509250929050565b6112cd613177565b6112d5613298565b345f6112df6133cb565b9050806fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff16101561133f576040517fbc7360a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008116600163ffffffff928316908101909216179091556113868482338661348e565b61138e6137bd565b61139661391c565b6040516fffffffffffffffffffffffffffffffff8416815263ffffffff82169033907fc631094c03138085768d8bb83a20972f0c4e2d391f73c76f0c45371c869aa8589060200160405180910390a350505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611419613177565b73ffffffffffffffffffffffffffffffffffffffff8116611466576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f90815260086020526040812054908190036114af576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152600860205260408082208290555173ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d805f8114611512576040519150601f19603f3d011682016040523d82523d5f602084013e611517565b606091505b5050905080156115735760405182815273ffffffffffffffffffffffffffffffffffffffff84169033907fd55b5fe81317b854ac11454adf7e5a9a0adf69184d643ef9ae6bfda6a015c5bc9060200160405180910390a36115a5565b6040517f27fcd9d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6115d8613177565b6115e0613bb5565b5f5f54600160a01b900460ff1660038111156115fe576115fe6144cc565b14611635576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611682576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025481111561169157506002545b80156117e057600280545f91906116aa90600190614670565b815481106116ba576116ba6145e9565b905f5260205f200154905060028054806116d6576116d6614683565b5f8281526020812082015f19908101919091550190556040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906342842e0e906064015f604051808303815f87803b15801561177f575f5ffd5b505af1158015611791573d5f5f3e3d5ffd5b505060405183925073ffffffffffffffffffffffffffffffffffffffff861691507f80ab4e79198d412b2f19a2ad592c0ddca68388cc35e514bcc9d8f0763ffacc8c905f90a3505f1901611691565b61180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b611815613177565b61181d613bb5565b5f5f54600160a01b900460ff16600381111561183b5761183b6144cc565b14611872576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025463ffffffff7f000000000000000000000000000000000000000000000000000000000000000016146118d3576040517f914212d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790554267ffffffffffffffff83161015611916574291505b61012c8167ffffffffffffffff16101561192f575061012c5b5f80547fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000067ffffffffffffffff85811682029290921792839055600180547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016858416908117909155611c20936119c29391929004166146b0565b6119cc91906146b0565b600180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560408051848316815291831660208301527f4ed0f60db614da86e9302a8df6d4e93543c794c6ce6a3e0f98a5a816740d55cd910160405180910390a161180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611a79613177565b60015f54600160a01b900460ff166003811115611a9857611a986144cc565b14611acf576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80549091611b089167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b90508067ffffffffffffffff164211611b4d576040517f6463738900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554640100000000900463ffffffff165f03611c94575f8054740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909116179055600580547f00000000000000000000000000000000000000000000000000000000000000006fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029282169290921792839055600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1668010000000000000000179055604080519290930416815290517f56a6518ae8519b2fa5fd5ac37465c4f46aa4382769e292bf03fc4fa5cd65d66a9181900360200190a16040517ffa73a4fea5fd06d0d6a99612856bf1c8c91b17959d34072d2d0230999f986717905f90a1611e34565b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560055463ffffffff7f000000000000000000000000000000000000000000000000000000000000000081166401000000009092041610611d4a576005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16611d6c565b7f00000000000000000000000000000000000000000000000000000000000000005b600580546fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009382168402179182905591810490911664010000000090910463ffffffff908116828102600755600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1668010000000000000000600193909301909316919091029190911790556040519081527f56a6518ae8519b2fa5fd5ac37465c4f46aa4382769e292bf03fc4fa5cd65d66a9060200160405180910390a15b50611e5e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b565b5f7f000000000000000000000000000000000000000000000000000000000000000063ffffffff168263ffffffff161180611e9f575063ffffffff8216155b15611ed6576040517fae958a4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026001830363ffffffff1681548110611ef257611ef26145e9565b905f5260205f2001549050919050565b611f0a613bb5565b611e5e5f613c07565b611f1b613177565b611f23613bb5565b60015f54600160a01b900460ff166003811115611f4257611f426144cc565b14611f79576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554640100000000900463ffffffff1615611fc1576040517fbac98d0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff168155600180547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690556040517fd9463465c2ef1e1dd20090d1d30d48dd6075133448fe55a18423f9e9d3fda2349190a1611e5e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612068613177565b612070613bb5565b5f5f54600160a01b900460ff16600381111561208e5761208e6144cc565b146120c5576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025463ffffffff7f000000000000000000000000000000000000000000000000000000000000000016906120fb9083906146d0565b1115612133576040517f748e67b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff841603612182576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b818110156122c2575f83838381811061219f5761219f6145e9565b600280546001810182555f9190915260209190910292909201357f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace909201829055506040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152306024830152604482018390529192507f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd906064015f604051808303815f87803b158015612279575f5ffd5b505af115801561228b573d5f5f3e3d5ffd5b50506040518392507f17b96a068bfa8e6864fff37af5aaae78b374a38c928ef85510704f039ed8728991505f90a250600101612184565b506122ec60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b5f610c6a6133cb565b612302613177565b60025f54600160a01b900460ff166003811115612321576123216144cc565b14612358576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546005546401000000009182900463ffffffff9081165f1901925f928483169190049091161161238a575f6123a6565b6005546123a6908390640100000000900463ffffffff166146e3565b90508063ffffffff168363ffffffff1611156123c0578092505b8263ffffffff165f036123ff576040517ff90a7b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065463ffffffff161580159061246a575060065461242e90600190640100000000900463ffffffff166146e3565b60065463ffffffff9081165f90815260036020526040902054780100000000000000000000000000000000000000000000000090048116911614155b156124a1576040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006545f9063ffffffff16156124e45760065463ffffffff9081165f908152600360205260409020547001000000000000000000000000000000009004166124fa565b60055468010000000000000000900463ffffffff165b60065490915063ffffffff165f5b8563ffffffff1681101561264d578263ffffffff165f03612555576040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068054600163ffffffff64010000000080840482169283018216027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff909316929092179092558481165f818152600360209081526040918290208054780100000000000000000000000000000000000000000000000087027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161790819055915185815270010000000000000000000000000000000090920490931696955090917ff1d2cd2d687f90ec76bd5f8d89cc4aceea509b42a5cd26fdfaf5a706061d88d0910160405180910390a250600101612508565b50600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8381169182179092556005546c010000000000000000000000009004909116900361100e575f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740300000000000000000000000000000000000000001781556040517ffa73a4fea5fd06d0d6a99612856bf1c8c91b17959d34072d2d0230999f9867179190a15050505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612738613177565b73ffffffffffffffffffffffffffffffffffffffff8216612785576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff16806127e0576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331461282f576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600960205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f000000000000000000000000000000000000000000000000000000000000000016906342842e0e906064015f604051808303815f87803b1580156128f5575f5ffd5b505af1158015612907573d5f5f3e3d5ffd5b505060405184925073ffffffffffffffffffffffffffffffffffffffff8616915033907fe6f6f0dc802cab1eaaddd08ec64d1f984dd0da346096a936acf37705de7cdeff905f90a45061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60028181548110612988575f80fd5b5f91825260209091200154905081565b5f6129a282613c7b565b92915050565b6129b0613177565b6129b8613bb5565b60035f54600160a01b900460ff1660038111156129d7576129d76144cc565b14612a0e576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055463ffffffff7f000000000000000000000000000000000000000000000000000000000000000081166401000000009092041603612a7a576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216612ac7576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006545f1963ffffffff680100000000000000009092048216908101917f000000000000000000000000000000000000000000000000000000000000000091909103600101908116831115612b20578063ffffffff1692505b825f03612b59576040517ff90a7b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b83811015612ccd5760068054600163ffffffff6801000000000000000080840482169283018216027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff90931692909217909255600280545f925f19850116908110612bc857612bc86145e9565b5f918252602090912001546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8981166024830152604482018390529192507f0000000000000000000000000000000000000000000000000000000000000000909116906342842e0e906064015f604051808303815f87803b158015612c6b575f5ffd5b505af1158015612c7d573d5f5f3e3d5ffd5b505060405183925073ffffffffffffffffffffffffffffffffffffffff8a1691507f80ab4e79198d412b2f19a2ad592c0ddca68388cc35e514bcc9d8f0763ffacc8c905f90a35050600101612b5b565b50505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612d01613177565b612d09613bb5565b60035f54600160a01b900460ff166003811115612d2857612d286144cc565b14612d5f576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612dac576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6007548311612dbc5782612dc0565b6007545b9050805f03612dfb576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007805482900390556040515f9073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d805f8114612e59576040519150601f19603f3d011682016040523d82523d5f602084013e612e5e565b606091505b5050905080612e99576040517f27fcd9d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612ecc613bb5565b73ffffffffffffffffffffffffffffffffffffffff8116612f20576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b61103b81613c07565b612f31613177565b612f39613298565b612f4282613ca6565b612f78576040517fc6388ef700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff82165f90815260036020908152604080832060049092529091205473ffffffffffffffffffffffffffffffffffffffff16338114612fe7576040517f03c3508200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546fffffffffffffffffffffffffffffffff1661300481613c7b565b6fffffffffffffffffffffffffffffffff1634101561304f576040517f697a56ac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61305a34836146ff565b845490915063ffffffff7001000000000000000000000000000000008204811691600160a01b90041661308c88613d7f565b6130988789878661348e565b855463ffffffff838116700100000000000000000000000000000000909204161415806130d65750855463ffffffff828116600160a01b9092041614155b156130e3576130e36137bd565b6040516fffffffffffffffffffffffffffffffff8416815263ffffffff89169073ffffffffffffffffffffffffffffffffffffffff8716907fe092a313734855a17c0c64b04e8c62de70d90b10bc29ab662d8fbe914395b9fd9060200160405180910390a350505050505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61317f613f70565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f8273ffffffffffffffffffffffffffffffffffffffff1682620186a0906040515f60405180830381858888f193505050503d805f8114613201576040519150601f19603f3d011682016040523d82523d5f602084013e613206565b606091505b50509050806122ec5773ffffffffffffffffffffffffffffffffffffffff83165f90815260086020526040812080548492906132439084906146d0565b909155505060405182815273ffffffffffffffffffffffffffffffffffffffff8416907f03346f418777de37a432a76ace912eeb3d1d63333a4f8c59df9ae07eb09732159060200160405180910390a2505050565b60015f54600160a01b900460ff1660038111156132b7576132b76144cc565b146132ee576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f547501000000000000000000000000000000000000000000900467ffffffffffffffff1642101561334c576040517f197ee35f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f805490916133859167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b67ffffffffffffffff1690508042111561103b576040517f7dc0cb3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005545f9063ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811664010000000090920416101561342d57507f000000000000000000000000000000000000000000000000000000000000000090565b6005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff1661271061347460fa83614727565b61347e919061473e565b61348890826146d0565b91505090565b5f6134998583613fcb565b90505f8163ffffffff165f036134f357506005805463ffffffff868116680100000000000000009081027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff8416179093559190041661354d565b5063ffffffff8082165f90815260036020526040902080548683167001000000000000000000000000000000009081027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff83161790925504165b6040805160a0810182526fffffffffffffffffffffffffffffffff858116825263ffffffff84811660208085018281528884168688019081525f60608801818152608089018281528f88168352600386528a832099518a54955194519251915199167fffffffffffffffffffffffff00000000000000000000000000000000000000009586161770010000000000000000000000000000000094891694909402939093177fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16600160a01b918816919091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff161778010000000000000000000000000000000000000000000000009290961691909102949094177fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000095151595909502949094179094556004909352928320805490911673ffffffffffffffffffffffffffffffffffffffff8816179055900361372757600580547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff881602179055613772565b63ffffffff8082165f9081526003602052604090208054918716600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790555b505060058054600163ffffffff64010000000080840482169290920116027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90911617905550505050565b6001545f805490916137f69167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b67ffffffffffffffff1690505f61380d4283614670565b905061012c811061381c575050565b5f61382961012c426146d0565b6001549091505f9068010000000000000000900467ffffffffffffffff168211613853578161386d565b60015468010000000000000000900467ffffffffffffffff165b905083811161387c5750505050565b5f546138ab907501000000000000000000000000000000000000000000900467ffffffffffffffff1682614776565b600180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff9290921691821790556040519081527faf11c4a8cc14ff1ca42279acfb46a962388e2cc718f46ed8b2443a3fe6c9b35e9060200160405180910390a150505050565b60055463ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116640100000000909204161161395857565b600580546c0100000000000000000000000080820463ffffffff9081165f818152600360208181526040808420815160a08101835281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048a1683870152600160a01b82048a16838601908152780100000000000000000000000000000000000000000000000083048b1660608501527c010000000000000000000000000000000000000000000000000000000090920460ff16151560808401528888526004808752858920805493517fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff909e168e8d169d8e02178f559b895296865293872080547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1690559587905281547fffffff0000000000000000000000000000000000000000000000000000000000169091559290915285547fffffffffffffffffffffffff00000000000000000000000000000000000000001690955586547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff81166401000000009182900486165f1901909516029390931790955581519094919373ffffffffffffffffffffffffffffffffffffffff90921692613b47918491166131a5565b82516040516fffffffffffffffffffffffffffffffff909116815263ffffffff85169073ffffffffffffffffffffffffffffffffffffffff8416907f1bda441362132d43f6620375e6116dd31d39478652707bc5b2f80024da841a759060200160405180910390a350505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611e5e576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612f17565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612710613c9c60326fffffffffffffffffffffffffffffffff8516614727565b6129a2919061473e565b63ffffffff81165f9081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff16613cdc57505f919050565b60055463ffffffff83811668010000000000000000909204161480613d1b575060055463ffffffff8381166c0100000000000000000000000090920416145b15613d2857506001919050565b63ffffffff8083165f90815260036020526040902054600160a01b9004161515806129a257505063ffffffff9081165f90815260036020526040902054700100000000000000000000000000000000900416151590565b63ffffffff8082165f90815260036020526040812054600160a01b81048316927001000000000000000000000000000000009091041690819003613e0157600580547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff851602179055613e4c565b63ffffffff8082165f9081526003602052604090208054918416600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790555b8163ffffffff165f03613e9957600580547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff166801000000000000000063ffffffff841602179055613ef1565b63ffffffff8083165f9081526003602052604090208054918316700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9092169190911790555b505063ffffffff9081165f90815260036020526040902080547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff169055600580547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff81166401000000009182900484165f190190931602919091179055565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054600203611e5e576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005545f90640100000000900463ffffffff16801580614042575060055468010000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16836fffffffffffffffffffffffffffffffff16115b15614050575f9150506129a2565b8363ffffffff8116158061406a575061406881613ca6565b155b15614086575060055468010000000000000000900463ffffffff165b63ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff90811690851611614149575f5b8263ffffffff168110156141435763ffffffff8083165f90815260036020526040902054700100000000000000000000000000000000900416801580614128575063ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff908116908716115b1561413957829450505050506129a2565b91506001016140b9565b506141ca565b5f5b8263ffffffff168110156141c85763ffffffff8083165f90815260036020526040902054600160a01b9004168015806141ae575063ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff90811690871611155b156141be5793506129a292505050565b915060010161414b565b505b6040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803563ffffffff8116811461420f575f5ffd5b919050565b5f60208284031215614224575f5ffd5b61422d826141fc565b9392505050565b5f5f60408385031215614245575f5ffd5b61424e836141fc565b915061425c602084016141fc565b90509250929050565b63ffffffff815116825273ffffffffffffffffffffffffffffffffffffffff60208201511660208301526fffffffffffffffffffffffffffffffff604082015116604083015263ffffffff606082015116606083015263ffffffff608082015116608083015260a08101516142e260a084018263ffffffff169052565b5060c08101516122ec60c084018215159052565b604080825283519082018190525f9060208501906060840190835b8181101561433a57614324838551614265565b6020939093019260e09290920191600101614311565b5050809250505063ffffffff831660208301529392505050565b60e081016129a28284614265565b803573ffffffffffffffffffffffffffffffffffffffff8116811461420f575f5ffd5b5f60208284031215614395575f5ffd5b61422d82614362565b5f5f604083850312156143af575f5ffd5b6143b883614362565b946020939093013593505050565b803567ffffffffffffffff8116811461420f575f5ffd5b5f5f604083850312156143ee575f5ffd5b6143f7836143c6565b915061425c602084016143c6565b5f5f5f60408486031215614417575f5ffd5b61442084614362565b9250602084013567ffffffffffffffff81111561443b575f5ffd5b8401601f8101861361444b575f5ffd5b803567ffffffffffffffff811115614461575f5ffd5b8660208260051b8401011115614475575f5ffd5b939660209190910195509293505050565b5f60208284031215614496575f5ffd5b5035919050565b5f602082840312156144ad575f5ffd5b81356fffffffffffffffffffffffffffffffff8116811461422d575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6004811061452e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b602081016129a282846144f9565b610100810161454f828b6144f9565b67ffffffffffffffff8916602083015267ffffffffffffffff8816604083015267ffffffffffffffff871660608301526fffffffffffffffffffffffffffffffff8616608083015263ffffffff851660a083015263ffffffff841660c083015263ffffffff831660e08301529998505050505050505050565b5f5f604083850312156145d9575f5ffd5b8235915061425c60208401614362565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156129a2576129a2614643565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b67ffffffffffffffff81811683821601908111156129a2576129a2614643565b808201808211156129a2576129a2614643565b63ffffffff82811682821603908111156129a2576129a2614643565b6fffffffffffffffffffffffffffffffff81811683821601908111156129a2576129a2614643565b80820281158282048414176129a2576129a2614643565b5f82614771577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b67ffffffffffffffff82811682821603908111156129a2576129a261464356fea26469706673582212209f2de25c12b07082e8f86dbfc97f1daf2a7ddcf6180afac8996dda1dd945e3df64736f6c634300081c003300000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e00000000000000000000000000000000000000000000000000121e6c485ac0000000000000000000000000000000000000000000000000000000000000000019

Deployed Bytecode

0x608060405260043610610319575f3560e01c806381cd8d621161019c578063b70ed9f3116100e7578063e343dc2d11610092578063ed042f031161006d578063ed042f0314610be2578063f2fde38b14610c23578063f47c84c514610c42578063fa5703f714610c57575f5ffd5b8063e343dc2d14610b54578063e7dd5d0a14610b70578063e8a60d3214610bba575f5ffd5b8063d94a3505116100c2578063d94a350514610a57578063dc26904914610b19578063e167956b14610b35575f5ffd5b8063b70ed9f3146109ed578063c19d93fb14610a0c578063c1c7033014610a38575f5ffd5b8063972c535611610147578063a68e79b711610122578063a68e79b714610977578063b02de0f4146109a3578063b613b114146109c2575f5ffd5b8063972c5356146108fc5780639c59e8c714610920578063a0e23ebd1461093f575f5ffd5b80638f7dcfa3116101775780638f7dcfa3146108a1578063916a661c146108c957806396c87e70146108dd575f5ffd5b806381cd8d62146108455780638cb39385146108645780638da5cb5b14610878575f5ffd5b80632b8f3689116102675780635681104a116102125780636e2c90e7116101ed5780636e2c90e7146107e9578063715018a6146108085780637bdcd6341461081c5780637d35045314610831575f5ffd5b80635681104a1461079c5780635d56ff48146107b1578063699ced4f146107d5575f5ffd5b806340fa01351161024257806340fa01351461073e5780634149db4814610754578063528cfa9814610787575f5ffd5b80632b8f3689146106c457806331d0cd92146106e357806332a0f2d714610702575f5ffd5b80631abbf0cd116102c75780631fda9a02116102a25780631fda9a0214610635578063267421c51461068d57806328dc501d146106a1575f5ffd5b80631abbf0cd146104845780631b8d6ed4146104975780631ea83a1d14610616575f5ffd5b80630fb5a6b4116102f75780630fb5a6b4146103dd57806313d8c8401461041657806318bff57614610457575f5ffd5b80630253492a1461031d57806303ed26291461037657806304951891146103bc575b5f5ffd5b348015610328575f5ffd5b506103507f00000000000000000000000000000000000000000000000000121e6c485ac00081565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610381575f5ffd5b5060055468010000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16610350565b3480156103c7575f5ffd5b506103db6103d6366004614214565b610c6f565b005b3480156103e8575f5ffd5b506001546103fd9067ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161036d565b348015610421575f5ffd5b50600554610442906c01000000000000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161036d565b348015610462575f5ffd5b50610476610471366004614234565b61103e565b60405161036d9291906142f6565b6103db610492366004614214565b6112c5565b3480156104a2575f5ffd5b506106096104b1366004614214565b6040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091525063ffffffff9081165f818152600360209081526040808320815160a0808201845291546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048916838701908152600160a01b83048a16848701908152780100000000000000000000000000000000000000000000000084048b1660608087019182527c010000000000000000000000000000000000000000000000000000000090950460ff16151560808088019182528c8c5260048b529a89902054895160e081018b529c8d5273ffffffffffffffffffffffffffffffffffffffff16998c01999099529451909216958901959095529351881690870152915186169385019390935251909316908201529051151560c082015290565b60405161036d9190614354565b348015610621575f5ffd5b506103db610630366004614385565b611411565b348015610640575f5ffd5b506106687f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e81565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161036d565b348015610698575f5ffd5b5061035060fa81565b3480156106ac575f5ffd5b506106b6611c2081565b60405190815260200161036d565b3480156106cf575f5ffd5b506103db6106de36600461439e565b6115d0565b3480156106ee575f5ffd5b506103db6106fd3660046143dd565b61180d565b34801561070d575f5ffd5b506005546103509070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1681565b348015610749575f5ffd5b506106b6620186a081565b34801561075f575f5ffd5b506104427f000000000000000000000000000000000000000000000000000000000000001981565b348015610792575f5ffd5b5061035061271081565b3480156107a7575f5ffd5b506106b661012c81565b3480156107bc575f5ffd5b5060065461044290640100000000900463ffffffff1681565b3480156107e0575f5ffd5b506103db611a71565b3480156107f4575f5ffd5b506106b6610803366004614214565b611e60565b348015610813575f5ffd5b506103db611f02565b348015610827575f5ffd5b506106b660075481565b34801561083c575f5ffd5b506103db611f13565b348015610850575f5ffd5b506103db61085f366004614405565b612060565b34801561086f575f5ffd5b506103506122f1565b348015610883575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff16610668565b3480156108ac575f5ffd5b506005546104429068010000000000000000900463ffffffff1681565b3480156108d4575f5ffd5b50610350603281565b3480156108e8575f5ffd5b506103db6108f7366004614214565b6122fa565b348015610907575f5ffd5b5060055461044290640100000000900463ffffffff1681565b34801561092b575f5ffd5b506103db61093a36600461439e565b612730565b34801561094a575f5ffd5b505f546103fd907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b348015610982575f5ffd5b506001546103fd9068010000000000000000900467ffffffffffffffff1681565b3480156109ae575f5ffd5b506106b66109bd366004614486565b612979565b3480156109cd575f5ffd5b506106b66109dc366004614385565b60086020525f908152604090205481565b3480156109f8575f5ffd5b50610350610a0736600461449d565b612998565b348015610a17575f5ffd5b505f54610a2b90600160a01b900460ff1681565b60405161036d9190614532565b348015610a43575f5ffd5b506103db610a5236600461439e565b6129a8565b348015610a62575f5ffd5b50610b055f5460015460055460ff600160a01b8404169367ffffffffffffffff7501000000000000000000000000000000000000000000909404841693838116936801000000000000000090819004909116926fffffffffffffffffffffffffffffffff7001000000000000000000000000000000008204169263ffffffff640100000000830481169383048116926c0100000000000000000000000090041690565b60405161036d989796959493929190614540565b348015610b24575f5ffd5b506005546104429063ffffffff1681565b348015610b40575f5ffd5b506103db610b4f3660046145c8565b612cf9565b348015610b5f575f5ffd5b506006546104429063ffffffff1681565b348015610b7b575f5ffd5b506005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16610350565b348015610bc5575f5ffd5b506006546104429068010000000000000000900463ffffffff1681565b348015610bed575f5ffd5b50610668610bfc366004614486565b60096020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b348015610c2e575f5ffd5b506103db610c3d366004614385565b612ec4565b348015610c4d575f5ffd5b506106b661020081565b6103db610c65366004614234565b612f29565b905090565b610c77613177565b60035f54600160a01b900460ff166003811115610c9657610c966144cc565b14610ccd576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8082165f90815260036020908152604080832060049092528220548154919373ffffffffffffffffffffffffffffffffffffffff909116927801000000000000000000000000000000000000000000000000909204169003610d60576040517fc6388ef700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547c0100000000000000000000000000000000000000000000000000000000900460ff1615610dbc576040517ff91356a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81547fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000017808355600280545f928392915f1963ffffffff7801000000000000000000000000000000000000000000000000909304831601909116908110610e4457610e446145e9565b5f9182526020909120015460055485549193506fffffffffffffffffffffffffffffffff7001000000000000000000000000000000009091048116918116919091031690508015610e9957610e9983826131a5565b6040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e16906342842e0e906064015f604051808303815f87803b158015610f2c575f5ffd5b505af1925050508015610f3d575060015b610fbc575f8281526009602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8716908117909155905184927fd25a34c2cc093efc542d272b8bd09c2a72770f059f3689157470ffa54e33d92691a361100e565b818373ffffffffffffffffffffffffffffffffffffffff167fbcca8c1b0b7c9cfecbcd6d78d2b7e577c64cc3feaa29bb5352169eac263225ca8360405161100591815260200190565b60405180910390a35b5050505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b50565b60605f8263ffffffff1667ffffffffffffffff81111561106057611060614616565b6040519080825280602002602001820160405280156110c557816020015b6040805160e0810182525f8082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282525f1990920191018161107e5790505b5091505f63ffffffff8516156110db57846110f1565b60055468010000000000000000900463ffffffff165b5f92509050815b8463ffffffff168110156112bc5763ffffffff8216156112bc5761126e826040805160e0810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c08101919091525063ffffffff9081165f818152600360209081526040808320815160a0808201845291546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048916838701908152600160a01b83048a16848701908152780100000000000000000000000000000000000000000000000084048b1660608087019182527c010000000000000000000000000000000000000000000000000000000090950460ff16151560808088019182528c8c5260048b529a89902054895160e081018b529c8d5273ffffffffffffffffffffffffffffffffffffffff16998c01999099529451909216958901959095529351881690870152915186169385019390935251909316908201529051151560c082015290565b848281518110611280576112806145e9565b60200260200101819052508260010192508381815181106112a3576112a36145e9565b60200260200101516060015191508060010190506110f8565b50509250929050565b6112cd613177565b6112d5613298565b345f6112df6133cb565b9050806fffffffffffffffffffffffffffffffff16826fffffffffffffffffffffffffffffffff16101561133f576040517fbc7360a800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600580547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000008116600163ffffffff928316908101909216179091556113868482338661348e565b61138e6137bd565b61139661391c565b6040516fffffffffffffffffffffffffffffffff8416815263ffffffff82169033907fc631094c03138085768d8bb83a20972f0c4e2d391f73c76f0c45371c869aa8589060200160405180910390a350505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611419613177565b73ffffffffffffffffffffffffffffffffffffffff8116611466576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f90815260086020526040812054908190036114af576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f908152600860205260408082208290555173ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d805f8114611512576040519150601f19603f3d011682016040523d82523d5f602084013e611517565b606091505b5050905080156115735760405182815273ffffffffffffffffffffffffffffffffffffffff84169033907fd55b5fe81317b854ac11454adf7e5a9a0adf69184d643ef9ae6bfda6a015c5bc9060200160405180910390a36115a5565b6040517f27fcd9d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6115d8613177565b6115e0613bb5565b5f5f54600160a01b900460ff1660038111156115fe576115fe6144cc565b14611635576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611682576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025481111561169157506002545b80156117e057600280545f91906116aa90600190614670565b815481106116ba576116ba6145e9565b905f5260205f200154905060028054806116d6576116d6614683565b5f8281526020812082015f19908101919091550190556040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018390527f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e16906342842e0e906064015f604051808303815f87803b15801561177f575f5ffd5b505af1158015611791573d5f5f3e3d5ffd5b505060405183925073ffffffffffffffffffffffffffffffffffffffff861691507f80ab4e79198d412b2f19a2ad592c0ddca68388cc35e514bcc9d8f0763ffacc8c905f90a3505f1901611691565b61180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b611815613177565b61181d613bb5565b5f5f54600160a01b900460ff16600381111561183b5761183b6144cc565b14611872576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025463ffffffff7f000000000000000000000000000000000000000000000000000000000000001916146118d3576040517f914212d800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790554267ffffffffffffffff83161015611916574291505b61012c8167ffffffffffffffff16101561192f575061012c5b5f80547fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000067ffffffffffffffff85811682029290921792839055600180547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016858416908117909155611c20936119c29391929004166146b0565b6119cc91906146b0565b600180547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff9384160217905560408051848316815291831660208301527f4ed0f60db614da86e9302a8df6d4e93543c794c6ce6a3e0f98a5a816740d55cd910160405180910390a161180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b611a79613177565b60015f54600160a01b900460ff166003811115611a9857611a986144cc565b14611acf576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80549091611b089167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b90508067ffffffffffffffff164211611b4d576040517f6463738900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554640100000000900463ffffffff165f03611c94575f8054740300000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909116179055600580547f00000000000000000000000000000000000000000000000000121e6c485ac0006fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009081029282169290921792839055600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1668010000000000000000179055604080519290930416815290517f56a6518ae8519b2fa5fd5ac37465c4f46aa4382769e292bf03fc4fa5cd65d66a9181900360200190a16040517ffa73a4fea5fd06d0d6a99612856bf1c8c91b17959d34072d2d0230999f986717905f90a1611e34565b5f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167402000000000000000000000000000000000000000017905560055463ffffffff7f000000000000000000000000000000000000000000000000000000000000001981166401000000009092041610611d4a576005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff16611d6c565b7f00000000000000000000000000000000000000000000000000121e6c485ac0005b600580546fffffffffffffffffffffffffffffffff9081167001000000000000000000000000000000009382168402179182905591810490911664010000000090910463ffffffff908116828102600755600680547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1668010000000000000000600193909301909316919091029190911790556040519081527f56a6518ae8519b2fa5fd5ac37465c4f46aa4382769e292bf03fc4fa5cd65d66a9060200160405180910390a15b50611e5e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b565b5f7f000000000000000000000000000000000000000000000000000000000000001963ffffffff168263ffffffff161180611e9f575063ffffffff8216155b15611ed6576040517fae958a4000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026001830363ffffffff1681548110611ef257611ef26145e9565b905f5260205f2001549050919050565b611f0a613bb5565b611e5e5f613c07565b611f1b613177565b611f23613bb5565b60015f54600160a01b900460ff166003811115611f4257611f426144cc565b14611f79576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600554640100000000900463ffffffff1615611fc1576040517fbac98d0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffff000000000000000000ffffffffffffffffffffffffffffffffffffffff168155600180547fffffffffffffffffffffffffffffffff000000000000000000000000000000001690556040517fd9463465c2ef1e1dd20090d1d30d48dd6075133448fe55a18423f9e9d3fda2349190a1611e5e60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612068613177565b612070613bb5565b5f5f54600160a01b900460ff16600381111561208e5761208e6144cc565b146120c5576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025463ffffffff7f000000000000000000000000000000000000000000000000000000000000001916906120fb9083906146d0565b1115612133576040517f748e67b200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff841603612182576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b818110156122c2575f83838381811061219f5761219f6145e9565b600280546001810182555f9190915260209190910292909201357f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace909201829055506040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152306024830152604482018390529192507f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e909116906323b872dd906064015f604051808303815f87803b158015612279575f5ffd5b505af115801561228b573d5f5f3e3d5ffd5b50506040518392507f17b96a068bfa8e6864fff37af5aaae78b374a38c928ef85510704f039ed8728991505f90a250600101612184565b506122ec60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b5f610c6a6133cb565b612302613177565b60025f54600160a01b900460ff166003811115612321576123216144cc565b14612358576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546005546401000000009182900463ffffffff9081165f1901925f928483169190049091161161238a575f6123a6565b6005546123a6908390640100000000900463ffffffff166146e3565b90508063ffffffff168363ffffffff1611156123c0578092505b8263ffffffff165f036123ff576040517ff90a7b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065463ffffffff161580159061246a575060065461242e90600190640100000000900463ffffffff166146e3565b60065463ffffffff9081165f90815260036020526040902054780100000000000000000000000000000000000000000000000090048116911614155b156124a1576040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006545f9063ffffffff16156124e45760065463ffffffff9081165f908152600360205260409020547001000000000000000000000000000000009004166124fa565b60055468010000000000000000900463ffffffff165b60065490915063ffffffff165f5b8563ffffffff1681101561264d578263ffffffff165f03612555576040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068054600163ffffffff64010000000080840482169283018216027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff909316929092179092558481165f818152600360209081526040918290208054780100000000000000000000000000000000000000000000000087027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9091161790819055915185815270010000000000000000000000000000000090920490931696955090917ff1d2cd2d687f90ec76bd5f8d89cc4aceea509b42a5cd26fdfaf5a706061d88d0910160405180910390a250600101612508565b50600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff8381169182179092556005546c010000000000000000000000009004909116900361100e575f80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740300000000000000000000000000000000000000001781556040517ffa73a4fea5fd06d0d6a99612856bf1c8c91b17959d34072d2d0230999f9867179190a15050505061103b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612738613177565b73ffffffffffffffffffffffffffffffffffffffff8216612785576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8181526009602052604090205473ffffffffffffffffffffffffffffffffffffffff16806127e0576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116331461282f576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600960205260409081902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e16906342842e0e906064015f604051808303815f87803b1580156128f5575f5ffd5b505af1158015612907573d5f5f3e3d5ffd5b505060405184925073ffffffffffffffffffffffffffffffffffffffff8616915033907fe6f6f0dc802cab1eaaddd08ec64d1f984dd0da346096a936acf37705de7cdeff905f90a45061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60028181548110612988575f80fd5b5f91825260209091200154905081565b5f6129a282613c7b565b92915050565b6129b0613177565b6129b8613bb5565b60035f54600160a01b900460ff1660038111156129d7576129d76144cc565b14612a0e576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055463ffffffff7f000000000000000000000000000000000000000000000000000000000000001981166401000000009092041603612a7a576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216612ac7576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006545f1963ffffffff680100000000000000009092048216908101917f000000000000000000000000000000000000000000000000000000000000001991909103600101908116831115612b20578063ffffffff1692505b825f03612b59576040517ff90a7b5f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b83811015612ccd5760068054600163ffffffff6801000000000000000080840482169283018216027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff90931692909217909255600280545f925f19850116908110612bc857612bc86145e9565b5f918252602090912001546040517f42842e0e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8981166024830152604482018390529192507f0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e909116906342842e0e906064015f604051808303815f87803b158015612c6b575f5ffd5b505af1158015612c7d573d5f5f3e3d5ffd5b505060405183925073ffffffffffffffffffffffffffffffffffffffff8a1691507f80ab4e79198d412b2f19a2ad592c0ddca68388cc35e514bcc9d8f0763ffacc8c905f90a35050600101612b5b565b50505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612d01613177565b612d09613bb5565b60035f54600160a01b900460ff166003811115612d2857612d286144cc565b14612d5f576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612dac576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6007548311612dbc5782612dc0565b6007545b9050805f03612dfb576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6007805482900390556040515f9073ffffffffffffffffffffffffffffffffffffffff84169083908381818185875af1925050503d805f8114612e59576040519150601f19603f3d011682016040523d82523d5f602084013e612e5e565b606091505b5050905080612e99576040517f27fcd9d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b612ecc613bb5565b73ffffffffffffffffffffffffffffffffffffffff8116612f20576040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081525f60048201526024015b60405180910390fd5b61103b81613c07565b612f31613177565b612f39613298565b612f4282613ca6565b612f78576040517fc6388ef700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff82165f90815260036020908152604080832060049092529091205473ffffffffffffffffffffffffffffffffffffffff16338114612fe7576040517f03c3508200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546fffffffffffffffffffffffffffffffff1661300481613c7b565b6fffffffffffffffffffffffffffffffff1634101561304f576040517f697a56ac00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61305a34836146ff565b845490915063ffffffff7001000000000000000000000000000000008204811691600160a01b90041661308c88613d7f565b6130988789878661348e565b855463ffffffff838116700100000000000000000000000000000000909204161415806130d65750855463ffffffff828116600160a01b9092041614155b156130e3576130e36137bd565b6040516fffffffffffffffffffffffffffffffff8416815263ffffffff89169073ffffffffffffffffffffffffffffffffffffffff8716907fe092a313734855a17c0c64b04e8c62de70d90b10bc29ab662d8fbe914395b9fd9060200160405180910390a350505050505061180960017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61317f613f70565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f8273ffffffffffffffffffffffffffffffffffffffff1682620186a0906040515f60405180830381858888f193505050503d805f8114613201576040519150601f19603f3d011682016040523d82523d5f602084013e613206565b606091505b50509050806122ec5773ffffffffffffffffffffffffffffffffffffffff83165f90815260086020526040812080548492906132439084906146d0565b909155505060405182815273ffffffffffffffffffffffffffffffffffffffff8416907f03346f418777de37a432a76ace912eeb3d1d63333a4f8c59df9ae07eb09732159060200160405180910390a2505050565b60015f54600160a01b900460ff1660038111156132b7576132b76144cc565b146132ee576040517f3d693ada00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f547501000000000000000000000000000000000000000000900467ffffffffffffffff1642101561334c576040517f197ee35f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f805490916133859167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b67ffffffffffffffff1690508042111561103b576040517f7dc0cb3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005545f9063ffffffff7f0000000000000000000000000000000000000000000000000000000000000019811664010000000090920416101561342d57507f00000000000000000000000000000000000000000000000000121e6c485ac00090565b6005546c01000000000000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff1661271061347460fa83614727565b61347e919061473e565b61348890826146d0565b91505090565b5f6134998583613fcb565b90505f8163ffffffff165f036134f357506005805463ffffffff868116680100000000000000009081027fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff8416179093559190041661354d565b5063ffffffff8082165f90815260036020526040902080548683167001000000000000000000000000000000009081027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff83161790925504165b6040805160a0810182526fffffffffffffffffffffffffffffffff858116825263ffffffff84811660208085018281528884168688019081525f60608801818152608089018281528f88168352600386528a832099518a54955194519251915199167fffffffffffffffffffffffff00000000000000000000000000000000000000009586161770010000000000000000000000000000000094891694909402939093177fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff16600160a01b918816919091027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff161778010000000000000000000000000000000000000000000000009290961691909102949094177fffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000095151595909502949094179094556004909352928320805490911673ffffffffffffffffffffffffffffffffffffffff8816179055900361372757600580547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff881602179055613772565b63ffffffff8082165f9081526003602052604090208054918716600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790555b505060058054600163ffffffff64010000000080840482169290920116027fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff90911617905550505050565b6001545f805490916137f69167ffffffffffffffff918216917501000000000000000000000000000000000000000000909104166146b0565b67ffffffffffffffff1690505f61380d4283614670565b905061012c811061381c575050565b5f61382961012c426146d0565b6001549091505f9068010000000000000000900467ffffffffffffffff168211613853578161386d565b60015468010000000000000000900467ffffffffffffffff165b905083811161387c5750505050565b5f546138ab907501000000000000000000000000000000000000000000900467ffffffffffffffff1682614776565b600180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff9290921691821790556040519081527faf11c4a8cc14ff1ca42279acfb46a962388e2cc718f46ed8b2443a3fe6c9b35e9060200160405180910390a150505050565b60055463ffffffff7f00000000000000000000000000000000000000000000000000000000000000198116640100000000909204161161395857565b600580546c0100000000000000000000000080820463ffffffff9081165f818152600360208181526040808420815160a08101835281546fffffffffffffffffffffffffffffffff808216835270010000000000000000000000000000000082048a1683870152600160a01b82048a16838601908152780100000000000000000000000000000000000000000000000083048b1660608501527c010000000000000000000000000000000000000000000000000000000090920460ff16151560808401528888526004808752858920805493517fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff909e168e8d169d8e02178f559b895296865293872080547fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff1690559587905281547fffffff0000000000000000000000000000000000000000000000000000000000169091559290915285547fffffffffffffffffffffffff00000000000000000000000000000000000000001690955586547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff81166401000000009182900486165f1901909516029390931790955581519094919373ffffffffffffffffffffffffffffffffffffffff90921692613b47918491166131a5565b82516040516fffffffffffffffffffffffffffffffff909116815263ffffffff85169073ffffffffffffffffffffffffffffffffffffffff8416907f1bda441362132d43f6620375e6116dd31d39478652707bc5b2f80024da841a759060200160405180910390a350505050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611e5e576040517f118cdaa7000000000000000000000000000000000000000000000000000000008152336004820152602401612f17565b5f805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612710613c9c60326fffffffffffffffffffffffffffffffff8516614727565b6129a2919061473e565b63ffffffff81165f9081526004602052604081205473ffffffffffffffffffffffffffffffffffffffff16613cdc57505f919050565b60055463ffffffff83811668010000000000000000909204161480613d1b575060055463ffffffff8381166c0100000000000000000000000090920416145b15613d2857506001919050565b63ffffffff8083165f90815260036020526040902054600160a01b9004161515806129a257505063ffffffff9081165f90815260036020526040902054700100000000000000000000000000000000900416151590565b63ffffffff8082165f90815260036020526040812054600160a01b81048316927001000000000000000000000000000000009091041690819003613e0157600580547fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff166c0100000000000000000000000063ffffffff851602179055613e4c565b63ffffffff8082165f9081526003602052604090208054918416600160a01b027fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff9092169190911790555b8163ffffffff165f03613e9957600580547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff166801000000000000000063ffffffff841602179055613ef1565b63ffffffff8083165f9081526003602052604090208054918316700100000000000000000000000000000000027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9092169190911790555b505063ffffffff9081165f90815260036020526040902080547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff169055600580547fffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffff81166401000000009182900484165f190190931602919091179055565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054600203611e5e576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005545f90640100000000900463ffffffff16801580614042575060055468010000000000000000900463ffffffff165f908152600360205260409020546fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16836fffffffffffffffffffffffffffffffff16115b15614050575f9150506129a2565b8363ffffffff8116158061406a575061406881613ca6565b155b15614086575060055468010000000000000000900463ffffffff165b63ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff90811690851611614149575f5b8263ffffffff168110156141435763ffffffff8083165f90815260036020526040902054700100000000000000000000000000000000900416801580614128575063ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff908116908716115b1561413957829450505050506129a2565b91506001016140b9565b506141ca565b5f5b8263ffffffff168110156141c85763ffffffff8083165f90815260036020526040902054600160a01b9004168015806141ae575063ffffffff81165f908152600360205260409020546fffffffffffffffffffffffffffffffff90811690871611155b156141be5793506129a292505050565b915060010161414b565b505b6040517fb215190700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b803563ffffffff8116811461420f575f5ffd5b919050565b5f60208284031215614224575f5ffd5b61422d826141fc565b9392505050565b5f5f60408385031215614245575f5ffd5b61424e836141fc565b915061425c602084016141fc565b90509250929050565b63ffffffff815116825273ffffffffffffffffffffffffffffffffffffffff60208201511660208301526fffffffffffffffffffffffffffffffff604082015116604083015263ffffffff606082015116606083015263ffffffff608082015116608083015260a08101516142e260a084018263ffffffff169052565b5060c08101516122ec60c084018215159052565b604080825283519082018190525f9060208501906060840190835b8181101561433a57614324838551614265565b6020939093019260e09290920191600101614311565b5050809250505063ffffffff831660208301529392505050565b60e081016129a28284614265565b803573ffffffffffffffffffffffffffffffffffffffff8116811461420f575f5ffd5b5f60208284031215614395575f5ffd5b61422d82614362565b5f5f604083850312156143af575f5ffd5b6143b883614362565b946020939093013593505050565b803567ffffffffffffffff8116811461420f575f5ffd5b5f5f604083850312156143ee575f5ffd5b6143f7836143c6565b915061425c602084016143c6565b5f5f5f60408486031215614417575f5ffd5b61442084614362565b9250602084013567ffffffffffffffff81111561443b575f5ffd5b8401601f8101861361444b575f5ffd5b803567ffffffffffffffff811115614461575f5ffd5b8660208260051b8401011115614475575f5ffd5b939660209190910195509293505050565b5f60208284031215614496575f5ffd5b5035919050565b5f602082840312156144ad575f5ffd5b81356fffffffffffffffffffffffffffffffff8116811461422d575f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b6004811061452e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b602081016129a282846144f9565b610100810161454f828b6144f9565b67ffffffffffffffff8916602083015267ffffffffffffffff8816604083015267ffffffffffffffff871660608301526fffffffffffffffffffffffffffffffff8616608083015263ffffffff851660a083015263ffffffff841660c083015263ffffffff831660e08301529998505050505050505050565b5f5f604083850312156145d9575f5ffd5b8235915061425c60208401614362565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156129a2576129a2614643565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b67ffffffffffffffff81811683821601908111156129a2576129a2614643565b808201808211156129a2576129a2614643565b63ffffffff82811682821603908111156129a2576129a2614643565b6fffffffffffffffffffffffffffffffff81811683821601908111156129a2576129a2614643565b80820281158282048414176129a2576129a2614643565b5f82614771577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b67ffffffffffffffff82811682821603908111156129a2576129a261464356fea26469706673582212209f2de25c12b07082e8f86dbfc97f1daf2a7ddcf6180afac8996dda1dd945e3df64736f6c634300081c0033

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

00000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e00000000000000000000000000000000000000000000000000121e6c485ac0000000000000000000000000000000000000000000000000000000000000000019

-----Decoded View---------------
Arg [0] : owner_ (address): 0x77B35947d508012589a91CA4c9d168824376Cc7D
Arg [1] : nftContract (address): 0x4a075606591369c41d7E90d13a1e094b3058683E
Arg [2] : startBid (uint128): 5100000000000000
Arg [3] : numTokens (uint32): 25

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000077b35947d508012589a91ca4c9d168824376cc7d
Arg [1] : 0000000000000000000000004a075606591369c41d7e90d13a1e094b3058683e
Arg [2] : 00000000000000000000000000000000000000000000000000121e6c485ac000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000019


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

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