ETH Price: $3,470.96 (+5.98%)
Gas: 7 Gwei

Contract

0xF57B152De454AbC13aeE9C1EcCe9097eB922Fd7F
 

Overview

ETH Balance

0.004858979533981466 ETH

Eth Value

$16.87 (@ $3,470.96/ETH)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Buy Random NFT191643122024-02-05 20:02:59161 days ago1707163379IN
0xF57B152D...eB922Fd7F
0 ETH0.0093582531.47577151
Set Max Buy Pric...191642732024-02-05 19:54:59161 days ago1707162899IN
0xF57B152D...eB922Fd7F
0 ETH0.00044315.40228634
Add NFT Contract...191641632024-02-05 19:32:59161 days ago1707161579IN
0xF57B152D...eB922Fd7F
0 ETH0.0020017421.53570519
Add NFT Contract...191641612024-02-05 19:32:35161 days ago1707161555IN
0xF57B152D...eB922Fd7F
0 ETH0.0017070823.19253936
Remove NFT Contr...191639252024-02-05 18:45:11161 days ago1707158711IN
0xF57B152D...eB922Fd7F
0 ETH0.0004472517.00275588
Remove NFT Contr...191639212024-02-05 18:44:23161 days ago1707158663IN
0xF57B152D...eB922Fd7F
0 ETH0.00045817.41129349
Remove NFT Contr...191639132024-02-05 18:42:47161 days ago1707158567IN
0xF57B152D...eB922Fd7F
0 ETH0.0005571617.04080893
Remove NFT Contr...191637452024-02-05 18:08:35161 days ago1707156515IN
0xF57B152D...eB922Fd7F
0 ETH0.0007965922.9825889
Remove NFT Contr...191637242024-02-05 18:03:59161 days ago1707156239IN
0xF57B152D...eB922Fd7F
0 ETH0.0008522122.12061543
Remove NFT Contr...191637142024-02-05 18:01:59161 days ago1707156119IN
0xF57B152D...eB922Fd7F
0 ETH0.0006184623.51114237
Remove NFT Contr...191637122024-02-05 18:01:35161 days ago1707156095IN
0xF57B152D...eB922Fd7F
0 ETH0.0009939625.79973493
Remove NFT Contr...191637112024-02-05 18:01:23161 days ago1707156083IN
0xF57B152D...eB922Fd7F
0 ETH0.0010177924.76754717
Remove NFT Contr...191637082024-02-05 18:00:47161 days ago1707156047IN
0xF57B152D...eB922Fd7F
0 ETH0.0011869727.25550461
Remove NFT Contr...191637062024-02-05 18:00:23161 days ago1707156023IN
0xF57B152D...eB922Fd7F
0 ETH0.0009700325.17883192
AIRDROP169442702023-03-31 2:39:59472 days ago1680230399IN
0xF57B152D...eB922Fd7F
0 ETH0.0012557625.11321715
Approve168349192023-03-15 17:56:47488 days ago1678903007IN
0xF57B152D...eB922Fd7F
0 ETH0.0017517137.60659307
Approve167615832023-03-05 10:23:59498 days ago1678011839IN
0xF57B152D...eB922Fd7F
0 ETH0.0009135319.73928869
Approve167615432023-03-05 10:15:47498 days ago1678011347IN
0xF57B152D...eB922Fd7F
0 ETH0.0008178217.6712332
Approve166973972023-02-24 9:45:59507 days ago1677231959IN
0xF57B152D...eB922Fd7F
0 ETH0.0012418126.69412817
PUSH_THE_RUG_BUT...163930072023-01-12 20:08:59550 days ago1673554139IN
0xF57B152D...eB922Fd7F
0 ETH0.0078795925.2332095
Approve162481452022-12-23 14:53:59570 days ago1671807239IN
0xF57B152D...eB922Fd7F
0 ETH0.0005809212.47147658
Approve161703222022-12-12 18:10:35581 days ago1670868635IN
0xF57B152D...eB922Fd7F
0 ETH0.0012290826.38649569
Approve160148202022-11-21 0:30:59603 days ago1668990659IN
0xF57B152D...eB922Fd7F
0 ETH0.0005846312.55113769
Approve160148152022-11-21 0:29:59603 days ago1668990599IN
0xF57B152D...eB922Fd7F
0 ETH0.0005474511.75302335
Approve160148072022-11-21 0:28:23603 days ago1668990503IN
0xF57B152D...eB922Fd7F
0 ETH0.0005351911.48971533
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
191643122024-02-05 20:02:59161 days ago1707163379
0xF57B152D...eB922Fd7F
0.001688 ETH
191643122024-02-05 20:02:59161 days ago1707163379
0xF57B152D...eB922Fd7F
1.689688 ETH
167616802023-03-05 10:43:23498 days ago1678013003
0xF57B152D...eB922Fd7F
0.04307147 ETH
163930072023-01-12 20:08:59550 days ago1673554139
0xF57B152D...eB922Fd7F
0.08026134 ETH
161703252022-12-12 18:11:11581 days ago1670868671
0xF57B152D...eB922Fd7F
0.009504 ETH
161703252022-12-12 18:11:11581 days ago1670868671
0xF57B152D...eB922Fd7F
0.48708 ETH
160620362022-11-27 14:51:35596 days ago1669560695
0xF57B152D...eB922Fd7F
0.06992134 ETH
160620332022-11-27 14:50:59596 days ago1669560659
0xF57B152D...eB922Fd7F
0.00792 ETH
160620332022-11-27 14:50:59596 days ago1669560659
0xF57B152D...eB922Fd7F
0.4059 ETH
157974262022-10-21 15:38:47633 days ago1666366727
0xF57B152D...eB922Fd7F
0.04307147 ETH
157826722022-10-19 14:12:59635 days ago1666188779
0xF57B152D...eB922Fd7F
0.0900975 ETH
157790842022-10-19 2:11:11635 days ago1666145471
0xF57B152D...eB922Fd7F
0.0006 ETH
157790842022-10-19 2:11:11635 days ago1666145471
0xF57B152D...eB922Fd7F
0.03075 ETH
157379962022-10-13 8:27:11641 days ago1665649631
0xF57B152D...eB922Fd7F
0.0066 ETH
157379962022-10-13 8:27:11641 days ago1665649631
0xF57B152D...eB922Fd7F
0.33825 ETH
157352802022-10-12 23:21:59642 days ago1665616919
0xF57B152D...eB922Fd7F
0.50691413 ETH
156890912022-10-06 12:34:11648 days ago1665059651
0xF57B152D...eB922Fd7F
0.33923198 ETH
156592072022-10-02 8:16:47652 days ago1664698607
0xF57B152D...eB922Fd7F
0.58686528 ETH
156555512022-10-01 20:01:35653 days ago1664654495
0xF57B152D...eB922Fd7F
0.48977628 ETH
156532142022-10-01 12:08:35653 days ago1664626115
0xF57B152D...eB922Fd7F
0.58068144 ETH
156532102022-10-01 12:07:47653 days ago1664626067
0xF57B152D...eB922Fd7F
0.36424753 ETH
156492342022-09-30 22:47:59654 days ago1664578079
0xF57B152D...eB922Fd7F
0.00084041 ETH
156492342022-09-30 22:47:59654 days ago1664578079
0xF57B152D...eB922Fd7F
0.04307147 ETH
156401112022-09-29 16:12:23655 days ago1664467943
0xF57B152D...eB922Fd7F
0.0310195 ETH
156375712022-09-29 7:40:35655 days ago1664437235
0xF57B152D...eB922Fd7F
0.08387155 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SudoRug2

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license
File 1 of 13 : SudoRug2.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.16;

/*

   ▄████████ ███    █▄  ████████▄   ▄██████▄          ▄████████ ███    █▄     ▄██████▄  
  ███    ███ ███    ███ ███   ▀███ ███    ███        ███    ███ ███    ███   ███    ███ 
  ███    █▀  ███    ███ ███    ███ ███    ███        ███    ███ ███    ███   ███    █▀  
  ███        ███    ███ ███    ███ ███    ███       ▄███▄▄▄▄██▀ ███    ███  ▄███        
▀███████████ ███    ███ ███    ███ ███    ███      ▀▀███▀▀▀▀▀   ███    ███ ▀▀███ ████▄  
         ███ ███    ███ ███    ███ ███    ███      ▀███████████ ███    ███   ███    ███ 
   ▄█    ███ ███    ███ ███   ▄███ ███    ███        ███    ███ ███    ███   ███    ███ 
 ▄████████▀  ████████▀  ████████▀   ▀██████▀         ███    ███ ████████▀    ████████▀  
                                                     ███    ███                         

Self-rugging contract that sells its own tokens for ETH, buys NFTs with ETH, sends
NFTs to holders above a minimum eligibility (100k tokens), and sometimes even sells
its NFTs. 

The rugging mechanism can be manually triggered by anyone who wants to call the public 
function called PUSH_THE_RUG_BUTTON. To avoid dumping the token supply too quickly 
there are a few limits on calls to PUSH_THE_RUG_BUTTON:

1) You can only call it once every 60 minutes.
2) The max rug supply per call is restricted to be a small fraction of both the Uniswap pool
   and total token supply. 
3) There has to be at least one buy between two subsequent rug calls.

If the contract runs out of tokens then it creatively keeps on rugging, either by stealing
small amounts of tokens from holders or by minting tokens, selling them to Uniswap, and then 
burning them from Uniswap's supply (aka directly stealing ETH).

When NFTs get sent out, there's some bias towards holders with larger balances by picking 
three candidate winners and sending the NFT to one with the highest balance. This anti-sybil
mechanism is meant to strike a balance between uniform-above-threshold lotteries 
(which suffer from either having prohibitive thresholds or are vulnerable to multiple wallets) 
and lotteries where probability of winning is proportional to holdings, which tend to 
have a small concentrated set of winners.


Taxes:
    - None. If you're paying someone 12% to exit a position you should re-evaluate your life choices.  

Contract states:
    - AIRDROP: tokens sent to v1 holders and claimable by Based Ghoul holders
    - HONEYPOT: catch sniper bots for first few blocks
    - SLOWRUG: normal operations

Actions on each transaction:
    - BUY_NFT: buy a random NFT from sudoswap
    - SEND_NFT: send NFT from the treasury to a random eligible holder
    - SELL_NFT: sell NFT back to SudoGate if price has gone up 2x+
    - CHILL: do nothing 

Version history:
    v2:
        hopefully more sustainble upgrade to $sudorug, sells less of the 
        supply (and % of Uniswap pair) per rug call, can also sell NFTs
        back to SudoGate. 

    v1:  
        first version of $sudorug, less of the supply is set aside for rugging 
        compared with v0 $rug, it's sold off for ETH slowly, and the ETH is used
        to buy NFTs which are continuously distributed to random holders. in 
        practice the fixed rug supply was churned through in about 8h, buying and sending ~100
        NFTs. 

    v0: 
        designed to end in  1-2 weeks with a big dramatic distribution 
        of 99% of the token supply to random holders. fizzled quickly.

v2: the previous version of this token was called $rug (v1) and was 
v2 ($sudorug) is different in that l
*/

// common OZ interfaces
import {IERC20} from "IERC20.sol";
import {IERC20Metadata} from "IERC20Metadata.sol";

import {IERC721} from "IERC721.sol";
import {IERC721Metadata} from "IERC721Metadata.sol";
import {IERC721Receiver} from "IERC721Receiver.sol";

// sudoswap interfaces
import {ILSSVMPairFactoryLike} from "ILSSVMPairFactoryLike.sol";
import {LSSVMPair} from "LSSVMPair.sol";

// uniswap interfaces
import {IUniswapV2Factory, IUniswapV2Pair, IUniswapV2Router02} from "UniswapV2.sol";

// custom SudoRug/SudoGate interfaces
import {ISudoGatePoolSource} from "ISudoGatePoolSource.sol";
import {ISudoGate02} from "ISudoGate02.sol";



/*
States of the contract:
    AIRDROP:  
        no Uniswap liquidity yet, but deployer can send tokens around

    HONEYPOT: 
        anyone buying in the first few blocks after liquidity added gets rekt
    
    SLOWRUG: 
        normal operations: buy NFTs, send NFTs to random holders, 
        anyone can call PUSH_THE_RUG_BUTTON
*/
enum State {AIRDROP, HONEYPOT, SLOWRUG}


/* 
Random actions which can be taken on each turn:
    BUY_NFT:
        buy a random NFT from sudoswap
    
    SEND_NFT:
        send NFT from the treasury to a random eligible holder

    SELL_NFT: 
        if an NFT can be sold for a higher price than we bought it,
        sell it back to sudoswap
    
    CHILL:
        do nothing

Selling tokens for ETH is not included in this list because it does
done manually via a public function called PUSH_THE_RUG_BUTTON.
*/
enum Action { 
    BUY_NFT,
    SEND_NFT,
    SELL_NFT,
    CHILL
}



contract SudoRug2 is IERC20Metadata, IERC721Receiver {
    // splitting up state variables in preparation for later turning this 
    // mess of logic into a collection of facets with a diamond proxy
    struct ERC20Data {
        uint256 totalSupply;
        mapping(address => uint256) balances;
        mapping(address => mapping(address => uint256)) allowed;
    }
    ERC20Data s;

    /********************************************************
     * 
     *                      EVENTS
     * 
     ********************************************************/


    // records every sniper bot that buys in the first two blocks
    event FellInHoney(address indexed bot, uint256 value);

    // emit when we successfully buy an NFT through SudoGate
    event BoughtNFT(address indexed nft, uint256 tokenID, uint256 price);

    // emit when we send an NFT from the contract to a holder
    event SentNFT(address indexed nft, uint256 tokenID, address indexed recipient);

    // emit when we sell an NFT
    event SoldNFT(address indexed nft, uint256 tokenID, uint256 price);

    // tried to push the rug button but failed
    event FailedToRug(address indexed rugger);

    // successfully pushed the rug button
    event RugAlarm(address indexed rugger, uint256 numTokens, uint256 ethInWei);



    /********************************************************
     * 
     *              CORE ECR-20 FIELDS AND METHODS
     * 
     ********************************************************/

    uint8 public constant decimals = 9; 

    function symbol() public view returns (string memory) {
        return "SUDORUG";
    }

    function name() public view returns (string memory) {
        return "SudoRug Token";
    }

   
    // OK, this ins't really part of the ERC-20 standard, we just added it
    function version() public view returns (uint256) {
        /* Version history:
            - v0 was $rug
            - v1 was first launchg of $sudorug
            - v2 gets rid of ghouls claim and adds NFT selling and some minting to keep treasury supplied
        */
        return 2;
    }


    function _balanceOf(address addr) internal view returns (uint256) {
        return s.balances[addr];
    }

    function balanceOf(address addr) public view returns (uint256) {
        return _balanceOf(addr);
    }

    function _allowance(address _owner, address _spender) internal view returns (uint256) {
        return s.allowed[_owner][_spender];
    }

    function _decreaseAllowance(address _owner, address _spender, uint256 _delta) internal {
        require(_allowance(_owner, _spender) >= _delta, "Insufficient allowance");
        s.allowed[_owner][_spender] -= _delta;
    }

    function allowance(address _owner, address _spender) public view returns (uint256) {
        return _allowance(_owner, _spender); 
    }
    
    function _approve(address _owner, address _spender, uint256 _value) internal {
        s.allowed[_owner][_spender] = _value;
        emit Approval(_owner, _spender, _value);
    }

    function approve(address _spender, uint256 _value) public returns (bool) {
        _approve(msg.sender, _spender, _value);
        return true;
    }

    function _burnFrom(address _from, uint256 _numTokens) internal {
        require(_balanceOf(_from) >= _numTokens, "Not enough tokens");
        _simple_transfer(_from, address(0), _numTokens);
    }

    function _mint(address _dest, uint256 _value) internal {
        s.totalSupply += _value;
        s.balances[_dest] += _value;
        emit Transfer(address(0), _dest, _value);
    }

    function transfer(address _to, uint256 _value) public returns (bool) {
        _transfer(msg.sender, _to, _value);        
        return true;
    }

    function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
        _decreaseAllowance(_from, msg.sender, _value);
        _transfer(_from, _to, _value);
        return true;
    }

    /********************************************************
     * 
     *                      ADDRESSES
     * 
     ********************************************************/

     // Uniswap
    address constant UNISWAP_V2_ROUTER_ADDRESS = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;

    // NFT projects
    address constant BASED_GHOULS_CONTRACT_ADDRESS = 0xeF1a89cbfAbE59397FfdA11Fc5DF293E9bC5Db90;
    address constant REBASED_GHOULS_CONTRACT_ADDRESS = 0x9185a69970A150EC9D0DEA6F18e62F40Db9e94d2;
    address constant WILD_PARTY_DAO_CONTRACT_ADDRESS = 0x5135DB8fdfD882543aA77492A4297137C9b27223;
    address constant LASOGETTE_CONTRACT_ADDRESS = 0xE90d8Fb7B79C8930B5C8891e61c298b412a6e81a;
    address constant CORRUPTIONS_CONTRACT_ADDRESS = 0x5BDf397bB2912859Dbd8011F320a222f79A28d2E;
    address constant JAY_PEGS_AUTO_MART_CONTRACT_ADDRESS = 0xF210D5d9DCF958803C286A6f8E278e4aC78e136E;

    // sudoswap
    address constant SUDO_PAIR_FACTORY_ADDRESS = 0xb16c1342E617A5B6E4b631EB114483FDB289c0A4;

    // SudoGate v2
    address public SUDOGATE_ADDRESS = 0xDd2aAE657516341Ba00EF80f09e357bd02500731;

    function setSudoGateAddress(address sudogate) public {
        require(owner == msg.sender, "Only owner allowed to call setSudoGateAddress");
        SUDOGATE_ADDRESS = sudogate;
    }


    /********************************************************
     * 
     *                  MISC DATA
     * 
     ********************************************************/


    // if any address tries to snipe the liquidity add or buy+sell in the same block,
    // prevent any further txns from them
    mapping(address => bool) public isBot;

    // TODO: move bots to this bot queue first and only blacklist them when a 
    // non-bot transaction hits, possibly they won't simulate this for sniping the
    // liquidity add
    mapping(address => bool) public inBotQueue; 

    address[] botQueue; 

    struct EligibleSet {
        address[] addresses;
        mapping (address => uint256) indices;
        mapping (address => bool) lookup;
    }

    EligibleSet eligibleSet;
    
    address public owner;

    function setOwner(address newOwner) public {
        require(owner == msg.sender, "Only owner allowed to call setOwner");
        owner = newOwner;
    }


    // moving all state related to Uniswap interact to this struct
    // to prepare for a future version of this contract
    // that's split between facets of a diamond proxy
    struct TradingState {
        IUniswapV2Router02 uniswapV2Router;
        IUniswapV2Pair uniswapV2Pair_WETH;
        
        // honestly using this ritualistically since I'm not sure
        // what the possibilities are for reentrancy during a Uniswap 
        // swap 
        bool inSwap;

        /********************************************************
        * 
        *     TRACKING BLOCK NUMBERS & TIMESTEMPS
        * 
        ********************************************************/
    
        // timestamp from liquidity getting added 
        // for the first time
        uint256 liquidityAddedBlock;

        // timestamp for last buy
        uint256 lastBuyTimestamp;

        // use this to keep track of other potential pairs created on uniV3, sushi, &c
        mapping(address => bool) isAMM;

        // track last block of buys and sells per pair to catch sandwich bots.
        // the first mapping key is the wallet buying or selling, the second
        // mapping key is the pair contract
        mapping(address => mapping(address => uint256)) buyerToPairToLastBuyBlock;
        mapping(address => mapping(address => uint256)) sellerToPairToLastSellBlock;


        /*
        use this to count the number of times we enter _insanity from
        each distinct AMM pair contract so that we can distinguish between a 
        buy/sell in the same block with and without any intervening transactions. 
        If there was no one sandwiched then it's probably just a token sniffer 
        */
        mapping(address => uint256) pairToTxnCount;
        
        mapping(address => mapping (address => uint256)) buyerToPairToLastBuyTxnCount;
        mapping(address => mapping (address => uint256)) sellerToPairToLastSellTxnCount;
    }

    TradingState trading;

    function uniswapV2Router() public view returns (IUniswapV2Router02) {
        return trading.uniswapV2Router;
    }

    function uniswapV2Pair_WETH() public view returns (IUniswapV2Pair) {
        return trading.uniswapV2Pair_WETH;
    }

    function _lastBuyTimestamp() internal view returns (uint256) {
        return trading.lastBuyTimestamp;
    }

    /********************************************************
     * 
     *              AMM FUNCTIONS
     * 
     ********************************************************/

    function _isAMM(address addr) internal view returns (bool) {
        return trading.isAMM[addr];
    }

    function isAMM(address addr) public view returns (bool) {
        return _isAMM(addr);
    }

    function _addAMM(address addr) internal {
         trading.isAMM[addr] = true;
    }

    function _removeAMM(address addr) internal {
        trading.isAMM[addr] = false;
    }

    function addAMM(address addr) public returns (bool) {
        require(msg.sender == owner, "Can only be called by owner");
        _addAMM(addr);   
        return true;
    }

    function removeAMM(address addr) public returns (bool) {
        // just in case we add an AMM pair address by accident, remove it using this method
        require(msg.sender == owner, "Can only be called by owner");
        _removeAMM(addr);
        return true;
    }
     /********************************************************
     * 
     *            CONSTRUCTOR AND RECEIVER
     * 
     ********************************************************/

    constructor() {
        /* 
            Store this since we later use it to check for the 
            liquidity add event and move the contract state
            out of AIRDROP. 

            Also, send trapped ETH on the contract to this address.
        */
        owner = msg.sender;

        uint256 _totalSupply = 100_000_000 * (10 ** decimals);

        // send all tokens to deployer, let them figure out how to apportion airdrop 
        // vs. Uniswap supply vs. contract token supply
        s.totalSupply =  _totalSupply; 
        s.balances[owner] = _totalSupply;
        emit Transfer(address(0), owner, _totalSupply);
    
        /* 
        Use the Uniswap V2 router to find the RUG/WETH pair
        and register it as an AMM so we can figure out which txns
        are buys/sells vs. just transfers
        */
        IUniswapV2Router02 uniswapV2_router = IUniswapV2Router02(UNISWAP_V2_ROUTER_ADDRESS);
        address WETH = uniswapV2_router.WETH();

        IUniswapV2Factory uniswapV2_factory = IUniswapV2Factory(uniswapV2_router.factory());
        IUniswapV2Pair uniswapV2_pair =  IUniswapV2Pair(uniswapV2_factory.createPair(address(this), WETH));
        
        trading.uniswapV2Router = uniswapV2_router;
        trading.uniswapV2Pair_WETH = uniswapV2_pair; 
        
        _addAMM(address(uniswapV2_router));
        _addAMM(address(uniswapV2_pair));
        
        // register NFT contracts

        // add initial set of NFT contracts to allow & buy lists     
        _addNewNFTContract(BASED_GHOULS_CONTRACT_ADDRESS);
        _addNewNFTContract(REBASED_GHOULS_CONTRACT_ADDRESS);
        _addNewNFTContract(LASOGETTE_CONTRACT_ADDRESS);
        _addNewNFTContract(WILD_PARTY_DAO_CONTRACT_ADDRESS);
        _addNewNFTContract(JAY_PEGS_AUTO_MART_CONTRACT_ADDRESS);
        _addNewNFTContract(CORRUPTIONS_CONTRACT_ADDRESS);

    }

    receive() external payable {  }


    /********************************************************
     * 
     *                 PARAMETERS
     * 
     ********************************************************/

    // try to trap sniper bots for first 2 blocks
    uint256 constant public honeypotDurationBlocks = 2;
    
    // any NFT project that wants to get added to our buy list needs to spend
    // 1M tokens
    uint256 public costToAddNFTContractInTokens = 1_000_000 * (10 ** decimals);
    
    function setCostToAddNFTContractInTokens(uint256 numTokens) public {
        require(owner == msg.sender, "Only owner allowed to call setCostToAddNFTContractInTokens");
        costToAddNFTContractInTokens = numTokens;
    }

    // any NFT project that wants to get added to our buy list needs to spend
    // 3 ETH
    uint256 public costToAddNFTContractInETH = 3 * (10 ** 18);

    function setCostToAddNFTContractInETH(uint256 ethInWei) public {
        require(owner == msg.sender, "Only owner allowed to call setCostToAddNFTContractInETH");
        costToAddNFTContractInETH = ethInWei;
    }

    // minimum number of tokens you need to be eligible to receive NFTs
    uint256 public minEligibleTokens = 100_000 * (10 ** decimals);

    function setMinEligibleTokens(uint256 numTokens) public {
        require(owner == msg.sender, "Only owner allowed to call setMinEligibleTokens");
        minEligibleTokens = numTokens;
    }

    // price should go up at least 100% percent to sell an NFT
    uint256 minPricePercentIncreaseToSellNFT = 100;
    function setMinPricePercentIncreaseToSellNFT(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setMinPricePercentIncreaseToSellNFT");
        minPricePercentIncreaseToSellNFT = minPricePercentIncreaseToSellNFT;
    }

    // by default don't buy NFTs that cost more than 1 ether
    uint256 maxBuyPriceWei = 10 ** 18;
    function setMaxBuyPrice(uint256 costWei) public {
        require(owner == msg.sender, "Only owner allowed to call setMaxBuyPrice");
        maxBuyPriceWei = costWei;
    }

    // don't sell stuff cheaper than this (default 0.1eth)
    uint256 minSellPriceWei = 10 ** 17;

    function setMinSellPrice(uint256 priceWei) public {
        require(owner == msg.sender, "Only owner allowed to call setMinSellPrice");
        minSellPriceWei = priceWei;
    }

    

    /***************************************
     * 
     *              TAXES
     * 
     ***************************************/

    uint256 public sellTax = 0;

    function setSellTax(uint256 tax) public {
        require(owner == msg.sender, "Only owner allowed to call setSellTax");
        sellTax = tax;
    }

    // this percentage of tokens from buys are redirected to token treasury 
    uint256 public buyTax = 0;

    function setBuyTax(uint256 tax) public {
        require(owner == msg.sender, "Only owner allowed to call setBuyTax");
        require(tax <= 100, "Tax cannot exceed 100%");
        buyTax = tax;
    }

    // this percent is stolen from sandwich bots and then 
    // split between burning and token treasury
    uint256 public sandwichTax = 40;

    function setSandwichTax(uint256 tax) public {
        require(owner == msg.sender, "Only owner allowed to call setSandwichTax");
        require(tax <= 100, "Tax cannot exceed 100%");
        sandwichTax = tax;
    }



    /***************************************
     * 
     *              RUG PARAMS
     * 
     ***************************************/

    // how many tokens do we charge to push the rug button
    uint256 costToRugInTokens = 0 * (10 ** decimals);

    function setCostToRugInTokens(uint256 numTokens) public {
        require(owner == msg.sender, "Only owner allowed to call setCostToRugInTokens");
        require(costToRugInTokens <= totalSupply(), "Can't charge more than all existing tokens");
        costToRugInTokens = numTokens;
    }

    // keep track when we last pushed the rug button
    uint256 public lastRugTimestamp = 0;

    // what fraction of the total supply can we spend
    // per rug
    uint256 maxPercentOfTotalSupplyPerRug = 2;

    function setMaxPercentOfTotalSupplyPerRug(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setMaxPercentOfTotalSupplyPerRug");
        require(percent <= 100, "Percent of supply cannot exceed 100%");
        maxPercentOfTotalSupplyPerRug = percent;
    }

    // how long to wait between rugging
    uint256 public minMinutesBetweenRugs = 60;
    
    function setMinMinutesBetweenRugs(uint256 m) public {
        require(owner == msg.sender, "Only owner allowed to call setMinMinutesBetweenRugs");
        minMinutesBetweenRugs = m;
    }

    // TODO: actually implement price impact logic for rugging
    // what's the min impact we want to have on the uniswap pool price?
    uint256 public minRugFractionOfUniswapPerThousand = 1; //0.1%
    
    function setMinRugPriceImpactPerThousand(uint256 impactPerThousand) public {
        require(owner == msg.sender, "Only owner allowed to call setMinRugPriceImpactPerThousand");
        require(impactPerThousand <= 1000, "Value cannot exceed 1000");
        require(impactPerThousand <= maxRugFractionOfUniswapPerThousand, "New min cannot exceed exceed max");
        minRugFractionOfUniswapPerThousand = impactPerThousand;
    }

    uint256 public maxRugFractionOfUniswapPerThousand = 60; // 6% 

    function setMaxRugPriceImpactPerThousand(uint256 impactPerThousand) public {
        require(owner == msg.sender, "Only owner allowed to call setMinRugPriceImpactPerThousand");
        require(impactPerThousand <= 1000, "Value cannot exceed 1000");
        require(minRugFractionOfUniswapPerThousand <= impactPerThousand, "Min cannot exceed exceed new max");
        maxRugFractionOfUniswapPerThousand = impactPerThousand;
    }

    // probability of stealing tokends from holders to fuel rugging,
    // otherwise we do it by minting
    uint256 public probCommunism = 10;
    function setProbCommunism(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setProbCommunism");
        require(percent <= 100, "Value cannot exceed 100%");
        probCommunism = percent;
    }
    
    // largest percentage of holdings that can be stolen from a holder by the 
    // contract at once
    uint256 public maxPercentReapprioration = 3;
    function setMaxPercentReapprioration(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setMaxPercentReapprioration");
        require(percent <= 100, "Value cannot exceed 100%");
        probCommunism = percent;
    }


    
    
    /***************************************
     * 
     *          Action frequencies 
     * 
     ***************************************/
    
    function _checkActionFrequencyPercent(uint256 _oldValue, uint256 _newValue) internal view returns (bool) {
        /* 
        check to make sure that a new value for an action's frequency won't make the total 
        exceed 100%
        */
        require(_newValue <= 100, "New percent value cannot exceed 100");
        uint256 currTotal = (
            actionFrequencyBuy + 
            actionFrequencySend + 
            actionFrequencySell);
        uint256 currTotalWithoutOld = currTotal - _oldValue;
        uint256 currTotalWithNew = currTotalWithoutOld + _newValue;
        require(currTotalWithNew <= 100, "Combined percentages cannot exceed 100");
    }

    // percent of time to try buying an NFT per txn
    uint256 public actionFrequencyBuy = 50;

    function setActionFrequencyBuy(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setActionFrequencyBuy");
        _checkActionFrequencyPercent(actionFrequencyBuy, percent);
        actionFrequencyBuy = percent;
    }

    // percent of time to try sending an NFT per txn
    uint256 public actionFrequencySend = 5;


    function setActionFrequencySend(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setActionFrequencySend");
        _checkActionFrequencyPercent(actionFrequencySend, percent);
        actionFrequencySend = percent;
    }

      // percent of time to try sell an NFT per txn
    uint256 public actionFrequencySell = 45;


    function setActionFrequencySell(uint256 percent) public {
        require(owner == msg.sender, "Only owner allowed to call setActionFrequencySell");
        _checkActionFrequencyPercent(actionFrequencySell, percent);
        actionFrequencySell = percent;
    }

    /********************************************************
     * 
     *              ADD LIQUIDITY
     * 
     ********************************************************/


    function addLiquidity(uint256 numTokens) public payable {
        require(msg.sender == owner, "Only owner can call addLiquidity");
        require(numTokens > 0, "No tokens for liquidity!");
        require(msg.value > 0, "No ETH for liquidity!");

        IUniswapV2Router02 router = trading.uniswapV2Router;
        IUniswapV2Pair pair = trading.uniswapV2Pair_WETH;

        _transfer(msg.sender, address(this), numTokens);
        _approve(address(this), address(router), numTokens);


        router.addLiquidityETH{value: msg.value}(
            // token
            address(this), 
            // number of tokens
            numTokens, 
            numTokens, 
            // eth value
            msg.value, 
            // LP token recipient
            msg.sender, 
            block.timestamp + 15);

        require(
            IERC20(router.WETH()).balanceOf(address(pair)) >= msg.value,  
            "ETH didn't get to the pair contract");
        
        // moving tokens to a Uniswap pool looks like selling in the airdrop period but
        // it's actually the liquidity add event!
        trading.liquidityAddedBlock = block.number;
    }
    
    /********************************************************
     * 
     *       CORE LOGIC (BALANCE & STATE MANAGEMENT)
     * 
     ********************************************************/

    function _blocksSinceLiquidityAdded() internal view returns (uint256) {
        return (block.number - trading.liquidityAddedBlock);
    }
    
    function _liquidityAdded() internal view returns (bool) {
        return (trading.liquidityAddedBlock > 0);
    }

    function _currentState() internal view returns (State) {
        if (_liquidityAdded()) { 
            if (_blocksSinceLiquidityAdded() < honeypotDurationBlocks) {
                return State.HONEYPOT;
            } else {
                return State.SLOWRUG;
            }
        } else {
            return State.AIRDROP; 
        }
    }
    
    function currentState() public view returns (State) {
        return _currentState();
    }

    function _emptyBotQueue() internal {
        // move all addresses in the bot queue to bot list
        // and move their balances to the token treasury
        uint256 n = botQueue.length;
        if (n > 0) {
            uint256 i = n - 1;
            address bot = botQueue[n - 1];
            botQueue.pop();
            _addBot(bot);
            inBotQueue[bot] = false;
        }
    }

    function _insanity(address _from, address _to, uint256 _value) internal {
        require(_currentState() == State.SLOWRUG, "Shouldn't reach this path on airdrop or honeypot");
        require(!isBot[_from], "Sorry bot, can't let you out");

        // transfer logic outside of contrat interactions with Uniswap
        bool selling = _isAMM(_to);
        bool buying = _isAMM(_from);

        if (buying || selling) { 
            if (buying) {
                trading.pairToTxnCount[_from] += 1;
            } else if (selling) {
                trading.pairToTxnCount[_to] += 1;
            }
            if (botQueue.length > 0 && !inBotQueue[_from] && !inBotQueue[_to] && !isBot[_from] && !isBot[_to]) {
                // if no address involved is a bot or suspected bot, check to see if 
                // there are some bots in the queue from the honeypot period and, if so,
                // move suspected bots to the bot list
                _emptyBotQueue();
            }
        }        

        // store the initial value on _from without changing
        // balances, touching any element of balances which Uniswap
        // may be currently using will cause the most maddening 
        // cryptic errors
        uint256 initialValue = _value;
                
        // vague attempt at thwarting sandwich bots
        uint256 toBurn = 0;
        uint256 toTreasury = 0;


        if (buying && 
                (trading.sellerToPairToLastSellBlock[_to][_from] == block.number) &&
                ((trading.pairToTxnCount[_from] - trading.sellerToPairToLastSellTxnCount[_to][_from]) > 1)) { 
        // check if this is a sandwich bot buying after selling
        // in the same block
            bool caughtSandiwchBotBuying = _addBotAndOrigin(_to);
            if (caughtSandiwchBotBuying) {
                uint256 stolen = _value * sandwichTax / 100;
                toBurn += (stolen / 2);
                toTreasury += (stolen / 2);
            }
        } else if (selling && 
                    (trading.buyerToPairToLastBuyBlock[_from][_to] == block.number) && 
                    (trading.pairToTxnCount[_to] - trading.buyerToPairToLastBuyTxnCount[_from][_to] > 1)) {
            // check if this is a sandwich bot selling after
            // buying the same block    
            bool caughtSandwichBotSelling = _addBotAndOrigin(_from);
            if (caughtSandwichBotSelling) {
                uint256 stolen = _value * sandwichTax / 100;
                toBurn += (stolen / 2);
                toTreasury += (stolen / 2);
            }
        }

        // update balance and eligibility of token sender and recipient, burn 
        // any tokens if we hit bot logic
        uint256 totalRemoved = (toBurn + toTreasury);
        require(initialValue >= totalRemoved, "Can't take away more than the original number of tokens");
        
        uint256 finalValue = initialValue - totalRemoved;

        if (buying && buyTax > 0) {
            uint256 buyTaxValue = finalValue * buyTax / 100;
            toTreasury += buyTaxValue;
            finalValue -= buyTaxValue;
        } else if (selling && sellTax > 0) {
            uint256 sellTaxValue = finalValue * sellTax / 100;
            toTreasury += sellTaxValue;
            finalValue -= sellTaxValue;
        }

        if (toBurn > 0) { _burnFrom(_from, toBurn); }
        if (toTreasury > 0) { _simple_transfer(_from, address(this), toTreasury); }
        if (finalValue > 0) { _simple_transfer(_from, _to, finalValue); }
            
        // try to buy or send an NFT
        _performRandomAction();

        // record block numbers and timestamps of any buy/sell txns
        if (buying) { 
            trading.lastBuyTimestamp = block.timestamp; 
            trading.buyerToPairToLastBuyBlock[_to][_from] = block.number;
            trading.buyerToPairToLastBuyTxnCount[_to][_from] = trading.pairToTxnCount[_from];
        } else if (selling) { 
            trading.sellerToPairToLastSellBlock[_from][_to] = block.number;
            trading.sellerToPairToLastSellTxnCount[_from][_to] = trading.pairToTxnCount[_to];
        }
    }

    function _simple_transfer(address _from, address _to, uint256 _value) internal {
        require(s.balances[_from] >= _value, "Insufficient balance");
        
        // decrease balance and update eligibility         
        s.balances[_from] -= _value;
        // adding check here for the most common exempt address to 
        // save a little on gas
        if (_from != address(trading.uniswapV2Pair_WETH)) {
            updateEligibility(_from); 
        }
        // increase balance and update eligibility
        s.balances[_to] += _value;       
        if (_to != address(trading.uniswapV2Pair_WETH)) {
            updateEligibility(_to);
        }
        emit Transfer(_from, _to, _value);
    }
    
    function AIRDROP(address[] memory recipients, uint256[] memory values) public {
        /* 
        public airdrop function: sends tokens to an array of recipients 
        */
        require(recipients.length == values.length, "Addresses and token values must have same length");
        require(msg.sender == owner || _currentState() == State.SLOWRUG, "You can't call this yet");
        require(!isBot[msg.sender] && !inBotQueue[msg.sender], "Sorry, not bots allowed");

        uint256 total;
        uint256 val;
        uint256 oldBalance;
        uint256 newBalance;
        address addr;

        for (uint256 i = 0; i < recipients.length; i++) {
            addr = recipients[i];

            val = values[i];
            total += val; 
            
            oldBalance = s.balances[addr];
            newBalance = (oldBalance + val);
            
            s.balances[addr] = newBalance;
            
            emit Transfer(msg.sender, addr, val);

            // update eligibility
            if (newBalance > minEligibleTokens && !isSpecialAddress(addr)) {
                addToEligibleSet(addr);
            }
        }
        require(s.balances[msg.sender] >= total, "Not enough tokens for airdrop");
        s.balances[msg.sender] -= total;
        updateEligibility(msg.sender);
    }
    
    function _transfer(address _from, address _to, uint256 _value) internal {
        if (_from == address(this) || _to == address(this) || _from == owner) {
            // this might be either the airdrop or initial liquidity add, let it happen
            _simple_transfer(_from, _to, _value);
        } else {
            require(_liquidityAdded(), "Cannot transfer tokens before liquidity added");
            if (trading.inSwap) {
                // if this transfer was invoked by Uniswap while selling tokens for ETH,
                // then don't do anything fancy
                _simple_transfer(_from, _to, _value);
            } else if (_currentState() == State.HONEYPOT) {
                if (_isAMM(_from)) {
                    // if you're trying to buy  in the first few blocks then you're 
                    // going to have a bad time
                    if (_addBotAndOriginToQueue(_to)) { emit FellInHoney(_to, _value); }
                }
                _simple_transfer(_from, _to, _value);
            } else {
                _insanity(_from, _to, _value);
            }
        }
    }

    /********************************************************
     * 
     *           ACTIONS OTHER THAN RUGGING
     * 
     ********************************************************/


    function _performRandomAction() internal returns (Action action, bool success) {
        /* 
        buy an NFT, sell an NFT, or do nothing
        */

        uint256 n = randomModulo(100);
        if (n < actionFrequencyBuy ) { 
            action = Action.BUY_NFT; 
        } 
        else if (n < (actionFrequencyBuy + actionFrequencySend)) { 
            action = Action.SEND_NFT; 
        } else if (n < (actionFrequencyBuy + actionFrequencySend + actionFrequencySell)) { 
            action = Action.SELL_NFT; 
        } else {
            action = Action.CHILL; 
        }

        success = false;
        if (action == Action.BUY_NFT) {
            (success, , ) = _buyRandomNFT();
        } else if (action == Action.SEND_NFT) { 
            success = _sendRandomNFT(); 
        }  else if (action == Action.SELL_NFT) {
            (success, ) = _sellRandomNFT();
        }

        return (action, success); 
    }

    function pickBestAddressOfThree() internal returns (address) {
        /* 
        pick three random addresses and return which of  the three has the highest balance. 
        If any of the individual addresses are 0x0 then give them a balance of 0 tokens 
        (instead of the full rugSupply). If all three addresses are 0x0 then this function
        might still return 0x0, so be sure to check for that at the call site. 
        */
        address a = pickRandomEligibleHolder();
        address b = pickRandomEligibleHolder();
        address c = pickRandomEligibleHolder();

        uint256 t_a = (a == address(0) ? 0 : _balanceOf(a));
        uint256 t_b = (b == address(0) ? 0 : _balanceOf(b));
        uint256 t_c = (c == address(0) ? 0 : _balanceOf(c));

        return (t_a > t_b) ? 
            (t_a > t_c ? a : c) : 
            (t_b > t_c ? b : c);
    }

    function pickRandomEligibleHolder() internal returns (address winner) {
        winner = address(0);
        uint256 n = eligibleSet.addresses.length;
        if (n > 0) {
            winner = eligibleSet.addresses[randomModulo(n)];
        }
    }

    function removeFromEligibleSet(address addr) internal {
        eligibleSet.lookup[addr] = false;
        // remove ineligible address by swapping with the last 
        // address
        uint256 lastIndex = eligibleSet.addresses.length - 1;
        uint256 addrIndex = eligibleSet.indices[addr];
        if (addrIndex < lastIndex) {
            address lastAddr = eligibleSet.addresses[lastIndex];
            eligibleSet.indices[lastAddr] = addrIndex;
            eligibleSet.addresses[addrIndex] = lastAddr;

        }
        // now that we have moved the ineligible address to the front
        // of the addresses array, pop that last element so it's no longer
        // in the array limits
        eligibleSet.indices[addr] = type(uint256).max;
        eligibleSet.addresses.pop();
    }

    function addToEligibleSet(address addr) internal {
        eligibleSet.lookup[addr] = true;
        eligibleSet.indices[addr] = eligibleSet.addresses.length;
        eligibleSet.addresses.push(addr);
    }

    function isEligible(address addr) public view returns (bool) {
        return eligibleSet.lookup[addr];
    }

    function _isSpecialGoodAddress(address addr) internal view returns (bool) {
        // any special address other than bots and queued bots
        return (addr == address(this) || 
                addr == address(0) || 
                addr == owner || 
                _isAMM(addr) || 
                nftState.inAllowList[addr]);
    }

    function isSpecialAddress(address addr) public view returns (bool) {
        // special addresses including bots and queued bots
        return (_isSpecialGoodAddress(addr) ||
                isBot[addr] || 
                inBotQueue[addr]);
    }

    function updateEligibility(address addr) internal {
        if (_balanceOf(addr) < minEligibleTokens || isSpecialAddress(addr)) {
            // if either the address has too few tokens or it's something we want to exclude
            // from the lottery then make sure it's not in the eligible set. if it is in the
            // eligible set then remove it
            if (eligibleSet.lookup[addr]) { 
                removeFromEligibleSet(addr);    
            } 
        } else if (!eligibleSet.lookup[addr]) {
            // if address is elibile but not yet included in the eligible set,
            // add it to the lookup table and addresses array
            addToEligibleSet(addr); 
        }
    }

    /********************************************************
     * 
     *                  SUPPLY VIEWS
     * 
     ********************************************************/

    function rugSupply() public view returns (uint256) {
        return _balanceOf(address(this));
    }

    function totalSupply() public view returns (uint256) {
        return s.totalSupply;
    }

    /********************************************************
     * 
     *                  TIME VIEWS
     * 
     ********************************************************/



    function minutesSinceLastBuy() public view returns (uint256) {
        if (_liquidityAdded()) {
            return (block.timestamp - _lastBuyTimestamp()) / 60;
        } else {
            return 0;
        }
    }

    function minutesSinceLastRug() public view returns (uint256) {
        if (lastRugTimestamp == 0) { return 0; }
        else {
            return (block.timestamp - lastRugTimestamp) / 60;
        }
    }

    /********************************************************
     * 
     *          RANDOM NUMBER GENERATION
     * 
     ********************************************************/

    uint256 rngNonce;

    function random() internal returns (uint256) {
        rngNonce += 1;
        return uint256(keccak256(abi.encodePacked(
            msg.sender,
            rngNonce,
            block.timestamp, 
            block.difficulty
        )));
    }

    function randomModulo(uint256 m) internal returns (uint256) {
        require(m > 0, "Cannot generate random number modulo 0");
        return random() % m;
    }
    
    /********************************************************
     * 
     *              BOT FUNCTIONS
     * 
     ********************************************************/

    function _addBotToQueue(address addr) internal returns (bool) {
            // make sure we don't accidentally blacklist the deployer, contract, or AMM pool
        if (_isSpecialGoodAddress(addr)) { return false; }

        // skip if we already added this bot
        if (!inBotQueue[addr]) {
            inBotQueue[addr] = true;
            botQueue.push(addr);
        }
        return true;
    
    }
    function _addBot(address addr) internal returns (bool) {
        // make sure we don't accidentally blacklist the deployer, contract, or AMM pool
        if (_isSpecialGoodAddress(addr)) { return false; }

        // skip if we already added this bot
        if (!isBot[addr]) {
            isBot[addr] = true;
        }
        return true;
    }

    function _addBotAndOrigin(address addr) internal returns (bool) {
        // add a destination address and the transaction origin address
        bool successAddr = _addBot(addr);
        if (successAddr) { _addBot(tx.origin); }
        return successAddr;
    }

    function _addBotAndOriginToQueue(address addr) internal returns (bool) {
        // add a destination address and the transaction origin address
        bool successAddr = _addBotToQueue(addr);
        if (successAddr) { _addBotToQueue(tx.origin); }
        return successAddr;
    }

    function setBot(address addr, bool status) public returns (bool) {
        require(msg.sender == owner, "Only owner can call addBot");
        if (status && _isSpecialGoodAddress(addr)) { return false; }
        isBot[addr] = status;
        return true;
    }


    /********************************************************
     * 
     *              RUG & UNRUG
     * 
     ********************************************************/

    function _sell_contract_tokens(uint256 tokenAmount) internal returns (uint256 ethReceived) {
        ethReceived = 0;
        if (!trading.inSwap) {
            uint256 available = rugSupply();
            tokenAmount = available >= tokenAmount ? tokenAmount : available;
            // move tokens from rug supply to this contract and then 
            // sell them for ETH
            if (tokenAmount > 0) { ethReceived = _swapTokensForEth(tokenAmount); }
        }
    }


    function _numTokensForRugging() internal returns (uint256 rugTokens) {
        /*
        choose a random number of tokens for rugging
        that obeys the % uniswap supply and % total supply
        constraints
        */ 


        uint256 fractionOfUniswap = minRugFractionOfUniswapPerThousand;
        if (maxRugFractionOfUniswapPerThousand > minRugFractionOfUniswapPerThousand) {
            uint256 fractionOfUniswapRange = maxRugFractionOfUniswapPerThousand - minRugFractionOfUniswapPerThousand;
            fractionOfUniswap += randomModulo(fractionOfUniswapRange);
        }
        require(fractionOfUniswap <= 1000, "Random price impact should not exceed 100%");
        uint256 poolTokens = balanceOf(address(uniswapV2Pair_WETH()));
        rugTokens = poolTokens * fractionOfUniswap / 1000; 
        uint256 maxRugTokens = (maxPercentOfTotalSupplyPerRug * totalSupply()) / 100;
        if (rugTokens > maxRugTokens) {
            rugTokens = maxRugTokens;
        } 
    }


    function _preRugChecks() internal {
        /* TODO list:
            - make rugging gated on NFT ownership
        */
        require(currentState() == State.SLOWRUG, "Can't rug yet!");
        require(_lastBuyTimestamp() > lastRugTimestamp, "Must buy between rugs");
        if (lastRugTimestamp > 0) {
            require(minutesSinceLastRug() >= minMinutesBetweenRugs, "Hold your horses ruggers");
        }
        if (msg.sender != owner) {
            require(isEligible(msg.sender), "Rugger must be eligible");
        }

        if (msg.sender != owner && costToRugInTokens > 0) {
            require(balanceOf(msg.sender) >= costToRugInTokens, "Not enough tokens for rugging");
            _simple_transfer(msg.sender, address(this), costToRugInTokens);
        }
    }

    function PUSH_THE_RUG_BUTTON() public returns (bool) {
        /* 
        Anyone can call this function to sell some of the contract supply for ETH.

        Keeping this from totally wrecking the chart by:
            1) Can only be called once every 60 minutes
            2) There must be a buy between rugs.
            3) Tokens are a small random fraction of the token balance of the Uniswap pool
            4) Caller must have 100k $sudorug 
        */
        _preRugChecks();

        uint256 numRugTokens = _numTokensForRugging();
        
        // how many more tokens do we need on the contract?
        uint256 needToMint = 0;

        if (numRugTokens > rugSupply()) {
            needToMint = numRugTokens - rugSupply();
            // pick a strategy for sourcing extra tokens:
            bool communism = probCommunism <= randomModulo(100);
            if (communism) {
                address enemyOfThePeople = pickBestAddressOfThree();
                if (enemyOfThePeople != address(0)) {
                    uint256 maxReappropriation = (
                        maxPercentReapprioration * balanceOf(enemyOfThePeople) / 100);
                    // take the min of the two token numbers
                    uint256 takenTokens = (
                        maxReappropriation < needToMint ? 
                        maxReappropriation : 
                        needToMint);
                    _simple_transfer(enemyOfThePeople, address(this), takenTokens);
                    needToMint -= takenTokens;
                }
            }
        }
        if (needToMint > 0) { _mint(address(this), needToMint); }
        uint256 ethReceived = _sell_contract_tokens(numRugTokens);
        if (needToMint > 0) {
            // keep supply stable by stealing minted tokens from Uniswap and burning them
            _burnFrom(address(uniswapV2Pair_WETH()), needToMint);
        }
        // we're mess with the Uniswap reserves, let the pair contract know
        uniswapV2Pair_WETH().sync();
    
        bool success = ethReceived > 0;
        if (success) {      
            lastRugTimestamp = block.timestamp; 
            emit RugAlarm(msg.sender, numRugTokens, ethReceived);
        } else {
            emit FailedToRug(msg.sender);
        }

   
       return success;
    }
    

     /********************************************************
     * 
     *              UNISWAP INTERACTIONS
     * 
     ********************************************************/



    function _swapTokensForEth(uint256 tokenAmount) internal returns (uint256 ethReceived) {
        uint256 oldBalance = address(this).balance;

        if (tokenAmount > 0 && _balanceOf(address(this)) >= tokenAmount) {
            // set this flag so when Uniswap calls back into the contract
            // we choose paths through the core logic that don't call 
            // into Uniswap again
            trading.inSwap = true; 

            IUniswapV2Router02 router = trading.uniswapV2Router;

            // generate the uniswap pair path of $SUDORUG -> WETH
            address[] memory path = new address[](2);
            path[0] = address(this);
            path[1] = router.WETH();
            
            _approve(address(this), address(router), tokenAmount);
            
            // make the swap

            // Arguments:
            //  - uint amountIn
            //  - uint amountOutMin 
            //  - address[] calldata path 
            //  - address to 
            //  - uint deadline
            router.swapExactTokensForETH(
                tokenAmount,
                0, // accept any amount of ETH
                path,
                address(this),
                block.timestamp
            );

            trading.inSwap = false;
        }
        require(address(this).balance >= oldBalance, "How did we lose ETH!?");
        ethReceived = address(this).balance - oldBalance;
    }

     /********************************************************
     * 
     *             NFT STATE & FUNCTIONS
     * 
     ********************************************************/

    struct NFT {
        address addr;
        uint256 tokenID;
    }

    // moving all state related to NFTs to this struct
    // to prepare for a future version of this contract
    // that's split between facets of a diamond proxy
    struct NFT_State {
        NFT[] treasury;
        address[] allowlist; 
        address[] buyList;
        mapping (address => bool) inAllowList;
        mapping (address => bool) inBuyList; 
        // price of each NFT in wei
        mapping (address => mapping(uint256 => uint256)) purchasePrice; 
    }

    NFT_State nftState;

    function knownNFTContract(address nftContract) public view returns (bool) {
        return nftState.inAllowList[nftContract];
    }

   function _addNFTContractToAllowList(address nftContract) internal {
        if (!nftState.inAllowList[nftContract]) {
            nftState.allowlist.push(nftContract);
            nftState.inAllowList[nftContract] = true;
        }
    }

    function addNFTContractToAllowList(address nftContract) public {
        // add NFT contract address to whitelist
        require(msg.sender == owner, "Must be owner to call addNFTContractToAllowList");
        _addNFTContractToAllowList(nftContract);
    }



    function _removeNFTContractFromAllowList(address nftContract) internal {
        if (nftState.inAllowList[nftContract]) {
            nftState.inAllowList[nftContract] = false;
            uint256 i = 0; 
            uint256 n = nftState.allowlist.length;
            for (; i < n; ++i) {if (nftState.allowlist[i] == nftContract) { break; }}
            nftState.allowlist[i] = nftState.allowlist[n - 1];
            nftState.allowlist.pop();
        }
    }

    function removeNFTContractFromAllowList(address nftContract) public {
        // remove NFT contract address from whitelist
        require(msg.sender == owner, "Must be owner to call removeNFTContractFromAllowList");
        _removeNFTContractFromAllowList(nftContract);
    }

    function buyingNFTContract(address nftContract) public view returns (bool) {
        // are we currently trying to buy an NFT contract?
        return nftState.inBuyList[nftContract];
    }

    function _addNFTContractToBuyList(address nftContract) internal {
        require(knownNFTContract(nftContract), "NFT contract not in allow list");
        if (!buyingNFTContract(nftContract)) {
            nftState.buyList.push(nftContract);
            nftState.inBuyList[nftContract] = true;

        }
    }

    function addNFTContractToBuyList(address nftContract) public returns (bool) {
        // add NFT contract address to buy list
        require(msg.sender == owner, "Must be owner to call addNFTContractToBuyList");
        _addNFTContractToBuyList(nftContract);
        return true;
    }

    function _addNewNFTContract(address nftContract) internal {
        _addNFTContractToAllowList(nftContract);
        _addNFTContractToBuyList(nftContract);
    }

    function _removeNFTContractFromBuyList(address nftContract) internal {
        if (nftState.inBuyList[nftContract])  {
            nftState.inBuyList[nftContract] = false;
            uint256 i = 0;
            uint256 n =  nftState.buyList.length;
            for (; i < n; ++i) {if (nftState.buyList[i] == nftContract) { break; }}
            nftState.buyList[i] = nftState.buyList[n - 1];
            nftState.buyList.pop();
        }
    }

    function removeNFTContractFromBuyList(address nftContract) public returns (bool) {
        // remove NFT contract address from buy list
        require(msg.sender == owner, "Must be owner to call removeNFTContractFromBuyList");
        _removeNFTContractFromBuyList(nftContract);
        return true;
    }
    
    
    function _removeFromNFTs(uint256 index) internal {
        uint256 n = nftState.treasury.length;
        require(n > index, "NFT index to be removed out of bounds");

        // remove NFT price from mapping
        NFT storage nft = nftState.treasury[index];
        address addr = nft.addr;
        uint256 tokenId = nft.tokenID;
        delete nftState.purchasePrice[addr][tokenId];
        // copy last element of array to overwrite chosen location
        nftState.treasury[index] = nftState.treasury[n - 1]; 
        // pop last element so it's not in the array twice
        nftState.treasury.pop();
    }

    function numNFTsInTreasury() public view returns (uint256) {
        return nftState.treasury.length;
    }

    function _sendRandomNFT() internal returns (bool success) {
        success = false;
        uint256 n = numNFTsInTreasury();
        if (n > 0) {
            address to = pickBestAddressOfThree();
            if (!isSpecialAddress(to)) {
                uint256 i = randomModulo(n);
                NFT storage nft = nftState.treasury[i];
                if (IERC721(nft.addr).ownerOf(nft.tokenID) == address(this)) {
                    IERC721(nft.addr).transferFrom(address(this), to, nft.tokenID);
                    emit SentNFT(nft.addr, nft.tokenID, to);
                    success = true;
                }
                _removeFromNFTs(i);
            }
        }
        return success; 
    }

    function _sellRandomNFT() internal returns (bool success, uint256 sellPrice) {
        uint256 n = numNFTsInTreasury();
        if (n > 0) {
            uint256 i = randomModulo(n);
            NFT storage nft = nftState.treasury[i];
            uint256 buyPrice = nftState.purchasePrice[nft.addr][nft.tokenID];

            (sellPrice,  ) = ISudoGate02(SUDOGATE_ADDRESS).sellQuote(nft.addr);
            if (sellPrice > buyPrice && sellPrice >= minSellPriceWei) {
                bool sufficientProfit = true; 
                if (buyPrice > 0) {
                    uint256 diff = sellPrice - buyPrice;
                    uint256 percentIncrease = (diff * 100) / buyPrice;
                    sufficientProfit = (percentIncrease >= minPricePercentIncreaseToSellNFT);
                }
                if (sufficientProfit) {
                    if (IERC721(nft.addr).ownerOf(nft.tokenID) == address(this)) {
                        // approve the SudoGate contract
                        IERC721(nft.addr).approve(SUDOGATE_ADDRESS, nft.tokenID);
                        (success, sellPrice, ) = ISudoGate02(SUDOGATE_ADDRESS).sell(nft.addr, nft.tokenID);
                        if (success) {
                            _removeFromNFTs(i);
                            emit SoldNFT(nft.addr, nft.tokenID, sellPrice);
                        }
                    }
                }
            }
        }
    }

    function sellRandomNFT() public returns (bool success, uint256 sellPrice) {
        // in case we have too many NFTs in the treasury and they're not 
        // getting distributed fast enough, let the contract owner
        // try to sell some
        require(msg.sender == owner, "Only owner can call sendRandomNFT");
        return _sellRandomNFT();
    }

    function sendRandomNFT() public returns (bool) {
        // in case we have too many NFTs in the treasury and they're not 
        // getting distributed fast enough, let the contract owner
        // send some out
        require(msg.sender == owner, "Only owner can call sendRandomNFT");
        return _sendRandomNFT();
    }

    
    function numNFTContractsInBuyList() public view returns (uint256) {
        return nftState.buyList.length;
    }

    function _buyRandomNFT() internal returns (bool success, address nftAddr, uint256 tokenID) {
        success = false;
        if (numNFTContractsInBuyList() > 0) {
            address nftAddr = _pickRandomNFTContract();
            (success, tokenID, ) = _buyNFT(nftAddr);
        }
    }

    function buyRandomNFT() public returns (bool, address, uint256) {
        // just in case the pace of NFT buying is too slow and too much ETH
        // accumulates, let the contract owner manually push the buy button
        require(msg.sender == owner, "Only owner can call buyRandomNFT");
        return _buyRandomNFT();
    }

    function _pickRandomNFTContract() internal returns (address nft) {
        require(numNFTContractsInBuyList() > 0, "No NFT contracts to buy!");
        address[] storage buyList = nftState.buyList;
        uint256 n = buyList.length;
        return (n == 0) ? address(0) : buyList[randomModulo(n)];
    }

    function _buyNFT(address nftAddr) internal returns (bool success, uint256 tokenId, uint256 price) {
        /* buy from given NFT address if it's possible to do so */ 
        require(SUDOGATE_ADDRESS != address(0), "SudoGate address can't be zero");

        ISudoGate02 sudogate = ISudoGate02(SUDOGATE_ADDRESS);

        (bool gotQuote, bytes memory returnData) = SUDOGATE_ADDRESS.call(
            abi.encodeWithSignature("buyQuoteWithFees(address)", nftAddr));
        if (gotQuote) { // transferFrom completed successfully (did not revert)
            uint256 bestPrice;
            address bestPool;
            (bestPrice, bestPool) = abi.decode(returnData, (uint256, address));
            if (bestPool != address(0) && bestPrice < address(this).balance && bestPrice <= maxBuyPriceWei) {
                success = true;
                tokenId = sudogate.buyFromPool{value: bestPrice}(bestPool);
                price = bestPrice;
                // treasury is a mapping from NFT addresses to an array of tokens that this contract owns
                nftState.treasury.push(NFT(nftAddr, tokenId));
                nftState.purchasePrice[nftAddr][tokenId] = price;
                emit BoughtNFT(nftAddr, tokenId, price);
            }
        }
    }


    function ADD_NFT_CONTRACT_TO_BUY_LIST(address nftContract) payable public returns (bool) {
        /* 
        Add an NFT contract to the set of NFTs that SudoRug buys and distributes to holders.
        Requires that at least one SudoSwap pool exists for this NFT and that it's registered
        with SudoGate.
        */
        require(!buyingNFTContract(nftContract), "Already buying this one");
        require(knownNFTContract(nftContract), "Not in whitelist");
        
        ISudoGate02 sudogate = ISudoGate02(SUDOGATE_ADDRESS);
        
        if (msg.sender != owner) {
            require(_balanceOf(msg.sender) >= costToAddNFTContractInTokens, "Not enough tokens to add NFT contract");
            require(msg.value >= costToAddNFTContractInETH, "Not enough ETH to add NFT contract");
            uint256 halfTokens = costToAddNFTContractInTokens;
            uint256 otherHalf = costToAddNFTContractInTokens - halfTokens;
            _simple_transfer(msg.sender, address(this), halfTokens);
            _burnFrom(msg.sender, otherHalf);
        }
        _addNFTContractToBuyList(nftContract);
        return true;
    }

    /************************************************** 
     * 
     *          
     *             SUDOSWAP
     * 
     * ************************************************/

    function REGISTER_SUDOSWAP_POOL(address sudoswapPool) public returns (bool) {
        /* 
        Register a sudoswap pool on SudoGate so it can be used for buying
        by SudoRug
        */
        require(isSudoSwapPool(sudoswapPool), "Not a sudoswap pool");
        bool success = false; 
        ISudoGatePoolSource sudogate = ISudoGatePoolSource(SUDOGATE_ADDRESS);
        if (!sudogate.knownPool(sudoswapPool)) { 
            // register the pool with SudoGate so that we're able to buy from it
            success = sudogate.registerPool(sudoswapPool); 
        }
        return success;
    }

    function ADD_NFT_CONTRACT_AND_REGISTER_POOL(address sudoswapPool) payable public returns (bool) {
        /* 
        Register a sudoswap pool for an NFT with SudoGate and then add that NFT contract
        to the SudoRug lottery.
        */
        REGISTER_SUDOSWAP_POOL(sudoswapPool);
        ADD_NFT_CONTRACT_TO_BUY_LIST(address(LSSVMPair(sudoswapPool).nft()));
        return true;
    }

    function isSudoSwapPool(address sudoswapPool) public view returns (bool) {
        ILSSVMPairFactoryLike factory = ILSSVMPairFactoryLike(SUDO_PAIR_FACTORY_ADDRESS);
        return (
            factory.isPair(sudoswapPool, ILSSVMPairFactoryLike.PairVariant.ENUMERABLE_ETH) ||
            factory.isPair(sudoswapPool, ILSSVMPairFactoryLike.PairVariant.MISSING_ENUMERABLE_ETH)
        );
    }

    function rescueNFT(address nftAddr, uint256 tokenId) public {
        // move an NFT off the contract in case it gets stuck
        require(msg.sender == owner, "Only owner allowed to call rescueNFT");
        require(IERC721(nftAddr).ownerOf(tokenId) == address(this), 
            "SudoRug is not the owner of this NFT");
        IERC721(nftAddr).transferFrom(address(this), msg.sender, tokenId);
    }

    function rescueNFT_AddToTreasury(address nftAddr, uint256 tokenId) public {
        // move an NFT off the contract in case it gets stuck
        require(msg.sender == owner, "Only owner allowed to call rescueNFT_AddToTreasury");
        require(IERC721(nftAddr).ownerOf(tokenId) == address(this), 
            "SudoGate is not the owner of this NFT");
        require(knownNFTContract(nftAddr), "NFT contract not in allow-list");
        nftState.treasury.push(NFT(nftAddr, tokenId));
    }


    // ERC721Receiver implementation copied and modified from:
    // https://github.com/GustasKlisauskas/ERC721Receiver/blob/master/ERC721Receiver.sol
    function onERC721Received(address, address, uint256 tokenId, bytes calldata) public pure returns(bytes4) {
        return this.onERC721Received.selector;
    }

}

File 2 of 13 : 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 3 of 13 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 4 of 13 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "IERC165.sol";

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

File 5 of 13 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

File 6 of 13 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

File 7 of 13 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 8 of 13 : ILSSVMPairFactoryLike.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;

interface ILSSVMPairFactoryLike {
    enum PairVariant {
        ENUMERABLE_ETH,
        MISSING_ENUMERABLE_ETH,
        ENUMERABLE_ERC20,
        MISSING_ENUMERABLE_ERC20
    }

    function protocolFeeMultiplier() external view returns (uint256);

    function protocolFeeRecipient() external view returns (address payable);

    function callAllowed(address target) external view returns (bool);
    /*
    function routerStatus(LSSVMRouter router)
        external
        view
        returns (bool allowed, bool wasEverAllowed);
    */

    function isPair(address potentialPair, PairVariant variant)
        external
        view
        returns (bool);
}

File 9 of 13 : LSSVMPair.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.10;

import {IERC721} from "IERC721.sol";
import {ILSSVMPairFactoryLike} from "ILSSVMPairFactoryLike.sol";

contract CurveErrorCodes {
    enum Error {
        OK, // No error
        INVALID_NUMITEMS, // The numItem value is 0
        SPOT_PRICE_OVERFLOW // The updated spot price doesn't fit into 128 bits
    }
}

interface LSSVMPair {

    enum PoolType {
        TOKEN,
        NFT,
        TRADE
    }

    function factory() external pure returns (ILSSVMPairFactoryLike);
    
    function nft() external pure returns (IERC721);
    
    function poolType() external pure returns (PoolType);
    
    function getBuyNFTQuote(uint256 numNFTs) external view returns (
            CurveErrorCodes.Error error,
            uint256 newSpotPrice,
            uint256 newDelta,
            uint256 inputAmount,
            uint256 protocolFee
        );

    function getSellNFTQuote(uint256 numNFTs) external view returns (
            CurveErrorCodes.Error error,
            uint256 newSpotPrice,
            uint256 newDelta,
            uint256 outputAmount,
            uint256 protocolFee
        );

      /**
        @notice Sends token to the pair in exchange for any `numNFTs` NFTs
        @dev To compute the amount of token to send, call bondingCurve.getBuyInfo.
        This swap function is meant for users who are ID agnostic
        @param numNFTs The number of NFTs to purchase
        @param maxExpectedTokenInput The maximum acceptable cost from the sender. If the actual
        amount is greater than this value, the transaction will be reverted.
        @param nftRecipient The recipient of the NFTs
        @param isRouter True if calling from LSSVMRouter, false otherwise. Not used for
        ETH pairs.
        @param routerCaller If isRouter is true, ERC20 tokens will be transferred from this address. Not used for
        ETH pairs.
        @return inputAmount The amount of token used for purchase
     */
    function swapTokenForAnyNFTs(
        uint256 numNFTs,
        uint256 maxExpectedTokenInput,
        address nftRecipient,
        bool isRouter,
        address routerCaller
    ) external payable  returns (uint256 inputAmount);

     function swapNFTsForToken(
        uint256[] calldata nftIds,
        uint256 minExpectedTokenOutput,
        address payable tokenRecipient,
        bool isRouter,
        address routerCaller
    ) external returns (uint256 outputAmount);

    function getAllHeldIds() external view returns (uint256[] memory);

    function owner() external view returns (address);
}

File 10 of 13 : UniswapV2.sol
pragma solidity ^0.8.7;

interface IUniswapV2Factory {
        event PairCreated(address indexed token0, address indexed token1, address pair, uint);

        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);

        function getPair(address tokenA, address tokenB) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);

        function createPair(address tokenA, address tokenB) external returns (address pair);

        function setFeeTo(address) external;
        function setFeeToSetter(address) external;
    } 

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

File 11 of 13 : ISudoGatePoolSource.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.16;

interface ISudoGatePoolSource {
    // base interface that just tracks a collection of SudoSwap pools 
    function pools(address, uint256) external view returns (address);
    function knownPool(address) external view returns (bool);
    function registerPool(address sudoswapPool) external returns (bool);
}

File 12 of 13 : ISudoGate02.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.16;

import {ISudoGate01} from "ISudoGate01.sol";

interface ISudoGate02 is ISudoGate01 { 
    // v2 API extends v1 with selling
    function sellQuote(address nft) external view returns (uint256 bestPrice, address bestPool);
    function sellQuoteWithFees(address nft) external view returns (uint256 bestPrice, address bestPool);
    
    function sell(address nft, uint256 tokenId) external returns (bool success, uint256 priceInWei, uint256 feesInWei);
    function sellToPool(address nft, uint256 tokenId, address sudoswapPool, uint256 minPrice) external returns (uint256 priceInWei, uint256 feesInWei);
}

File 13 of 13 : ISudoGate01.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.16;

import {ISudoGatePoolSource} from "ISudoGatePoolSource.sol";

interface ISudoGate01 is ISudoGatePoolSource { 
    // In addition to ISudoGatePoolSource's tracking of pools, the v1 API allows buying
    function buyQuote(address nft) external view returns (uint256 bestPrice, address bestPool);
    function buyQuoteWithFees(address nft) external view returns (uint256 bestPrice, address bestPool);
    function buyFromPool(address pool) external payable returns (uint256 tokenID);
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "libraries": {
    "SudoRug2.sol": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"BoughtNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rugger","type":"address"}],"name":"FailedToRug","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bot","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"FellInHoney","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rugger","type":"address"},{"indexed":false,"internalType":"uint256","name":"numTokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ethInWei","type":"uint256"}],"name":"RugAlarm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"SentNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"SoldNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"sudoswapPool","type":"address"}],"name":"ADD_NFT_CONTRACT_AND_REGISTER_POOL","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"ADD_NFT_CONTRACT_TO_BUY_LIST","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"AIRDROP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"PUSH_THE_RUG_BUTTON","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sudoswapPool","type":"address"}],"name":"REGISTER_SUDOSWAP_POOL","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"SUDOGATE_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actionFrequencyBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actionFrequencySell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actionFrequencySend","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"addAMM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"addNFTContractToAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"addNFTContractToBuyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"buyRandomNFT","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"buyingNFTContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"costToAddNFTContractInETH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"costToAddNFTContractInTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentState","outputs":[{"internalType":"enum State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"honeypotDurationBlocks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"inBotQueue","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAMM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isEligible","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isSpecialAddress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sudoswapPool","type":"address"}],"name":"isSudoSwapPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"knownNFTContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRugTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPercentReapprioration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRugFractionOfUniswapPerThousand","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minEligibleTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minMinutesBetweenRugs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minRugFractionOfUniswapPerThousand","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minutesSinceLastBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minutesSinceLastRug","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numNFTContractsInBuyList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numNFTsInTreasury","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"probCommunism","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"removeAMM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"removeNFTContractFromAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftContract","type":"address"}],"name":"removeNFTContractFromBuyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddr","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"rescueNFT_AddToTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rugSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sandwichTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sellRandomNFT","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"sellPrice","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sellTax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sendRandomNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setActionFrequencyBuy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setActionFrequencySell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setActionFrequencySend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setBot","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tax","type":"uint256"}],"name":"setBuyTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"ethInWei","type":"uint256"}],"name":"setCostToAddNFTContractInETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"setCostToAddNFTContractInTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"setCostToRugInTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"costWei","type":"uint256"}],"name":"setMaxBuyPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setMaxPercentOfTotalSupplyPerRug","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setMaxPercentReapprioration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"impactPerThousand","type":"uint256"}],"name":"setMaxRugPriceImpactPerThousand","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numTokens","type":"uint256"}],"name":"setMinEligibleTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"m","type":"uint256"}],"name":"setMinMinutesBetweenRugs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setMinPricePercentIncreaseToSellNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"impactPerThousand","type":"uint256"}],"name":"setMinRugPriceImpactPerThousand","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"priceWei","type":"uint256"}],"name":"setMinSellPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percent","type":"uint256"}],"name":"setProbCommunism","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tax","type":"uint256"}],"name":"setSandwichTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tax","type":"uint256"}],"name":"setSellTax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sudogate","type":"address"}],"name":"setSudoGateAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV2Pair_WETH","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV2Router","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052600380546001600160a01b03191673dd2aae657516341ba00ef80f09e357bd02500731179055620000386009600a620006dd565b6200004790620f4240620006f5565b6015556729a2241af62c0000601655620000646009600a620006dd565b6200007390620186a0620006f5565b6017556064601855670de0b6b3a764000060195567016345785d8a0000601a556000601b819055601c556028601d55620000b06009600a620006dd565b620000bd906000620006f5565b601e556000601f556002602055603c6021556001602255603c602355600a602455600360255560326026556005602755602d602855348015620000ff57600080fd5b50600a80546001600160a01b031916331781556000906200012390600990620006dd565b62000133906305f5e100620006f5565b6000818155600a80546001600160a01b039081168352600160205260408084208590559154915193945016917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906200018f9085815260200190565b60405180910390a36000737a250d5630b4cf539739df2c5dacb4c659f2488d90506000816001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000217919062000717565b90506000826001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200025a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000280919062000717565b6040516364e329cb60e11b81523060048201526001600160a01b03848116602483015291925060009183169063c9c65396906044016020604051808303816000875af1158015620002d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fb919062000717565b600b80546001600160a01b038781166001600160a01b03199283168117909355600c8054918516919092161790556000908152600f60205260409020805460ff1916600117905590506200036d816001600160a01b03166000908152600f60205260409020805460ff19166001179055565b6200038c73ef1a89cbfabe59397ffda11fc5df293e9bc5db9062000432565b620003ab739185a69970a150ec9d0dea6f18e62f40db9e94d262000432565b620003ca73e90d8fb7b79c8930b5c8891e61c298b412a6e81a62000432565b620003e9735135db8fdfd882543aa77492a4297137c9b2722362000432565b6200040873f210d5d9dcf958803c286a6f8e278e4ac78e136e62000432565b62000427735bdf397bb2912859dbd8011f320a222f79a28d2e62000432565b505050505062000742565b6200043d816200044b565b6200044881620004d3565b50565b6001600160a01b0381166000908152602d602052604090205460ff166200044857602b805460018181019092557f11c44e4875b74d31ff9fd779bf2566af7bd15b87fc985d01f5094b89e3669e4f0180546001600160a01b0384166001600160a01b031990911681179091556000908152602d60205260409020805460ff1916909117905550565b6001600160a01b0381166000908152602d602052604090205460ff16620005405760405162461bcd60e51b815260206004820152601e60248201527f4e465420636f6e7472616374206e6f7420696e20616c6c6f77206c6973740000604482015260640160405180910390fd5b6001600160a01b0381166000908152602e602052604090205460ff166200044857602c805460018181019092557f7416c943b4a09859521022fd2e90eac0dd9026dad28fa317782a135f28a860910180546001600160a01b0384166001600160a01b031990911681179091556000908152602e60205260409020805460ff1916909117905550565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200061f578160001904821115620006035762000603620005c8565b808516156200061157918102915b93841c9390800290620005e3565b509250929050565b6000826200063857506001620006d7565b816200064757506000620006d7565b81600181146200066057600281146200066b576200068b565b6001915050620006d7565b60ff8411156200067f576200067f620005c8565b50506001821b620006d7565b5060208310610133831016604e8410600b8410161715620006b0575081810a620006d7565b620006bc8383620005de565b8060001904821115620006d357620006d3620005c8565b0290505b92915050565b6000620006ee60ff84168362000627565b9392505050565b6000816000190483118215151615620007125762000712620005c8565b500290565b6000602082840312156200072a57600080fd5b81516001600160a01b0381168114620006ee57600080fd5b615fad80620007526000396000f3fe6080604052600436106104a35760003560e01c80637f399bcb11610260578063b8c1825f11610144578063dc1052e2116100c1578063e98491ce11610085578063e98491ce14610e86578063ea336c7414610ea6578063eb4072db14610ebb578063f54d474414610ed0578063f9b12b0714610ef0578063fa656f4a14610f1057600080fd5b8063dc1052e214610df1578063dd62ed3e14610e11578063e26467be14610e31578063e33ad33c14610e51578063e879780214610e7157600080fd5b8063c5296a0f11610108578063c5296a0f14610d4b578063cc1776d314610d85578063d3428cfd14610d9b578063d46b6a3014610db1578063d66bbec714610dd157600080fd5b8063b8c1825f14610cbf578063bed7a20614610cdf578063beecd38b14610cff578063c1bf048a14610d15578063c241417814610d3557600080fd5b80639a2421eb116101dd578063a9059cbb116101a1578063a9059cbb14610bf9578063ac7f90d514610c19578063adce4cbf14610c39578063af99cc4f14610c59578063b0e9895d14610c6f578063b72995c814610c8f57600080fd5b80639a2421eb14610b4a5780639e21d7db14610b6a578063a3c7783b14610ba3578063a403fbd114610bb9578063a4a9860514610bd957600080fd5b80638cd09d50116102245780638cd09d5014610aae5780638ce4832414610ace5780638da5cb5b14610ae45780639182e0b114610b0457806395d89b4114610b1a57600080fd5b80637f399bcb14610a0c578063820941e214610a2a5780638253747e14610a3f57806388399f4d14610a5f578063896c034914610a7557600080fd5b80633bbac579116103875780635db231621161030457806366e305fd116102c857806366e305fd1461094857806370a082311461098157806370b65246146109a15780637160598d146109b657806373845954146109cc5780637f22bed8146109ec57600080fd5b80635db23162146108b25780635dcb14d2146108d25780636479255d146108f2578063651f8c851461091257806365c3d0511461092857600080fd5b80635098d5fb1161034b5780635098d5fb1461082c57806351c6590a1461085857806352a00fbb1461086b57806354fd4d501461087e5780635cc6780e1461089257600080fd5b80633bbac579146107905780633edb223f146107c057806340fb5698146107e05780634bd7ccfb146107f65780634f7041a51461081657600080fd5b8063154dca2c116104205780632137ede9116103e45780632137ede9146106d457806323b872dd146106e9578063313ce56714610709578063342aa8b51461073057806336ed48c01461075057806338a55f0e1461077057600080fd5b8063154dca2c146106445780631694505e1461065757806318160ddd146106895780631ab82d6d1461069e5780631f632cb2146106be57600080fd5b80630c3f6acf116104675780630c3f6acf146105885780630d326463146105aa5780631307d65a146105bf57806313af4035146105df578063150b7a02146105ff57600080fd5b8063052d1d48146104af57806306fdde03146104d7578063095ea7b3146105165780630ae96731146105465780630b13ace21461056857600080fd5b366104aa57005b600080fd5b3480156104bb57600080fd5b506104c4610f26565b6040519081526020015b60405180910390f35b3480156104e357600080fd5b5060408051808201909152600d81526c29bab237a93ab3902a37b5b2b760991b60208201525b6040516104ce91906157fe565b34801561052257600080fd5b50610536610531366004615846565b610f36565b60405190151581526020016104ce565b34801561055257600080fd5b50610566610561366004615872565b610f4d565b005b34801561057457600080fd5b5061053661058336600461588b565b611024565b34801561059457600080fd5b5061059d611077565b6040516104ce91906158be565b3480156105b657600080fd5b506104c4611081565b3480156105cb57600080fd5b506105366105da36600461588b565b6110b8565b3480156105eb57600080fd5b506105666105fa36600461588b565b611141565b34801561060b57600080fd5b5061062b61061a3660046158d8565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016104ce565b61053661065236600461588b565b6111c9565b34801561066357600080fd5b50600b546001600160a01b03165b6040516001600160a01b0390911681526020016104ce565b34801561069557600080fd5b506000546104c4565b3480156106aa57600080fd5b506105666106b9366004615872565b61139d565b3480156106ca57600080fd5b506104c4601f5481565b3480156106e057600080fd5b5061053661140e565b3480156106f557600080fd5b50610536610704366004615977565b6115f0565b34801561071557600080fd5b5061071e600981565b60405160ff90911681526020016104ce565b34801561073c57600080fd5b5061053661074b3660046159c6565b611612565b34801561075c57600080fd5b5061056661076b366004615872565b6116bc565b34801561077c57600080fd5b5061056661078b366004615846565b611742565b34801561079c57600080fd5b506105366107ab36600461588b565b60046020526000908152604090205460ff1681565b3480156107cc57600080fd5b506105666107db366004615872565b6118df565b3480156107ec57600080fd5b506104c460285481565b34801561080257600080fd5b50610566610811366004615872565b611964565b34801561082257600080fd5b506104c4601c5481565b34801561083857600080fd5b506108416119e9565b6040805192151583526020830191909152016104ce565b610566610866366004615872565b611a28565b61053661087936600461588b565b611d2a565b34801561088a57600080fd5b5060026104c4565b34801561089e57600080fd5b506105666108ad366004615846565b611d9b565b3480156108be57600080fd5b506105666108cd366004615872565b611fdc565b3480156108de57600080fd5b506105666108ed366004615872565b6120ab565b3480156108fe57600080fd5b5061053661090d36600461588b565b612130565b34801561091e57600080fd5b506104c460265481565b34801561093457600080fd5b50610566610943366004615872565b61222c565b34801561095457600080fd5b5061053661096336600461588b565b6001600160a01b031660009081526009602052604090205460ff1690565b34801561098d57600080fd5b506104c461099c36600461588b565b61230a565b3480156109ad57600080fd5b506104c4600281565b3480156109c257600080fd5b506104c460215481565b3480156109d857600080fd5b50600354610671906001600160a01b031681565b3480156109f857600080fd5b50610566610a07366004615872565b612315565b348015610a1857600080fd5b50600c546001600160a01b0316610671565b348015610a3657600080fd5b50602a546104c4565b348015610a4b57600080fd5b50610566610a5a36600461588b565b612375565b348015610a6b57600080fd5b506104c4601d5481565b348015610a8157600080fd5b50610536610a9036600461588b565b6001600160a01b03166000908152602e602052604090205460ff1690565b348015610aba57600080fd5b50610566610ac9366004615872565b612407565b348015610ada57600080fd5b506104c460275481565b348015610af057600080fd5b50600a54610671906001600160a01b031681565b348015610b1057600080fd5b506104c460175481565b348015610b2657600080fd5b506040805180820190915260078152665355444f52554760c81b6020820152610509565b348015610b5657600080fd5b50610566610b65366004615872565b612474565b348015610b7657600080fd5b50610536610b8536600461588b565b6001600160a01b03166000908152602d602052604090205460ff1690565b348015610baf57600080fd5b506104c460165481565b348015610bc557600080fd5b50610566610bd4366004615872565b6124e2565b348015610be557600080fd5b50610566610bf4366004615872565b6125c4565b348015610c0557600080fd5b50610536610c14366004615846565b612692565b348015610c2557600080fd5b50610536610c3436600461588b565b61269f565b348015610c4557600080fd5b50610536610c5436600461588b565b6127d7565b348015610c6557600080fd5b506104c460255481565b348015610c7b57600080fd5b50610566610c8a366004615ad5565b61285c565b348015610c9b57600080fd5b50610536610caa36600461588b565b60056020526000908152604090205460ff1681565b348015610ccb57600080fd5b50610566610cda366004615872565b612b65565b348015610ceb57600080fd5b50610566610cfa366004615872565b612beb565b348015610d0b57600080fd5b506104c460225481565b348015610d2157600080fd5b50610566610d30366004615872565b612c54565b348015610d4157600080fd5b506104c460155481565b348015610d5757600080fd5b50610d60612cc5565b6040805193151584526001600160a01b039092166020840152908201526060016104ce565b348015610d9157600080fd5b506104c4601b5481565b348015610da757600080fd5b506104c460235481565b348015610dbd57600080fd5b50610536610dcc36600461588b565b612d39565b348015610ddd57600080fd5b50610566610dec366004615872565b612d44565b348015610dfd57600080fd5b50610566610e0c366004615872565b612da9565b348015610e1d57600080fd5b506104c4610e2c366004615b97565b612e5e565b348015610e3d57600080fd5b50610566610e4c36600461588b565b612e8b565b348015610e5d57600080fd5b50610566610e6c36600461588b565b612f06565b348015610e7d57600080fd5b506104c4612f86565b348015610e9257600080fd5b50610536610ea136600461588b565b612fa8565b348015610eb257600080fd5b50610536613024565b348015610ec757600080fd5b50602c546104c4565b348015610edc57600080fd5b50610536610eeb36600461588b565b613059565b348015610efc57600080fd5b50610566610f0b366004615872565b6130db565b348015610f1c57600080fd5b506104c460245481565b6000610f3130613196565b905090565b6000610f433384846131b1565b5060015b92915050565b600a546001600160a01b03163314610f805760405162461bcd60e51b8152600401610f7790615bc5565b60405180910390fd5b6103e8811115610fcd5760405162461bcd60e51b8152602060048201526018602482015277056616c75652063616e6e6f742065786365656420313030360441b6044820152606401610f77565b80602254111561101f5760405162461bcd60e51b815260206004820181905260248201527f4d696e2063616e6e6f742065786365656420657863656564206e6577206d61786044820152606401610f77565b602355565b600061102f82613213565b8061105257506001600160a01b03821660009081526004602052604090205460ff165b80610f475750506001600160a01b031660009081526005602052604090205460ff1690565b6000610f3161327f565b600061108e600d54151590565b156110b257603c61109e600e5490565b6110a89042615c26565b610f319190615c4f565b50600090565b600a546000906001600160a01b031633146111305760405162461bcd60e51b815260206004820152603260248201527f4d757374206265206f776e657220746f2063616c6c2072656d6f76654e4654436044820152711bdb9d1c9858dd119c9bdb509d5e531a5cdd60721b6064820152608401610f77565b611139826132ad565b506001919050565b600a546001600160a01b031633146111a75760405162461bcd60e51b815260206004820152602360248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744f776044820152623732b960e91b6064820152608401610f77565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166000908152602e602052604081205460ff16156112325760405162461bcd60e51b815260206004820152601760248201527f416c726561647920627579696e672074686973206f6e650000000000000000006044820152606401610f77565b6001600160a01b0382166000908152602d602052604090205460ff1661128d5760405162461bcd60e51b815260206004820152601060248201526f139bdd081a5b881dda1a5d195b1a5cdd60821b6044820152606401610f77565b600354600a546001600160a01b0391821691163314611394576015546112b233613196565b101561130e5760405162461bcd60e51b815260206004820152602560248201527f4e6f7420656e6f75676820746f6b656e7320746f20616464204e465420636f6e6044820152641d1c9858dd60da1b6064820152608401610f77565b60165434101561136b5760405162461bcd60e51b815260206004820152602260248201527f4e6f7420656e6f7567682045544820746f20616464204e465420636f6e74726160448201526118dd60f21b6064820152608401610f77565b601554600061137a8280615c26565b90506113873330846133ee565b6113913382613528565b50505b610f4383613584565b600a546001600160a01b0316331461140b5760405162461bcd60e51b815260206004820152603e6024820152600080516020615f5883398151915260448201527f6e507269636550657263656e74496e637265617365546f53656c6c4e465400006064820152608401610f77565b50565b6000611418613673565b6000611422613874565b9050600061142e610f26565b8211156114d35761143d610f26565b6114479083615c26565b90506000611455606461397f565b60245411801591506114d157600061146b6139f2565b90506001600160a01b038116156114cf57600060646114898361230a565b6025546114969190615c63565b6114a09190615c4f565b905060008482106114b157846114b3565b815b90506114c08330836133ee565b6114ca8186615c26565b945050505b505b505b80156114e3576114e33082613ab7565b60006114ee83613b42565b905081156115115761151161150b600c546001600160a01b031690565b83613528565b600c546001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561155757600080fd5b505af115801561156b573d6000803e3d6000fd5b5050508115801591506115bc5742601f55604080518581526020810184905233917f9a5178ff42681b627314726ddac5afb7bf7f43659a3d45fba04e4cac720d0936910160405180910390a26115e8565b60405133907f2c58021a2da7aa3664cfb8e7baa4497f73c94ae0974ce255e30904702935844790600090a25b949350505050565b60006115fd843384613b8a565b611608848484613c39565b5060019392505050565b600a546000906001600160a01b0316331461166f5760405162461bcd60e51b815260206004820152601a60248201527f4f6e6c79206f776e65722063616e2063616c6c20616464426f740000000000006044820152606401610f77565b818015611680575061168083613213565b1561168d57506000610f47565b506001600160a01b0382166000908152600460205260409020805482151560ff19909116179055600192915050565b600a546001600160a01b031633146117305760405162461bcd60e51b815260206004820152603160248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657441636044820152701d1a5bdb919c995c5d595b98de54d95b99607a1b6064820152608401610f77565b61173c60275482613d9d565b50602755565b600a546001600160a01b031633146117a85760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2072657363756044820152631953919560e21b6064820152608401610f77565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa1580156117ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118139190615c82565b6001600160a01b0316146118755760405162461bcd60e51b8152602060048201526024808201527f5375646f527567206973206e6f7420746865206f776e6572206f6620746869736044820152630813919560e21b6064820152608401610f77565b6040516323b872dd60e01b8152306004820152336024820152604481018290526001600160a01b038316906323b872dd90606401600060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050505050565b600a546001600160a01b0316331461195f5760405162461bcd60e51b815260206004820152603760248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201527f7374546f4164644e4654436f6e7472616374496e4554480000000000000000006064820152608401610f77565b601655565b600a546001600160a01b031633146119e45760405162461bcd60e51b815260206004820152603a60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201527f7374546f4164644e4654436f6e7472616374496e546f6b656e730000000000006064820152608401610f77565b601555565b600a5460009081906001600160a01b03163314611a185760405162461bcd60e51b8152600401610f7790615c9f565b611a20613ea2565b915091509091565b600a546001600160a01b03163314611a825760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722063616e2063616c6c206164644c69717569646974796044820152606401610f77565b60008111611ad25760405162461bcd60e51b815260206004820152601860248201527f4e6f20746f6b656e7320666f72206c69717569646974792100000000000000006044820152606401610f77565b60003411611b1a5760405162461bcd60e51b81526020600482015260156024820152744e6f2045544820666f72206c69717569646974792160581b6044820152606401610f77565b600b54600c546001600160a01b039182169116611b38333085613c39565b611b433083856131b1565b6001600160a01b03821663f305d719343086808333611b6342600f615ce0565b60405160e089901b6001600160e01b03191681526001600160a01b039687166004820152602481019590955260448501939093526064840191909152909216608482015260a481019190915260c40160606040518083038185885af1158015611bd0573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611bf59190615cf3565b50505034826001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5b9190615c82565b6040516370a0823160e01b81526001600160a01b03848116600483015291909116906370a0823190602401602060405180830381865afa158015611ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc79190615d21565b1015611d215760405162461bcd60e51b815260206004820152602360248201527f455448206469646e27742067657420746f20746865207061697220636f6e74726044820152621858dd60ea1b6064820152608401610f77565b505043600d5550565b6000611d358261269f565b50610f43826001600160a01b03166347ccca026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d77573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106529190615c82565b600a546001600160a01b03163314611e105760405162461bcd60e51b815260206004820152603260248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207265736375604482015271654e46545f416464546f547265617375727960701b6064820152608401610f77565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa158015611e57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7b9190615c82565b6001600160a01b031614611edf5760405162461bcd60e51b815260206004820152602560248201527f5375646f47617465206973206e6f7420746865206f776e6572206f66207468696044820152641cc813919560da1b6064820152608401610f77565b6001600160a01b0382166000908152602d602052604090205460ff16611f475760405162461bcd60e51b815260206004820152601e60248201527f4e465420636f6e7472616374206e6f7420696e20616c6c6f772d6c69737400006044820152606401610f77565b604080518082019091526001600160a01b03928316815260208101918252602a805460018101825560009190915290517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2600290920291820180546001600160a01b0319169190941617909255517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390910155565b600a546001600160a01b031633146120555760405162461bcd60e51b815260206004820152603660248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d616044820152753c2832b931b2b73a2932b0b8383934b7b930ba34b7b760511b6064820152608401610f77565b60648111156120a65760405162461bcd60e51b815260206004820152601860248201527f56616c75652063616e6e6f7420657863656564203130302500000000000000006044820152606401610f77565b602455565b600a546001600160a01b0316331461211e5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574416360448201526f74696f6e4672657175656e637942757960801b6064820152608401610f77565b61212a60265482613d9d565b50602655565b6040516308f25a8f60e01b815260009073b16c1342e617a5b6e4b631eb114483fdb289c0a49081906308f25a8f9061216e9086908690600401615d3a565b602060405180830381865afa15801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121af9190615d67565b8061222557506040516308f25a8f60e01b81526001600160a01b038216906308f25a8f906121e4908690600190600401615d3a565b602060405180830381865afa158015612201573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122259190615d67565b9392505050565b600a546001600160a01b0316331461229e5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201526e7374546f527567496e546f6b656e7360881b6064820152608401610f77565b600054601e5411156123055760405162461bcd60e51b815260206004820152602a60248201527f43616e277420636861726765206d6f7265207468616e20616c6c206578697374604482015269696e6720746f6b656e7360b01b6064820152608401610f77565b601e55565b6000610f4782613196565b600a546001600160a01b031633146123705760405162461bcd60e51b815260206004820152602a6024820152600080516020615f588339815191526044820152696e53656c6c507269636560b01b6064820152608401610f77565b601a55565b600a546001600160a01b031633146123e55760405162461bcd60e51b815260206004820152602d60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574537560448201526c646f476174654164647265737360981b6064820152608401610f77565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b600a546001600160a01b0316331461246f5760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657453656044820152640d8d8a8c2f60db1b6064820152608401610f77565b601b55565b600a546001600160a01b031633146120555760405162461bcd60e51b815260206004820152602b60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574507260448201526a6f62436f6d6d756e69736d60a81b6064820152608401610f77565b600a546001600160a01b031633146125625760405162461bcd60e51b815260206004820152603b60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d6160448201527f7850657263656e744f66546f74616c537570706c7950657252756700000000006064820152608401610f77565b60648111156125bf5760405162461bcd60e51b8152602060048201526024808201527f50657263656e74206f6620737570706c792063616e6e6f7420657863656564206044820152633130302560e01b6064820152608401610f77565b602055565b600a546001600160a01b031633146125ee5760405162461bcd60e51b8152600401610f7790615bc5565b6103e881111561263b5760405162461bcd60e51b8152602060048201526018602482015277056616c75652063616e6e6f742065786365656420313030360441b6044820152606401610f77565b60235481111561268d5760405162461bcd60e51b815260206004820181905260248201527f4e6577206d696e2063616e6e6f742065786365656420657863656564206d61786044820152606401610f77565b602255565b6000610f43338484613c39565b60006126aa82612130565b6126ec5760405162461bcd60e51b8152602060048201526013602482015272139bdd0818481cdd591bdcddd85c081c1bdbdb606a1b6044820152606401610f77565b6003546040516366fe44d560e11b81526001600160a01b0384811660048301526000921690819063cdfc89aa90602401602060405180830381865afa158015612739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275d9190615d67565b6127d0576040516355ec842360e11b81526001600160a01b03858116600483015282169063abd90846906024016020604051808303816000875af11580156127a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cd9190615d67565b91505b5092915050565b600a546000906001600160a01b031633146128345760405162461bcd60e51b815260206004820152601b60248201527f43616e206f6e6c792062652063616c6c6564206279206f776e657200000000006044820152606401610f77565b611139826001600160a01b03166000908152600f60205260409020805460ff19166001179055565b80518251146128c65760405162461bcd60e51b815260206004820152603060248201527f41646472657373657320616e6420746f6b656e2076616c756573206d7573742060448201526f0d0c2ecca40e6c2daca40d8cadccee8d60831b6064820152608401610f77565b600a546001600160a01b03163314806128f7575060026128e461327f565b60028111156128f5576128f56158a8565b145b6129435760405162461bcd60e51b815260206004820152601760248201527f596f752063616e27742063616c6c2074686973207965740000000000000000006044820152606401610f77565b3360009081526004602052604090205460ff1615801561297357503360009081526005602052604090205460ff16155b6129bf5760405162461bcd60e51b815260206004820152601760248201527f536f7272792c206e6f7420626f747320616c6c6f7765640000000000000000006044820152606401610f77565b600080808080805b8751811015612ace578781815181106129e2576129e2615d84565b602002602001015191508681815181106129fe576129fe615d84565b602002602001015194508486612a149190615ce0565b6001600160a01b0383166000908152600160205260409020549096509350612a3c8585615ce0565b6001600160a01b03831660008181526001602052604090819020839055519194509033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612a8f9089815260200190565b60405180910390a360175483118015612aae5750612aac82611024565b155b15612abc57612abc826141af565b80612ac681615d9a565b9150506129c7565b5033600090815260016020526040902054851115612b2e5760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320666f722061697264726f700000006044820152606401610f77565b3360009081526001602052604081208054879290612b4d908490615c26565b90915550612b5c905033614222565b50505050505050565b600a546001600160a01b03163314612bd95760405162461bcd60e51b815260206004820152603160248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657441636044820152701d1a5bdb919c995c5d595b98de54d95b1b607a1b6064820152608401610f77565b612be560285482613d9d565b50602855565b600a546001600160a01b03163314612c4f5760405162461bcd60e51b81526020600482015260336024820152600080516020615f588339815191526044820152726e4d696e757465734265747765656e5275677360681b6064820152608401610f77565b602155565b600a546001600160a01b03163314612cc05760405162461bcd60e51b815260206004820152602960248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d6160448201526878427579507269636560b81b6064820152608401610f77565b601955565b600a54600090819081906001600160a01b03163314612d265760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722063616e2063616c6c2062757952616e646f6d4e46546044820152606401610f77565b612d2e614296565b925092509250909192565b6000610f47826142cc565b600a546001600160a01b03163314612da45760405162461bcd60e51b815260206004820152602f6024820152600080516020615f5883398151915260448201526e6e456c696769626c65546f6b656e7360881b6064820152608401610f77565b601755565b600a546001600160a01b03163314612e0f5760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657442756044820152630f2a8c2f60e31b6064820152608401610f77565b6064811115612e595760405162461bcd60e51b81526020600482015260166024820152755461782063616e6e6f7420657863656564203130302560501b6044820152606401610f77565b601c55565b6001600160a01b038083166000908152600260209081526040808320938516835292905290812054612225565b600a546001600160a01b03163314612efd5760405162461bcd60e51b815260206004820152602f60248201527f4d757374206265206f776e657220746f2063616c6c206164644e4654436f6e7460448201526e1c9858dd151bd05b1b1bddd31a5cdd608a1b6064820152608401610f77565b61140b816142ea565b600a546001600160a01b03163314612f7d5760405162461bcd60e51b815260206004820152603460248201527f4d757374206265206f776e657220746f2063616c6c2072656d6f76654e4654436044820152731bdb9d1c9858dd119c9bdb505b1b1bddd31a5cdd60621b6064820152608401610f77565b61140b81614371565b6000601f54600003612f985750600090565b603c601f54426110a89190615c26565b600a546000906001600160a01b0316331461301b5760405162461bcd60e51b815260206004820152602d60248201527f4d757374206265206f776e657220746f2063616c6c206164644e4654436f6e7460448201526c1c9858dd151bd09d5e531a5cdd609a1b6064820152608401610f77565b61113982613584565b600a546000906001600160a01b031633146130515760405162461bcd60e51b8152600401610f7790615c9f565b610f3161448b565b600a546000906001600160a01b031633146130b65760405162461bcd60e51b815260206004820152601b60248201527f43616e206f6e6c792062652063616c6c6564206279206f776e657200000000006044820152606401610f77565b611139826001600160a01b03166000908152600f60205260409020805460ff19169055565b600a546001600160a01b031633146131475760405162461bcd60e51b815260206004820152602960248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657453616044820152680dcc8eed2c6d0a8c2f60bb1b6064820152608401610f77565b60648111156131915760405162461bcd60e51b81526020600482015260166024820152755461782063616e6e6f7420657863656564203130302560501b6044820152606401610f77565b601d55565b6001600160a01b031660009081526001602052604090205490565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006001600160a01b03821630148061323357506001600160a01b038216155b8061324b5750600a546001600160a01b038381169116145b8061325a575061325a826142cc565b80610f475750506001600160a01b03166000908152602d602052604090205460ff1690565b600061328c600d54151590565b156110b257600261329b614643565b10156132a75750600190565b50600290565b6001600160a01b0381166000908152602e602052604090205460ff161561140b576001600160a01b0381166000908152602e60205260408120805460ff19169055602c545b8082101561334457826001600160a01b0316602a600201838154811061331a5761331a615d84565b6000918252602090912001546001600160a01b0316146133445761333d82615d9a565b91506132f2565b602c613351600183615c26565b8154811061336157613361615d84565b600091825260209091200154602c80546001600160a01b03909216918490811061338d5761338d615d84565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055602c8054806133c7576133c7615db3565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b6001600160a01b03831660009081526001602052604090205481111561344d5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610f77565b6001600160a01b03831660009081526001602052604081208054839290613475908490615c26565b9091555050600c546001600160a01b038481169116146134985761349883614222565b6001600160a01b038216600090815260016020526040812080548392906134c0908490615ce0565b9091555050600c546001600160a01b038381169116146134e3576134e382614222565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161320691815260200190565b8061353283613196565b10156135745760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610f77565b613580826000836133ee565b5050565b6001600160a01b0381166000908152602d602052604090205460ff166135ec5760405162461bcd60e51b815260206004820152601e60248201527f4e465420636f6e7472616374206e6f7420696e20616c6c6f77206c69737400006044820152606401610f77565b6001600160a01b0381166000908152602e602052604090205460ff1661140b57602c805460018181019092557f7416c943b4a09859521022fd2e90eac0dd9026dad28fa317782a135f28a860910180546001600160a01b0384166001600160a01b031990911681179091556000908152602e60205260409020805460ff1916909117905550565b600261367d611077565b600281111561368e5761368e6158a8565b146136cc5760405162461bcd60e51b815260206004820152600e60248201526d43616e277420727567207965742160901b6044820152606401610f77565b601f54600e54116137175760405162461bcd60e51b81526020600482015260156024820152744d75737420627579206265747765656e207275677360581b6044820152606401610f77565b601f54156137785760215461372a612f86565b10156137785760405162461bcd60e51b815260206004820152601860248201527f486f6c6420796f757220686f72736573207275676765727300000000000000006044820152606401610f77565b600a546001600160a01b031633146137e9573360009081526009602052604090205460ff166137e95760405162461bcd60e51b815260206004820152601760248201527f527567676572206d75737420626520656c696769626c650000000000000000006044820152606401610f77565b600a546001600160a01b0316331480159061380657506000601e54115b1561387257601e546138173361230a565b10156138655760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320666f722072756767696e670000006044820152606401610f77565b6138723330601e546133ee565b565b602254602354600091908110156138b05760006022546023546138979190615c26565b90506138a28161397f565b6138ac9083615ce0565b9150505b6103e88111156139155760405162461bcd60e51b815260206004820152602a60248201527f52616e646f6d20707269636520696d706163742073686f756c64206e6f7420656044820152697863656564203130302560b01b6064820152608401610f77565b600061392c61099c600c546001600160a01b031690565b90506103e861393b8383615c63565b6139459190615c4f565b92506000606461395460005490565b6020546139619190615c63565b61396b9190615c4f565b905080841115613979578093505b50505090565b60008082116139df5760405162461bcd60e51b815260206004820152602660248201527f43616e6e6f742067656e65726174652072616e646f6d206e756d626572206d6f604482015265064756c6f20360d41b6064820152608401610f77565b816139e8614653565b610f479190615dc9565b6000806139fd6146c0565b90506000613a096146c0565b90506000613a156146c0565b905060006001600160a01b03841615613a3657613a3184613196565b613a39565b60005b905060006001600160a01b03841615613a5a57613a5584613196565b613a5d565b60005b905060006001600160a01b03841615613a7e57613a7984613196565b613a81565b60005b9050818311613a9d57808211613a975783613aac565b84613aac565b808311613aaa5783613aac565b855b965050505050505090565b80600080016000828254613acb9190615ce0565b90915550506001600160a01b03821660009081526001602052604081208054839290613af8908490615ce0565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b600c54600090600160a01b900460ff16613b85576000613b60610f26565b905082811015613b705780613b72565b825b92508215613b835761222583614702565b505b919050565b6001600160a01b03808416600090815260026020908152604080832093861683529290522054811115613bf85760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b6044820152606401610f77565b6001600160a01b03808416600090815260026020908152604080832093861683529290529081208054839290613c2f908490615c26565b9091555050505050565b6001600160a01b038316301480613c5857506001600160a01b03821630145b80613c705750600a546001600160a01b038481169116145b15613c8557613c808383836133ee565b505050565b600d54613cea5760405162461bcd60e51b815260206004820152602d60248201527f43616e6e6f74207472616e7366657220746f6b656e73206265666f7265206c6960448201526c1c5d5a591a5d1e481859191959609a1b6064820152608401610f77565b600c54600160a01b900460ff1615613d0757613c808383836133ee565b6001613d1161327f565b6002811115613d2257613d226158a8565b03613d9257613d30836142cc565b15613d8757613d3e82614917565b15613d8757816001600160a01b03167f83efabacf9f7cf6e679b0fd9de0113ad1e05f72b1955dedadf0e01422a52234a82604051613d7e91815260200190565b60405180910390a25b613c808383836133ee565b613c80838383614934565b60006064821115613dfc5760405162461bcd60e51b815260206004820152602360248201527f4e65772070657263656e742076616c75652063616e6e6f74206578636565642060448201526203130360ec1b6064820152608401610f77565b6000602854602754602654613e119190615ce0565b613e1b9190615ce0565b90506000613e298583615c26565b90506000613e378583615ce0565b90506064811115613e995760405162461bcd60e51b815260206004820152602660248201527f436f6d62696e65642070657263656e74616765732063616e6e6f74206578636560448201526506564203130360d41b6064820152608401610f77565b50505092915050565b6000806000613eb0602a5490565b905080156141aa576000613ec38261397f565b90506000602a6000018281548110613edd57613edd615d84565b6000918252602080832060029290920290910180546001600160a01b03908116808552602f845260408086206001850154875290945293839020546003549351636ec9facd60e11b81526004810195909552919450909291169063dd93f59a906024016040805180830381865afa158015613f5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f809190615ddd565b5094508085118015613f945750601a548510155b156141a65760018115613fd1576000613fad8388615c26565b9050600083613fbd836064615c63565b613fc79190615c4f565b6018541115925050505b80156141a457825460018401546040516331a9108f60e11b8152600481019190915230916001600160a01b031690636352211e90602401602060405180830381865afa158015614025573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140499190615c82565b6001600160a01b0316036141a4578254600354600185015460405163095ea7b360e01b81526001600160a01b039283166004820152602481019190915291169063095ea7b390604401600060405180830381600087803b1580156140ac57600080fd5b505af11580156140c0573d6000803e3d6000fd5b505060035485546001870154604051636c197ff560e01b81526001600160a01b039283166004820152602481019190915291169250636c197ff591506044016060604051808303816000875af115801561411e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141429190615e02565b50909750955086156141a45761415784614f3d565b8254600184015460408051918252602082018990526001600160a01b03909216917f3148efce73b39b088f8c1497d8e056a6e8d58e3ffa171525862a6d4238397b90910160405180910390a25b505b5050505b509091565b6001600160a01b03166000818152600960209081526040808320805460ff19166001908117909155600780546008909452918420839055820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319169091179055565b60175461422e82613196565b108061423e575061423e81611024565b1561426d576001600160a01b03811660009081526009602052604090205460ff161561140b5761140b816150b2565b6001600160a01b03811660009081526009602052604090205460ff1661140b5761140b816141af565b60008080806142a4602c5490565b11156142c75760006142b46151bb565b90506142bf8161525c565b509094509150505b909192565b6001600160a01b03166000908152600f602052604090205460ff1690565b6001600160a01b0381166000908152602d602052604090205460ff1661140b57602b805460018181019092557f11c44e4875b74d31ff9fd779bf2566af7bd15b87fc985d01f5094b89e3669e4f0180546001600160a01b0384166001600160a01b031990911681179091556000908152602d60205260409020805460ff1916909117905550565b6001600160a01b0381166000908152602d602052604090205460ff161561140b576001600160a01b0381166000908152602d60205260408120805460ff19169055602b545b8082101561440857826001600160a01b0316602a60010183815481106143de576143de615d84565b6000918252602090912001546001600160a01b0316146144085761440182615d9a565b91506143b6565b602b614415600183615c26565b8154811061442557614425615d84565b600091825260209091200154602b80546001600160a01b03909216918490811061445157614451615d84565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055602b8054806133c7576133c7615db3565b600080614497602a5490565b9050801561463f5760006144a96139f2565b90506144b481611024565b61463d5760006144c38361397f565b90506000602a60000182815481106144dd576144dd615d84565b60009182526020909120600290910201805460018201546040516331a9108f60e11b8152600481019190915291925030916001600160a01b0390911690636352211e90602401602060405180830381865afa158015614540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145649190615c82565b6001600160a01b03160361463157805460018201546040516323b872dd60e01b81523060048201526001600160a01b03868116602483015260448201929092529116906323b872dd90606401600060405180830381600087803b1580156145ca57600080fd5b505af11580156145de573d6000803e3d6000fd5b5050825460018401546040519081526001600160a01b03878116945090911691507f0ab2d5a490c8d5451470363f35341c42582170bbaf5bf4cd96b1afc7304e22ae9060200160405180910390a3600194505b61463a82614f3d565b50505b505b5090565b600d54600090610f319043615c26565b60006001602960008282546146689190615ce0565b90915550506029546040516bffffffffffffffffffffffff193360601b16602082015260348101919091524260548201524460748201526094016040516020818303038152906040528051906020012060001c905090565b600754600090801561463f5760076146d78261397f565b815481106146e7576146e7615d84565b6000918252602090912001546001600160a01b031691505090565b600047821580159061471c57508261471930613196565b10155b156148c557600c805460ff60a01b1916600160a01b179055600b546040805160028082526060820183526001600160a01b0390931692600092602083019080368337019050509050308160008151811061477857614778615d84565b60200260200101906001600160a01b031690816001600160a01b031681525050816001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147fa9190615c82565b8160018151811061480d5761480d615d84565b60200260200101906001600160a01b031690816001600160a01b0316815250506148383083876131b1565b6040516318cbafe560e01b81526001600160a01b038316906318cbafe59061486d908890600090869030904290600401615e39565b6000604051808303816000875af115801561488c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526148b49190810190615eaa565b5050600c805460ff60a01b19169055505b8047101561490d5760405162461bcd60e51b8152602060048201526015602482015274486f7720646964207765206c6f736520455448213f60581b6044820152606401610f77565b6122258147615c26565b60008061492383615511565b90508015610f47576127d032615511565b600261493e61327f565b600281111561494f5761494f6158a8565b146149b55760405162461bcd60e51b815260206004820152603060248201527f53686f756c646e277420726561636820746869732070617468206f6e2061697260448201526f191c9bdc081bdc881a1bdb995e5c1bdd60821b6064820152608401610f77565b6001600160a01b03831660009081526004602052604090205460ff1615614a1e5760405162461bcd60e51b815260206004820152601c60248201527f536f72727920626f742c2063616e2774206c657420796f75206f7574000000006044820152606401610f77565b6000614a29836142cc565b90506000614a36856142cc565b90508080614a415750815b15614b5b578015614a80576001600160a01b0385166000908152601260205260408120805460019290614a75908490615ce0565b90915550614ab59050565b8115614ab5576001600160a01b0384166000908152601260205260408120805460019290614aaf908490615ce0565b90915550505b60065415801590614adf57506001600160a01b03851660009081526005602052604090205460ff16155b8015614b0457506001600160a01b03841660009081526005602052604090205460ff16155b8015614b2957506001600160a01b03851660009081526004602052604090205460ff16155b8015614b4e57506001600160a01b03841660009081526004602052604090205460ff16155b15614b5b57614b5b6155b3565b82600080838015614b9057506001600160a01b038088166000908152601160209081526040808320938c168352929052205443145b8015614bd657506001600160a01b038088166000908152601460209081526040808320938c16835292815282822054601290915291902054600191614bd491615c26565b115b15614c42576000614be688615664565b90508015614c3c5760006064601d5489614c009190615c63565b614c0a9190615c4f565b9050614c17600282615c4f565b614c219085615ce0565b9350614c2e600282615c4f565b614c389084615ce0565b9250505b50614d21565b848015614c7357506001600160a01b038089166000908152601060209081526040808320938b168352929052205443145b8015614cb957506001600160a01b038089166000908152601360209081526040808320938b16835292815282822054601290915291902054600191614cb791615c26565b115b15614d21576000614cc989615664565b90508015614d1f5760006064601d5489614ce39190615c63565b614ced9190615c4f565b9050614cfa600282615c4f565b614d049085615ce0565b9350614d11600282615c4f565b614d1b9084615ce0565b9250505b505b6000614d2d8284615ce0565b905080841015614da55760405162461bcd60e51b815260206004820152603760248201527f43616e27742074616b652061776179206d6f7265207468616e20746865206f7260448201527f6967696e616c206e756d626572206f6620746f6b656e730000000000000000006064820152608401610f77565b6000614db18286615c26565b9050858015614dc257506000601c54115b15614e035760006064601c5483614dd99190615c63565b614de39190615c4f565b9050614def8185615ce0565b9350614dfb8183615c26565b915050614e4f565b868015614e1257506000601b54115b15614e4f5760006064601b5483614e299190615c63565b614e339190615c4f565b9050614e3f8185615ce0565b9350614e4b8183615c26565b9150505b8315614e5f57614e5f8a85613528565b8215614e7057614e708a30856133ee565b8015614e8157614e818a8a836133ee565b614e89615681565b50508515614ee25742600e556001600160a01b03808a166000818152601060209081526040808320948f168084529482528083204390556012825280832054938352601382528083209483529390529190912055614f31565b8615614f31576001600160a01b03808b166000818152601160209081526040808320948e1680845294825280832043905560128252808320549383526014825280832094835293905291909120555b50505050505050505050565b602a54818111614f9d5760405162461bcd60e51b815260206004820152602560248201527f4e465420696e64657820746f2062652072656d6f766564206f7574206f6620626044820152646f756e647360d81b6064820152608401610f77565b6000602a6000018381548110614fb557614fb5615d84565b60009182526020808320600290920290910180546001808301546001600160a01b03909216808652602f85526040808720848852909552938520949094559093509091602a906150059086615c26565b8154811061501557615015615d84565b9060005260206000209060020201602a600001868154811061503957615039615d84565b60009182526020909120825460029092020180546001600160a01b0319166001600160a01b03909216919091178155600191820154910155602a80548061508257615082615db3565b60008281526020812060026000199093019283020180546001600160a01b03191681556001015590555050505050565b6001600160a01b0381166000908152600960205260408120805460ff191690556007546150e190600190615c26565b6001600160a01b0383166000908152600860205260409020549091508181101561518d5760006007600001838154811061511d5761511d615d84565b60009182526020808320909101546001600160a01b0316808352600890915260409091208390556007805491925082918490811061515d5761515d615d84565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b6001600160a01b0383166000908152600860205260409020600019905560078054806133c7576133c7615db3565b6000806151c7602c5490565b116152145760405162461bcd60e51b815260206004820152601860248201527f4e6f204e465420636f6e74726163747320746f206275792100000000000000006044820152606401610f77565b602c8054801561525257816152288261397f565b8154811061523857615238615d84565b6000918252602090912001546001600160a01b0316615255565b60005b9250505090565b600354600090819081906001600160a01b03166152bb5760405162461bcd60e51b815260206004820152601e60248201527f5375646f4761746520616464726573732063616e2774206265207a65726f00006044820152606401610f77565b6003546040516001600160a01b038681166024830152909116906000908190839060440160408051601f198184030181529181526020820180516001600160e01b03166337404c6160e21b179052516153149190615f3b565b6000604051808303816000865af19150503d8060008114615351576040519150601f19603f3d011682016040523d82523d6000602084013e615356565b606091505b5091509150811561550757600080828060200190518101906153789190615ddd565b90925090506001600160a01b0381161580159061539457504782105b80156153a257506019548211155b156155045760405163ba5bddd760e01b81526001600160a01b0382811660048301526001995086169063ba5bddd790849060240160206040518083038185885af11580156153f4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906154199190615d21565b6040805180820182526001600160a01b038c81168083526020808401868152602a8054600181018255600091825295517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2600290970296870180546001600160a01b0319169190961617909455517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390940193909355808252602f8352838220858352835290839020869055825184815291820186905292995093975087937fd99878669b9e12c01419b6a5f8f4669400ae8da15fcdfb466066e2c785c4d5c2910160405180910390a25b50505b5050509193909250565b600061551c82613213565b1561552957506000919050565b6001600160a01b03821660009081526005602052604090205460ff1661113957506001600160a01b03166000818152600560205260408120805460ff1916600190811790915560068054808301825592527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90910180546001600160a01b03191690921790915590565b600654801561140b5760006155c9600183615c26565b9050600060066155da600185615c26565b815481106155ea576155ea615d84565b600091825260209091200154600680546001600160a01b039092169250908061561557615615615db3565b600082815260209020810160001990810180546001600160a01b031916905501905561564081615777565b506001600160a01b03166000908152600560205260409020805460ff191690555050565b60008061567083615777565b90508015610f47576127d032615777565b6000806000615690606461397f565b90506026548110156156a557600092506156f7565b6027546026546156b59190615ce0565b8110156156c557600192506156f7565b6028546027546026546156d89190615ce0565b6156e29190615ce0565b8110156156f257600292506156f7565b600392505b600091508183600381111561570e5761570e6158a8565b036157265761571b614296565b509092506141aa9050565b600183600381111561573a5761573a6158a8565b0361574e5761574761448b565b9150509091565b6002836003811115615762576157626158a8565b036141aa5761576f613ea2565b509150509091565b600061578282613213565b1561578f57506000919050565b6001600160a01b03821660009081526004602052604090205460ff16611139576001600160a01b0382166000908152600460205260409020805460ff19166001179055506001919050565b60005b838110156157f55781810151838201526020016157dd565b50506000910152565b602081526000825180602084015261581d8160408501602087016157da565b601f01601f19169190910160400192915050565b6001600160a01b038116811461140b57600080fd5b6000806040838503121561585957600080fd5b823561586481615831565b946020939093013593505050565b60006020828403121561588457600080fd5b5035919050565b60006020828403121561589d57600080fd5b813561222581615831565b634e487b7160e01b600052602160045260246000fd5b60208101600383106158d2576158d26158a8565b91905290565b6000806000806000608086880312156158f057600080fd5b85356158fb81615831565b9450602086013561590b81615831565b935060408601359250606086013567ffffffffffffffff8082111561592f57600080fd5b818801915088601f83011261594357600080fd5b81358181111561595257600080fd5b89602082850101111561596457600080fd5b9699959850939650602001949392505050565b60008060006060848603121561598c57600080fd5b833561599781615831565b925060208401356159a781615831565b929592945050506040919091013590565b801515811461140b57600080fd5b600080604083850312156159d957600080fd5b82356159e481615831565b915060208301356159f4816159b8565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615a3e57615a3e6159ff565b604052919050565b600067ffffffffffffffff821115615a6057615a606159ff565b5060051b60200190565b600082601f830112615a7b57600080fd5b81356020615a90615a8b83615a46565b615a15565b82815260059290921b84018101918181019086841115615aaf57600080fd5b8286015b84811015615aca5780358352918301918301615ab3565b509695505050505050565b60008060408385031215615ae857600080fd5b823567ffffffffffffffff80821115615b0057600080fd5b818501915085601f830112615b1457600080fd5b81356020615b24615a8b83615a46565b82815260059290921b84018101918181019089841115615b4357600080fd5b948201945b83861015615b6a578535615b5b81615831565b82529482019490820190615b48565b96505086013592505080821115615b8057600080fd5b50615b8d85828601615a6a565b9150509250929050565b60008060408385031215615baa57600080fd5b8235615bb581615831565b915060208301356159f481615831565b6020808252603a90820152600080516020615f5883398151915260408201527f6e5275675072696365496d7061637450657254686f7573616e64000000000000606082015260800190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f4757610f47615c10565b634e487b7160e01b600052601260045260246000fd5b600082615c5e57615c5e615c39565b500490565b6000816000190483118215151615615c7d57615c7d615c10565b500290565b600060208284031215615c9457600080fd5b815161222581615831565b60208082526021908201527f4f6e6c79206f776e65722063616e2063616c6c2073656e6452616e646f6d4e466040820152601560fa1b606082015260800190565b80820180821115610f4757610f47615c10565b600080600060608486031215615d0857600080fd5b8351925060208401519150604084015190509250925092565b600060208284031215615d3357600080fd5b5051919050565b6001600160a01b03831681526040810160048310615d5a57615d5a6158a8565b8260208301529392505050565b600060208284031215615d7957600080fd5b8151612225816159b8565b634e487b7160e01b600052603260045260246000fd5b600060018201615dac57615dac615c10565b5060010190565b634e487b7160e01b600052603160045260246000fd5b600082615dd857615dd8615c39565b500690565b60008060408385031215615df057600080fd5b8251915060208301516159f481615831565b600080600060608486031215615e1757600080fd5b8351615e22816159b8565b602085015160409095015190969495509392505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015615e895784516001600160a01b031683529383019391830191600101615e64565b50506001600160a01b03969096166060850152505050608001529392505050565b60006020808385031215615ebd57600080fd5b825167ffffffffffffffff811115615ed457600080fd5b8301601f81018513615ee557600080fd5b8051615ef3615a8b82615a46565b81815260059190911b82018301908381019087831115615f1257600080fd5b928401925b82841015615f3057835182529284019290840190615f17565b979650505050505050565b60008251615f4d8184602087016157da565b919091019291505056fe4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d69a264697066735822122003b7a432b53fee78df5836de40516a7034b850577127775e91ebea41ded5d81764736f6c63430008100033

Deployed Bytecode

0x6080604052600436106104a35760003560e01c80637f399bcb11610260578063b8c1825f11610144578063dc1052e2116100c1578063e98491ce11610085578063e98491ce14610e86578063ea336c7414610ea6578063eb4072db14610ebb578063f54d474414610ed0578063f9b12b0714610ef0578063fa656f4a14610f1057600080fd5b8063dc1052e214610df1578063dd62ed3e14610e11578063e26467be14610e31578063e33ad33c14610e51578063e879780214610e7157600080fd5b8063c5296a0f11610108578063c5296a0f14610d4b578063cc1776d314610d85578063d3428cfd14610d9b578063d46b6a3014610db1578063d66bbec714610dd157600080fd5b8063b8c1825f14610cbf578063bed7a20614610cdf578063beecd38b14610cff578063c1bf048a14610d15578063c241417814610d3557600080fd5b80639a2421eb116101dd578063a9059cbb116101a1578063a9059cbb14610bf9578063ac7f90d514610c19578063adce4cbf14610c39578063af99cc4f14610c59578063b0e9895d14610c6f578063b72995c814610c8f57600080fd5b80639a2421eb14610b4a5780639e21d7db14610b6a578063a3c7783b14610ba3578063a403fbd114610bb9578063a4a9860514610bd957600080fd5b80638cd09d50116102245780638cd09d5014610aae5780638ce4832414610ace5780638da5cb5b14610ae45780639182e0b114610b0457806395d89b4114610b1a57600080fd5b80637f399bcb14610a0c578063820941e214610a2a5780638253747e14610a3f57806388399f4d14610a5f578063896c034914610a7557600080fd5b80633bbac579116103875780635db231621161030457806366e305fd116102c857806366e305fd1461094857806370a082311461098157806370b65246146109a15780637160598d146109b657806373845954146109cc5780637f22bed8146109ec57600080fd5b80635db23162146108b25780635dcb14d2146108d25780636479255d146108f2578063651f8c851461091257806365c3d0511461092857600080fd5b80635098d5fb1161034b5780635098d5fb1461082c57806351c6590a1461085857806352a00fbb1461086b57806354fd4d501461087e5780635cc6780e1461089257600080fd5b80633bbac579146107905780633edb223f146107c057806340fb5698146107e05780634bd7ccfb146107f65780634f7041a51461081657600080fd5b8063154dca2c116104205780632137ede9116103e45780632137ede9146106d457806323b872dd146106e9578063313ce56714610709578063342aa8b51461073057806336ed48c01461075057806338a55f0e1461077057600080fd5b8063154dca2c146106445780631694505e1461065757806318160ddd146106895780631ab82d6d1461069e5780631f632cb2146106be57600080fd5b80630c3f6acf116104675780630c3f6acf146105885780630d326463146105aa5780631307d65a146105bf57806313af4035146105df578063150b7a02146105ff57600080fd5b8063052d1d48146104af57806306fdde03146104d7578063095ea7b3146105165780630ae96731146105465780630b13ace21461056857600080fd5b366104aa57005b600080fd5b3480156104bb57600080fd5b506104c4610f26565b6040519081526020015b60405180910390f35b3480156104e357600080fd5b5060408051808201909152600d81526c29bab237a93ab3902a37b5b2b760991b60208201525b6040516104ce91906157fe565b34801561052257600080fd5b50610536610531366004615846565b610f36565b60405190151581526020016104ce565b34801561055257600080fd5b50610566610561366004615872565b610f4d565b005b34801561057457600080fd5b5061053661058336600461588b565b611024565b34801561059457600080fd5b5061059d611077565b6040516104ce91906158be565b3480156105b657600080fd5b506104c4611081565b3480156105cb57600080fd5b506105366105da36600461588b565b6110b8565b3480156105eb57600080fd5b506105666105fa36600461588b565b611141565b34801561060b57600080fd5b5061062b61061a3660046158d8565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020016104ce565b61053661065236600461588b565b6111c9565b34801561066357600080fd5b50600b546001600160a01b03165b6040516001600160a01b0390911681526020016104ce565b34801561069557600080fd5b506000546104c4565b3480156106aa57600080fd5b506105666106b9366004615872565b61139d565b3480156106ca57600080fd5b506104c4601f5481565b3480156106e057600080fd5b5061053661140e565b3480156106f557600080fd5b50610536610704366004615977565b6115f0565b34801561071557600080fd5b5061071e600981565b60405160ff90911681526020016104ce565b34801561073c57600080fd5b5061053661074b3660046159c6565b611612565b34801561075c57600080fd5b5061056661076b366004615872565b6116bc565b34801561077c57600080fd5b5061056661078b366004615846565b611742565b34801561079c57600080fd5b506105366107ab36600461588b565b60046020526000908152604090205460ff1681565b3480156107cc57600080fd5b506105666107db366004615872565b6118df565b3480156107ec57600080fd5b506104c460285481565b34801561080257600080fd5b50610566610811366004615872565b611964565b34801561082257600080fd5b506104c4601c5481565b34801561083857600080fd5b506108416119e9565b6040805192151583526020830191909152016104ce565b610566610866366004615872565b611a28565b61053661087936600461588b565b611d2a565b34801561088a57600080fd5b5060026104c4565b34801561089e57600080fd5b506105666108ad366004615846565b611d9b565b3480156108be57600080fd5b506105666108cd366004615872565b611fdc565b3480156108de57600080fd5b506105666108ed366004615872565b6120ab565b3480156108fe57600080fd5b5061053661090d36600461588b565b612130565b34801561091e57600080fd5b506104c460265481565b34801561093457600080fd5b50610566610943366004615872565b61222c565b34801561095457600080fd5b5061053661096336600461588b565b6001600160a01b031660009081526009602052604090205460ff1690565b34801561098d57600080fd5b506104c461099c36600461588b565b61230a565b3480156109ad57600080fd5b506104c4600281565b3480156109c257600080fd5b506104c460215481565b3480156109d857600080fd5b50600354610671906001600160a01b031681565b3480156109f857600080fd5b50610566610a07366004615872565b612315565b348015610a1857600080fd5b50600c546001600160a01b0316610671565b348015610a3657600080fd5b50602a546104c4565b348015610a4b57600080fd5b50610566610a5a36600461588b565b612375565b348015610a6b57600080fd5b506104c4601d5481565b348015610a8157600080fd5b50610536610a9036600461588b565b6001600160a01b03166000908152602e602052604090205460ff1690565b348015610aba57600080fd5b50610566610ac9366004615872565b612407565b348015610ada57600080fd5b506104c460275481565b348015610af057600080fd5b50600a54610671906001600160a01b031681565b348015610b1057600080fd5b506104c460175481565b348015610b2657600080fd5b506040805180820190915260078152665355444f52554760c81b6020820152610509565b348015610b5657600080fd5b50610566610b65366004615872565b612474565b348015610b7657600080fd5b50610536610b8536600461588b565b6001600160a01b03166000908152602d602052604090205460ff1690565b348015610baf57600080fd5b506104c460165481565b348015610bc557600080fd5b50610566610bd4366004615872565b6124e2565b348015610be557600080fd5b50610566610bf4366004615872565b6125c4565b348015610c0557600080fd5b50610536610c14366004615846565b612692565b348015610c2557600080fd5b50610536610c3436600461588b565b61269f565b348015610c4557600080fd5b50610536610c5436600461588b565b6127d7565b348015610c6557600080fd5b506104c460255481565b348015610c7b57600080fd5b50610566610c8a366004615ad5565b61285c565b348015610c9b57600080fd5b50610536610caa36600461588b565b60056020526000908152604090205460ff1681565b348015610ccb57600080fd5b50610566610cda366004615872565b612b65565b348015610ceb57600080fd5b50610566610cfa366004615872565b612beb565b348015610d0b57600080fd5b506104c460225481565b348015610d2157600080fd5b50610566610d30366004615872565b612c54565b348015610d4157600080fd5b506104c460155481565b348015610d5757600080fd5b50610d60612cc5565b6040805193151584526001600160a01b039092166020840152908201526060016104ce565b348015610d9157600080fd5b506104c4601b5481565b348015610da757600080fd5b506104c460235481565b348015610dbd57600080fd5b50610536610dcc36600461588b565b612d39565b348015610ddd57600080fd5b50610566610dec366004615872565b612d44565b348015610dfd57600080fd5b50610566610e0c366004615872565b612da9565b348015610e1d57600080fd5b506104c4610e2c366004615b97565b612e5e565b348015610e3d57600080fd5b50610566610e4c36600461588b565b612e8b565b348015610e5d57600080fd5b50610566610e6c36600461588b565b612f06565b348015610e7d57600080fd5b506104c4612f86565b348015610e9257600080fd5b50610536610ea136600461588b565b612fa8565b348015610eb257600080fd5b50610536613024565b348015610ec757600080fd5b50602c546104c4565b348015610edc57600080fd5b50610536610eeb36600461588b565b613059565b348015610efc57600080fd5b50610566610f0b366004615872565b6130db565b348015610f1c57600080fd5b506104c460245481565b6000610f3130613196565b905090565b6000610f433384846131b1565b5060015b92915050565b600a546001600160a01b03163314610f805760405162461bcd60e51b8152600401610f7790615bc5565b60405180910390fd5b6103e8811115610fcd5760405162461bcd60e51b8152602060048201526018602482015277056616c75652063616e6e6f742065786365656420313030360441b6044820152606401610f77565b80602254111561101f5760405162461bcd60e51b815260206004820181905260248201527f4d696e2063616e6e6f742065786365656420657863656564206e6577206d61786044820152606401610f77565b602355565b600061102f82613213565b8061105257506001600160a01b03821660009081526004602052604090205460ff165b80610f475750506001600160a01b031660009081526005602052604090205460ff1690565b6000610f3161327f565b600061108e600d54151590565b156110b257603c61109e600e5490565b6110a89042615c26565b610f319190615c4f565b50600090565b600a546000906001600160a01b031633146111305760405162461bcd60e51b815260206004820152603260248201527f4d757374206265206f776e657220746f2063616c6c2072656d6f76654e4654436044820152711bdb9d1c9858dd119c9bdb509d5e531a5cdd60721b6064820152608401610f77565b611139826132ad565b506001919050565b600a546001600160a01b031633146111a75760405162461bcd60e51b815260206004820152602360248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744f776044820152623732b960e91b6064820152608401610f77565b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166000908152602e602052604081205460ff16156112325760405162461bcd60e51b815260206004820152601760248201527f416c726561647920627579696e672074686973206f6e650000000000000000006044820152606401610f77565b6001600160a01b0382166000908152602d602052604090205460ff1661128d5760405162461bcd60e51b815260206004820152601060248201526f139bdd081a5b881dda1a5d195b1a5cdd60821b6044820152606401610f77565b600354600a546001600160a01b0391821691163314611394576015546112b233613196565b101561130e5760405162461bcd60e51b815260206004820152602560248201527f4e6f7420656e6f75676820746f6b656e7320746f20616464204e465420636f6e6044820152641d1c9858dd60da1b6064820152608401610f77565b60165434101561136b5760405162461bcd60e51b815260206004820152602260248201527f4e6f7420656e6f7567682045544820746f20616464204e465420636f6e74726160448201526118dd60f21b6064820152608401610f77565b601554600061137a8280615c26565b90506113873330846133ee565b6113913382613528565b50505b610f4383613584565b600a546001600160a01b0316331461140b5760405162461bcd60e51b815260206004820152603e6024820152600080516020615f5883398151915260448201527f6e507269636550657263656e74496e637265617365546f53656c6c4e465400006064820152608401610f77565b50565b6000611418613673565b6000611422613874565b9050600061142e610f26565b8211156114d35761143d610f26565b6114479083615c26565b90506000611455606461397f565b60245411801591506114d157600061146b6139f2565b90506001600160a01b038116156114cf57600060646114898361230a565b6025546114969190615c63565b6114a09190615c4f565b905060008482106114b157846114b3565b815b90506114c08330836133ee565b6114ca8186615c26565b945050505b505b505b80156114e3576114e33082613ab7565b60006114ee83613b42565b905081156115115761151161150b600c546001600160a01b031690565b83613528565b600c546001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561155757600080fd5b505af115801561156b573d6000803e3d6000fd5b5050508115801591506115bc5742601f55604080518581526020810184905233917f9a5178ff42681b627314726ddac5afb7bf7f43659a3d45fba04e4cac720d0936910160405180910390a26115e8565b60405133907f2c58021a2da7aa3664cfb8e7baa4497f73c94ae0974ce255e30904702935844790600090a25b949350505050565b60006115fd843384613b8a565b611608848484613c39565b5060019392505050565b600a546000906001600160a01b0316331461166f5760405162461bcd60e51b815260206004820152601a60248201527f4f6e6c79206f776e65722063616e2063616c6c20616464426f740000000000006044820152606401610f77565b818015611680575061168083613213565b1561168d57506000610f47565b506001600160a01b0382166000908152600460205260409020805482151560ff19909116179055600192915050565b600a546001600160a01b031633146117305760405162461bcd60e51b815260206004820152603160248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657441636044820152701d1a5bdb919c995c5d595b98de54d95b99607a1b6064820152608401610f77565b61173c60275482613d9d565b50602755565b600a546001600160a01b031633146117a85760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2072657363756044820152631953919560e21b6064820152608401610f77565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa1580156117ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118139190615c82565b6001600160a01b0316146118755760405162461bcd60e51b8152602060048201526024808201527f5375646f527567206973206e6f7420746865206f776e6572206f6620746869736044820152630813919560e21b6064820152608401610f77565b6040516323b872dd60e01b8152306004820152336024820152604481018290526001600160a01b038316906323b872dd90606401600060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050505050565b600a546001600160a01b0316331461195f5760405162461bcd60e51b815260206004820152603760248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201527f7374546f4164644e4654436f6e7472616374496e4554480000000000000000006064820152608401610f77565b601655565b600a546001600160a01b031633146119e45760405162461bcd60e51b815260206004820152603a60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201527f7374546f4164644e4654436f6e7472616374496e546f6b656e730000000000006064820152608401610f77565b601555565b600a5460009081906001600160a01b03163314611a185760405162461bcd60e51b8152600401610f7790615c9f565b611a20613ea2565b915091509091565b600a546001600160a01b03163314611a825760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722063616e2063616c6c206164644c69717569646974796044820152606401610f77565b60008111611ad25760405162461bcd60e51b815260206004820152601860248201527f4e6f20746f6b656e7320666f72206c69717569646974792100000000000000006044820152606401610f77565b60003411611b1a5760405162461bcd60e51b81526020600482015260156024820152744e6f2045544820666f72206c69717569646974792160581b6044820152606401610f77565b600b54600c546001600160a01b039182169116611b38333085613c39565b611b433083856131b1565b6001600160a01b03821663f305d719343086808333611b6342600f615ce0565b60405160e089901b6001600160e01b03191681526001600160a01b039687166004820152602481019590955260448501939093526064840191909152909216608482015260a481019190915260c40160606040518083038185885af1158015611bd0573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611bf59190615cf3565b50505034826001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5b9190615c82565b6040516370a0823160e01b81526001600160a01b03848116600483015291909116906370a0823190602401602060405180830381865afa158015611ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc79190615d21565b1015611d215760405162461bcd60e51b815260206004820152602360248201527f455448206469646e27742067657420746f20746865207061697220636f6e74726044820152621858dd60ea1b6064820152608401610f77565b505043600d5550565b6000611d358261269f565b50610f43826001600160a01b03166347ccca026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d77573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106529190615c82565b600a546001600160a01b03163314611e105760405162461bcd60e51b815260206004820152603260248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207265736375604482015271654e46545f416464546f547265617375727960701b6064820152608401610f77565b6040516331a9108f60e11b81526004810182905230906001600160a01b03841690636352211e90602401602060405180830381865afa158015611e57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e7b9190615c82565b6001600160a01b031614611edf5760405162461bcd60e51b815260206004820152602560248201527f5375646f47617465206973206e6f7420746865206f776e6572206f66207468696044820152641cc813919560da1b6064820152608401610f77565b6001600160a01b0382166000908152602d602052604090205460ff16611f475760405162461bcd60e51b815260206004820152601e60248201527f4e465420636f6e7472616374206e6f7420696e20616c6c6f772d6c69737400006044820152606401610f77565b604080518082019091526001600160a01b03928316815260208101918252602a805460018101825560009190915290517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2600290920291820180546001600160a01b0319169190941617909255517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390910155565b600a546001600160a01b031633146120555760405162461bcd60e51b815260206004820152603660248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d616044820152753c2832b931b2b73a2932b0b8383934b7b930ba34b7b760511b6064820152608401610f77565b60648111156120a65760405162461bcd60e51b815260206004820152601860248201527f56616c75652063616e6e6f7420657863656564203130302500000000000000006044820152606401610f77565b602455565b600a546001600160a01b0316331461211e5760405162461bcd60e51b815260206004820152603060248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574416360448201526f74696f6e4672657175656e637942757960801b6064820152608401610f77565b61212a60265482613d9d565b50602655565b6040516308f25a8f60e01b815260009073b16c1342e617a5b6e4b631eb114483fdb289c0a49081906308f25a8f9061216e9086908690600401615d3a565b602060405180830381865afa15801561218b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121af9190615d67565b8061222557506040516308f25a8f60e01b81526001600160a01b038216906308f25a8f906121e4908690600190600401615d3a565b602060405180830381865afa158015612201573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122259190615d67565b9392505050565b600a546001600160a01b0316331461229e5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574436f60448201526e7374546f527567496e546f6b656e7360881b6064820152608401610f77565b600054601e5411156123055760405162461bcd60e51b815260206004820152602a60248201527f43616e277420636861726765206d6f7265207468616e20616c6c206578697374604482015269696e6720746f6b656e7360b01b6064820152608401610f77565b601e55565b6000610f4782613196565b600a546001600160a01b031633146123705760405162461bcd60e51b815260206004820152602a6024820152600080516020615f588339815191526044820152696e53656c6c507269636560b01b6064820152608401610f77565b601a55565b600a546001600160a01b031633146123e55760405162461bcd60e51b815260206004820152602d60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574537560448201526c646f476174654164647265737360981b6064820152608401610f77565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b600a546001600160a01b0316331461246f5760405162461bcd60e51b815260206004820152602560248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657453656044820152640d8d8a8c2f60db1b6064820152608401610f77565b601b55565b600a546001600160a01b031633146120555760405162461bcd60e51b815260206004820152602b60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c20736574507260448201526a6f62436f6d6d756e69736d60a81b6064820152608401610f77565b600a546001600160a01b031633146125625760405162461bcd60e51b815260206004820152603b60248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d6160448201527f7850657263656e744f66546f74616c537570706c7950657252756700000000006064820152608401610f77565b60648111156125bf5760405162461bcd60e51b8152602060048201526024808201527f50657263656e74206f6620737570706c792063616e6e6f7420657863656564206044820152633130302560e01b6064820152608401610f77565b602055565b600a546001600160a01b031633146125ee5760405162461bcd60e51b8152600401610f7790615bc5565b6103e881111561263b5760405162461bcd60e51b8152602060048201526018602482015277056616c75652063616e6e6f742065786365656420313030360441b6044820152606401610f77565b60235481111561268d5760405162461bcd60e51b815260206004820181905260248201527f4e6577206d696e2063616e6e6f742065786365656420657863656564206d61786044820152606401610f77565b602255565b6000610f43338484613c39565b60006126aa82612130565b6126ec5760405162461bcd60e51b8152602060048201526013602482015272139bdd0818481cdd591bdcddd85c081c1bdbdb606a1b6044820152606401610f77565b6003546040516366fe44d560e11b81526001600160a01b0384811660048301526000921690819063cdfc89aa90602401602060405180830381865afa158015612739573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275d9190615d67565b6127d0576040516355ec842360e11b81526001600160a01b03858116600483015282169063abd90846906024016020604051808303816000875af11580156127a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127cd9190615d67565b91505b5092915050565b600a546000906001600160a01b031633146128345760405162461bcd60e51b815260206004820152601b60248201527f43616e206f6e6c792062652063616c6c6564206279206f776e657200000000006044820152606401610f77565b611139826001600160a01b03166000908152600f60205260409020805460ff19166001179055565b80518251146128c65760405162461bcd60e51b815260206004820152603060248201527f41646472657373657320616e6420746f6b656e2076616c756573206d7573742060448201526f0d0c2ecca40e6c2daca40d8cadccee8d60831b6064820152608401610f77565b600a546001600160a01b03163314806128f7575060026128e461327f565b60028111156128f5576128f56158a8565b145b6129435760405162461bcd60e51b815260206004820152601760248201527f596f752063616e27742063616c6c2074686973207965740000000000000000006044820152606401610f77565b3360009081526004602052604090205460ff1615801561297357503360009081526005602052604090205460ff16155b6129bf5760405162461bcd60e51b815260206004820152601760248201527f536f7272792c206e6f7420626f747320616c6c6f7765640000000000000000006044820152606401610f77565b600080808080805b8751811015612ace578781815181106129e2576129e2615d84565b602002602001015191508681815181106129fe576129fe615d84565b602002602001015194508486612a149190615ce0565b6001600160a01b0383166000908152600160205260409020549096509350612a3c8585615ce0565b6001600160a01b03831660008181526001602052604090819020839055519194509033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612a8f9089815260200190565b60405180910390a360175483118015612aae5750612aac82611024565b155b15612abc57612abc826141af565b80612ac681615d9a565b9150506129c7565b5033600090815260016020526040902054851115612b2e5760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320666f722061697264726f700000006044820152606401610f77565b3360009081526001602052604081208054879290612b4d908490615c26565b90915550612b5c905033614222565b50505050505050565b600a546001600160a01b03163314612bd95760405162461bcd60e51b815260206004820152603160248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657441636044820152701d1a5bdb919c995c5d595b98de54d95b1b607a1b6064820152608401610f77565b612be560285482613d9d565b50602855565b600a546001600160a01b03163314612c4f5760405162461bcd60e51b81526020600482015260336024820152600080516020615f588339815191526044820152726e4d696e757465734265747765656e5275677360681b6064820152608401610f77565b602155565b600a546001600160a01b03163314612cc05760405162461bcd60e51b815260206004820152602960248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d6160448201526878427579507269636560b81b6064820152608401610f77565b601955565b600a54600090819081906001600160a01b03163314612d265760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79206f776e65722063616e2063616c6c2062757952616e646f6d4e46546044820152606401610f77565b612d2e614296565b925092509250909192565b6000610f47826142cc565b600a546001600160a01b03163314612da45760405162461bcd60e51b815260206004820152602f6024820152600080516020615f5883398151915260448201526e6e456c696769626c65546f6b656e7360881b6064820152608401610f77565b601755565b600a546001600160a01b03163314612e0f5760405162461bcd60e51b8152602060048201526024808201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657442756044820152630f2a8c2f60e31b6064820152608401610f77565b6064811115612e595760405162461bcd60e51b81526020600482015260166024820152755461782063616e6e6f7420657863656564203130302560501b6044820152606401610f77565b601c55565b6001600160a01b038083166000908152600260209081526040808320938516835292905290812054612225565b600a546001600160a01b03163314612efd5760405162461bcd60e51b815260206004820152602f60248201527f4d757374206265206f776e657220746f2063616c6c206164644e4654436f6e7460448201526e1c9858dd151bd05b1b1bddd31a5cdd608a1b6064820152608401610f77565b61140b816142ea565b600a546001600160a01b03163314612f7d5760405162461bcd60e51b815260206004820152603460248201527f4d757374206265206f776e657220746f2063616c6c2072656d6f76654e4654436044820152731bdb9d1c9858dd119c9bdb505b1b1bddd31a5cdd60621b6064820152608401610f77565b61140b81614371565b6000601f54600003612f985750600090565b603c601f54426110a89190615c26565b600a546000906001600160a01b0316331461301b5760405162461bcd60e51b815260206004820152602d60248201527f4d757374206265206f776e657220746f2063616c6c206164644e4654436f6e7460448201526c1c9858dd151bd09d5e531a5cdd609a1b6064820152608401610f77565b61113982613584565b600a546000906001600160a01b031633146130515760405162461bcd60e51b8152600401610f7790615c9f565b610f3161448b565b600a546000906001600160a01b031633146130b65760405162461bcd60e51b815260206004820152601b60248201527f43616e206f6e6c792062652063616c6c6564206279206f776e657200000000006044820152606401610f77565b611139826001600160a01b03166000908152600f60205260409020805460ff19169055565b600a546001600160a01b031633146131475760405162461bcd60e51b815260206004820152602960248201527f4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c2073657453616044820152680dcc8eed2c6d0a8c2f60bb1b6064820152608401610f77565b60648111156131915760405162461bcd60e51b81526020600482015260166024820152755461782063616e6e6f7420657863656564203130302560501b6044820152606401610f77565b601d55565b6001600160a01b031660009081526001602052604090205490565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006001600160a01b03821630148061323357506001600160a01b038216155b8061324b5750600a546001600160a01b038381169116145b8061325a575061325a826142cc565b80610f475750506001600160a01b03166000908152602d602052604090205460ff1690565b600061328c600d54151590565b156110b257600261329b614643565b10156132a75750600190565b50600290565b6001600160a01b0381166000908152602e602052604090205460ff161561140b576001600160a01b0381166000908152602e60205260408120805460ff19169055602c545b8082101561334457826001600160a01b0316602a600201838154811061331a5761331a615d84565b6000918252602090912001546001600160a01b0316146133445761333d82615d9a565b91506132f2565b602c613351600183615c26565b8154811061336157613361615d84565b600091825260209091200154602c80546001600160a01b03909216918490811061338d5761338d615d84565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055602c8054806133c7576133c7615db3565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b6001600160a01b03831660009081526001602052604090205481111561344d5760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606401610f77565b6001600160a01b03831660009081526001602052604081208054839290613475908490615c26565b9091555050600c546001600160a01b038481169116146134985761349883614222565b6001600160a01b038216600090815260016020526040812080548392906134c0908490615ce0565b9091555050600c546001600160a01b038381169116146134e3576134e382614222565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161320691815260200190565b8061353283613196565b10156135745760405162461bcd60e51b81526020600482015260116024820152704e6f7420656e6f75676820746f6b656e7360781b6044820152606401610f77565b613580826000836133ee565b5050565b6001600160a01b0381166000908152602d602052604090205460ff166135ec5760405162461bcd60e51b815260206004820152601e60248201527f4e465420636f6e7472616374206e6f7420696e20616c6c6f77206c69737400006044820152606401610f77565b6001600160a01b0381166000908152602e602052604090205460ff1661140b57602c805460018181019092557f7416c943b4a09859521022fd2e90eac0dd9026dad28fa317782a135f28a860910180546001600160a01b0384166001600160a01b031990911681179091556000908152602e60205260409020805460ff1916909117905550565b600261367d611077565b600281111561368e5761368e6158a8565b146136cc5760405162461bcd60e51b815260206004820152600e60248201526d43616e277420727567207965742160901b6044820152606401610f77565b601f54600e54116137175760405162461bcd60e51b81526020600482015260156024820152744d75737420627579206265747765656e207275677360581b6044820152606401610f77565b601f54156137785760215461372a612f86565b10156137785760405162461bcd60e51b815260206004820152601860248201527f486f6c6420796f757220686f72736573207275676765727300000000000000006044820152606401610f77565b600a546001600160a01b031633146137e9573360009081526009602052604090205460ff166137e95760405162461bcd60e51b815260206004820152601760248201527f527567676572206d75737420626520656c696769626c650000000000000000006044820152606401610f77565b600a546001600160a01b0316331480159061380657506000601e54115b1561387257601e546138173361230a565b10156138655760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320666f722072756767696e670000006044820152606401610f77565b6138723330601e546133ee565b565b602254602354600091908110156138b05760006022546023546138979190615c26565b90506138a28161397f565b6138ac9083615ce0565b9150505b6103e88111156139155760405162461bcd60e51b815260206004820152602a60248201527f52616e646f6d20707269636520696d706163742073686f756c64206e6f7420656044820152697863656564203130302560b01b6064820152608401610f77565b600061392c61099c600c546001600160a01b031690565b90506103e861393b8383615c63565b6139459190615c4f565b92506000606461395460005490565b6020546139619190615c63565b61396b9190615c4f565b905080841115613979578093505b50505090565b60008082116139df5760405162461bcd60e51b815260206004820152602660248201527f43616e6e6f742067656e65726174652072616e646f6d206e756d626572206d6f604482015265064756c6f20360d41b6064820152608401610f77565b816139e8614653565b610f479190615dc9565b6000806139fd6146c0565b90506000613a096146c0565b90506000613a156146c0565b905060006001600160a01b03841615613a3657613a3184613196565b613a39565b60005b905060006001600160a01b03841615613a5a57613a5584613196565b613a5d565b60005b905060006001600160a01b03841615613a7e57613a7984613196565b613a81565b60005b9050818311613a9d57808211613a975783613aac565b84613aac565b808311613aaa5783613aac565b855b965050505050505090565b80600080016000828254613acb9190615ce0565b90915550506001600160a01b03821660009081526001602052604081208054839290613af8908490615ce0565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b600c54600090600160a01b900460ff16613b85576000613b60610f26565b905082811015613b705780613b72565b825b92508215613b835761222583614702565b505b919050565b6001600160a01b03808416600090815260026020908152604080832093861683529290522054811115613bf85760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420616c6c6f77616e636560501b6044820152606401610f77565b6001600160a01b03808416600090815260026020908152604080832093861683529290529081208054839290613c2f908490615c26565b9091555050505050565b6001600160a01b038316301480613c5857506001600160a01b03821630145b80613c705750600a546001600160a01b038481169116145b15613c8557613c808383836133ee565b505050565b600d54613cea5760405162461bcd60e51b815260206004820152602d60248201527f43616e6e6f74207472616e7366657220746f6b656e73206265666f7265206c6960448201526c1c5d5a591a5d1e481859191959609a1b6064820152608401610f77565b600c54600160a01b900460ff1615613d0757613c808383836133ee565b6001613d1161327f565b6002811115613d2257613d226158a8565b03613d9257613d30836142cc565b15613d8757613d3e82614917565b15613d8757816001600160a01b03167f83efabacf9f7cf6e679b0fd9de0113ad1e05f72b1955dedadf0e01422a52234a82604051613d7e91815260200190565b60405180910390a25b613c808383836133ee565b613c80838383614934565b60006064821115613dfc5760405162461bcd60e51b815260206004820152602360248201527f4e65772070657263656e742076616c75652063616e6e6f74206578636565642060448201526203130360ec1b6064820152608401610f77565b6000602854602754602654613e119190615ce0565b613e1b9190615ce0565b90506000613e298583615c26565b90506000613e378583615ce0565b90506064811115613e995760405162461bcd60e51b815260206004820152602660248201527f436f6d62696e65642070657263656e74616765732063616e6e6f74206578636560448201526506564203130360d41b6064820152608401610f77565b50505092915050565b6000806000613eb0602a5490565b905080156141aa576000613ec38261397f565b90506000602a6000018281548110613edd57613edd615d84565b6000918252602080832060029290920290910180546001600160a01b03908116808552602f845260408086206001850154875290945293839020546003549351636ec9facd60e11b81526004810195909552919450909291169063dd93f59a906024016040805180830381865afa158015613f5c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f809190615ddd565b5094508085118015613f945750601a548510155b156141a65760018115613fd1576000613fad8388615c26565b9050600083613fbd836064615c63565b613fc79190615c4f565b6018541115925050505b80156141a457825460018401546040516331a9108f60e11b8152600481019190915230916001600160a01b031690636352211e90602401602060405180830381865afa158015614025573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140499190615c82565b6001600160a01b0316036141a4578254600354600185015460405163095ea7b360e01b81526001600160a01b039283166004820152602481019190915291169063095ea7b390604401600060405180830381600087803b1580156140ac57600080fd5b505af11580156140c0573d6000803e3d6000fd5b505060035485546001870154604051636c197ff560e01b81526001600160a01b039283166004820152602481019190915291169250636c197ff591506044016060604051808303816000875af115801561411e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141429190615e02565b50909750955086156141a45761415784614f3d565b8254600184015460408051918252602082018990526001600160a01b03909216917f3148efce73b39b088f8c1497d8e056a6e8d58e3ffa171525862a6d4238397b90910160405180910390a25b505b5050505b509091565b6001600160a01b03166000818152600960209081526040808320805460ff19166001908117909155600780546008909452918420839055820181559091527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180546001600160a01b0319169091179055565b60175461422e82613196565b108061423e575061423e81611024565b1561426d576001600160a01b03811660009081526009602052604090205460ff161561140b5761140b816150b2565b6001600160a01b03811660009081526009602052604090205460ff1661140b5761140b816141af565b60008080806142a4602c5490565b11156142c75760006142b46151bb565b90506142bf8161525c565b509094509150505b909192565b6001600160a01b03166000908152600f602052604090205460ff1690565b6001600160a01b0381166000908152602d602052604090205460ff1661140b57602b805460018181019092557f11c44e4875b74d31ff9fd779bf2566af7bd15b87fc985d01f5094b89e3669e4f0180546001600160a01b0384166001600160a01b031990911681179091556000908152602d60205260409020805460ff1916909117905550565b6001600160a01b0381166000908152602d602052604090205460ff161561140b576001600160a01b0381166000908152602d60205260408120805460ff19169055602b545b8082101561440857826001600160a01b0316602a60010183815481106143de576143de615d84565b6000918252602090912001546001600160a01b0316146144085761440182615d9a565b91506143b6565b602b614415600183615c26565b8154811061442557614425615d84565b600091825260209091200154602b80546001600160a01b03909216918490811061445157614451615d84565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055602b8054806133c7576133c7615db3565b600080614497602a5490565b9050801561463f5760006144a96139f2565b90506144b481611024565b61463d5760006144c38361397f565b90506000602a60000182815481106144dd576144dd615d84565b60009182526020909120600290910201805460018201546040516331a9108f60e11b8152600481019190915291925030916001600160a01b0390911690636352211e90602401602060405180830381865afa158015614540573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145649190615c82565b6001600160a01b03160361463157805460018201546040516323b872dd60e01b81523060048201526001600160a01b03868116602483015260448201929092529116906323b872dd90606401600060405180830381600087803b1580156145ca57600080fd5b505af11580156145de573d6000803e3d6000fd5b5050825460018401546040519081526001600160a01b03878116945090911691507f0ab2d5a490c8d5451470363f35341c42582170bbaf5bf4cd96b1afc7304e22ae9060200160405180910390a3600194505b61463a82614f3d565b50505b505b5090565b600d54600090610f319043615c26565b60006001602960008282546146689190615ce0565b90915550506029546040516bffffffffffffffffffffffff193360601b16602082015260348101919091524260548201524460748201526094016040516020818303038152906040528051906020012060001c905090565b600754600090801561463f5760076146d78261397f565b815481106146e7576146e7615d84565b6000918252602090912001546001600160a01b031691505090565b600047821580159061471c57508261471930613196565b10155b156148c557600c805460ff60a01b1916600160a01b179055600b546040805160028082526060820183526001600160a01b0390931692600092602083019080368337019050509050308160008151811061477857614778615d84565b60200260200101906001600160a01b031690816001600160a01b031681525050816001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147fa9190615c82565b8160018151811061480d5761480d615d84565b60200260200101906001600160a01b031690816001600160a01b0316815250506148383083876131b1565b6040516318cbafe560e01b81526001600160a01b038316906318cbafe59061486d908890600090869030904290600401615e39565b6000604051808303816000875af115801561488c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526148b49190810190615eaa565b5050600c805460ff60a01b19169055505b8047101561490d5760405162461bcd60e51b8152602060048201526015602482015274486f7720646964207765206c6f736520455448213f60581b6044820152606401610f77565b6122258147615c26565b60008061492383615511565b90508015610f47576127d032615511565b600261493e61327f565b600281111561494f5761494f6158a8565b146149b55760405162461bcd60e51b815260206004820152603060248201527f53686f756c646e277420726561636820746869732070617468206f6e2061697260448201526f191c9bdc081bdc881a1bdb995e5c1bdd60821b6064820152608401610f77565b6001600160a01b03831660009081526004602052604090205460ff1615614a1e5760405162461bcd60e51b815260206004820152601c60248201527f536f72727920626f742c2063616e2774206c657420796f75206f7574000000006044820152606401610f77565b6000614a29836142cc565b90506000614a36856142cc565b90508080614a415750815b15614b5b578015614a80576001600160a01b0385166000908152601260205260408120805460019290614a75908490615ce0565b90915550614ab59050565b8115614ab5576001600160a01b0384166000908152601260205260408120805460019290614aaf908490615ce0565b90915550505b60065415801590614adf57506001600160a01b03851660009081526005602052604090205460ff16155b8015614b0457506001600160a01b03841660009081526005602052604090205460ff16155b8015614b2957506001600160a01b03851660009081526004602052604090205460ff16155b8015614b4e57506001600160a01b03841660009081526004602052604090205460ff16155b15614b5b57614b5b6155b3565b82600080838015614b9057506001600160a01b038088166000908152601160209081526040808320938c168352929052205443145b8015614bd657506001600160a01b038088166000908152601460209081526040808320938c16835292815282822054601290915291902054600191614bd491615c26565b115b15614c42576000614be688615664565b90508015614c3c5760006064601d5489614c009190615c63565b614c0a9190615c4f565b9050614c17600282615c4f565b614c219085615ce0565b9350614c2e600282615c4f565b614c389084615ce0565b9250505b50614d21565b848015614c7357506001600160a01b038089166000908152601060209081526040808320938b168352929052205443145b8015614cb957506001600160a01b038089166000908152601360209081526040808320938b16835292815282822054601290915291902054600191614cb791615c26565b115b15614d21576000614cc989615664565b90508015614d1f5760006064601d5489614ce39190615c63565b614ced9190615c4f565b9050614cfa600282615c4f565b614d049085615ce0565b9350614d11600282615c4f565b614d1b9084615ce0565b9250505b505b6000614d2d8284615ce0565b905080841015614da55760405162461bcd60e51b815260206004820152603760248201527f43616e27742074616b652061776179206d6f7265207468616e20746865206f7260448201527f6967696e616c206e756d626572206f6620746f6b656e730000000000000000006064820152608401610f77565b6000614db18286615c26565b9050858015614dc257506000601c54115b15614e035760006064601c5483614dd99190615c63565b614de39190615c4f565b9050614def8185615ce0565b9350614dfb8183615c26565b915050614e4f565b868015614e1257506000601b54115b15614e4f5760006064601b5483614e299190615c63565b614e339190615c4f565b9050614e3f8185615ce0565b9350614e4b8183615c26565b9150505b8315614e5f57614e5f8a85613528565b8215614e7057614e708a30856133ee565b8015614e8157614e818a8a836133ee565b614e89615681565b50508515614ee25742600e556001600160a01b03808a166000818152601060209081526040808320948f168084529482528083204390556012825280832054938352601382528083209483529390529190912055614f31565b8615614f31576001600160a01b03808b166000818152601160209081526040808320948e1680845294825280832043905560128252808320549383526014825280832094835293905291909120555b50505050505050505050565b602a54818111614f9d5760405162461bcd60e51b815260206004820152602560248201527f4e465420696e64657820746f2062652072656d6f766564206f7574206f6620626044820152646f756e647360d81b6064820152608401610f77565b6000602a6000018381548110614fb557614fb5615d84565b60009182526020808320600290920290910180546001808301546001600160a01b03909216808652602f85526040808720848852909552938520949094559093509091602a906150059086615c26565b8154811061501557615015615d84565b9060005260206000209060020201602a600001868154811061503957615039615d84565b60009182526020909120825460029092020180546001600160a01b0319166001600160a01b03909216919091178155600191820154910155602a80548061508257615082615db3565b60008281526020812060026000199093019283020180546001600160a01b03191681556001015590555050505050565b6001600160a01b0381166000908152600960205260408120805460ff191690556007546150e190600190615c26565b6001600160a01b0383166000908152600860205260409020549091508181101561518d5760006007600001838154811061511d5761511d615d84565b60009182526020808320909101546001600160a01b0316808352600890915260409091208390556007805491925082918490811061515d5761515d615d84565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b6001600160a01b0383166000908152600860205260409020600019905560078054806133c7576133c7615db3565b6000806151c7602c5490565b116152145760405162461bcd60e51b815260206004820152601860248201527f4e6f204e465420636f6e74726163747320746f206275792100000000000000006044820152606401610f77565b602c8054801561525257816152288261397f565b8154811061523857615238615d84565b6000918252602090912001546001600160a01b0316615255565b60005b9250505090565b600354600090819081906001600160a01b03166152bb5760405162461bcd60e51b815260206004820152601e60248201527f5375646f4761746520616464726573732063616e2774206265207a65726f00006044820152606401610f77565b6003546040516001600160a01b038681166024830152909116906000908190839060440160408051601f198184030181529181526020820180516001600160e01b03166337404c6160e21b179052516153149190615f3b565b6000604051808303816000865af19150503d8060008114615351576040519150601f19603f3d011682016040523d82523d6000602084013e615356565b606091505b5091509150811561550757600080828060200190518101906153789190615ddd565b90925090506001600160a01b0381161580159061539457504782105b80156153a257506019548211155b156155045760405163ba5bddd760e01b81526001600160a01b0382811660048301526001995086169063ba5bddd790849060240160206040518083038185885af11580156153f4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906154199190615d21565b6040805180820182526001600160a01b038c81168083526020808401868152602a8054600181018255600091825295517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d2600290970296870180546001600160a01b0319169190961617909455517fbeced09521047d05b8960b7e7bcc1d1292cf3e4b2a6b63f48335cbde5f7545d390940193909355808252602f8352838220858352835290839020869055825184815291820186905292995093975087937fd99878669b9e12c01419b6a5f8f4669400ae8da15fcdfb466066e2c785c4d5c2910160405180910390a25b50505b5050509193909250565b600061551c82613213565b1561552957506000919050565b6001600160a01b03821660009081526005602052604090205460ff1661113957506001600160a01b03166000818152600560205260408120805460ff1916600190811790915560068054808301825592527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f90910180546001600160a01b03191690921790915590565b600654801561140b5760006155c9600183615c26565b9050600060066155da600185615c26565b815481106155ea576155ea615d84565b600091825260209091200154600680546001600160a01b039092169250908061561557615615615db3565b600082815260209020810160001990810180546001600160a01b031916905501905561564081615777565b506001600160a01b03166000908152600560205260409020805460ff191690555050565b60008061567083615777565b90508015610f47576127d032615777565b6000806000615690606461397f565b90506026548110156156a557600092506156f7565b6027546026546156b59190615ce0565b8110156156c557600192506156f7565b6028546027546026546156d89190615ce0565b6156e29190615ce0565b8110156156f257600292506156f7565b600392505b600091508183600381111561570e5761570e6158a8565b036157265761571b614296565b509092506141aa9050565b600183600381111561573a5761573a6158a8565b0361574e5761574761448b565b9150509091565b6002836003811115615762576157626158a8565b036141aa5761576f613ea2565b509150509091565b600061578282613213565b1561578f57506000919050565b6001600160a01b03821660009081526004602052604090205460ff16611139576001600160a01b0382166000908152600460205260409020805460ff19166001179055506001919050565b60005b838110156157f55781810151838201526020016157dd565b50506000910152565b602081526000825180602084015261581d8160408501602087016157da565b601f01601f19169190910160400192915050565b6001600160a01b038116811461140b57600080fd5b6000806040838503121561585957600080fd5b823561586481615831565b946020939093013593505050565b60006020828403121561588457600080fd5b5035919050565b60006020828403121561589d57600080fd5b813561222581615831565b634e487b7160e01b600052602160045260246000fd5b60208101600383106158d2576158d26158a8565b91905290565b6000806000806000608086880312156158f057600080fd5b85356158fb81615831565b9450602086013561590b81615831565b935060408601359250606086013567ffffffffffffffff8082111561592f57600080fd5b818801915088601f83011261594357600080fd5b81358181111561595257600080fd5b89602082850101111561596457600080fd5b9699959850939650602001949392505050565b60008060006060848603121561598c57600080fd5b833561599781615831565b925060208401356159a781615831565b929592945050506040919091013590565b801515811461140b57600080fd5b600080604083850312156159d957600080fd5b82356159e481615831565b915060208301356159f4816159b8565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615a3e57615a3e6159ff565b604052919050565b600067ffffffffffffffff821115615a6057615a606159ff565b5060051b60200190565b600082601f830112615a7b57600080fd5b81356020615a90615a8b83615a46565b615a15565b82815260059290921b84018101918181019086841115615aaf57600080fd5b8286015b84811015615aca5780358352918301918301615ab3565b509695505050505050565b60008060408385031215615ae857600080fd5b823567ffffffffffffffff80821115615b0057600080fd5b818501915085601f830112615b1457600080fd5b81356020615b24615a8b83615a46565b82815260059290921b84018101918181019089841115615b4357600080fd5b948201945b83861015615b6a578535615b5b81615831565b82529482019490820190615b48565b96505086013592505080821115615b8057600080fd5b50615b8d85828601615a6a565b9150509250929050565b60008060408385031215615baa57600080fd5b8235615bb581615831565b915060208301356159f481615831565b6020808252603a90820152600080516020615f5883398151915260408201527f6e5275675072696365496d7061637450657254686f7573616e64000000000000606082015260800190565b634e487b7160e01b600052601160045260246000fd5b81810381811115610f4757610f47615c10565b634e487b7160e01b600052601260045260246000fd5b600082615c5e57615c5e615c39565b500490565b6000816000190483118215151615615c7d57615c7d615c10565b500290565b600060208284031215615c9457600080fd5b815161222581615831565b60208082526021908201527f4f6e6c79206f776e65722063616e2063616c6c2073656e6452616e646f6d4e466040820152601560fa1b606082015260800190565b80820180821115610f4757610f47615c10565b600080600060608486031215615d0857600080fd5b8351925060208401519150604084015190509250925092565b600060208284031215615d3357600080fd5b5051919050565b6001600160a01b03831681526040810160048310615d5a57615d5a6158a8565b8260208301529392505050565b600060208284031215615d7957600080fd5b8151612225816159b8565b634e487b7160e01b600052603260045260246000fd5b600060018201615dac57615dac615c10565b5060010190565b634e487b7160e01b600052603160045260246000fd5b600082615dd857615dd8615c39565b500690565b60008060408385031215615df057600080fd5b8251915060208301516159f481615831565b600080600060608486031215615e1757600080fd5b8351615e22816159b8565b602085015160409095015190969495509392505050565b600060a082018783526020878185015260a0604085015281875180845260c086019150828901935060005b81811015615e895784516001600160a01b031683529383019391830191600101615e64565b50506001600160a01b03969096166060850152505050608001529392505050565b60006020808385031215615ebd57600080fd5b825167ffffffffffffffff811115615ed457600080fd5b8301601f81018513615ee557600080fd5b8051615ef3615a8b82615a46565b81815260059190911b82018301908381019087831115615f1257600080fd5b928401925b82841015615f3057835182529284019290840190615f17565b979650505050505050565b60008251615f4d8184602087016157da565b919091019291505056fe4f6e6c79206f776e657220616c6c6f77656420746f2063616c6c207365744d69a264697066735822122003b7a432b53fee78df5836de40516a7034b850577127775e91ebea41ded5d81764736f6c63430008100033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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