ETH Price: $3,777.53 (-1.72%)

Contract

0xd4DCB4E92B0F434f1297D5239A3AaD875E25F675
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
Value
Initialize1065836782023-07-07 21:42:13327 days ago1688766133IN
0xd4DCB4E9...75E25F675
0 ETH00.00000006
0x608060401064992662023-07-05 22:48:29329 days ago1688597309IN
 Create: RubiconMarket
0 ETH0.000000030.00001

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
1075582992023-07-30 11:09:35304 days ago1690715375
0xd4DCB4E9...75E25F675
0 ETH
1075582962023-07-30 11:09:29304 days ago1690715369
0xd4DCB4E9...75E25F675
0 ETH
1075582572023-07-30 11:08:11304 days ago1690715291
0xd4DCB4E9...75E25F675
0 ETH
1075582482023-07-30 11:07:53304 days ago1690715273
0xd4DCB4E9...75E25F675
0 ETH
1075581302023-07-30 11:03:57304 days ago1690715037
0xd4DCB4E9...75E25F675
0 ETH
1075581302023-07-30 11:03:57304 days ago1690715037
0xd4DCB4E9...75E25F675
0 ETH
1075581302023-07-30 11:03:57304 days ago1690715037
0xd4DCB4E9...75E25F675
0 ETH
1075578242023-07-30 10:53:45304 days ago1690714425
0xd4DCB4E9...75E25F675
0 ETH
1075578152023-07-30 10:53:27304 days ago1690714407
0xd4DCB4E9...75E25F675
0 ETH
1075578152023-07-30 10:53:27304 days ago1690714407
0xd4DCB4E9...75E25F675
0 ETH
1075578152023-07-30 10:53:27304 days ago1690714407
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075578002023-07-30 10:52:57304 days ago1690714377
0xd4DCB4E9...75E25F675
0 ETH
1075575612023-07-30 10:44:59304 days ago1690713899
0xd4DCB4E9...75E25F675
0 ETH
1075575522023-07-30 10:44:41304 days ago1690713881
0xd4DCB4E9...75E25F675
0 ETH
1075573542023-07-30 10:38:05304 days ago1690713485
0xd4DCB4E9...75E25F675
0 ETH
1075573542023-07-30 10:38:05304 days ago1690713485
0xd4DCB4E9...75E25F675
0 ETH
1075573542023-07-30 10:38:05304 days ago1690713485
0xd4DCB4E9...75E25F675
0 ETH
1075572232023-07-30 10:33:43304 days ago1690713223
0xd4DCB4E9...75E25F675
0 ETH
View All Internal Transactions

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RubiconMarket

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 5 runs

Other Settings:
default evmVersion
File 1 of 6 : RubiconMarket.sol
/// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.9;

// Uncomment this line to use console.log
// import "hardhat/console.sol";

/// @title RubiconMarket.sol
/// @notice Please see the repository for this code at https://github.com/RubiconDeFi/rubicon-protocol-v1;
/// @notice This contract is a derivative work, and spiritual continuation, of the open-source work from Oasis DEX: https://github.com/OasisDEX/oasis

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/StorageSlot.sol";

/// @notice DSAuth events for authentication schema
contract DSAuthEvents {
    /// event LogSetAuthority(address indexed authority); /// TODO: this event is not used in the contract, remove?
    event LogSetOwner(address indexed owner);
}

/// @notice DSAuth library for setting owner of the contract
/// @dev Provides the auth modifier for authenticated function calls
contract DSAuth is DSAuthEvents {
    address public owner;

    function setOwner(address owner_) external auth {
        owner = owner_;
        emit LogSetOwner(owner);
    }

    modifier auth() {
        require(isAuthorized(msg.sender), "ds-auth-unauthorized");
        _;
    }

    function isAuthorized(address src) internal view returns (bool) {
        if (src == owner) {
            return true;
        } else {
            return false;
        }
    }
}

/// @notice DSMath library for safe math without integer overflow/underflow
contract DSMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x, "ds-math-sub-underflow");
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x <= y ? x : y;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x >= y ? x : y;
    }

    function imin(int256 x, int256 y) internal pure returns (int256 z) {
        return x <= y ? x : y;
    }

    function imax(int256 x, int256 y) internal pure returns (int256 z) {
        return x >= y ? x : y;
    }

    uint256 constant WAD = 10 ** 18;
    uint256 constant RAY = 10 ** 27;

    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }

    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, WAD), y / 2) / y;
    }

    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, RAY), y / 2) / y;
    }
}

/// @notice Events contract for logging trade activity on Rubicon Market
/// @dev Provides the key event logs that are used in all core functionality of exchanging on the Rubicon Market
contract EventfulMarket {
    event LogItemUpdate(uint256 id);

    /// TODO: double check it is sound logic to kill this event
    /// event LogTrade(
    ///     uint256 pay_amt,
    ///     address indexed pay_gem,
    ///     uint256 buy_amt,
    ///     address indexed buy_gem
    /// );

    /// event LogMake(
    ///     bytes32 indexed id,
    ///     bytes32 indexed pair,
    ///     address indexed maker,
    ///     IERC20 pay_gem,
    ///     IERC20 buy_gem,
    ///     uint128 pay_amt,
    ///     uint128 buy_amt,
    ///     uint64 timestamp
    /// );

    event emitOffer(
        bytes32 indexed id,
        bytes32 indexed pair,
        address indexed maker,
        IERC20 pay_gem,
        IERC20 buy_gem,
        uint128 pay_amt,
        uint128 buy_amt
    );

    /// TODO: double check it is sound logic to kill this event
    /// event LogBump(
    ///     bytes32 indexed id,
    ///     bytes32 indexed pair,
    ///     address indexed maker,
    ///     IERC20 pay_gem,
    ///     IERC20 buy_gem,
    ///     uint128 pay_amt,
    ///     uint128 buy_amt,
    ///     uint64 timestamp
    /// );

    /// event LogTake(
    ///     bytes32 id,
    ///     bytes32 indexed pair,
    ///     address indexed maker,
    ///     IERC20 pay_gem,
    ///     IERC20 buy_gem,
    ///     address indexed taker,
    ///     uint128 take_amt,
    ///     uint128 give_amt,
    ///     uint64 timestamp
    /// );

    event emitTake(
        bytes32 indexed id,
        bytes32 indexed pair,
        address indexed maker,
        address taker,
        IERC20 pay_gem,
        IERC20 buy_gem,
        uint128 take_amt,
        uint128 give_amt
    );

    /// event LogKill(
    ///     bytes32 indexed id,
    ///     bytes32 indexed pair,
    ///     address indexed maker,
    ///     IERC20 pay_gem,
    ///     IERC20 buy_gem,
    ///     uint128 pay_amt,
    ///     uint128 buy_amt,
    ///     uint64 timestamp
    /// );

    event emitCancel(
        bytes32 indexed id,
        bytes32 indexed pair,
        address indexed maker,
        IERC20 pay_gem,
        IERC20 buy_gem,
        uint128 pay_amt,
        uint128 buy_amt
    );

    /// TODO: double check it is sound logic to kill this event
    /// event LogInt(string lol, uint256 input);

    /// event FeeTake(
    ///     bytes32 indexed id,
    ///     bytes32 indexed pair,
    ///     IERC20 asset,
    ///     address indexed taker,
    ///     address feeTo,
    ///     uint256 feeAmt,
    ///     uint64 timestamp
    /// );

    /// TODO: we will need to make sure this emit is included in any taker pay maker scenario
    event emitFee(
        bytes32 indexed id,
        address indexed taker,
        address indexed feeTo,
        bytes32 pair,
        IERC20 asset,
        uint256 feeAmt
    );

    /// event OfferDeleted(bytes32 indexed id);

    event emitDelete(
        bytes32 indexed id,
        bytes32 indexed pair,
        address indexed maker
    );
}

/// @notice Core trading logic for ERC-20 pairs, an orderbook, and transacting of tokens
/// @dev This contract holds the core ERC-20 / ERC-20 offer, buy, and cancel logic
contract SimpleMarket is EventfulMarket, DSMath {
    using SafeERC20 for IERC20;

    uint256 public last_offer_id;

    /// @dev The mapping that makes up the core orderbook of the exchange
    mapping(uint256 => OfferInfo) public offers;

    bool locked;

    /// @dev This parameter is in basis points
    uint256 internal feeBPS;

    /// @dev This parameter provides the address to which fees are sent
    address internal feeTo;

    bytes32 internal constant MAKER_FEE_SLOT = keccak256("WOB_MAKER_FEE");

    struct OfferInfo {
        uint256 pay_amt;
        IERC20 pay_gem;
        uint256 buy_amt;
        IERC20 buy_gem;
        address recipient;
        uint64 timestamp;
        address owner;
    }

    /// @notice Modifier that insures an order exists and is properly in the orderbook
    modifier can_buy(uint256 id) virtual {
        require(isActive(id));
        _;
    }

    // /// @notice Modifier that checks the user to make sure they own the offer and its valid before they attempt to cancel it
    modifier can_cancel(uint256 id) virtual {
        require(isActive(id));
        require(
            (msg.sender == getOwner(id)) ||
                (msg.sender == getRecipient(id) && getOwner(id) == address(0))
        );
        _;
    }

    modifier can_offer() virtual {
        _;
    }

    modifier synchronized() {
        require(!locked);
        locked = true;
        _;
        locked = false;
    }

    /// @notice Get makerFee value.
    function makerFee() public view returns (uint256) {
        return StorageSlot.getUint256Slot(MAKER_FEE_SLOT).value;
    }

    function protocolFee() public view returns (uint256) {
        return feeBPS;
    }

    function isActive(uint256 id) public view returns (bool active) {
        return offers[id].timestamp > 0;
    }

    function getOwner(uint256 id) public view returns (address owner) {
        return offers[id].owner;
    }

    function getRecipient(uint256 id) public view returns (address owner) {
        return offers[id].recipient;
    }

    function getOffer(
        uint256 id
    ) public view returns (uint256, IERC20, uint256, IERC20) {
        OfferInfo memory _offer = offers[id];
        return (_offer.pay_amt, _offer.pay_gem, _offer.buy_amt, _offer.buy_gem);
    }

    /// @notice Accept a given `quantity` of an offer. Transfers funds from caller/taker to offer maker, and from market to caller/taker.
    /// @notice The fee for taker trades is paid in this function.
    function buy(
        uint256 id,
        uint256 quantity
    ) public virtual can_buy(id) synchronized returns (bool) {
        OfferInfo memory _offer = offers[id];
        uint256 spend = mul(quantity, _offer.buy_amt) / _offer.pay_amt;

        require(uint128(spend) == spend, "spend is not an int");
        require(uint128(quantity) == quantity, "quantity is not an int");

        ///@dev For backwards semantic compatibility.
        if (
            quantity == 0 ||
            spend == 0 ||
            quantity > _offer.pay_amt ||
            spend > _offer.buy_amt
        ) {
            return false;
        }

        offers[id].pay_amt = sub(_offer.pay_amt, quantity);
        offers[id].buy_amt = sub(_offer.buy_amt, spend);

        /// @dev Fee logic added on taker trades
        uint256 fee = mul(spend, feeBPS) / 100_000;

        _offer.buy_gem.safeTransferFrom(msg.sender, feeTo, fee);

        // taker pay maker 0_0
        if (makerFee() > 0) {
            uint256 mFee = mul(spend, makerFee()) / 100_000;

            /// @dev Handle the v1 -> v2 migration case where if owner == address(0) we transfer this fee to _offer.recipient
            if (_offer.owner == address(0) && getRecipient(id) != address(0)) {
                _offer.buy_gem.safeTransferFrom(
                    msg.sender,
                    _offer.recipient,
                    mFee
                );
            } else {
                _offer.buy_gem.safeTransferFrom(msg.sender, _offer.owner, mFee);
            }

            emit emitFee(
                bytes32(id),
                msg.sender,
                _offer.owner != address(0) ? _offer.owner : _offer.recipient,
                keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
                _offer.buy_gem,
                mFee
            );
        }
        _offer.buy_gem.safeTransferFrom(msg.sender, _offer.recipient, spend);

        _offer.pay_gem.safeTransfer(msg.sender, quantity);

        emit LogItemUpdate(id);

        emit emitTake(
            bytes32(id),
            keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
            _offer.owner != address(0) ? _offer.owner : _offer.recipient,
            msg.sender,
            _offer.pay_gem,
            _offer.buy_gem,
            uint128(quantity),
            uint128(spend)
        );

        emit emitFee(
            bytes32(id),
            msg.sender,
            feeTo,
            keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
            _offer.buy_gem,
            fee
        );

        if (offers[id].pay_amt == 0) {
            delete offers[id];

            emit emitDelete(
                bytes32(id),
                keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
                _offer.owner != address(0) ? _offer.owner : _offer.recipient
            );
        }

        return true;
    }

    /// @notice Allows the caller to cancel the offer if it is their own.
    /// @notice This function refunds the offer to the maker.
    function cancel(
        uint256 id
    ) public virtual can_cancel(id) synchronized returns (bool success) {
        OfferInfo memory _offer = offers[id];
        delete offers[id];

        /// @dev V1 orders after V2 upgrade will point to address(0) in owner
        _offer.owner == address(0)
            ? _offer.pay_gem.safeTransfer(_offer.recipient, _offer.pay_amt)
            : _offer.pay_gem.safeTransfer(_offer.owner, _offer.pay_amt);

        emit LogItemUpdate(id);

        emit emitCancel(
            bytes32(id),
            keccak256(abi.encodePacked(_offer.pay_gem, _offer.buy_gem)),
            _offer.owner != address(0) ? _offer.owner : _offer.recipient,
            _offer.pay_gem,
            _offer.buy_gem,
            uint128(_offer.pay_amt),
            uint128(_offer.buy_amt)
        );

        success = true;
    }

    /// @notice Key function to make a new offer. Takes funds from the caller into market escrow.
    function offer(
        uint256 pay_amt,
        IERC20 pay_gem,
        uint256 buy_amt,
        IERC20 buy_gem,
        address owner,
        address recipient
    ) public virtual can_offer synchronized returns (uint256 id) {
        require(uint128(pay_amt) == pay_amt);
        require(uint128(buy_amt) == buy_amt);
        require(pay_amt > 0);
        require(pay_gem != IERC20(address(0))); /// @dev Note, modified from: require(pay_gem != IERC20(0x0)) which compiles in 0.7.6
        require(buy_amt > 0);
        require(buy_gem != IERC20(address(0))); /// @dev Note, modified from: require(buy_gem != IERC20(0x0)) which compiles in 0.7.6
        require(pay_gem != buy_gem);
        require(owner != address(0), "Zero owner address");
        require(recipient != address(0), "Zero recipient address");

        OfferInfo memory info;
        info.pay_amt = pay_amt;
        info.pay_gem = pay_gem;
        info.buy_amt = buy_amt;
        info.buy_gem = buy_gem;
        info.recipient = recipient;
        info.owner = owner;
        info.timestamp = uint64(block.timestamp);
        id = _next_id();
        offers[id] = info;

        pay_gem.safeTransferFrom(msg.sender, address(this), pay_amt);

        emit LogItemUpdate(id);

        emit emitOffer(
            bytes32(id),
            keccak256(abi.encodePacked(pay_gem, buy_gem)),
            msg.sender,
            pay_gem,
            buy_gem,
            uint128(pay_amt),
            uint128(buy_amt)
        );
    }

    function _next_id() internal returns (uint256) {
        last_offer_id++;
        return last_offer_id;
    }

    // Fee logic
    function getFeeBPS() public view returns (uint256) {
        return feeBPS;
    }
}

/// @notice Expiring market is a Simple Market with a market lifetime.
/// @dev When the close_time has been reached, offers can only be cancelled (offer and buy will throw).
contract ExpiringMarket is DSAuth, SimpleMarket {
    bool public stopped;

    /// @dev After close_time has been reached, no new offers are allowed.
    modifier can_offer() override {
        require(!isClosed());
        _;
    }

    /// @dev After close, no new buys are allowed.
    modifier can_buy(uint256 id) override {
        require(isActive(id));
        require(!isClosed());
        _;
    }

    /// @dev After close, anyone can cancel an offer.
    modifier can_cancel(uint256 id) virtual override {
        require(isActive(id));
        require(
            (msg.sender == getOwner(id)) ||
                isClosed() ||
                (msg.sender == getRecipient(id) && getOwner(id) == address(0))
        );
        _;
    }

    function isClosed() public pure returns (bool closed) {
        return false;
    }

    function getTime() public view returns (uint64) {
        return uint64(block.timestamp);
    }

    function stop() external auth {
        stopped = true;
    }
}

contract DSNote {
    event LogNote(
        bytes4 indexed sig,
        address indexed guy,
        bytes32 indexed foo,
        bytes32 indexed bar,
        uint256 wad,
        bytes fax
    ) anonymous;

    modifier note() {
        bytes32 foo;
        bytes32 bar;
        uint256 wad;

        assembly {
            foo := calldataload(4)
            bar := calldataload(36)
            wad := callvalue()
        }

        emit LogNote(msg.sig, msg.sender, foo, bar, wad, msg.data);

        _;
    }
}

contract MatchingEvents {
    /// event LogBuyEnabled(bool isEnabled); /// TODO: this event is not used in the contract, remove?
    event LogMinSell(address pay_gem, uint256 min_amount);
    /// event LogMatchingEnabled(bool isEnabled); /// TODO: this event is not used in the contract, remove?
    event LogUnsortedOffer(uint256 id);
    event LogSortedOffer(uint256 id);
    /// event LogInsert(address keeper, uint256 id); /// TODO: this event is not used in the contract, remove?
    event LogDelete(address keeper, uint256 id);
    event LogMatch(uint256 id, uint256 amount);
}

/// @notice The core Rubicon Market smart contract
/// @notice This contract is based on the original open-source work done by OasisDEX under the Apache License 2.0
/// @dev This contract inherits the key trading functionality from SimpleMarket
contract RubiconMarket is MatchingEvents, ExpiringMarket, DSNote {
    bool public buyEnabled = true; //buy enabled TODO: review this decision!
    bool public matchingEnabled = true; //true: enable matching,

    /// @dev Below is variable to allow for a proxy-friendly constructor
    bool public initialized;

    /// @dev unused deprecated variable for applying a token distribution on top of a trade
    bool public AqueductDistributionLive;
    /// @dev unused deprecated variable for applying a token distribution of this token on top of a trade
    address public AqueductAddress;

    struct sortInfo {
        uint256 next; //points to id of next higher offer
        uint256 prev; //points to id of previous lower offer
        uint256 delb; //the blocknumber where this entry was marked for delete
    }
    mapping(uint256 => sortInfo) public _rank; //doubly linked lists of sorted offer ids
    mapping(address => mapping(address => uint256)) public _best; //id of the highest offer for a token pair
    mapping(address => mapping(address => uint256)) public _span; //number of offers stored for token pair in sorted orderbook
    mapping(address => uint256) public _dust; //minimum sell amount for a token to avoid dust offers
    mapping(uint256 => uint256) public _near; //next unsorted offer id
    uint256 public _head; //first unsorted offer id
    uint256 public dustId; // id of the latest offer marked as dust

    // *** MAPPING TO CHECK POTENTIALLY BLACKLISTED TOKENS ***
    mapping(address => bool) public tokenRequiresBlacklistCheck;
    mapping(address => bytes4) public blacklistSelectors;

    /// @dev Proxy-safe initialization of storage
    function initialize(address _feeTo) public {
        require(!initialized, "contract is already initialized");
        require(_feeTo != address(0));

        /// @notice The market fee recipient
        feeTo = _feeTo;

        owner = msg.sender;
        emit LogSetOwner(msg.sender);

        /// @notice The starting fee on taker trades in basis points
        feeBPS = 1;

        initialized = true;
        matchingEnabled = true;
        buyEnabled = true;
    }

    // // After close, anyone can cancel an offer
    modifier can_cancel(uint256 id) override {
        require(isActive(id), "Offer was deleted or taken, or never existed.");
        require(
            isClosed() ||
                msg.sender == getOwner(id) ||
                id == dustId ||
                (msg.sender == getRecipient(id) && getOwner(id) == address(0)),
            "Offer can not be cancelled because user is not owner, and market is open, and offer sells required amount of tokens."
        );
        _;
    }

    // ---- Public entrypoints ---- //
    // simplest offer entry-point
    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        IERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //maker (ask) buy how much
        IERC20 buy_gem //maker (ask) buy which token
    ) public can_offer returns (uint256) {
        return
            offer(
                pay_amt,
                pay_gem,
                buy_amt,
                buy_gem,
                0,
                true,
                msg.sender,
                msg.sender
            );
    }

    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        IERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //maker (ask) buy how much
        IERC20 buy_gem, //maker (ask) buy which token
        uint pos, //position to insert offer, 0 should be used if unknown
        bool rounding
    ) external can_offer returns (uint256) {
        return
            offer(
                pay_amt,
                pay_gem,
                buy_amt,
                buy_gem,
                pos,
                rounding,
                msg.sender,
                msg.sender
            );
    }

    // Make a new offer. Takes funds from the caller into market escrow.
    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        IERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //maker (ask) buy how much
        IERC20 buy_gem, //maker (ask) buy which token
        uint256 pos, //position to insert offer, 0 should be used if unknown
        address owner,
        address recipient
    ) external can_offer returns (uint256) {
        return
            offer(
                pay_amt,
                pay_gem,
                buy_amt,
                buy_gem,
                pos,
                true,
                owner,
                recipient
            );
    }

    function offer(
        uint256 pay_amt,
        IERC20 pay_gem,
        uint256 buy_amt,
        IERC20 buy_gem,
        address owner,
        address recipient
    ) public override can_offer returns (uint) {
        return
            offer(
                pay_amt,
                pay_gem,
                buy_amt,
                buy_gem,
                0,
                true,
                owner,
                recipient
            );
    }

    function offer(
        uint256 pay_amt, //maker (ask) sell how much
        IERC20 pay_gem, //maker (ask) sell which token
        uint256 buy_amt, //maker (ask) buy how much
        IERC20 buy_gem, //maker (ask) buy which token
        uint256 pos, //position to insert offer, 0 should be used if unknown
        bool matching, //match "close enough" orders?
        address _owner, // owner of the offer
        address recipient // recipient of the offer's fill
    ) public can_offer returns (uint256) {
        require(!locked, "Reentrancy attempt");
        require(_dust[address(pay_gem)] <= pay_amt);

        if (tokenRequiresBlacklistCheck[address(buy_gem)]) {
            require(
                !_addressIsBlacklisted(address(buy_gem), _owner, recipient),
                "offer: BLACKLIST ERROR"
            );
        }

        /// @dev currently matching is perma-enabled
        // if (matchingEnabled) {
        return
            _matcho(
                pay_amt,
                pay_gem,
                buy_amt,
                buy_gem,
                pos,
                matching,
                _owner,
                recipient
            );
        // }
        // return super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
    }

    //Transfers funds from caller to offer maker, and from market to caller.
    function buy(
        uint256 id,
        uint256 amount
    ) public override can_buy(id) returns (bool) {
        require(!locked, "Reentrancy attempt");

        function(uint256, uint256) returns (bool) fn = matchingEnabled
            ? _buys
            : super.buy;

        return fn(id, amount);
    }

    // Cancel an offer. Refunds offer maker.
    function cancel(
        uint256 id
    ) public override can_cancel(id) returns (bool success) {
        require(!locked, "Reentrancy attempt");
        if (matchingEnabled) {
            if (isOfferSorted(id)) {
                require(_unsort(id));
            } else {
                require(_hide(id), "can't hide");
            }
        }
        return super.cancel(id); //delete the offer.
    }

    // *** Batch Functionality ***
    /// @notice Batch offer functionality - multuple offers in a single transaction
    function batchOffer(
        uint[] calldata payAmts,
        address[] calldata payGems,
        uint[] calldata buyAmts,
        address[] calldata buyGems
    ) external {
        require(
            payAmts.length == payGems.length &&
                payAmts.length == buyAmts.length &&
                payAmts.length == buyGems.length,
            "Array lengths do not match"
        );
        for (uint i = 0; i < payAmts.length; i++) {
            offer(
                payAmts[i],
                IERC20(payGems[i]),
                buyAmts[i],
                IERC20(buyGems[i])
            );
        }
    }

    /// @notice Cancel multiple offers in a single transaction
    function batchCancel(uint[] calldata ids) external {
        for (uint i = 0; i < ids.length; i++) {
            cancel(ids[i]);
        }
    }

    /// @notice Update outstanding offers to new offers, in a batch, in a single transaction
    function batchRequote(
        uint[] calldata ids,
        uint[] calldata payAmts,
        address[] calldata payGems,
        uint[] calldata buyAmts,
        address[] calldata buyGems
    ) external {
        require(
            payAmts.length == payGems.length &&
                payAmts.length == ids.length &&
                payAmts.length == buyAmts.length &&
                payAmts.length == buyGems.length,
            "Array lengths do not match"
        );
        for (uint i = 0; i < ids.length; i++) {
            cancel(ids[i]);
            offer(
                payAmts[i],
                IERC20(payGems[i]),
                buyAmts[i],
                IERC20(buyGems[i])
            );
        }
    }

    //deletes _rank [id]
    //  Function should be called by keepers.
    function del_rank(uint256 id) external returns (bool) {
        require(!locked);

        require(
            !isActive(id) &&
                _rank[id].delb != 0 &&
                _rank[id].delb < block.number - 10
        );
        delete _rank[id];
        emit LogDelete(msg.sender, id);
        return true;
    }

    //set the minimum sell amount for a token
    //    Function is used to avoid "dust offers" that have
    //    very small amount of tokens to sell, and it would
    //    cost more gas to accept the offer, than the value
    //    of tokens received.
    function setMinSell(
        IERC20 pay_gem, //token to assign minimum sell amount to
        uint256 dust //maker (ask) minimum sell amount
    ) external auth note returns (bool) {
        _dust[address(pay_gem)] = dust;
        emit LogMinSell(address(pay_gem), dust);
        return true;
    }

    //returns the minimum sell amount for an offer
    function getMinSell(
        IERC20 pay_gem //token for which minimum sell amount is queried
    ) external view returns (uint256) {
        return _dust[address(pay_gem)];
    }

    //return the best offer for a token pair
    //      the best offer is the lowest one if it's an ask,
    //      and highest one if it's a bid offer
    function getBestOffer(
        IERC20 sell_gem,
        IERC20 buy_gem
    ) public view returns (uint256) {
        return _best[address(sell_gem)][address(buy_gem)];
    }

    //return the next worse offer in the sorted list
    //      the worse offer is the higher one if its an ask,
    //      a lower one if its a bid offer,
    //      and in both cases the newer one if they're equal.
    function getWorseOffer(uint256 id) public view returns (uint256) {
        return _rank[id].prev;
    }

    //return the next better offer in the sorted list
    //      the better offer is in the lower priced one if its an ask,
    //      the next higher priced one if its a bid offer
    //      and in both cases the older one if they're equal.
    function getBetterOffer(uint256 id) external view returns (uint256) {
        return _rank[id].next;
    }

    //return the amount of better offers for a token pair
    function getOfferCount(
        IERC20 sell_gem,
        IERC20 buy_gem
    ) public view returns (uint256) {
        return _span[address(sell_gem)][address(buy_gem)];
    }

    //get the first unsorted offer that was inserted by a contract
    //      Contracts can't calculate the insertion position of their offer because it is not an O(1) operation.
    //      Their offers get put in the unsorted list of offers.
    //      Keepers can calculate the insertion position offchain and pass it to the insert() function to insert
    //      the unsorted offer into the sorted list. Unsorted offers will not be matched, but can be bought with buy().
    function getFirstUnsortedOffer() public view returns (uint256) {
        return _head;
    }

    //get the next unsorted offer
    //      Can be used to cycle through all the unsorted offers.
    function getNextUnsortedOffer(uint256 id) public view returns (uint256) {
        return _near[id];
    }

    function isOfferSorted(uint256 id) public view returns (bool) {
        return
            _rank[id].next != 0 ||
            _rank[id].prev != 0 ||
            _best[address(offers[id].pay_gem)][address(offers[id].buy_gem)] ==
            id;
    }

    function sellAllAmount(
        IERC20 pay_gem,
        uint256 pay_amt,
        IERC20 buy_gem,
        uint256 min_fill_amount
    ) external returns (uint256 fill_amt) {
        require(!locked);

        uint256 offerId;
        while (pay_amt > 0) {
            //while there is amount to sell
            offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair
            require(offerId != 0, "0 offerId"); //Fails if there are not more offers

            // There is a chance that pay_amt is smaller than 1 wei of the other token
            if (
                mul(pay_amt, 1 ether) <
                wdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)
            ) {
                break; //We consider that all amount is sold
            }
            if (pay_amt >= offers[offerId].buy_amt) {
                //If amount to sell is higher or equal than current offer amount to buy
                fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount bought to acumulator
                pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to sell
                buy((offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer
            } else {
                // if lower
                uint256 baux = rmul(
                    mul(pay_amt, 10 ** 9),
                    rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)
                ) / 10 ** 9;
                fill_amt = add(fill_amt, baux); //Add amount bought to acumulator
                buy((offerId), uint128(baux)); //We take the portion of the offer that we need
                pay_amt = 0; //All amount is sold
            }
        }
        require(fill_amt >= min_fill_amount, "min_fill_amount isn't filled");
    }

    function buyAllAmount(
        IERC20 buy_gem,
        uint256 buy_amt,
        IERC20 pay_gem,
        uint256 max_fill_amount
    ) external returns (uint256 fill_amt) {
        require(!locked);
        uint256 offerId;
        while (buy_amt > 0) {
            //Meanwhile there is amount to buy
            offerId = getBestOffer(buy_gem, pay_gem); //Get the best offer for the token pair
            require(offerId != 0, "offerId == 0");

            // There is a chance that buy_amt is smaller than 1 wei of the other token
            if (
                mul(buy_amt, 1 ether) <
                wdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)
            ) {
                break; //We consider that all amount is sold
            }
            if (buy_amt >= offers[offerId].pay_amt) {
                //If amount to buy is higher or equal than current offer amount to sell
                fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount sold to acumulator
                buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy
                buy((offerId), uint128(offers[offerId].pay_amt)); //We take the whole offer
            } else {
                //if lower
                fill_amt = add(
                    fill_amt,
                    rmul(
                        mul(buy_amt, 10 ** 9),
                        rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)
                    ) / 10 ** 9
                ); //Add amount sold to acumulator
                buy((offerId), uint128(buy_amt)); //We take the portion of the offer that we need
                buy_amt = 0; //All amount is bought
            }
        }
        require(
            fill_amt <= max_fill_amount,
            "fill_amt exceeds max_fill_amount"
        );
    }

    function calculateFees(
        uint256 amount,
        bool isPay /// @param denote direction
    ) public view returns (uint256 _amount) {
        uint256 _makerFee = makerFee();
        _amount = amount;

        // getPay fee calculation
        if (isPay) {
            _amount += mul(amount, feeBPS) / 100_000;

            if (_makerFee > 0) {
                _amount += mul(amount, _makerFee) / 100_000;
            }
        }
        // getBuy fee calculation
        else {
            _amount -=
                (((_makerFee + feeBPS) * amount) * 1e18) /
                (100_000 + _makerFee + feeBPS) /
                1e18;
        }
    }

    /// @return buy_amt - value to send to contract in order to get pay_amt
    /// @return approvalAmount - amount user should approve for interaction
    function getBuyAmountWithFee(
        IERC20 buy_gem,
        IERC20 pay_gem,
        uint256 pay_amt
    ) external view returns (uint256 buy_amt, uint256 approvalAmount) {
        uint256 pay_amt_minus_fee = calculateFees(pay_amt, false);
        buy_amt = getBuyAmount(buy_gem, pay_gem, pay_amt_minus_fee);

        approvalAmount = pay_amt;
    }

    /// @return fill_amt - fill amount without fee!
    function getBuyAmount(
        IERC20 buy_gem,
        IERC20 pay_gem,
        uint256 pay_amt
    ) public view returns (uint256 fill_amt) {
        uint256 offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair
        while (pay_amt > offers[offerId].buy_amt) {
            fill_amt = add(fill_amt, offers[offerId].pay_amt); //Add amount to buy accumulator
            pay_amt = sub(pay_amt, offers[offerId].buy_amt); //Decrease amount to pay
            if (pay_amt > 0) {
                //If we still need more offers
                offerId = getWorseOffer(offerId); //We look for the next best offer
                require(offerId != 0); //Fails if there are not enough offers to complete
            }
        }

        fill_amt = add(
            fill_amt,
            rmul(
                mul(pay_amt, 10 ** 9),
                rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)
            ) / 10 ** 9
        ); //Add proportional amount of last offer to buy accumulator
    }

    /// @return pay_amt - amount to send to contract in order to get buy_amt
    /// @return approvalAmount - amount user should approve for interaction to cover the pay_amt + fee
    function getPayAmountWithFee(
        IERC20 pay_gem,
        IERC20 buy_gem,
        uint256 buy_amt
    ) public view returns (uint256 pay_amt, uint256 approvalAmount) {
        pay_amt = (getPayAmount(pay_gem, buy_gem, buy_amt));
        uint256 modifiedAmount = calculateFees(pay_amt, true);

        approvalAmount = modifiedAmount;
    }

    function getPayAmount(
        IERC20 pay_gem,
        IERC20 buy_gem,
        uint256 buy_amt
    ) public view returns (uint256 fill_amt) {
        uint256 offerId = getBestOffer(buy_gem, pay_gem); //Get best offer for the token pair
        while (buy_amt > offers[offerId].pay_amt) {
            fill_amt = add(fill_amt, offers[offerId].buy_amt); //Add amount to pay accumulator
            buy_amt = sub(buy_amt, offers[offerId].pay_amt); //Decrease amount to buy
            if (buy_amt > 0) {
                //If we still need more offers
                offerId = getWorseOffer(offerId); //We look for the next best offer
                require(offerId != 0); //Fails if there are not enough offers to complete
            }
        }
        fill_amt = add(
            fill_amt,
            rmul(
                mul(buy_amt, 10 ** 9),
                rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)
            ) / 10 ** 9
        ); //Add proportional amount of last offer to pay accumulator
    }

    // ---- Internal Functions ---- //

    function _isBlacklistedWithSelector(
        address _token,
        address _user,
        bytes4 _selector
    ) internal view returns (bool) {
        (bool success, bytes memory result) = _token.staticcall(
            abi.encodeWithSelector(_selector, _user)
        );

        return success && abi.decode(result, (bool));
    }

    function _addressIsBlacklisted(
        address _token,
        address _owner,
        address _recipient
    ) internal view returns (bool) {
        bytes4 _selector = blacklistSelectors[_token];

        return (_isBlacklistedWithSelector(_token, _owner, _selector) ||
            _isBlacklistedWithSelector(_token, _recipient, _selector));
    }

    function _buys(uint256 id, uint256 amount) internal returns (bool) {
        require(buyEnabled);
        if (amount == offers[id].pay_amt) {
            if (isOfferSorted(id)) {
                //offers[id] must be removed from sorted list because all of it is bought
                _unsort(id);
            } else {
                _hide(id);
            }
        }

        require(super.buy(id, amount));

        // If offer has become dust during buy, we cancel it
        if (
            isActive(id) &&
            offers[id].pay_amt < _dust[address(offers[id].pay_gem)]
        ) {
            dustId = id; //enable current msg.sender to call cancel(id)
            cancel(id);
        }
        return true;
    }

    //find the id of the next higher offer after offers[id]
    function _find(uint256 id) internal view returns (uint256) {
        require(id > 0);

        address buy_gem = address(offers[id].buy_gem);
        address pay_gem = address(offers[id].pay_gem);
        uint256 top = _best[pay_gem][buy_gem];
        uint256 old_top = 0;

        // Find the larger-than-id order whose successor is less-than-id.
        while (top != 0 && _isPricedLtOrEq(id, top)) {
            old_top = top;
            top = _rank[top].prev;
        }
        return old_top;
    }

    //find the id of the next higher offer after offers[id]
    function _findpos(uint256 id, uint256 pos) internal view returns (uint256) {
        require(id > 0);

        // Look for an active order.
        while (pos != 0 && !isActive(pos)) {
            pos = _rank[pos].prev;
        }

        if (pos == 0) {
            //if we got to the end of list without a single active offer
            return _find(id);
        } else {
            // if we did find a nearby active offer
            // Walk the order book down from there...
            if (_isPricedLtOrEq(id, pos)) {
                uint256 old_pos;

                // Guaranteed to run at least once because of
                // the prior if statements.
                while (pos != 0 && _isPricedLtOrEq(id, pos)) {
                    old_pos = pos;
                    pos = _rank[pos].prev;
                }
                return old_pos;

                // ...or walk it up.
            } else {
                while (pos != 0 && !_isPricedLtOrEq(id, pos)) {
                    pos = _rank[pos].next;
                }
                return pos;
            }
        }
    }

    //return true if offers[low] priced less than or equal to offers[high]
    function _isPricedLtOrEq(
        uint256 low, //lower priced offer's id
        uint256 high //higher priced offer's id
    ) internal view returns (bool) {
        return
            mul(offers[low].buy_amt, offers[high].pay_amt) >=
            mul(offers[high].buy_amt, offers[low].pay_amt);
    }

    //these variables are global only because of solidity local variable limit

    //match offers with taker offer, and execute token transactions
    function _matcho(
        uint256 t_pay_amt, //taker sell how much
        IERC20 t_pay_gem, //taker sell which token
        uint256 t_buy_amt, //taker buy how much
        IERC20 t_buy_gem, //taker buy which token
        uint256 pos, //position id
        bool rounding, //match "close enough" orders?
        address owner,
        address recipient
    ) internal returns (uint256 id) {
        uint256 best_maker_id; //highest maker id
        uint256 t_buy_amt_old; //taker buy how much saved
        uint256 m_buy_amt; //maker offer wants to buy this much token
        uint256 m_pay_amt; //maker offer wants to sell this much token

        // there is at least one offer stored for token pair
        while (_best[address(t_buy_gem)][address(t_pay_gem)] > 0) {
            best_maker_id = _best[address(t_buy_gem)][address(t_pay_gem)];
            m_buy_amt = offers[best_maker_id].buy_amt;
            m_pay_amt = offers[best_maker_id].pay_amt;

            // Ugly hack to work around rounding errors. Based on the idea that
            // the furthest the amounts can stray from their "true" values is 1.
            // Ergo the worst case has t_pay_amt and m_pay_amt at +1 away from
            // their "correct" values and m_buy_amt and t_buy_amt at -1.
            // Since (c - 1) * (d - 1) > (a + 1) * (b + 1) is equivalent to
            // c * d > a * b + a + b + c + d, we write...
            if (
                mul(m_buy_amt, t_buy_amt) >
                mul(t_pay_amt, m_pay_amt) +
                    (
                        rounding
                            ? m_buy_amt + t_buy_amt + t_pay_amt + m_pay_amt
                            : 0
                    )
            ) {
                break;
            }
            // ^ The `rounding` parameter is a compromise borne of a couple days
            // of discussion.
            buy(best_maker_id, min(m_pay_amt, t_buy_amt));
            emit LogMatch(id, min(m_pay_amt, t_buy_amt));
            t_buy_amt_old = t_buy_amt;
            t_buy_amt = sub(t_buy_amt, min(m_pay_amt, t_buy_amt));
            t_pay_amt = mul(t_buy_amt, t_pay_amt) / t_buy_amt_old;

            if (t_pay_amt == 0 || t_buy_amt == 0) {
                break;
            }
        }

        if (
            t_buy_amt > 0 &&
            t_pay_amt > 0 &&
            t_pay_amt >= _dust[address(t_pay_gem)]
        ) {
            //new offer should be created
            id = super.offer(
                t_pay_amt,
                t_pay_gem,
                t_buy_amt,
                t_buy_gem,
                owner,
                recipient
            );
            //insert offer into the sorted list
            _sort(id, pos);
        }
    }

    //put offer into the sorted list
    function _sort(
        uint256 id, //maker (ask) id
        uint256 pos //position to insert into
    ) internal {
        require(isActive(id));

        IERC20 buy_gem = offers[id].buy_gem;
        IERC20 pay_gem = offers[id].pay_gem;
        uint256 prev_id; //maker (ask) id

        pos = pos == 0 ||
            offers[pos].pay_gem != pay_gem ||
            offers[pos].buy_gem != buy_gem ||
            !isOfferSorted(pos)
            ? _find(id)
            : _findpos(id, pos);

        if (pos != 0) {
            //offers[id] is not the highest offer
            //requirement below is satisfied by statements above
            //require(_isPricedLtOrEq(id, pos));
            prev_id = _rank[pos].prev;
            _rank[pos].prev = id;
            _rank[id].next = pos;
        } else {
            //offers[id] is the highest offer
            prev_id = _best[address(pay_gem)][address(buy_gem)];
            _best[address(pay_gem)][address(buy_gem)] = id;
        }

        if (prev_id != 0) {
            //if lower offer does exist
            //requirement below is satisfied by statements above
            //require(!_isPricedLtOrEq(id, prev_id));
            _rank[prev_id].next = id;
            _rank[id].prev = prev_id;
        }

        _span[address(pay_gem)][address(buy_gem)]++;
        emit LogSortedOffer(id);
    }

    // Remove offer from the sorted list (does not cancel offer)
    function _unsort(
        uint256 id //id of maker (ask) offer to remove from sorted list
    ) internal returns (bool) {
        address buy_gem = address(offers[id].buy_gem);
        address pay_gem = address(offers[id].pay_gem);
        require(_span[pay_gem][buy_gem] > 0);

        require(
            _rank[id].delb == 0 && //assert id is in the sorted list
                isOfferSorted(id)
        );

        if (id != _best[pay_gem][buy_gem]) {
            // offers[id] is not the highest offer
            require(_rank[_rank[id].next].prev == id);
            _rank[_rank[id].next].prev = _rank[id].prev;
        } else {
            //offers[id] is the highest offer
            _best[pay_gem][buy_gem] = _rank[id].prev;
        }

        if (_rank[id].prev != 0) {
            //offers[id] is not the lowest offer
            require(_rank[_rank[id].prev].next == id);
            _rank[_rank[id].prev].next = _rank[id].next;
        }

        _span[pay_gem][buy_gem]--;
        _rank[id].delb = block.number; //mark _rank[id] for deletion
        return true;
    }

    //Hide offer from the unsorted order book (does not cancel offer)
    function _hide(
        uint256 id //id of maker offer to remove from unsorted list
    ) internal returns (bool) {
        uint256 uid = _head; //id of an offer in unsorted offers list
        uint256 pre = uid; //id of previous offer in unsorted offers list

        require(!isOfferSorted(id), "offer sorted"); //make sure offer id is not in sorted offers list

        if (_head == id) {
            //check if offer is first offer in unsorted offers list
            _head = _near[id]; //set head to new first unsorted offer
            _near[id] = 0; //delete order from unsorted order list
            return true;
        }
        while (uid > 0 && uid != id) {
            //find offer in unsorted order list
            pre = uid;
            uid = _near[uid];
        }
        if (uid != id) {
            //did not find offer id in unsorted offers list
            return false;
        }
        _near[pre] = _near[id]; //set previous unsorted offer to point to offer after offer id
        _near[id] = 0; //delete order from unsorted order list
        return true;
    }

    function setFeeBPS(uint256 _newFeeBPS) external auth returns (bool) {
        feeBPS = _newFeeBPS;
        return true;
    }

    function setMakerFee(uint256 _newMakerFee) external auth returns (bool) {
        StorageSlot.getUint256Slot(MAKER_FEE_SLOT).value = _newMakerFee;
        return true;
    }

    function setFeeTo(address newFeeTo) external auth returns (bool) {
        require(newFeeTo != address(0));
        feeTo = newFeeTo;
        return true;
    }

    function getFeeTo() external view returns (address) {
        return feeTo;
    }

    function setTokenRequiresBlacklistCheck(
        address token,
        bool requiresCheck,
        bytes4 selector
    ) external auth {
        tokenRequiresBlacklistCheck[token] = requiresCheck;
        blacklistSelectors[token] = selector;
    }

    // *** Admin only function to remove blacklisted offers, if needed
    /// @dev If a user places orders in the book and then later becomes blacklisted, we need a way to handle that for no DOS by removing the order
    function cancelBlacklistedOffer(uint256 id) external auth synchronized {
        OfferInfo memory _offer = offers[id];

        // owner or recipient MUST be blacklisted in buy_gem OR pay_gem
        bool isBlacklisted = _addressIsBlacklisted(
            address(_offer.buy_gem),
            _offer.owner,
            _offer.recipient
        );
        require(isBlacklisted, "neither owner nor recipient is blacklisted");

        // remove order from the sorted list
        require(_unsort(id));
        // delete offer manually
        // not returning tokens back to the bad guy
        delete offers[id];
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 4 of 6 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

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

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

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 5 of 6 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

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

pragma solidity ^0.8.0;

/**
 * @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 ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

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

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

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

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

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 5
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"keeper","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"LogDelete","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"LogItemUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LogMatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pay_gem","type":"address"},{"indexed":false,"internalType":"uint256","name":"min_amount","type":"uint256"}],"name":"LogMinSell","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":true,"internalType":"bytes32","name":"foo","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"bar","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"LogSortedOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"LogUnsortedOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"pair","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"indexed":false,"internalType":"uint128","name":"pay_amt","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"buy_amt","type":"uint128"}],"name":"emitCancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"pair","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"}],"name":"emitDelete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"address","name":"taker","type":"address"},{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"bytes32","name":"pair","type":"bytes32"},{"indexed":false,"internalType":"contract IERC20","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmt","type":"uint256"}],"name":"emitFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"pair","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"indexed":false,"internalType":"uint128","name":"pay_amt","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"buy_amt","type":"uint128"}],"name":"emitOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"pair","type":"bytes32"},{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"indexed":false,"internalType":"uint128","name":"take_amt","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"give_amt","type":"uint128"}],"name":"emitTake","type":"event"},{"inputs":[],"name":"AqueductAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AqueductDistributionLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"_best","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_dust","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_head","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_near","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_rank","outputs":[{"internalType":"uint256","name":"next","type":"uint256"},{"internalType":"uint256","name":"prev","type":"uint256"},{"internalType":"uint256","name":"delb","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"_span","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"batchCancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"payAmts","type":"uint256[]"},{"internalType":"address[]","name":"payGems","type":"address[]"},{"internalType":"uint256[]","name":"buyAmts","type":"uint256[]"},{"internalType":"address[]","name":"buyGems","type":"address[]"}],"name":"batchOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"payAmts","type":"uint256[]"},{"internalType":"address[]","name":"payGems","type":"address[]"},{"internalType":"uint256[]","name":"buyAmts","type":"uint256[]"},{"internalType":"address[]","name":"buyGems","type":"address[]"}],"name":"batchRequote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklistSelectors","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"buy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"max_fill_amount","type":"uint256"}],"name":"buyAllAmount","outputs":[{"internalType":"uint256","name":"fill_amt","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"isPay","type":"bool"}],"name":"calculateFees","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancel","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"cancelBlacklistedOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"del_rank","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dustId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"sell_gem","type":"address"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"}],"name":"getBestOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getBetterOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"pay_amt","type":"uint256"}],"name":"getBuyAmount","outputs":[{"internalType":"uint256","name":"fill_amt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"pay_amt","type":"uint256"}],"name":"getBuyAmountWithFee","outputs":[{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"uint256","name":"approvalAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFirstUnsortedOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"pay_gem","type":"address"}],"name":"getMinSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getNextUnsortedOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"contract IERC20","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"sell_gem","type":"address"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"}],"name":"getOfferCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getOwner","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"}],"name":"getPayAmount","outputs":[{"internalType":"uint256","name":"fill_amt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"}],"name":"getPayAmountWithFee","outputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"uint256","name":"approvalAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getRecipient","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTime","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getWorseOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeTo","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isActive","outputs":[{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isClosed","outputs":[{"internalType":"bool","name":"closed","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isOfferSorted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"last_offer_id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"makerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"matchingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"pos","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"offer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"pos","type":"uint256"},{"internalType":"bool","name":"matching","type":"bool"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"offer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"pos","type":"uint256"},{"internalType":"bool","name":"rounding","type":"bool"}],"name":"offer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"}],"name":"offer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"offer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"offers","outputs":[{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"buy_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"pay_amt","type":"uint256"},{"internalType":"contract IERC20","name":"buy_gem","type":"address"},{"internalType":"uint256","name":"min_fill_amount","type":"uint256"}],"name":"sellAllAmount","outputs":[{"internalType":"uint256","name":"fill_amt","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newFeeBPS","type":"uint256"}],"name":"setFeeBPS","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeTo","type":"address"}],"name":"setFeeTo","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMakerFee","type":"uint256"}],"name":"setMakerFee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"pay_gem","type":"address"},{"internalType":"uint256","name":"dust","type":"uint256"}],"name":"setMinSell","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"requiresCheck","type":"bool"},{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"setTokenRequiresBlacklistCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenRequiresBlacklistCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60806040526005805461ffff60a81b191661010160a81b17905534801561002557600080fd5b506141eb806100356000396000f3fe608060405234801561001057600080fd5b50600436106102d45760003560e01c8062c99685146102d957806301492a0b1461031a5780630374fc6f1461033e5780630621b4f61461035f57806307da68f51461037257806313af40351461037c578063144a27521461038f578063158ef93e146103a257806319fb4abf146103b657806321d10c69146103c9578063232cae0b146103f15780632f90a6fc146103fa57806340e58ee51461040e5780634579268a14610421578063467f0b7b146104e057806346955585146104f35780634a57e53214610506578063511fa48714610519578063557ed1ba1461054257806356ad8764146105595780635bdf5bb214610562578063604b6a9c1461057557806361f54a79146105885780636611f528146105a8578063677170e1146105c257806368b8f2ed146105ed5780636b9d8c4b146106005780636d0cee75146106135780636f7c1820146106265780637203bb511461062e57806374c1d7d31461064157806375f12b211461066c578063774e4617146106805780637ca9429a146106a35780638185402b146106dc57806382afd23b146106ef5780638755a47414610702578063899111b7146107155780638a72ea6a1461071e5780638af82a2e146107ce5780638da5cb5b146107d6578063911550f4146107e957806391be90c814610809578063943911bc14610829578063a78d43161461083c578063b0e21e8a14610626578063b8bd3dbb1461085c578063bf7c734e1461086f578063c2b6b58c14610882578063c2d526aa14610889578063c41a360a146108d3578063c4d66de8146108e6578063d2b420ce146108f9578063d3ef94941461090c578063d6febde81461091f578063e1a6f01414610932578063e4af54cb14610945578063f09ea2a614610958578063f46901ed1461096b578063f582d2931461097e578063fc741c7c14610992578063fdac85b21461099a578063ff1fd974146109ad575b600080fd5b6102fc6102e7366004613755565b600f6020526000908152604090205460e01b81565b6040516001600160e01b031990911681526020015b60405180910390f35b60055461032e90600160b01b900460ff1681565b6040519015158152602001610311565b61035161034c366004613772565b6109c0565b604051908152602001610311565b61035161036d3660046137ab565b6109ed565b61037a610bda565b005b61037a61038a366004613755565b610c14565b61035161039d3660046137f3565b610c6f565b60055461032e90600160b81b900460ff1681565b61037a6103c436600461387f565b610d4c565b6103dc6103d73660046137f3565b610d90565b60408051928352602083019190915201610311565b61035160015481565b60055461032e90600160c01b900460ff1681565b61032e61041c3660046138c0565b610db9565b6104b561042f3660046138c0565b600090815260026020818152604092839020835160e081018552815480825260018301546001600160a01b0390811694830185905294830154958201869052600383015485166060830181905260048401548087166080850152600160a01b90046001600160401b031660a084015260059093015490941660c090910152919390929190565b604080519485526001600160a01b039384166020860152840191909152166060820152608001610311565b61032e6104ee3660046138c0565b610f12565b6103516105013660046138e7565b610fda565b61035161051436600461390c565b6110bd565b610351610527366004613755565b6001600160a01b03166000908152600a602052604090205490565b6040516001600160401b0342168152602001610311565b610351600d5481565b61037a610570366004613987565b6110dc565b61032e6105833660046138c0565b6111bd565b6103516105963660046138c0565b6000908152600b602052604090205490565b6005546001600160a01b03165b6040516103119190613a4a565b6103516105d0366004613772565b600960209081526000928352604080842090915290825290205481565b6103516105fb366004613a5e565b6111ed565b6006546105b5906001600160a01b031681565b6105b56106213660046138c0565b6112c6565b600454610351565b61037a61063c366004613aec565b6112e4565b61035161064f366004613772565b600860209081526000928352604080842090915290825290205481565b60055461032e90600160a01b900460ff1681565b61032e61068e366004613755565b600e6020526000908152604090205460ff1681565b6103516106b1366004613772565b6001600160a01b03918216600090815260096020908152604080832093909416825291909152205490565b6103516106ea3660046137ab565b611352565b61032e6106fd3660046138c0565b611518565b61037a610710366004613b44565b61153f565b610351600c5481565b61078661072c3660046138c0565b600260208190526000918252604090912080546001820154928201546003830154600484015460059094015492946001600160a01b039081169492939181169281811692600160a01b9091046001600160401b0316911687565b604080519788526001600160a01b0396871660208901528701949094529184166060860152831660808501526001600160401b031660a08401521660c082015260e001610311565b600c54610351565b6000546105b5906001600160a01b031681565b6103516107f73660046138c0565b60009081526007602052604090205490565b610351610817366004613755565b600a6020526000908152604090205481565b6103516108373660046138c0565b6115d5565b61035161084a3660046138c0565b600b6020526000908152604090205481565b61032e61086a3660046138c0565b6115ea565b61032e61087d366004613c34565b611627565b600061032e565b6108b86108973660046138c0565b60076020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610311565b6105b56108e13660046138c0565b6116e6565b61037a6108f4366004613755565b611704565b61032e6109073660046138c0565b6117ce565b6103dc61091a3660046137f3565b61183e565b61032e61092d366004613c60565b611868565b610351610940366004613c82565b6118d1565b61037a6109533660046138c0565b6118ee565b610351610966366004613ce9565b611a96565b61032e610979366004613755565b611ab5565b60055461032e90600160a81b900460ff1681565b610351611b14565b6103516109a8366004613d33565b611b27565b6103516109bb3660046137f3565b611b3b565b6001600160a01b038083166000908152600860209081526040808320938516835292905220545b92915050565b60035460009060ff1615610a0057600080fd5b60005b8415610b8257610a1384876109c0565b905080600003610a565760405162461bcd60e51b81526020600482015260096024820152680c081bd999995c925960ba1b60448201526064015b60405180910390fd5b6000818152600260208190526040909120908101549054610a779190611bdd565b610a8986670de0b6b3a7640000611c0a565b10610b8257600081815260026020819052604090912001548510610b0f57600081815260026020526040902054610ac1908390611c71565b9150610ae3856002600084815260200190815260200160002060020154611cc6565b600082815260026020526040902054909550610b099082906001600160801b0316611868565b50610a03565b6000633b9aca00610b4c610b2788633b9aca00611c0a565b60008581526002602081905260409091208054910154610b479190611d1c565b611d37565b610b569190613dab565b9050610b628382611c71565b9250610b7782826001600160801b0316611868565b506000955050610a03565b82821015610bd15760405162461bcd60e51b815260206004820152601c60248201527b1b5a5b97d99a5b1b17d85b5bdd5b9d081a5cdb89dd08199a5b1b195960221b6044820152606401610a4d565b50949350505050565b610be333611d68565b610bff5760405162461bcd60e51b8152600401610a4d90613dcd565b6005805460ff60a01b1916600160a01b179055565b610c1d33611d68565b610c395760405162461bcd60e51b8152600401610a4d90613dcd565b600080546001600160a01b0319166001600160a01b0383169081178255604051909160008051602061419683398151915291a250565b600080610c7c85856109c0565b90505b60008181526002602081905260409091200154831115610cfa57600081815260026020526040902054610cb3908390611c71565b9150610cd5836002600084815260200190815260200160002060020154611cc6565b92508215610cf557610ce6816115d5565b905080600003610cf557600080fd5b610c7f565b610d4382633b9aca00610d34610d1487633b9aca00611c0a565b60008681526002602081905260409091208054910154610b479190611d1c565b610d3e9190613dab565b611c71565b95945050505050565b60005b81811015610d8b57610d78838383818110610d6c57610d6c613dfb565b90506020020135610db9565b5080610d8381613e11565b915050610d4f565b505050565b6000806000610da0846000610fda565b9050610dad868683610c6f565b96939550929350505050565b600081610dc581611518565b610de15760405162461bcd60e51b8152600401610a4d90613e2a565b610dea816116e6565b6001600160a01b0316336001600160a01b03161480610e0a5750600d5481145b80610e4a5750610e19816112c6565b6001600160a01b0316336001600160a01b0316148015610e4a57506000610e3f826116e6565b6001600160a01b0316145b610e665760405162461bcd60e51b8152600401610a4d90613e77565b60035460ff1615610e895760405162461bcd60e51b8152600401610a4d90613f17565b600554600160b01b900460ff1615610f0257610ea4836117ce565b15610ec057610eb283611d8f565b610ebb57600080fd5b610f02565b610ec983611f57565b610f025760405162461bcd60e51b815260206004820152600a60248201526963616e2774206869646560b01b6044820152606401610a4d565b610f0b8361202f565b9392505050565b60035460009060ff1615610f2557600080fd5b610f2e82611518565b158015610f4b575060008281526007602052604090206002015415155b8015610f715750610f5d600a43613f43565b600083815260076020526040902060020154105b610f7a57600080fd5b6000828152600760205260408082208281556001810183905560020191909155517fcb9d6176c6aac6478ebb9a2754cdce22a944de29ed1f2642f8613884eba4b40c90610fca9033908590613f56565b60405180910390a1506001919050565b600080610fe5611b14565b9050839150821561104657620186a061100085600454611c0a565b61100a9190613dab565b6110149083613f6f565b9150801561104157620186a061102a8583611c0a565b6110349190613dab565b61103e9083613f6f565b91505b6110b6565b600454670de0b6b3a76400009061106083620186a0613f6f565b61106a9190613f6f565b85600454846110799190613f6f565b6110839190613f82565b61109590670de0b6b3a7640000613f82565b61109f9190613dab565b6110a99190613dab565b6110b39083613f43565b91505b5092915050565b60006110d08888888888600189896111ed565b98975050505050505050565b86851480156110ea57508683145b80156110f557508681145b6111115760405162461bcd60e51b8152600401610a4d90613f99565b60005b878110156111b25761119f89898381811061113157611131613dfb565b9050602002013588888481811061114a5761114a613dfb565b905060200201602081019061115f9190613755565b87878581811061117157611171613dfb565b9050602002013586868681811061118a5761118a613dfb565b90506020020160208101906109669190613755565b50806111aa81613e11565b915050611114565b505050505050505050565b60006111c833611d68565b6111e45760405162461bcd60e51b8152600401610a4d90613dcd565b50600455600190565b600060035460ff16156112125760405162461bcd60e51b8152600401610a4d90613f17565b6001600160a01b0388166000908152600a602052604090205489101561123757600080fd5b6001600160a01b0386166000908152600e602052604090205460ff16156112a957611263868484612410565b156112a95760405162461bcd60e51b815260206004820152601660248201527537b33332b91d10212620a1a5a624a9aa1022a92927a960511b6044820152606401610a4d565b6112b98989898989898989612448565b9998505050505050505050565b6000908152600260205260409020600401546001600160a01b031690565b6112ed33611d68565b6113095760405162461bcd60e51b8152600401610a4d90613dcd565b6001600160a01b03929092166000908152600e60209081526040808320805460ff191694151594909417909355600f905220805463ffffffff191660e09290921c919091179055565b60035460009060ff161561136557600080fd5b60005b84156114c85761137886856109c0565b9050806000036113b95760405162461bcd60e51b815260206004820152600c60248201526b06f666665724964203d3d20360a41b6044820152606401610a4d565b600081815260026020819052604090912080549101546113d99190611bdd565b6113eb86670de0b6b3a7640000611c0a565b106114c857600081815260026020526040902054851061146e57611425826002600084815260200190815260200160002060020154611c71565b600082815260026020526040902054909250611442908690611cc6565b6000828152600260205260409020549095506114689082906001600160801b0316611868565b50611368565b6114a982633b9aca00610d3461148889633b9aca00611c0a565b6000868152600260208190526040909120908101549054610b479190611d1c565b91506114be81866001600160801b0316611868565b5060009450611368565b82821115610bd15760405162461bcd60e51b815260206004820181905260248201527f66696c6c5f616d742065786365656473206d61785f66696c6c5f616d6f756e746044820152606401610a4d565b600090815260026020526040902060040154600160a01b90046001600160401b0316151590565b868514801561154d57508689145b801561155857508683145b801561156357508681145b61157f5760405162461bcd60e51b8152600401610a4d90613f99565b60005b898110156115c85761159f8b8b83818110610d6c57610d6c613dfb565b506115b589898381811061113157611131613dfb565b50806115c081613e11565b915050611582565b5050505050505050505050565b60009081526007602052604090206001015490565b60006115f533611d68565b6116115760405162461bcd60e51b8152600401610a4d90613dcd565b5060008051602061417683398151915255600190565b600061163233611d68565b61164e5760405162461bcd60e51b8152600401610a4d90613dcd565b60405160043590602435903490829084903390600080356001600160e01b0319169161167d9187913690613fcd565b60405180910390a46001600160a01b0386166000908152600a602052604090819020869055517fc28d56449b0bb31e64ee7487e061f57a2e72aea8019d810832f26dda099823d0906116d29088908890613f56565b60405180910390a150600195945050505050565b6000908152600260205260409020600501546001600160a01b031690565b600554600160b81b900460ff161561175e5760405162461bcd60e51b815260206004820152601f60248201527f636f6e747261637420697320616c726561647920696e697469616c697a6564006044820152606401610a4d565b6001600160a01b03811661177157600080fd5b600580546001600160a01b03199081166001600160a01b0384161790915560008054339216821781556040516000805160206141968339815191529190a25060016004556005805462ffffff60a81b19166201010160a81b179055565b6000818152600760205260408120541515806117fa575060008281526007602052604090206001015415155b806109e7575050600081815260026020908152604080832060018101546001600160a01b039081168552600884528285206003909201541684529091529020541490565b60008061184c858585611b3b565b9150600061185b836001610fda565b9296929550919350505050565b60008261187481611518565b61187d57600080fd5b60035460ff16156118a05760405162461bcd60e51b8152600401610a4d90613f17565b60055461373390600160b01b900460ff166118bd576126286118c1565b612c435b9050610d4385858363ffffffff16565b60006118e387878787878733336111ed565b979650505050505050565b6118f733611d68565b6119135760405162461bcd60e51b8152600401610a4d90613dcd565b60035460ff161561192357600080fd5b60038054600160ff19909116811782556000838152600260208181526040808420815160e08101835281548152958101546001600160a01b0390811693870193909352928301549085015293810154841660608401819052600482015480861660808601819052600160a01b9091046001600160401b031660a086015260059092015490941660c08401819052929391926119be9291612410565b905080611a205760405162461bcd60e51b815260206004820152602a60248201527f6e656974686572206f776e6572206e6f7220726563697069656e7420697320626044820152691b1858dadb1a5cdd195960b21b6064820152608401610a4d565b611a2983611d8f565b611a3257600080fd5b5050600090815260026020819052604082208281556001810180546001600160a01b03199081169091559181019290925560038083018054831690556004830180546001600160e01b0319169055600590920180549091169055805460ff19169055565b6000611aaa858585856000600133336111ed565b90505b949350505050565b6000611ac033611d68565b611adc5760405162461bcd60e51b8152600401610a4d90613dcd565b6001600160a01b038216611aef57600080fd5b50600580546001600160a01b0383166001600160a01b03199091161790556001919050565b6000805160206141768339815191525490565b60006118e3878787876000600189896111ed565b600080611b4884866109c0565b90505b600081815260026020526040902054831115611bc357611b81826002600084815260200190815260200160002060020154611c71565b600082815260026020526040902054909250611b9e908490611cc6565b92508215611bbe57611baf816115d5565b905080600003611bbe57600080fd5b611b4b565b610d4382633b9aca00610d3461148887633b9aca00611c0a565b600081611c00611bf585670de0b6b3a7640000611c0a565b610d3e600286613dab565b610f0b9190613dab565b6000811580611c2e57508282611c208183613f82565b9250611c2c9083613dab565b145b6109e75760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b6044820152606401610a4d565b600082611c7e8382613f6f565b91508110156109e75760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b6044820152606401610a4d565b600082611cd38382613f43565b91508111156109e75760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b6044820152606401610a4d565b600081611c00611bf585676765c793fa10079d601b1b611c0a565b6000676765c793fa10079d601b1b611c00611d528585611c0a565b610d3e6002676765c793fa10079d601b1b613dab565b600080546001600160a01b0390811690831603611d8757506001919050565b506000919050565b600081815260026020908152604080832060038101546001909101546001600160a01b039081168086526009855283862091909216808652935290832054611dd657600080fd5b600084815260076020526040902060020154158015611df95750611df9846117ce565b611e0257600080fd5b6001600160a01b038082166000908152600860209081526040808320938616835292905220548414611e75576000848152600760205260408082205482529020600101548414611e5157600080fd5b60008481526007602052604080822060018082015491548452919092200155611eab565b6000848152600760209081526040808320600101546001600160a01b038086168552600884528285209087168552909252909120555b60008481526007602052604090206001015415611f02576000848152600760205260408082206001015482529020548414611ee557600080fd5b600084815260076020526040808220805460019091015483529120555b6001600160a01b0380821660009081526009602090815260408083209386168352929052908120805491611f3583614003565b9091555050506000928352505060076020526040902043600290910155600190565b600c5460009080611f67846117ce565b15611fa35760405162461bcd60e51b815260206004820152600c60248201526b1bd999995c881cdbdc9d195960a21b6044820152606401610a4d565b83600c5403611fc8575050506000908152600b602052604081208054600c5555600190565b5b600082118015611fd95750838214155b15611ff457506000818152600b602052604090205490611fc9565b838214612005575060009392505050565b6000848152600b602052604080822080549383529082209290925593845292909255506001919050565b60008161203b81611518565b6120575760405162461bcd60e51b8152600401610a4d90613e2a565b612060816116e6565b6001600160a01b0316336001600160a01b031614806120805750600d5481145b806120c0575061208f816112c6565b6001600160a01b0316336001600160a01b03161480156120c0575060006120b5826116e6565b6001600160a01b0316145b6120dc5760405162461bcd60e51b8152600401610a4d90613e77565b60035460ff16156120ec57600080fd5b6001600360006101000a81548160ff0219169083151502179055506000600260008581526020019081526020016000206040518060e0016040529081600082015481526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016005820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815250509050600260008581526020019081526020016000206000808201600090556001820160006101000a8154906001600160a01b03021916905560028201600090556003820160006101000a8154906001600160a01b0302191690556004820160006101000a8154906001600160a01b0302191690556004820160146101000a8154906001600160401b0302191690556005820160006101000a8154906001600160a01b030219169055505060006001600160a01b03168160c001516001600160a01b0316146123145760c08101518151602083015161230f926001600160a01b0390911691612d0d565b612335565b608081015181516020830151612335926001600160a01b0390911691612d0d565b6040518481526000805160206141568339815191529060200160405180910390a160c08101516001600160a01b0316612372578060800151612378565b8060c001515b6001600160a01b03168160200151826060015160405160200161239c92919061401a565b60408051601f19818403018152828252805160209182012090850151606086015186519387015192948a947f0cc6820f2e5726c213068df19a715ab85e147b123f63b90f81802a37e431f548946123f494939261403c565b60405180910390a450506003805460ff19169055506001919050565b6001600160a01b0383166000908152600f602052604081205460e01b612437858583612d63565b80610d435750610d43858483612d63565b60008060008060005b6000600860008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000205411156125c55750506001600160a01b038089166000908152600860209081526040808320938e168352928152828220548083526002918290529290912090810154905491935090876124ef57600061250f565b808d6124fb8d85613f6f565b6125059190613f6f565b61250f9190613f6f565b6125198e83611c0a565b6125239190613f6f565b61252d838d611c0a565b116125c5576125408461092d838e612e2d565b507f3156f1facedd2c8392e4de7babf62e19484c1ac8f306f3a857c46a1bf39013b98561256d838e612e2d565b6040805192835260208301919091520160405180910390a18a925061259b8b612596838e612e2d565b611cc6565b9a50826125a88c8f611c0a565b6125b29190613dab565b9c508c15806125bf57508a155b15612451575b60008b1180156125d5575060008d115b80156125f957506001600160a01b038c166000908152600a60205260409020548d10155b156126185761260c8d8d8d8d8b8b612e44565b9450612618858a613136565b5050505098975050505050505050565b60008261263481611518565b61263d57600080fd5b60035460ff161561264d57600080fd5b6003805460ff1916600190811782556000868152600260208181526040808420815160e0810183528154808252968201546001600160a01b0390811694820194909452938101549184018290529586015482166060840152600486015480831660808501526001600160401b03600160a01b9091041660a08401526005909501541660c0820152929091906126e3908790611c0a565b6126ed9190613dab565b905080816001600160801b03161461273d5760405162461bcd60e51b81526020600482015260136024820152721cdc195b99081a5cc81b9bdd08185b881a5b9d606a1b6044820152606401610a4d565b84856001600160801b03161461278e5760405162461bcd60e51b81526020600482015260166024820152751c5d585b9d1a5d1e481a5cc81b9bdd08185b881a5b9d60521b6044820152606401610a4d565b841580612799575080155b806127a45750815185115b806127b25750816040015181115b156127c257600093505050612c32565b81516127ce9086611cc6565b60008781526002602052604090819020919091558201516127ef9082611cc6565b600087815260026020819052604082200191909155600454620186a090612817908490611c0a565b6128219190613dab565b6005546060850151919250612845916001600160a01b0390811691339116846132e0565b600061284f611b14565b1115612996576000620186a061286c84612867611b14565b611c0a565b6128769190613dab565b60c08501519091506001600160a01b03161580156128a65750600061289a896112c6565b6001600160a01b031614155b156128d8576128d33385608001518387606001516001600160a01b03166132e0909392919063ffffffff16565b612900565b612900338560c001518387606001516001600160a01b03166132e0909392919063ffffffff16565b60c08401516001600160a01b031661291c578360800151612922565b8360c001515b6001600160a01b0316336001600160a01b03168960001b6000805160206141368339815191528760200151886060015160405160200161296392919061401a565b60408051601f1981840301815290829052805160209091012060608a015161298c928890614070565b60405180910390a4505b6129be3384608001518486606001516001600160a01b03166132e0909392919063ffffffff16565b60208301516129d7906001600160a01b03163388612d0d565b6040518781526000805160206141568339815191529060200160405180910390a160c08301516001600160a01b0316612a14578260800151612a1a565b8260c001515b6001600160a01b031683602001518460600151604051602001612a3e92919061401a565b60408051808303601f190181528282528051602091820120878201516060808a01513387526001600160a01b03928316948701949094529216848401526001600160801b038b8116928501929092529086166080840152905190918a917fab26582f2a01a3631091bb7dd3e17b455ec11fe059fd129cac490e377dcf1e0f9181900360a00190a460055460208085015160608601516040516001600160a01b039094169333938c9360008051602061413683398151915293612b0493919290910161401a565b60408051601f198184030181529082905280516020909101206060890151612b2d928890614070565b60405180910390a46000878152600260205260408120549003612c2a57600087815260026020819052604082208281556001810180546001600160a01b031990811690915591810192909255600382018054821690556004820180546001600160e01b031916905560059091018054909116905560c08301516001600160a01b0316612bbd578260800151612bc3565b8260c001515b6001600160a01b031683602001518460600151604051602001612be792919061401a565b60408051601f198184030181529082905280516020909101209089907fc9186487a67a2c1b217828c69dc0a6376172f91ac269cd7545fc060cc09ab34590600090a45b600194505050505b506003805460ff1916905592915050565b600554600090600160a81b900460ff16612c5c57600080fd5b6000838152600260205260409020548203612c9957612c7a836117ce565b15612c8e57612c8883611d8f565b50612c99565b612c9783611f57565b505b612ca38383612628565b612cac57600080fd5b612cb583611518565b8015612cef5750600083815260026020818152604080842060018101546001600160a01b03168552600a8352908420549387905291905254105b15612d0457600d839055612d0283610db9565b505b50600192915050565b610d8b8363a9059cbb60e01b8484604051602401612d2c929190613f56565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261331e565b6000806000856001600160a01b03168486604051602401612d849190613a4a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612dc291906140b3565b600060405180830381855afa9150503d8060008114612dfd576040519150601f19603f3d011682016040523d82523d6000602084013e612e02565b606091505b5091509150818015612e23575080806020019051810190612e2391906140cf565b9695505050505050565b600081831115612e3d5781610f0b565b5090919050565b600060035460ff1615612e5657600080fd5b6003805460ff191660011790556001600160801b0387168714612e7857600080fd5b84856001600160801b031614612e8d57600080fd5b60008711612e9a57600080fd5b6001600160a01b038616612ead57600080fd5b60008511612eba57600080fd5b6001600160a01b038416612ecd57600080fd5b836001600160a01b0316866001600160a01b031603612eeb57600080fd5b6001600160a01b038316612f365760405162461bcd60e51b81526020600482015260126024820152715a65726f206f776e6572206164647265737360701b6044820152606401610a4d565b6001600160a01b038216612f855760405162461bcd60e51b81526020600482015260166024820152755a65726f20726563697069656e74206164647265737360501b6044820152606401610a4d565b6040805160e0810182528881526001600160a01b0388811660208301529181018790528582166060820152838216608082015290841660c0820152426001600160401b031660a0820152612fd76133f0565b60008181526002602081815260409283902085518155908501516001820180546001600160a01b039283166001600160a01b03199182161790915593860151928201929092556060850151600382018054918416918516919091179055608085015160048201805460a08801516001600160401b0316600160a01b026001600160e01b03199091169285169290921791909117905560c085015160059091018054918316919093161790915590925061309490881633308b6132e0565b6040518281526000805160206141568339815191529060200160405180910390a160405133906130ca908990889060200161401a565b604051602081830303815290604052805190602001208360001b7fd90d2b6b91ebf3c941eef50331b4ef8100c8f29c08f67d9d5c73170633eb96638a898d8c604051613119949392919061403c565b60405180910390a4506003805460ff191690559695505050505050565b61313f82611518565b61314857600080fd5b600082815260026020526040812060038101546001909101546001600160a01b039182169291169083158061319a57506000848152600260205260409020600101546001600160a01b03838116911614155b806131c257506000848152600260205260409020600301546001600160a01b03848116911614155b806131d357506131d1846117ce565b155b6131e6576131e1858561340e565b6131ef565b6131ef856134e3565b9350831561321d5750600083815260076020526040808220600101805490879055868352912084905561324a565b506001600160a01b0381811660009081526008602090815260408083209386168352929052208054908590555b801561326e5760008181526007602052604080822087905586825290206001018190555b6001600160a01b03808316600090815260096020908152604080832093871683529290529081208054916132a183613e11565b90915550506040518581527f20fb9bad86c18f7e22e8065258790d9416a7d2df8ff05f80f82c46d38b925acd9060200160405180910390a15050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526133189085906323b872dd60e01b90608401612d2c565b50505050565b6000613373826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135679092919063ffffffff16565b805190915015610d8b578080602001905181019061339191906140cf565b610d8b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a4d565b600180546000918261340183613e11565b9190505550600154905090565b600080831161341c57600080fd5b8115801590613431575061342f82611518565b155b1561344f57600091825260076020526040909120600101549061341c565b8160000361346757613460836134e3565b90506109e7565b6134718383613576565b156134ab5760005b821580159061348d575061348d8484613576565b15613460575060008281526007602052604090206001015491613479565b81158015906134c157506134bf8383613576565b155b156134dc5760009182526007602052604090912054906134ab565b50806109e7565b60008082116134f157600080fd5b600082815260026020908152604080832060038101546001909101546001600160a01b03908116808652600885528386209190921680865293529083205491929091905b811580159061354957506135498683613576565b15610d43575060008181526007602052604090206001015490613535565b6060611aad84846000856135ca565b6000818152600260208190526040808320909101548483529082205461359c9190611c0a565b6000848152600260208190526040808320909101548583529120546135c19190611c0a565b10159392505050565b60608247101561362b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a4d565b600080866001600160a01b0316858760405161364791906140b3565b60006040518083038185875af1925050503d8060008114613684576040519150601f19603f3d011682016040523d82523d6000602084013e613689565b606091505b50915091506118e387838387606083156137045782516000036136fd576001600160a01b0385163b6136fd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a4d565b5081611aad565b611aad83838151156137195781518083602001fd5b8060405162461bcd60e51b8152600401610a4d91906140ec565b61373b61411f565b565b6001600160a01b038116811461375257600080fd5b50565b60006020828403121561376757600080fd5b8135610f0b8161373d565b6000806040838503121561378557600080fd5b82356137908161373d565b915060208301356137a08161373d565b809150509250929050565b600080600080608085870312156137c157600080fd5b84356137cc8161373d565b93506020850135925060408501356137e38161373d565b9396929550929360600135925050565b60008060006060848603121561380857600080fd5b83356138138161373d565b925060208401356138238161373d565b929592945050506040919091013590565b60008083601f84011261384657600080fd5b5081356001600160401b0381111561385d57600080fd5b6020830191508360208260051b850101111561387857600080fd5b9250929050565b6000806020838503121561389257600080fd5b82356001600160401b038111156138a857600080fd5b6138b485828601613834565b90969095509350505050565b6000602082840312156138d257600080fd5b5035919050565b801515811461375257600080fd5b600080604083850312156138fa57600080fd5b8235915060208301356137a0816138d9565b600080600080600080600060e0888a03121561392757600080fd5b8735965060208801356139398161373d565b95506040880135945060608801356139508161373d565b93506080880135925060a08801356139678161373d565b915060c08801356139778161373d565b8091505092959891949750929550565b6000806000806000806000806080898b0312156139a357600080fd5b88356001600160401b03808211156139ba57600080fd5b6139c68c838d01613834565b909a50985060208b01359150808211156139df57600080fd5b6139eb8c838d01613834565b909850965060408b0135915080821115613a0457600080fd5b613a108c838d01613834565b909650945060608b0135915080821115613a2957600080fd5b50613a368b828c01613834565b999c989b5096995094979396929594505050565b6001600160a01b0391909116815260200190565b600080600080600080600080610100898b031215613a7b57600080fd5b883597506020890135613a8d8161373d565b9650604089013595506060890135613aa48161373d565b94506080890135935060a0890135613abb816138d9565b925060c0890135613acb8161373d565b915060e0890135613adb8161373d565b809150509295985092959890939650565b600080600060608486031215613b0157600080fd5b8335613b0c8161373d565b92506020840135613b1c816138d9565b915060408401356001600160e01b031981168114613b3957600080fd5b809150509250925092565b60008060008060008060008060008060a08b8d031215613b6357600080fd5b8a356001600160401b0380821115613b7a57600080fd5b613b868e838f01613834565b909c509a5060208d0135915080821115613b9f57600080fd5b613bab8e838f01613834565b909a50985060408d0135915080821115613bc457600080fd5b613bd08e838f01613834565b909850965060608d0135915080821115613be957600080fd5b613bf58e838f01613834565b909650945060808d0135915080821115613c0e57600080fd5b50613c1b8d828e01613834565b915080935050809150509295989b9194979a5092959850565b60008060408385031215613c4757600080fd5b8235613c528161373d565b946020939093013593505050565b60008060408385031215613c7357600080fd5b50508035926020909101359150565b60008060008060008060c08789031215613c9b57600080fd5b863595506020870135613cad8161373d565b9450604087013593506060870135613cc48161373d565b92506080870135915060a0870135613cdb816138d9565b809150509295509295509295565b60008060008060808587031215613cff57600080fd5b843593506020850135613d118161373d565b9250604085013591506060850135613d288161373d565b939692955090935050565b60008060008060008060c08789031215613d4c57600080fd5b863595506020870135613d5e8161373d565b9450604087013593506060870135613d758161373d565b92506080870135613d858161373d565b915060a0870135613cdb8161373d565b634e487b7160e01b600052601160045260246000fd5b600082613dc857634e487b7160e01b600052601260045260246000fd5b500490565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060018201613e2357613e23613d95565b5060010190565b6020808252602d908201527f4f66666572207761732064656c65746564206f722074616b656e2c206f72206e60408201526c32bb32b91032bc34b9ba32b21760991b606082015260800190565b60208082526074908201527f4f666665722063616e206e6f742062652063616e63656c6c656420626563617560408201527f73652075736572206973206e6f74206f776e65722c20616e64206d61726b657460608201527f206973206f70656e2c20616e64206f666665722073656c6c732072657175697260808201527332b21030b6b7bab73a1037b3103a37b5b2b7399760611b60a082015260c00190565b6020808252601290820152711499595b9d1c985b98de48185d1d195b5c1d60721b604082015260600190565b818103818111156109e7576109e7613d95565b6001600160a01b03929092168252602082015260400190565b808201808211156109e7576109e7613d95565b80820281158282048414176109e7576109e7613d95565b6020808252601a9082015279082e4e4c2f240d8cadccee8d0e640c8de40dcdee840dac2e8c6d60331b604082015260600190565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008161401257614012613d95565b506000190190565b6001600160601b0319606093841b811682529190921b16601482015260280190565b6001600160a01b0394851681529290931660208301526001600160801b039081166040830152909116606082015260800190565b9283526001600160a01b03919091166020830152604082015260600190565b60005b838110156140aa578181015183820152602001614092565b50506000910152565b600082516140c581846020870161408f565b9190910192915050565b6000602082840312156140e157600080fd5b8151610f0b816138d9565b602081526000825180602084015261410b81604085016020870161408f565b601f01601f19169190910160400192915050565b634e487b7160e01b600052605160045260246000fdfe998a3936f157471bfa675789c6ae52cb078e5679f4764a57a587aca731e66206a2c251311b1a7a475913900a2a73dc9789a21b04bc737e050bbc506dd4eb348855a583bf144a5516c8de6ffe85b1859d93234d5e765ed3e895106330766044b8ce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94a2646970667358221220fe957018c046ef928e0cf1182395edf38e78736e008a0832d6f2b6e0180c375764736f6c63430008110033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102d45760003560e01c8062c99685146102d957806301492a0b1461031a5780630374fc6f1461033e5780630621b4f61461035f57806307da68f51461037257806313af40351461037c578063144a27521461038f578063158ef93e146103a257806319fb4abf146103b657806321d10c69146103c9578063232cae0b146103f15780632f90a6fc146103fa57806340e58ee51461040e5780634579268a14610421578063467f0b7b146104e057806346955585146104f35780634a57e53214610506578063511fa48714610519578063557ed1ba1461054257806356ad8764146105595780635bdf5bb214610562578063604b6a9c1461057557806361f54a79146105885780636611f528146105a8578063677170e1146105c257806368b8f2ed146105ed5780636b9d8c4b146106005780636d0cee75146106135780636f7c1820146106265780637203bb511461062e57806374c1d7d31461064157806375f12b211461066c578063774e4617146106805780637ca9429a146106a35780638185402b146106dc57806382afd23b146106ef5780638755a47414610702578063899111b7146107155780638a72ea6a1461071e5780638af82a2e146107ce5780638da5cb5b146107d6578063911550f4146107e957806391be90c814610809578063943911bc14610829578063a78d43161461083c578063b0e21e8a14610626578063b8bd3dbb1461085c578063bf7c734e1461086f578063c2b6b58c14610882578063c2d526aa14610889578063c41a360a146108d3578063c4d66de8146108e6578063d2b420ce146108f9578063d3ef94941461090c578063d6febde81461091f578063e1a6f01414610932578063e4af54cb14610945578063f09ea2a614610958578063f46901ed1461096b578063f582d2931461097e578063fc741c7c14610992578063fdac85b21461099a578063ff1fd974146109ad575b600080fd5b6102fc6102e7366004613755565b600f6020526000908152604090205460e01b81565b6040516001600160e01b031990911681526020015b60405180910390f35b60055461032e90600160b01b900460ff1681565b6040519015158152602001610311565b61035161034c366004613772565b6109c0565b604051908152602001610311565b61035161036d3660046137ab565b6109ed565b61037a610bda565b005b61037a61038a366004613755565b610c14565b61035161039d3660046137f3565b610c6f565b60055461032e90600160b81b900460ff1681565b61037a6103c436600461387f565b610d4c565b6103dc6103d73660046137f3565b610d90565b60408051928352602083019190915201610311565b61035160015481565b60055461032e90600160c01b900460ff1681565b61032e61041c3660046138c0565b610db9565b6104b561042f3660046138c0565b600090815260026020818152604092839020835160e081018552815480825260018301546001600160a01b0390811694830185905294830154958201869052600383015485166060830181905260048401548087166080850152600160a01b90046001600160401b031660a084015260059093015490941660c090910152919390929190565b604080519485526001600160a01b039384166020860152840191909152166060820152608001610311565b61032e6104ee3660046138c0565b610f12565b6103516105013660046138e7565b610fda565b61035161051436600461390c565b6110bd565b610351610527366004613755565b6001600160a01b03166000908152600a602052604090205490565b6040516001600160401b0342168152602001610311565b610351600d5481565b61037a610570366004613987565b6110dc565b61032e6105833660046138c0565b6111bd565b6103516105963660046138c0565b6000908152600b602052604090205490565b6005546001600160a01b03165b6040516103119190613a4a565b6103516105d0366004613772565b600960209081526000928352604080842090915290825290205481565b6103516105fb366004613a5e565b6111ed565b6006546105b5906001600160a01b031681565b6105b56106213660046138c0565b6112c6565b600454610351565b61037a61063c366004613aec565b6112e4565b61035161064f366004613772565b600860209081526000928352604080842090915290825290205481565b60055461032e90600160a01b900460ff1681565b61032e61068e366004613755565b600e6020526000908152604090205460ff1681565b6103516106b1366004613772565b6001600160a01b03918216600090815260096020908152604080832093909416825291909152205490565b6103516106ea3660046137ab565b611352565b61032e6106fd3660046138c0565b611518565b61037a610710366004613b44565b61153f565b610351600c5481565b61078661072c3660046138c0565b600260208190526000918252604090912080546001820154928201546003830154600484015460059094015492946001600160a01b039081169492939181169281811692600160a01b9091046001600160401b0316911687565b604080519788526001600160a01b0396871660208901528701949094529184166060860152831660808501526001600160401b031660a08401521660c082015260e001610311565b600c54610351565b6000546105b5906001600160a01b031681565b6103516107f73660046138c0565b60009081526007602052604090205490565b610351610817366004613755565b600a6020526000908152604090205481565b6103516108373660046138c0565b6115d5565b61035161084a3660046138c0565b600b6020526000908152604090205481565b61032e61086a3660046138c0565b6115ea565b61032e61087d366004613c34565b611627565b600061032e565b6108b86108973660046138c0565b60076020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610311565b6105b56108e13660046138c0565b6116e6565b61037a6108f4366004613755565b611704565b61032e6109073660046138c0565b6117ce565b6103dc61091a3660046137f3565b61183e565b61032e61092d366004613c60565b611868565b610351610940366004613c82565b6118d1565b61037a6109533660046138c0565b6118ee565b610351610966366004613ce9565b611a96565b61032e610979366004613755565b611ab5565b60055461032e90600160a81b900460ff1681565b610351611b14565b6103516109a8366004613d33565b611b27565b6103516109bb3660046137f3565b611b3b565b6001600160a01b038083166000908152600860209081526040808320938516835292905220545b92915050565b60035460009060ff1615610a0057600080fd5b60005b8415610b8257610a1384876109c0565b905080600003610a565760405162461bcd60e51b81526020600482015260096024820152680c081bd999995c925960ba1b60448201526064015b60405180910390fd5b6000818152600260208190526040909120908101549054610a779190611bdd565b610a8986670de0b6b3a7640000611c0a565b10610b8257600081815260026020819052604090912001548510610b0f57600081815260026020526040902054610ac1908390611c71565b9150610ae3856002600084815260200190815260200160002060020154611cc6565b600082815260026020526040902054909550610b099082906001600160801b0316611868565b50610a03565b6000633b9aca00610b4c610b2788633b9aca00611c0a565b60008581526002602081905260409091208054910154610b479190611d1c565b611d37565b610b569190613dab565b9050610b628382611c71565b9250610b7782826001600160801b0316611868565b506000955050610a03565b82821015610bd15760405162461bcd60e51b815260206004820152601c60248201527b1b5a5b97d99a5b1b17d85b5bdd5b9d081a5cdb89dd08199a5b1b195960221b6044820152606401610a4d565b50949350505050565b610be333611d68565b610bff5760405162461bcd60e51b8152600401610a4d90613dcd565b6005805460ff60a01b1916600160a01b179055565b610c1d33611d68565b610c395760405162461bcd60e51b8152600401610a4d90613dcd565b600080546001600160a01b0319166001600160a01b0383169081178255604051909160008051602061419683398151915291a250565b600080610c7c85856109c0565b90505b60008181526002602081905260409091200154831115610cfa57600081815260026020526040902054610cb3908390611c71565b9150610cd5836002600084815260200190815260200160002060020154611cc6565b92508215610cf557610ce6816115d5565b905080600003610cf557600080fd5b610c7f565b610d4382633b9aca00610d34610d1487633b9aca00611c0a565b60008681526002602081905260409091208054910154610b479190611d1c565b610d3e9190613dab565b611c71565b95945050505050565b60005b81811015610d8b57610d78838383818110610d6c57610d6c613dfb565b90506020020135610db9565b5080610d8381613e11565b915050610d4f565b505050565b6000806000610da0846000610fda565b9050610dad868683610c6f565b96939550929350505050565b600081610dc581611518565b610de15760405162461bcd60e51b8152600401610a4d90613e2a565b610dea816116e6565b6001600160a01b0316336001600160a01b03161480610e0a5750600d5481145b80610e4a5750610e19816112c6565b6001600160a01b0316336001600160a01b0316148015610e4a57506000610e3f826116e6565b6001600160a01b0316145b610e665760405162461bcd60e51b8152600401610a4d90613e77565b60035460ff1615610e895760405162461bcd60e51b8152600401610a4d90613f17565b600554600160b01b900460ff1615610f0257610ea4836117ce565b15610ec057610eb283611d8f565b610ebb57600080fd5b610f02565b610ec983611f57565b610f025760405162461bcd60e51b815260206004820152600a60248201526963616e2774206869646560b01b6044820152606401610a4d565b610f0b8361202f565b9392505050565b60035460009060ff1615610f2557600080fd5b610f2e82611518565b158015610f4b575060008281526007602052604090206002015415155b8015610f715750610f5d600a43613f43565b600083815260076020526040902060020154105b610f7a57600080fd5b6000828152600760205260408082208281556001810183905560020191909155517fcb9d6176c6aac6478ebb9a2754cdce22a944de29ed1f2642f8613884eba4b40c90610fca9033908590613f56565b60405180910390a1506001919050565b600080610fe5611b14565b9050839150821561104657620186a061100085600454611c0a565b61100a9190613dab565b6110149083613f6f565b9150801561104157620186a061102a8583611c0a565b6110349190613dab565b61103e9083613f6f565b91505b6110b6565b600454670de0b6b3a76400009061106083620186a0613f6f565b61106a9190613f6f565b85600454846110799190613f6f565b6110839190613f82565b61109590670de0b6b3a7640000613f82565b61109f9190613dab565b6110a99190613dab565b6110b39083613f43565b91505b5092915050565b60006110d08888888888600189896111ed565b98975050505050505050565b86851480156110ea57508683145b80156110f557508681145b6111115760405162461bcd60e51b8152600401610a4d90613f99565b60005b878110156111b25761119f89898381811061113157611131613dfb565b9050602002013588888481811061114a5761114a613dfb565b905060200201602081019061115f9190613755565b87878581811061117157611171613dfb565b9050602002013586868681811061118a5761118a613dfb565b90506020020160208101906109669190613755565b50806111aa81613e11565b915050611114565b505050505050505050565b60006111c833611d68565b6111e45760405162461bcd60e51b8152600401610a4d90613dcd565b50600455600190565b600060035460ff16156112125760405162461bcd60e51b8152600401610a4d90613f17565b6001600160a01b0388166000908152600a602052604090205489101561123757600080fd5b6001600160a01b0386166000908152600e602052604090205460ff16156112a957611263868484612410565b156112a95760405162461bcd60e51b815260206004820152601660248201527537b33332b91d10212620a1a5a624a9aa1022a92927a960511b6044820152606401610a4d565b6112b98989898989898989612448565b9998505050505050505050565b6000908152600260205260409020600401546001600160a01b031690565b6112ed33611d68565b6113095760405162461bcd60e51b8152600401610a4d90613dcd565b6001600160a01b03929092166000908152600e60209081526040808320805460ff191694151594909417909355600f905220805463ffffffff191660e09290921c919091179055565b60035460009060ff161561136557600080fd5b60005b84156114c85761137886856109c0565b9050806000036113b95760405162461bcd60e51b815260206004820152600c60248201526b06f666665724964203d3d20360a41b6044820152606401610a4d565b600081815260026020819052604090912080549101546113d99190611bdd565b6113eb86670de0b6b3a7640000611c0a565b106114c857600081815260026020526040902054851061146e57611425826002600084815260200190815260200160002060020154611c71565b600082815260026020526040902054909250611442908690611cc6565b6000828152600260205260409020549095506114689082906001600160801b0316611868565b50611368565b6114a982633b9aca00610d3461148889633b9aca00611c0a565b6000868152600260208190526040909120908101549054610b479190611d1c565b91506114be81866001600160801b0316611868565b5060009450611368565b82821115610bd15760405162461bcd60e51b815260206004820181905260248201527f66696c6c5f616d742065786365656473206d61785f66696c6c5f616d6f756e746044820152606401610a4d565b600090815260026020526040902060040154600160a01b90046001600160401b0316151590565b868514801561154d57508689145b801561155857508683145b801561156357508681145b61157f5760405162461bcd60e51b8152600401610a4d90613f99565b60005b898110156115c85761159f8b8b83818110610d6c57610d6c613dfb565b506115b589898381811061113157611131613dfb565b50806115c081613e11565b915050611582565b5050505050505050505050565b60009081526007602052604090206001015490565b60006115f533611d68565b6116115760405162461bcd60e51b8152600401610a4d90613dcd565b5060008051602061417683398151915255600190565b600061163233611d68565b61164e5760405162461bcd60e51b8152600401610a4d90613dcd565b60405160043590602435903490829084903390600080356001600160e01b0319169161167d9187913690613fcd565b60405180910390a46001600160a01b0386166000908152600a602052604090819020869055517fc28d56449b0bb31e64ee7487e061f57a2e72aea8019d810832f26dda099823d0906116d29088908890613f56565b60405180910390a150600195945050505050565b6000908152600260205260409020600501546001600160a01b031690565b600554600160b81b900460ff161561175e5760405162461bcd60e51b815260206004820152601f60248201527f636f6e747261637420697320616c726561647920696e697469616c697a6564006044820152606401610a4d565b6001600160a01b03811661177157600080fd5b600580546001600160a01b03199081166001600160a01b0384161790915560008054339216821781556040516000805160206141968339815191529190a25060016004556005805462ffffff60a81b19166201010160a81b179055565b6000818152600760205260408120541515806117fa575060008281526007602052604090206001015415155b806109e7575050600081815260026020908152604080832060018101546001600160a01b039081168552600884528285206003909201541684529091529020541490565b60008061184c858585611b3b565b9150600061185b836001610fda565b9296929550919350505050565b60008261187481611518565b61187d57600080fd5b60035460ff16156118a05760405162461bcd60e51b8152600401610a4d90613f17565b60055461373390600160b01b900460ff166118bd576126286118c1565b612c435b9050610d4385858363ffffffff16565b60006118e387878787878733336111ed565b979650505050505050565b6118f733611d68565b6119135760405162461bcd60e51b8152600401610a4d90613dcd565b60035460ff161561192357600080fd5b60038054600160ff19909116811782556000838152600260208181526040808420815160e08101835281548152958101546001600160a01b0390811693870193909352928301549085015293810154841660608401819052600482015480861660808601819052600160a01b9091046001600160401b031660a086015260059092015490941660c08401819052929391926119be9291612410565b905080611a205760405162461bcd60e51b815260206004820152602a60248201527f6e656974686572206f776e6572206e6f7220726563697069656e7420697320626044820152691b1858dadb1a5cdd195960b21b6064820152608401610a4d565b611a2983611d8f565b611a3257600080fd5b5050600090815260026020819052604082208281556001810180546001600160a01b03199081169091559181019290925560038083018054831690556004830180546001600160e01b0319169055600590920180549091169055805460ff19169055565b6000611aaa858585856000600133336111ed565b90505b949350505050565b6000611ac033611d68565b611adc5760405162461bcd60e51b8152600401610a4d90613dcd565b6001600160a01b038216611aef57600080fd5b50600580546001600160a01b0383166001600160a01b03199091161790556001919050565b6000805160206141768339815191525490565b60006118e3878787876000600189896111ed565b600080611b4884866109c0565b90505b600081815260026020526040902054831115611bc357611b81826002600084815260200190815260200160002060020154611c71565b600082815260026020526040902054909250611b9e908490611cc6565b92508215611bbe57611baf816115d5565b905080600003611bbe57600080fd5b611b4b565b610d4382633b9aca00610d3461148887633b9aca00611c0a565b600081611c00611bf585670de0b6b3a7640000611c0a565b610d3e600286613dab565b610f0b9190613dab565b6000811580611c2e57508282611c208183613f82565b9250611c2c9083613dab565b145b6109e75760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b6044820152606401610a4d565b600082611c7e8382613f6f565b91508110156109e75760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b6044820152606401610a4d565b600082611cd38382613f43565b91508111156109e75760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b6044820152606401610a4d565b600081611c00611bf585676765c793fa10079d601b1b611c0a565b6000676765c793fa10079d601b1b611c00611d528585611c0a565b610d3e6002676765c793fa10079d601b1b613dab565b600080546001600160a01b0390811690831603611d8757506001919050565b506000919050565b600081815260026020908152604080832060038101546001909101546001600160a01b039081168086526009855283862091909216808652935290832054611dd657600080fd5b600084815260076020526040902060020154158015611df95750611df9846117ce565b611e0257600080fd5b6001600160a01b038082166000908152600860209081526040808320938616835292905220548414611e75576000848152600760205260408082205482529020600101548414611e5157600080fd5b60008481526007602052604080822060018082015491548452919092200155611eab565b6000848152600760209081526040808320600101546001600160a01b038086168552600884528285209087168552909252909120555b60008481526007602052604090206001015415611f02576000848152600760205260408082206001015482529020548414611ee557600080fd5b600084815260076020526040808220805460019091015483529120555b6001600160a01b0380821660009081526009602090815260408083209386168352929052908120805491611f3583614003565b9091555050506000928352505060076020526040902043600290910155600190565b600c5460009080611f67846117ce565b15611fa35760405162461bcd60e51b815260206004820152600c60248201526b1bd999995c881cdbdc9d195960a21b6044820152606401610a4d565b83600c5403611fc8575050506000908152600b602052604081208054600c5555600190565b5b600082118015611fd95750838214155b15611ff457506000818152600b602052604090205490611fc9565b838214612005575060009392505050565b6000848152600b602052604080822080549383529082209290925593845292909255506001919050565b60008161203b81611518565b6120575760405162461bcd60e51b8152600401610a4d90613e2a565b612060816116e6565b6001600160a01b0316336001600160a01b031614806120805750600d5481145b806120c0575061208f816112c6565b6001600160a01b0316336001600160a01b03161480156120c0575060006120b5826116e6565b6001600160a01b0316145b6120dc5760405162461bcd60e51b8152600401610a4d90613e77565b60035460ff16156120ec57600080fd5b6001600360006101000a81548160ff0219169083151502179055506000600260008581526020019081526020016000206040518060e0016040529081600082015481526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016004820160149054906101000a90046001600160401b03166001600160401b03166001600160401b031681526020016005820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815250509050600260008581526020019081526020016000206000808201600090556001820160006101000a8154906001600160a01b03021916905560028201600090556003820160006101000a8154906001600160a01b0302191690556004820160006101000a8154906001600160a01b0302191690556004820160146101000a8154906001600160401b0302191690556005820160006101000a8154906001600160a01b030219169055505060006001600160a01b03168160c001516001600160a01b0316146123145760c08101518151602083015161230f926001600160a01b0390911691612d0d565b612335565b608081015181516020830151612335926001600160a01b0390911691612d0d565b6040518481526000805160206141568339815191529060200160405180910390a160c08101516001600160a01b0316612372578060800151612378565b8060c001515b6001600160a01b03168160200151826060015160405160200161239c92919061401a565b60408051601f19818403018152828252805160209182012090850151606086015186519387015192948a947f0cc6820f2e5726c213068df19a715ab85e147b123f63b90f81802a37e431f548946123f494939261403c565b60405180910390a450506003805460ff19169055506001919050565b6001600160a01b0383166000908152600f602052604081205460e01b612437858583612d63565b80610d435750610d43858483612d63565b60008060008060005b6000600860008c6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000205411156125c55750506001600160a01b038089166000908152600860209081526040808320938e168352928152828220548083526002918290529290912090810154905491935090876124ef57600061250f565b808d6124fb8d85613f6f565b6125059190613f6f565b61250f9190613f6f565b6125198e83611c0a565b6125239190613f6f565b61252d838d611c0a565b116125c5576125408461092d838e612e2d565b507f3156f1facedd2c8392e4de7babf62e19484c1ac8f306f3a857c46a1bf39013b98561256d838e612e2d565b6040805192835260208301919091520160405180910390a18a925061259b8b612596838e612e2d565b611cc6565b9a50826125a88c8f611c0a565b6125b29190613dab565b9c508c15806125bf57508a155b15612451575b60008b1180156125d5575060008d115b80156125f957506001600160a01b038c166000908152600a60205260409020548d10155b156126185761260c8d8d8d8d8b8b612e44565b9450612618858a613136565b5050505098975050505050505050565b60008261263481611518565b61263d57600080fd5b60035460ff161561264d57600080fd5b6003805460ff1916600190811782556000868152600260208181526040808420815160e0810183528154808252968201546001600160a01b0390811694820194909452938101549184018290529586015482166060840152600486015480831660808501526001600160401b03600160a01b9091041660a08401526005909501541660c0820152929091906126e3908790611c0a565b6126ed9190613dab565b905080816001600160801b03161461273d5760405162461bcd60e51b81526020600482015260136024820152721cdc195b99081a5cc81b9bdd08185b881a5b9d606a1b6044820152606401610a4d565b84856001600160801b03161461278e5760405162461bcd60e51b81526020600482015260166024820152751c5d585b9d1a5d1e481a5cc81b9bdd08185b881a5b9d60521b6044820152606401610a4d565b841580612799575080155b806127a45750815185115b806127b25750816040015181115b156127c257600093505050612c32565b81516127ce9086611cc6565b60008781526002602052604090819020919091558201516127ef9082611cc6565b600087815260026020819052604082200191909155600454620186a090612817908490611c0a565b6128219190613dab565b6005546060850151919250612845916001600160a01b0390811691339116846132e0565b600061284f611b14565b1115612996576000620186a061286c84612867611b14565b611c0a565b6128769190613dab565b60c08501519091506001600160a01b03161580156128a65750600061289a896112c6565b6001600160a01b031614155b156128d8576128d33385608001518387606001516001600160a01b03166132e0909392919063ffffffff16565b612900565b612900338560c001518387606001516001600160a01b03166132e0909392919063ffffffff16565b60c08401516001600160a01b031661291c578360800151612922565b8360c001515b6001600160a01b0316336001600160a01b03168960001b6000805160206141368339815191528760200151886060015160405160200161296392919061401a565b60408051601f1981840301815290829052805160209091012060608a015161298c928890614070565b60405180910390a4505b6129be3384608001518486606001516001600160a01b03166132e0909392919063ffffffff16565b60208301516129d7906001600160a01b03163388612d0d565b6040518781526000805160206141568339815191529060200160405180910390a160c08301516001600160a01b0316612a14578260800151612a1a565b8260c001515b6001600160a01b031683602001518460600151604051602001612a3e92919061401a565b60408051808303601f190181528282528051602091820120878201516060808a01513387526001600160a01b03928316948701949094529216848401526001600160801b038b8116928501929092529086166080840152905190918a917fab26582f2a01a3631091bb7dd3e17b455ec11fe059fd129cac490e377dcf1e0f9181900360a00190a460055460208085015160608601516040516001600160a01b039094169333938c9360008051602061413683398151915293612b0493919290910161401a565b60408051601f198184030181529082905280516020909101206060890151612b2d928890614070565b60405180910390a46000878152600260205260408120549003612c2a57600087815260026020819052604082208281556001810180546001600160a01b031990811690915591810192909255600382018054821690556004820180546001600160e01b031916905560059091018054909116905560c08301516001600160a01b0316612bbd578260800151612bc3565b8260c001515b6001600160a01b031683602001518460600151604051602001612be792919061401a565b60408051601f198184030181529082905280516020909101209089907fc9186487a67a2c1b217828c69dc0a6376172f91ac269cd7545fc060cc09ab34590600090a45b600194505050505b506003805460ff1916905592915050565b600554600090600160a81b900460ff16612c5c57600080fd5b6000838152600260205260409020548203612c9957612c7a836117ce565b15612c8e57612c8883611d8f565b50612c99565b612c9783611f57565b505b612ca38383612628565b612cac57600080fd5b612cb583611518565b8015612cef5750600083815260026020818152604080842060018101546001600160a01b03168552600a8352908420549387905291905254105b15612d0457600d839055612d0283610db9565b505b50600192915050565b610d8b8363a9059cbb60e01b8484604051602401612d2c929190613f56565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261331e565b6000806000856001600160a01b03168486604051602401612d849190613a4a565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612dc291906140b3565b600060405180830381855afa9150503d8060008114612dfd576040519150601f19603f3d011682016040523d82523d6000602084013e612e02565b606091505b5091509150818015612e23575080806020019051810190612e2391906140cf565b9695505050505050565b600081831115612e3d5781610f0b565b5090919050565b600060035460ff1615612e5657600080fd5b6003805460ff191660011790556001600160801b0387168714612e7857600080fd5b84856001600160801b031614612e8d57600080fd5b60008711612e9a57600080fd5b6001600160a01b038616612ead57600080fd5b60008511612eba57600080fd5b6001600160a01b038416612ecd57600080fd5b836001600160a01b0316866001600160a01b031603612eeb57600080fd5b6001600160a01b038316612f365760405162461bcd60e51b81526020600482015260126024820152715a65726f206f776e6572206164647265737360701b6044820152606401610a4d565b6001600160a01b038216612f855760405162461bcd60e51b81526020600482015260166024820152755a65726f20726563697069656e74206164647265737360501b6044820152606401610a4d565b6040805160e0810182528881526001600160a01b0388811660208301529181018790528582166060820152838216608082015290841660c0820152426001600160401b031660a0820152612fd76133f0565b60008181526002602081815260409283902085518155908501516001820180546001600160a01b039283166001600160a01b03199182161790915593860151928201929092556060850151600382018054918416918516919091179055608085015160048201805460a08801516001600160401b0316600160a01b026001600160e01b03199091169285169290921791909117905560c085015160059091018054918316919093161790915590925061309490881633308b6132e0565b6040518281526000805160206141568339815191529060200160405180910390a160405133906130ca908990889060200161401a565b604051602081830303815290604052805190602001208360001b7fd90d2b6b91ebf3c941eef50331b4ef8100c8f29c08f67d9d5c73170633eb96638a898d8c604051613119949392919061403c565b60405180910390a4506003805460ff191690559695505050505050565b61313f82611518565b61314857600080fd5b600082815260026020526040812060038101546001909101546001600160a01b039182169291169083158061319a57506000848152600260205260409020600101546001600160a01b03838116911614155b806131c257506000848152600260205260409020600301546001600160a01b03848116911614155b806131d357506131d1846117ce565b155b6131e6576131e1858561340e565b6131ef565b6131ef856134e3565b9350831561321d5750600083815260076020526040808220600101805490879055868352912084905561324a565b506001600160a01b0381811660009081526008602090815260408083209386168352929052208054908590555b801561326e5760008181526007602052604080822087905586825290206001018190555b6001600160a01b03808316600090815260096020908152604080832093871683529290529081208054916132a183613e11565b90915550506040518581527f20fb9bad86c18f7e22e8065258790d9416a7d2df8ff05f80f82c46d38b925acd9060200160405180910390a15050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526133189085906323b872dd60e01b90608401612d2c565b50505050565b6000613373826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135679092919063ffffffff16565b805190915015610d8b578080602001905181019061339191906140cf565b610d8b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a4d565b600180546000918261340183613e11565b9190505550600154905090565b600080831161341c57600080fd5b8115801590613431575061342f82611518565b155b1561344f57600091825260076020526040909120600101549061341c565b8160000361346757613460836134e3565b90506109e7565b6134718383613576565b156134ab5760005b821580159061348d575061348d8484613576565b15613460575060008281526007602052604090206001015491613479565b81158015906134c157506134bf8383613576565b155b156134dc5760009182526007602052604090912054906134ab565b50806109e7565b60008082116134f157600080fd5b600082815260026020908152604080832060038101546001909101546001600160a01b03908116808652600885528386209190921680865293529083205491929091905b811580159061354957506135498683613576565b15610d43575060008181526007602052604090206001015490613535565b6060611aad84846000856135ca565b6000818152600260208190526040808320909101548483529082205461359c9190611c0a565b6000848152600260208190526040808320909101548583529120546135c19190611c0a565b10159392505050565b60608247101561362b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610a4d565b600080866001600160a01b0316858760405161364791906140b3565b60006040518083038185875af1925050503d8060008114613684576040519150601f19603f3d011682016040523d82523d6000602084013e613689565b606091505b50915091506118e387838387606083156137045782516000036136fd576001600160a01b0385163b6136fd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a4d565b5081611aad565b611aad83838151156137195781518083602001fd5b8060405162461bcd60e51b8152600401610a4d91906140ec565b61373b61411f565b565b6001600160a01b038116811461375257600080fd5b50565b60006020828403121561376757600080fd5b8135610f0b8161373d565b6000806040838503121561378557600080fd5b82356137908161373d565b915060208301356137a08161373d565b809150509250929050565b600080600080608085870312156137c157600080fd5b84356137cc8161373d565b93506020850135925060408501356137e38161373d565b9396929550929360600135925050565b60008060006060848603121561380857600080fd5b83356138138161373d565b925060208401356138238161373d565b929592945050506040919091013590565b60008083601f84011261384657600080fd5b5081356001600160401b0381111561385d57600080fd5b6020830191508360208260051b850101111561387857600080fd5b9250929050565b6000806020838503121561389257600080fd5b82356001600160401b038111156138a857600080fd5b6138b485828601613834565b90969095509350505050565b6000602082840312156138d257600080fd5b5035919050565b801515811461375257600080fd5b600080604083850312156138fa57600080fd5b8235915060208301356137a0816138d9565b600080600080600080600060e0888a03121561392757600080fd5b8735965060208801356139398161373d565b95506040880135945060608801356139508161373d565b93506080880135925060a08801356139678161373d565b915060c08801356139778161373d565b8091505092959891949750929550565b6000806000806000806000806080898b0312156139a357600080fd5b88356001600160401b03808211156139ba57600080fd5b6139c68c838d01613834565b909a50985060208b01359150808211156139df57600080fd5b6139eb8c838d01613834565b909850965060408b0135915080821115613a0457600080fd5b613a108c838d01613834565b909650945060608b0135915080821115613a2957600080fd5b50613a368b828c01613834565b999c989b5096995094979396929594505050565b6001600160a01b0391909116815260200190565b600080600080600080600080610100898b031215613a7b57600080fd5b883597506020890135613a8d8161373d565b9650604089013595506060890135613aa48161373d565b94506080890135935060a0890135613abb816138d9565b925060c0890135613acb8161373d565b915060e0890135613adb8161373d565b809150509295985092959890939650565b600080600060608486031215613b0157600080fd5b8335613b0c8161373d565b92506020840135613b1c816138d9565b915060408401356001600160e01b031981168114613b3957600080fd5b809150509250925092565b60008060008060008060008060008060a08b8d031215613b6357600080fd5b8a356001600160401b0380821115613b7a57600080fd5b613b868e838f01613834565b909c509a5060208d0135915080821115613b9f57600080fd5b613bab8e838f01613834565b909a50985060408d0135915080821115613bc457600080fd5b613bd08e838f01613834565b909850965060608d0135915080821115613be957600080fd5b613bf58e838f01613834565b909650945060808d0135915080821115613c0e57600080fd5b50613c1b8d828e01613834565b915080935050809150509295989b9194979a5092959850565b60008060408385031215613c4757600080fd5b8235613c528161373d565b946020939093013593505050565b60008060408385031215613c7357600080fd5b50508035926020909101359150565b60008060008060008060c08789031215613c9b57600080fd5b863595506020870135613cad8161373d565b9450604087013593506060870135613cc48161373d565b92506080870135915060a0870135613cdb816138d9565b809150509295509295509295565b60008060008060808587031215613cff57600080fd5b843593506020850135613d118161373d565b9250604085013591506060850135613d288161373d565b939692955090935050565b60008060008060008060c08789031215613d4c57600080fd5b863595506020870135613d5e8161373d565b9450604087013593506060870135613d758161373d565b92506080870135613d858161373d565b915060a0870135613cdb8161373d565b634e487b7160e01b600052601160045260246000fd5b600082613dc857634e487b7160e01b600052601260045260246000fd5b500490565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060018201613e2357613e23613d95565b5060010190565b6020808252602d908201527f4f66666572207761732064656c65746564206f722074616b656e2c206f72206e60408201526c32bb32b91032bc34b9ba32b21760991b606082015260800190565b60208082526074908201527f4f666665722063616e206e6f742062652063616e63656c6c656420626563617560408201527f73652075736572206973206e6f74206f776e65722c20616e64206d61726b657460608201527f206973206f70656e2c20616e64206f666665722073656c6c732072657175697260808201527332b21030b6b7bab73a1037b3103a37b5b2b7399760611b60a082015260c00190565b6020808252601290820152711499595b9d1c985b98de48185d1d195b5c1d60721b604082015260600190565b818103818111156109e7576109e7613d95565b6001600160a01b03929092168252602082015260400190565b808201808211156109e7576109e7613d95565b80820281158282048414176109e7576109e7613d95565b6020808252601a9082015279082e4e4c2f240d8cadccee8d0e640c8de40dcdee840dac2e8c6d60331b604082015260600190565b83815260406020820152816040820152818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008161401257614012613d95565b506000190190565b6001600160601b0319606093841b811682529190921b16601482015260280190565b6001600160a01b0394851681529290931660208301526001600160801b039081166040830152909116606082015260800190565b9283526001600160a01b03919091166020830152604082015260600190565b60005b838110156140aa578181015183820152602001614092565b50506000910152565b600082516140c581846020870161408f565b9190910192915050565b6000602082840312156140e157600080fd5b8151610f0b816138d9565b602081526000825180602084015261410b81604085016020870161408f565b601f01601f19169190910160400192915050565b634e487b7160e01b600052605160045260246000fdfe998a3936f157471bfa675789c6ae52cb078e5679f4764a57a587aca731e66206a2c251311b1a7a475913900a2a73dc9789a21b04bc737e050bbc506dd4eb348855a583bf144a5516c8de6ffe85b1859d93234d5e765ed3e895106330766044b8ce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed94a2646970667358221220fe957018c046ef928e0cf1182395edf38e78736e008a0832d6f2b6e0180c375764736f6c63430008110033

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.