ETH Price: $1,580.64 (-4.09%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve184081352023-10-22 20:12:23547 days ago1698005543IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005680312.18173001
Recover Link183945892023-10-20 22:42:47549 days ago1697841767IN
0x9C07aC03...F85a9C1e8
0 ETH0.0008983623.48227865
Close Trading An...183944002023-10-20 22:04:59549 days ago1697839499IN
0x9C07aC03...F85a9C1e8
0 ETH0.00221818.36044176
Approve183944002023-10-20 22:04:59549 days ago1697839499IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005239811.23716625
Approve183875422023-10-19 23:04:23550 days ago1697756663IN
0x9C07aC03...F85a9C1e8
0 ETH0.0007832116.7963552
Approve183872612023-10-19 22:08:11550 days ago1697753291IN
0x9C07aC03...F85a9C1e8
0 ETH0.0002941710.07237738
Approve183872462023-10-19 22:05:11550 days ago1697753111IN
0x9C07aC03...F85a9C1e8
0 ETH0.000446919.5842852
Approve183872422023-10-19 22:04:23550 days ago1697753063IN
0x9C07aC03...F85a9C1e8
0 ETH0.000468910.06882045
Approve183872382023-10-19 22:03:35550 days ago1697753015IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005189111.14258305
Approve183872152023-10-19 21:58:59550 days ago1697752739IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006061913
Approve183872142023-10-19 21:58:47550 days ago1697752727IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006549614.04951801
Approve183872132023-10-19 21:58:35550 days ago1697752715IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005739312.30831373
Approve183872092023-10-19 21:57:47550 days ago1697752667IN
0x9C07aC03...F85a9C1e8
0 ETH0.000433559.3096431
Approve183872022023-10-19 21:56:23550 days ago1697752583IN
0x9C07aC03...F85a9C1e8
0 ETH0.0004650910.04126219
Approve183871892023-10-19 21:53:47550 days ago1697752427IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005885212.62113423
Approve183871882023-10-19 21:53:35550 days ago1697752415IN
0x9C07aC03...F85a9C1e8
0 ETH0.000458629.90688271
Approve183871882023-10-19 21:53:35550 days ago1697752415IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005971812.80688271
Approve183871862023-10-19 21:53:11550 days ago1697752391IN
0x9C07aC03...F85a9C1e8
0 ETH0.0013843229.68750644
Approve183871862023-10-19 21:53:11550 days ago1697752391IN
0x9C07aC03...F85a9C1e8
0 ETH0.0005216711.18750644
Approve183871852023-10-19 21:52:59550 days ago1697752379IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006869714.73616992
Approve183871832023-10-19 21:52:35550 days ago1697752355IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006255313.41494219
Approve183871832023-10-19 21:52:35550 days ago1697752355IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006255313.41494219
Approve183871812023-10-19 21:52:11550 days ago1697752331IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006304613.52052851
Approve183871802023-10-19 21:51:59550 days ago1697752319IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006074913.02804679
Approve183871802023-10-19 21:51:59550 days ago1697752319IN
0x9C07aC03...F85a9C1e8
0 ETH0.0006074913.02804679
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer183944042023-10-20 22:05:47549 days ago1697839547
0x9C07aC03...F85a9C1e8
3.12998135 ETH
Transfer183944042023-10-20 22:05:47549 days ago1697839547
0x9C07aC03...F85a9C1e8
3.12998135 ETH
Transfer183944002023-10-20 22:04:59549 days ago1697839499
0x9C07aC03...F85a9C1e8
1.65790314 ETH
Transfer183918132023-10-20 13:24:47549 days ago1697808287
0x9C07aC03...F85a9C1e8
0.00244591 ETH
Transfer183876842023-10-19 23:32:47550 days ago1697758367
0x9C07aC03...F85a9C1e8
0.01083927 ETH
Transfer183873472023-10-19 22:25:23550 days ago1697754323
0x9C07aC03...F85a9C1e8
0.00311024 ETH
Transfer183873462023-10-19 22:25:11550 days ago1697754311
0x9C07aC03...F85a9C1e8
0.00328465 ETH
Transfer183873462023-10-19 22:25:11550 days ago1697754311
0x9C07aC03...F85a9C1e8
0.00275441 ETH
Transfer183873462023-10-19 22:25:11550 days ago1697754311
0x9C07aC03...F85a9C1e8
0.00361924 ETH
Transfer183873452023-10-19 22:24:59550 days ago1697754299
0x9C07aC03...F85a9C1e8
0.00375102 ETH
Transfer183873452023-10-19 22:24:59550 days ago1697754299
0x9C07aC03...F85a9C1e8
0.00379199 ETH
Transfer183873452023-10-19 22:24:59550 days ago1697754299
0x9C07aC03...F85a9C1e8
0.00400722 ETH
Transfer183873452023-10-19 22:24:59550 days ago1697754299
0x9C07aC03...F85a9C1e8
0.00345457 ETH
Transfer183873452023-10-19 22:24:59550 days ago1697754299
0x9C07aC03...F85a9C1e8
0.00611627 ETH
Transfer183873442023-10-19 22:24:47550 days ago1697754287
0x9C07aC03...F85a9C1e8
0.00436305 ETH
Transfer183873442023-10-19 22:24:47550 days ago1697754287
0x9C07aC03...F85a9C1e8
0.00363539 ETH
Transfer183873422023-10-19 22:24:23550 days ago1697754263
0x9C07aC03...F85a9C1e8
0.00468275 ETH
Transfer183873182023-10-19 22:19:35550 days ago1697753975
0x9C07aC03...F85a9C1e8
0.00450902 ETH
Transfer183872802023-10-19 22:11:59550 days ago1697753519
0x9C07aC03...F85a9C1e8
0.0057682 ETH
Transfer183872692023-10-19 22:09:47550 days ago1697753387
0x9C07aC03...F85a9C1e8
0.00498304 ETH
Transfer183872692023-10-19 22:09:47550 days ago1697753387
0x9C07aC03...F85a9C1e8
0.00597488 ETH
Transfer183872372023-10-19 22:03:23550 days ago1697753003
0x9C07aC03...F85a9C1e8
0.00608096 ETH
Transfer183872332023-10-19 22:02:35550 days ago1697752955
0x9C07aC03...F85a9C1e8
0.0089928 ETH
Transfer183872262023-10-19 22:01:11550 days ago1697752871
0x9C07aC03...F85a9C1e8
0.01293339 ETH
Transfer183872242023-10-19 22:00:47550 days ago1697752847
0x9C07aC03...F85a9C1e8
0.00781304 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
IGMI

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
shanghai EvmVersion
File 1 of 13 : CarpetBomb.sol
/* SPDX-License-Identifier: MIT */
/**
 *
 *
 *
 * "we're gonna make it"? fuck yall, I'M gonna make it
 *
 *
 * https://igmi.tech
 *
 *
 * @title IGMI - good traders may profit, but only one buyer is gonna make it.
 *
 * @notice
 * Increase your balanace above qualifying tiers to earn entries for the prize, decrease your balance below those tiers to lose them.
 * Once the timeframe has elapsed, only one current entrant will win the entire LP.
 *
 * IMPORTANT: THE ABILITY TO TRADE THIS TOKEN WILL END WHEN A WINNER IS REQUESTED.
 *
 * @notice
 * ONE ENTRY - 500 tokens (500 * 10 ** 18) // .05%
 * TWO ENTRIES - 1_000 tokens (1_000 * 10 ** 18) // .1%
 * THREE ENTRIES - 1_500 tokens (1_500 * 10 ** 18) // .15%
 * FOUR ENTRIES - 2_000 tokens (2_000 * 10 ** 18) // .2%
 * FIVE ENTRIES - 2_500 tokens (2_500 * 10 ** 18) // .25%
 * SEVEN ENTRIES - 3_500 tokens (3_500 * 10 ** 18) // .35%
 * TEN ENTRIES - 5_000 tokens (5_000 * 10 ** 18) // .5%
 *
 * @notice
 * DETAILS:
 * After 24 hours, owner will close trading permanently and request a random number off-chain.
 * The random number is automatically used to find a random user by their entry index.
 * When the winner is found, liquidity is completely pulled by the contract, and the winning user gets ALL of the ETH pulled from the liquidity pool.
 * You are free to swap in and out of the pool, earning and losing entries as you wish, until that point.
 * Exit the game and take your profits, or risk it for a chance at the big prize. Are you gonna make it?
 *
 * NOTE: The contract owner is permanently incapable of pulling liquidity for themself.
 */

pragma solidity ^0.8.20;

import {VRFV2WrapperConsumerBase} from "@chainlink/v0.8/vrf/VRFV2WrapperConsumerBase.sol";
import {IUniswapV2Pair} from "@uniswap-core/interfaces/IUniswapV2Pair.sol";
import {IUniswapV2Router02} from "@uniswap-periphery/interfaces/IUniswapV2Router02.sol";
import {IUniswapV2Factory} from "@uniswap-core/interfaces/IUniswapV2Factory.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH {
    function deposit() external payable;

    function transfer(address to, uint256 value) external returns (bool);

    function balanceOf(address holder) external returns (uint256);
}

contract IGMI is ERC20, Ownable, VRFV2WrapperConsumerBase {
    /*//////////////////////////////////////////////////////////////
                                 STRUCTS
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev comments on structs denote the bit size of the element
     */

    /**
     * @dev struct assigned to all users
     * @param buy user's buy block
     * @param exemptfee sets user exempt from fees
     * @param exemptlimit sets user exempt from limits
     * @param index the user's entry index (represents the user in the global entries)
     */
    struct USER {
        uint256 buy; // 32
        uint256 exemptfee; // 8
        uint256 exemptlimit; // 8
        uint256 index; // 24
    }

    /**
     * @dev struct which stores values used in transfer checks
     * @param changeblock the block on which trading begins
     * @param limitsblock the block after which limits are no longer checked
     * @param standardmode when enabled, there are no fees, restrictions, or entry logging
     * @param feesenabled when enabled, fees are taken
     * @param cooldown the minimum block count that must pass before a user can perform another transfer
     * @param eoatransfers when enabled, wallet-to-wallet transfers (externally-owned addresses, EOAs) are allowed
     */
    struct CHECKS {
        uint256 changeblock; // 32
        uint256 limitsblock; // 32
        uint256 standardmode; // 8
        uint256 feesenabled; // 8
        uint256 cooldown; // 8
        uint256 eoatransfers; // 8
    }

    /**
     * @dev struct which stores fee values
     * @param feebuy fee on buy
     * @param feesell fee on sell
     * @param feeliq fee for liquidity on both buys and sells
     */
    struct FEES {
        uint256 feebuy; // 8
        uint256 feesell; // 8
        uint256 feeliq; // 8
    }

    /**
     * @dev struct which stores max amounts at the 0th decimal (1 vs. 1 * 1e18)
     * @param maxtx max transaction amount for non-exempt users within the limits window
     * @param maxbal max balance for non-exempt users within the limits window
     */
    struct MAX {
        uint256 maxtx; // 16
        uint256 maxbal; // 24
    }

    /*//////////////////////////////////////////////////////////////
                                 CONSTANTS
    //////////////////////////////////////////////////////////////*/

    // minimum amount of tokens held to qualify for corresponding entry counts
    uint256 private constant ONE_ENTRY = 500 * 1e18;
    uint256 private constant TWO_ENTRIES = 1_000 * 1e18;
    uint256 private constant THREE_ENTRIES = 1_500 * 1e18;
    uint256 private constant FOUR_ENTRIES = 2_000 * 1e18;
    uint256 private constant FIVE_ENTRIES = 2_500 * 1e18;
    uint256 private constant SEVEN_ENTRIES = 3_500 * 1e18;
    uint256 private constant TEN_ENTRIES = 5_000 * 1e18;

    uint256 private constant DECIMAL_MULTIPLIER = 1e18;
    uint256 private constant ROLL_IN_PROGRESS = 9999999;

    /*//////////////////////////////////////////////////////////////
                                 STORAGE
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev
     * this uint256 holds these values in this order: CHECKS, FEES, MAX, currentUserIndex, currentEntryIndex
     * see getAllData()
     */
    uint256 private data_;

    uint128 public _randomResult;
    uint48 public _closeLimitBlock;
    uint48 public _closedAtTimestamp;
    uint32 public _linkFee;
    uint256 public _pureRandomNumber;

    // general user storage
    mapping(address => uint256) private _users;
    // individual user entry tracking
    mapping(address => uint256) private _userEntries;
    // entries 'array'
    mapping(uint256 => uint256) private _allEntries;
    // user index matching
    mapping(uint256 => address) private _indexUser;

    address private immutable WETH;
    IUniswapV2Router02 public immutable ROUTER;

    address private _pair;
    address private _wrapper;
    address public _winner;

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

    event FeesUpdated(uint256 buy, uint256 sell, uint256 liq);
    event MaxUpdated(uint256 maxtx, uint256 maxbal);
    event FeesToggled(bool feesenabled);
    event StandardModeToggled(bool standardmode);
    event EOATransfersToggled(bool eoatransfers);
    event LimitBlockReduced(uint256 newblock);
    event CooldownReduced(uint256 newcooldown);
    event LinkFeeUpdated(uint256 newfee);
    event LiqBoosted(address token, uint256 amount);
    event EntriesGained(address user, uint256 amount);
    event EntriesLost(address user, uint256 amount);
    event DiceRolled(uint256 indexed requestId);
    event DiceLanded(uint256 indexed requestId, uint256 indexed result);
    event SentToWinner(address _holder);

    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error sendToZero();
    error notOpen();
    error alreadyOpen();
    error vrfCallbackNotComplete();
    error closeConditionsUnmet();
    error notAuthorized();
    error exceedMaxBalance();
    error belowMinBalance();
    error exceedMaxTx();
    error valueTooLow();
    error valueTooHigh();
    error txCooldown();
    error noEOAtoEOATransfers();
    error failedToSendETH();
    error castOverflow(uint256 value, uint256 bytecount);

    /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address router_, address linkAddress, address wrapperAddress)
        payable
        ERC20("IGMI", "IGMI")
        VRFV2WrapperConsumerBase(linkAddress, wrapperAddress)
    {
        _wrapper = wrapperAddress;
        _setUserData(address(this), 0, 1, 1, 0);
        _setUserData(msg.sender, 0, 1, 1, 0);
        _mint(address(this), 1_000_000 * DECIMAL_MULTIPLIER);
        ROUTER = IUniswapV2Router02(router_);
        WETH = ROUTER.WETH();
        _linkFee = uint32(1_000_000);
    }

    /*//////////////////////////////////////////////////////////////
                            STANDARD LOGIC
    //////////////////////////////////////////////////////////////*/

    receive() external payable {}

    // ERC20 override
    function _transfer(address sender, address recipient, uint256 amount) internal override {
        uint256 data = data_;
        CHECKS memory checks = _getChecksData(data);
        USER memory senderData = _getUserData(_users[sender]);
        USER memory recipientData = _getUserData(_users[recipient]);
        // common conditions for no fee/limit transfers
        if (
            sender == address(this) // mid-swap
                || checks.standardmode != 0 // no fees, no restrictions for anyone
                || (senderData.exemptfee != 0 && senderData.exemptlimit != 0) // token contract, owner, or, after trading close, the router
                || (recipientData.exemptfee != 0 && recipientData.exemptlimit != 0) // token contract, owner, or, after trading close, the router
        ) {
            super._transfer(sender, recipient, amount);

            // fee/limit logic
        } else {
            // check if trading is open
            if (checks.changeblock == 0) {
                revert notOpen();
            }

            bool buy;
            address pair = _pair;
            MAX memory max = _getMaxData(data);
            FEES memory fees = _getFeesData(data);
            USER memory origData = _getUserData(_users[tx.origin]);

            // ------BUY------ //
            if (pair == sender) {
                // buy restrictions
                if (recipientData.exemptlimit == 0) {
                    // restrictions - launch window
                    if (checks.limitsblock > block.number) {
                        if (block.number < checks.changeblock + 2) {
                            // first two blocks get 20% buy fees
                            fees.feebuy = 10;
                            fees.feeliq = 10;
                        }
                        if (amount > max.maxtx * DECIMAL_MULTIPLIER) {
                            revert exceedMaxTx();
                        }
                        if ((balanceOf(recipient) + amount) > max.maxbal * DECIMAL_MULTIPLIER) {
                            revert exceedMaxBalance();
                        }
                        // cooldown
                        unchecked {
                            if (
                                recipientData.buy + checks.cooldown > block.number
                                    || origData.buy + checks.cooldown > block.number
                            ) {
                                revert txCooldown();
                            }
                        }
                        // 10% buy first 10 minutes
                        fees.feebuy = 7;
                        fees.feeliq = 3;
                    }
                    // set user's buy block
                    recipientData.buy = block.number;

                    // update user buy block if they have previously bought (this is otherwise handled in _checkEligibility)
                    if (recipientData.index != 0) {
                        _setUserData(
                            recipient,
                            recipientData.buy,
                            recipientData.exemptfee,
                            recipientData.exemptlimit,
                            recipientData.index
                        );
                    }

                    _checkEligibility(
                        recipient, recipientData, amount, data, fees, true, checks.feesenabled != 0 ? true : false
                    );

                    // assigning a buy block to tx.origin
                    if (tx.origin != recipient && checks.limitsblock > block.number) {
                        _setUserData(
                            tx.origin,
                            recipientData.buy,
                            recipientData.exemptfee,
                            recipientData.exemptlimit,
                            recipientData.index
                        );
                    }
                }

                buy = true;
            } else {
                // ------SELL------ //
                if (pair == recipient) {
                    // restrictions - permanent
                    if (senderData.exemptlimit == 0 && checks.cooldown != 0) {
                        unchecked {
                            if (
                                senderData.buy + checks.cooldown > block.number
                                    || origData.buy + checks.cooldown > block.number
                            ) {
                                revert txCooldown();
                            }
                        }
                    }

                    _checkEligibility(
                        sender, senderData, amount, data, fees, false, checks.feesenabled != 0 ? true : false
                    );

                    uint256 contractBalance = balanceOf(address(this));
                    // only attempt to sell an amount that uniswap shouldnt complain about (INSUFFICIENT_OUTPUT_AMOUNT)
                    if (contractBalance > ONE_ENTRY) {
                        // perform fee swap for maximum 5% price impact
                        uint256 priceImpactLimiter = (balanceOf(recipient) * 5) / 100;
                        _nestedSwap(contractBalance > priceImpactLimiter ? priceImpactLimiter : (contractBalance - 1));
                    }
                }
            }

            // take fees on swaps to/from pair only, and perform final transfer
            if (
                checks.feesenabled != 0
                    && (
                        ((recipientData.exemptfee == 0) && pair == sender)
                            || ((senderData.exemptfee == 0) && pair == recipient)
                    )
            ) {
                _collectAndTransfer(sender, recipient, amount, buy, fees);

                // EOA to EOA transfer (no fees)
            } else {
                // if recipient is not exempt from limits, assign highest limit between sender and recipient to recipient
                if (pair != sender && pair != recipient) {
                    // if EOA to EOA transfers are disabled, revert
                    if (checks.eoatransfers == 0) revert noEOAtoEOATransfers();
                    if (recipientData.exemptfee == 0 && recipientData.buy < senderData.buy) {
                        recipientData.buy = senderData.buy;
                    }

                    // check if sender loses entries
                    _checkEligibility(sender, senderData, amount, data, fees, false, false);

                    // check if recipient gains entries
                    _checkEligibility(recipient, recipientData, amount, data, fees, true, false);
                }

                super._transfer(sender, recipient, amount);
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        PRIVATE/INTERNAL WRITE
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev
     * use this function to take fees and perform the final transfer
     * although this function is only used once, it's separated due to stack-too-deep error
     * @param sender the address of the sender
     * @param recipient the address of the recipient
     * @param amount the amount being sent
     * @param buy whether or not this is a buy
     * @param fees the FEES struct
     */
    function _collectAndTransfer(address sender, address recipient, uint256 amount, bool buy, FEES memory fees)
        private
    {
        (uint256 fee, uint256 liqFee) = buy ? (fees.feebuy, fees.feeliq) : (fees.feesell, fees.feeliq);
        uint256 collection = (amount * fee) / 100;
        uint256 liq = (amount * liqFee) / 100;
        uint256 remainder = amount - collection - liq;
        if (buy) {
            // on buy, keep liq fee amount in the pair
            super._transfer(sender, recipient, remainder);
        } else {
            // ensures liq fee tokens are not counted as part of the amountIn
            if (liq != 0) {
                super._transfer(sender, recipient, liq);
                IUniswapV2Pair(recipient).sync();
            }
            super._transfer(sender, recipient, remainder);
        }
        if (collection != 0) {
            super._transfer(sender, address(this), collection);
        }
    }

    function _nestedSwap(uint256 amount) private {
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = WETH;
        ROUTER.swapExactTokensForETHSupportingFeeOnTransferTokens(amount, 0, path, address(this), block.timestamp);
    }

    /**
     * @dev
     * this function determines if user will gain or lose entries for this transaction, and adds/removes them accordingly
     * this function also sets all data for this user and assigns them an index if they are receiving tokens for the first time
     * @param user address of the user being checked
     * @param userData the user's USER struct
     * @param amount the amount being sent
     * @param data the global data_ value, sent through memory
     * @param buy used to determine whether we should check if user is gaining or losing entries
     */
    function _checkEligibility(
        address user,
        USER memory userData,
        uint256 amount,
        uint256 data,
        FEES memory fees,
        bool buy,
        bool checkFees
    ) private {
        uint256 entriesCount = _getUserEntryCount(user);
        uint256 eligibleCount;

        // balance is increasing
        if (buy) {
            if (checkFees) {
                if (fees.feebuy != 0 && fees.feeliq != 0) {
                    eligibleCount = getEligibleCount(
                        balanceOf(user) + (amount - ((amount * fees.feebuy) / 100) - ((amount * fees.feeliq) / 100))
                    );
                } else if (fees.feebuy != 0 && fees.feeliq == 0) {
                    eligibleCount = getEligibleCount(balanceOf(user) + (amount - ((amount * fees.feebuy) / 100)));
                } else if (fees.feebuy == 0 && fees.feeliq != 0) {
                    eligibleCount = getEligibleCount(balanceOf(user) + (amount - ((amount * fees.feeliq) / 100)));
                } else {
                    // feebuy == 0 && feeliq == 0, but feesell != 0
                    eligibleCount = getEligibleCount(balanceOf(user) + amount);
                }
                // EOA to EOA transfer
            } else {
                eligibleCount = getEligibleCount(balanceOf(user) + amount);
            }

            uint256 userIndex = userData.index;
            uint256 newUserIndex = userData.index;

            // store user and assign an index if not yet assigned (first buy)
            if (userIndex == 0) {
                userIndex = _getCurrentUserIndex(data);
                newUserIndex = userIndex;
                _setUserData(user, userData.buy, userData.exemptfee, userData.exemptlimit, userIndex);
                _indexUser[userIndex] = user;
                unchecked {
                    ++newUserIndex;
                }
            }

            // skip remaining logic and only update userIndex if user is new and entry count is unchanged
            if ((eligibleCount == 0 || eligibleCount == entriesCount) && userIndex != newUserIndex) {
                _setCurrentUserIndex(data, newUserIndex);
                return;
            }

            if (eligibleCount > entriesCount) {
                uint256 entryIndex = _getCurrentEntryIndex(data);
                // add user entries to the user's entries 'array'
                (uint256 newEntriesAmount) = _addEntriesToUserEntries(user, eligibleCount - entriesCount, entryIndex);

                // add user entries to the total entries 'array'
                uint256 newEntryIndex = _addEntriesToAllEntries(userIndex, newEntriesAmount, entryIndex);

                if (userIndex != newUserIndex) {
                    // update both current user index and entry index if adding a qualifying user on this buy
                    _setCurrentIndeces(data, newUserIndex, newEntryIndex);
                } else {
                    // only update entry index
                    _setCurrentEntryIndex(data, newEntryIndex);
                }

                emit EntriesGained(user, eligibleCount - entriesCount);
            }
            // balance is decreasing
        } else {
            // avoid underflow
            if (balanceOf(user) < amount) return;

            eligibleCount = getEligibleCount(balanceOf(user) - amount);

            if (eligibleCount < entriesCount) {
                uint256 subAmount = entriesCount - eligibleCount;
                uint24[] memory removedEntries = new uint24[](subAmount);

                // remove user entries from the user's entries 'array'
                removedEntries = _removeEntriesFromUserEntries(user, subAmount);

                // remove user entries from the total entries 'array'
                _removeEntriesFromAllEntries(removedEntries);

                emit EntriesLost(user, subAmount);
            }
        }
    }

    /**
     * @dev
     * this function iteratively adds entries to the _allEntries mapping
     * the _allEntries mapping is treated as an object which contains sequential arrays of 10 numbers each.
     * entries are stored as such: _allEntries[0] = [0,1,2,3,4,5,6,7,8,9], _allEntries[1] = [10,11,12,13,14,15,16,17,18,19], etc.
     * we can use division and modulo on a given entry index to always find the key of the 'array' it's in, and its position in that 'array'
     * note that 24 in the following function represents the maximum bit size of an index.
     * @param indexUser the index of the user being assigned entries
     * @param entryCount the number of entries to assign this user
     * @param currentEntryIndex the next entry index to assign a user
     * @return currentEntryIndex the new value of currentEntryIndex, after adding entries
     */
    function _addEntriesToAllEntries(uint256 indexUser, uint256 entryCount, uint256 currentEntryIndex)
        private
        returns (uint256)
    {
        uint256 currentKey;
        unchecked {
            currentKey = currentEntryIndex / 10;
        }
        uint256 currentBitObject = _allEntries[currentKey];

        for (uint256 i; i < entryCount;) {
            // retrieve key of current bit object
            uint256 key;
            unchecked {
                key = currentEntryIndex / 10;
            }

            // determine position within that bit object
            // ex. currentPosition = 35
            // key = 35 / 10 = 3
            // position within bit object = 35 % (3 * 10) = 5
            // cannot modulo by 0, so just use currentPosition if key is 0
            uint256 position;
            unchecked {
                position = currentEntryIndex > 9 ? currentEntryIndex % (key * 10) : currentEntryIndex;
            }

            // determine starting position
            // ex. position within bit object is 2
            // startingPosition = 24 (length) * 2 = 48
            uint256 startingPosition;
            unchecked {
                startingPosition = 24 * position;
            }

            if (startingPosition != 0) {
                currentBitObject |= indexUser << startingPosition;
            } else {
                currentBitObject = indexUser << startingPosition;
            }

            // update storage if at the end of the uint, or the loop is complete
            unchecked {
                if (position == 9 || i + 1 == entryCount) {
                    _allEntries[key] = currentBitObject;
                }

                ++currentEntryIndex;
                ++i;
            }
        }
        // return new entry index, to be stored in calling function
        return currentEntryIndex;
    }

    /**
     * @dev adds entries to a user's entries 'array'
     * @param user the address of the user
     * @param addAmount the amount of entries to add
     * @param currentEntryIndex the global current entry index, which was not affected by this function
     * @return addAmount the amount of entries added
     */
    function _addEntriesToUserEntries(address user, uint256 addAmount, uint256 currentEntryIndex)
        private
        returns (uint256)
    {
        uint256 currentBitObject = _userEntries[user];
        // get the next entry position
        (, uint256 nextEntryPosition) = _getCurrentEntryCountAndNextEntryPosition(currentBitObject);

        // although a 10th entry means the next entry bit position is 240 (24 * 10),
        // nextEntryPosition doesn't get a final 24 added to it in _getCurrentEntryCountAndNextEntryPosition() before the loop ends.
        // this would matter if we had a tier that qualifies for 9 entries, but we don't, so it doesn't.
        // it's cheaper not to perform that check and addition.
        if (nextEntryPosition == 216) return (addAmount);

        for (uint256 i; i < addAmount;) {
            currentBitObject |= currentEntryIndex << nextEntryPosition;
            unchecked {
                ++currentEntryIndex;
                ++i;
            }
            if (nextEntryPosition == 216) {
                // ensure we don't attempt to add more entries than will fit (216 means user is in the 10-entry tier already)
                break;
            }
            unchecked {
                nextEntryPosition += 24;
            }
        }
        _userEntries[user] = currentBitObject;
        return (addAmount);
    }

    /**
     * @dev this function accepts an array of entries to find and remove from the global entries 'array'
     * @param entries an array of entries to remove
     */
    function _removeEntriesFromAllEntries(uint24[] memory entries) private {
        uint256 entriesLength = entries.length;
        uint256 previousKey;
        uint256 currentBitObject;
        for (uint256 i; i < entriesLength;) {
            uint256 entry = entries[i];
            uint256 currentKey;

            // get the key for the current entry
            unchecked {
                currentKey = entry / 10;
            }
            if (i == 0) {
                currentBitObject = _allEntries[currentKey];
            }
            if (i != 0 && previousKey != currentKey) {
                // store previous changes
                _allEntries[previousKey] = currentBitObject;
                // get current key's 'bit object' and store it to memory
                currentBitObject = _allEntries[currentKey];
            }

            // determine position within that bit object
            // cannot modulo by 0, so just use currentPosition if key is 0
            uint256 position;
            unchecked {
                position = entry > 9 ? entry % (currentKey * 10) : entry;
            }
            uint256 startingPosition;
            unchecked {
                startingPosition = 24 * position;
            }
            // update the bit object by removing this entry
            currentBitObject = _clearBits(currentBitObject, startingPosition, 24);

            // retain the updated bit object in memory, unless this is the last iteration of the loop
            unchecked {
                if (i + 1 == entriesLength) {
                    _allEntries[currentKey] = currentBitObject;
                }
                previousKey = currentKey;
                ++i;
            }
        }
    }

    /**
     * @dev this function removes entries from a user's entries 'array', starting at the most recently-added entry
     * @param user the address of the user to remove entries from
     * @param subAmount the amount of entries to remove
     * @return removedEntries the entries that were removed, which now must be removed from the global entries 'array'
     */
    function _removeEntriesFromUserEntries(address user, uint256 subAmount) private returns (uint24[] memory) {
        // get existing entry count
        uint256 entryCount = _getUserEntryCount(user);
        // get the user's bit object
        uint256 entriesBits = _userEntries[user];
        // initialize array of entries being removed
        uint24[] memory removedEntries = new uint24[](subAmount);
        // start bitPosition at the user's last entry
        uint256 bitPosition = (entryCount * 24);
        // add entries being removed to memory array and find starting point for mask
        for (uint256 i; i < subAmount;) {
            // move to the beginning of entry's bit space
            unchecked {
                bitPosition -= 24;
            }
            removedEntries[i] = uint24(entriesBits >> bitPosition);
            unchecked {
                ++i;
            }
        }
        // update the bit object by removing this entry
        _userEntries[user] = _clearBits(entriesBits, bitPosition, (24 * subAmount));

        // return an array of the user's removed entries to remove from the total entries
        return removedEntries;
    }

    /**
     * @dev
     * sets the entire global data_ value at once
     * the bitSize array holds the size of each sequential element to ensure they are put in the right position
     * @param tempData an array of all of the values in the global data_ value. they are as follows, with corresponding bit size:
     * @dev uint256 changeblock, // 32
     * @dev uint256 limitsblock, // 32
     * @dev uint256 standardmode, // 8
     * @dev uint256 feesenabled, // 8
     * @dev uint256 cooldown, // 8
     * @dev uint256 feebuy, // 8
     * @dev uint256 feesell, // 8
     * @dev uint256 feeliq, // 8
     * @dev uint256 maxtx, // 16
     * @dev uint256 maxbal, // 24
     * @dev uint256 userIndex, // 24
     * @dev uint256 entryIndex, // 24
     */
    function _setData(uint256[13] memory tempData) private {
        uint256 length = tempData.length;
        uint256 shift;
        uint256 data;
        uint8[13] memory bitSize = [32, 32, 8, 8, 8, 8, 8, 8, 8, 16, 24, 24, 24]; // bit size for each element
        require(length == 13);
        for (uint256 i; i < length;) {
            _overflowCheck(tempData[i], bitSize[i]);
            data |= tempData[i] << shift;
            unchecked {
                shift += bitSize[i];
                ++i;
            }
        }
        data_ = data;
    }

    /**
     * @dev sets data assigned to a user
     * @param user the address of the user
     * @param buy the user's buy block
     * @param exemptfee whether or not the user is exempt from fees (0 is false, 1 is true)
     * @param exemptlimit whether or not the user is exempt from limits (0 is false, 1 is true)
     * @param index the user's index, used when giving them entries
     */
    function _setUserData(
        address user,
        uint256 buy, // 32
        uint256 exemptfee, // 8
        uint256 exemptlimit, // 8
        uint256 index // 24
    ) private {
        _overflowCheck(buy, 32);
        uint256 data = buy;
        _overflowCheck(exemptfee, 8);
        data |= exemptfee << 32;
        _overflowCheck(exemptlimit, 8);
        data |= exemptlimit << 40;
        _overflowCheck(index, 24);
        data |= index << 48;
        _users[user] = data;
    }

    /**
     * @dev sets just the CHECKS struct in the global data_ value
     * @param changeblock the block on which trading begins
     * @param limitsblock the block after which limits are no longer checked
     * @param standardmode when enabled, there are no fees, restrictions, or entry logging
     * @param feesenabled when enabled, fees are taken
     * @param cooldown the minimum block count that must pass before a user can perform another transfer
     * @param eoatransfers when enabled, allow transfers from one EOA to another (wallet to wallet)
     */
    function _setChecksData(
        uint256 changeblock, // 32
        uint256 limitsblock, // 32
        uint256 standardmode, // 8
        uint256 feesenabled, // 8
        uint256 cooldown, // 8
        uint256 eoatransfers // 8
    ) private {
        uint256 data = _clearBits(data_, 0, 96);
        _overflowCheck(changeblock, 32);
        data |= changeblock << 0;
        _overflowCheck(limitsblock, 32);
        data |= limitsblock << 32;
        _overflowCheck(standardmode, 8);
        data |= standardmode << 64;
        _overflowCheck(feesenabled, 8);
        data |= feesenabled << 72;
        _overflowCheck(cooldown, 8);
        data |= cooldown << 80;
        _overflowCheck(eoatransfers, 8);
        data |= eoatransfers << 88;
        data_ = data;
    }

    /**
     * @dev sets the changeblock to 0 to halt trading
     */
    function _setChecksDataCloseTrading() private {
        data_ = _clearBits(data_, 0, 32);
    }

    /**
     * @dev sets just the FEES struct in the global data_ value
     * @param feebuy fee on buy
     * @param feesell fee on sell
     * @param feeliq fee for liquidity on both buys and sells
     */
    function _setFeesData(
        uint256 feebuy, // 8
        uint256 feesell, // 8
        uint256 feeliq // 8
    ) private {
        uint256 data = _clearBits(data_, 96, 24);
        _overflowCheck(feebuy, 8);
        data |= feebuy << 96;
        _overflowCheck(feesell, 8);
        data |= feesell << 104;
        _overflowCheck(feeliq, 8);
        data |= feeliq << 112;
        data_ = data;
    }

    /**
     * @dev sets just the MAX struct in the global data_ value
     * @param maxtx max transaction amount for non-exempt users within the limits window
     * @param maxbal max balance for non-exempt users within the limits window
     */
    function _setMaxData(
        uint256 maxtx, // 16
        uint256 maxbal // 24
    ) private {
        uint256 data = _clearBits(data_, 120, 40);
        _overflowCheck(maxtx, 16);
        data |= maxtx << 120;
        _overflowCheck(maxbal, 24);
        data |= maxbal << 136;
        data_ = data;
    }

    /**
     * @dev sets the next user index
     * @param data the global data_ value
     * @param index the next user index to assign a user
     */
    function _setCurrentUserIndex(uint256 data, uint256 index) private {
        data = _clearBits(data, 160, 24);
        _overflowCheck(index, 24);
        data |= index << 160;
        data_ = data;
    }

    /**
     * @dev sets the next entry index
     * @param data the global data_ value
     * @param index the next entry index to assign a user
     */
    function _setCurrentEntryIndex(uint256 data, uint256 index) private {
        data = _clearBits(data, 184, 24);
        _overflowCheck(index, 24);
        data |= index << 184;
        data_ = data;
    }

    /**
     * @dev sets both the next user index and the next entry index
     * @param data the global data_ value
     * @param userIndex the next index to assign a user
     * @param entryIndex the next entry index to assign a user
     */
    function _setCurrentIndeces(uint256 data, uint256 userIndex, uint256 entryIndex) private {
        data = _clearBits(data, 160, 48);
        _overflowCheck(userIndex, 24);
        data |= userIndex << 160;
        _overflowCheck(entryIndex, 24);
        data |= entryIndex << 184;
        data_ = data;
    }

    /**
     * @dev sets a user exempt from fees, limits, or both
     * @param userAddress the address of the user
     * @param exemptfee whether or not the user is exempt from fees (0 is false, 1 is true)
     * @param exemptlimit whether or not the user is exempt from limits (0 is false, 1 is true)
     */
    function _setUserExempt(address userAddress, bool exemptfee, bool exemptlimit) private {
        USER memory user = _getUserData(_users[userAddress]);
        uint256 fee = exemptfee ? uint256(1) : 0;
        uint256 limit = exemptlimit ? uint256(1) : 0;
        _setUserData(userAddress, user.buy, fee, limit, user.index);
    }

    /**
     * @dev
     * this function is run as the result of a callback from the VRF coordinator
     * we are taking the huge random number we get back, and getting a random entry index <= the total number of entries recorded
     * @param _requestId the id created by the original request
     * @param _randomWords the random number
     */
    function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
        uint256 finalIndex = _getCurrentEntryIndex(data_);
        unchecked {
            --finalIndex; // last entry index assigned is one less than current value of currentEntryIndex
        }
        _pureRandomNumber = _randomWords[0];

        uint128 randomResult = uint128(_pureRandomNumber % (finalIndex));
        _randomResult = randomResult;
        emit DiceLanded(_requestId, uint256(randomResult));

        // perform an encodeCall so that the values above can get set successfully even if this function call fails
        // it is possible for this function to fail if it consumes more gas than the coordinator expects it to
        // in that case, dev will run the external sendToWinner function and pay the gas themself
        (bool success,) = address(this).call(abi.encodeCall(this.sendToWinner, (uint256(randomResult), finalIndex)));
        success;
    }

    /**
     * @dev
     * first, we attempt to get a winner at the previously-defined winner entry index
     * if there is no user index at this position (because the user that was here sold and lost this entry),
     * we iterate up through the entries looking for a user index that is not 0
     * if there are none above this point, we go back to the original winner entry index and iterate down
     * we do not accept any circumstance in which the user index is 0, as this index is not assigned to anyone.
     * when we find a winner, we pull all liquidity and send the winner all of the ETH.
     * @param randomResult the currently-selected random entry index
     * @param finalIndex the very last recorded entry index (used for finding a new entry if the selected index has no entrant)
     */
    function _sendToWinner(uint256 randomResult, uint256 finalIndex) private {
        uint256 winnerIndex = randomResult;
        address winner;
        (, winner) = _getEntrantIdAndAddressAtIndex(winnerIndex);
        // if address at this index is unassigned (sold their entry), find the next entry index assigned to a user
        if (winner == address(0)) {
            // if not at the end of the entry list, increment through entries
            if (winnerIndex < finalIndex) {
                uint256 diff = finalIndex - winnerIndex;
                for (uint256 i; i < diff;) {
                    unchecked {
                        ++winnerIndex;
                    }
                    (, winner) = _getEntrantIdAndAddressAtIndex(winnerIndex);
                    if (winner != address(0)) {
                        break;
                    }
                    unchecked {
                        ++i;
                    }
                }
            }
            // contingency for reaching the end of the list - decrement from originally-selected entry index
            if (winner == address(0) && winnerIndex == finalIndex) {
                winnerIndex = randomResult;
                for (uint256 i; i < randomResult;) {
                    unchecked {
                        --winnerIndex;
                    }
                    (, winner) = _getEntrantIdAndAddressAtIndex(winnerIndex);
                    if (winner != address(0)) {
                        break;
                    }
                    unchecked {
                        ++i;
                    }
                }
            }
            require(winner != address(0));
            _randomResult = uint128(winnerIndex);
        }

        _winner = winner;
        IERC20(_pair).approve(address(ROUTER), type(uint256).max);
        (, uint256 lpEth) = ROUTER.removeLiquidityETH(
            address(this), IERC20(_pair).balanceOf(address(this)), 0, 0, address(this), block.timestamp
        );
        (bool sent,) = winner.call{value: lpEth}("");
        require(sent, "Failed to send!");
        emit SentToWinner(winner);
    }

    /*//////////////////////////////////////////////////////////////
                        PRIVATE/INTERNAL VIEW/PURE
    //////////////////////////////////////////////////////////////*/

    /**
     * @dev checks amount qualifies for entries
     * @param amount amount being transferred
     * @return entryCount the amount of entries this amount qualifies for
     */
    function getEligibleCount(uint256 amount) private pure returns (uint256) {
        if (amount < ONE_ENTRY) {
            return 0;
        } else if (amount < TWO_ENTRIES) {
            return 1;
        } else if (amount < THREE_ENTRIES) {
            return 2;
        } else if (amount < FOUR_ENTRIES) {
            return 3;
        } else if (amount < FIVE_ENTRIES) {
            return 4;
        } else if (amount < SEVEN_ENTRIES) {
            return 5;
        } else if (amount < TEN_ENTRIES) {
            return 7;
        } else {
            return 10;
        }
    }

    /**
     * @param user address of the user being checked
     * @param position the position of the entry being retrieved in the user's entries 'array' (0 through 9, 10 total possible positions)
     * @return entryId the entry id at that position
     */
    function _getUserEntries(address user, uint256 position) private view returns (uint24) {
        require(position < 10, "Out of range");
        uint256 bitPosition = position * 24;
        uint256 bitObj = _userEntries[user];

        uint24 entryId = uint24(bitObj >> bitPosition);
        return (entryId);
    }

    /**
     * @param user address of the user being checked
     * @return count the amount of entries user has
     */
    function _getUserEntryCount(address user) private view returns (uint256) {
        uint256 currentBitObject = _userEntries[user];
        // get the current entry count
        (uint256 count,) = _getCurrentEntryCountAndNextEntryPosition(currentBitObject);
        return count;
    }

    /**
     * @dev performs bit masking. see comments in function for step-by-step description of behavior
     * @param bitObject the bits to be manipulated
     * @param startingPosition the position within the bits to start the mask
     * @param bitSize the total bit size to mask from the starting position
     * @return clearedBits the original bit 'object' with the targeted bit space cleared
     */
    function _clearBits(uint256 bitObject, uint256 startingPosition, uint256 bitSize)
        private
        pure
        returns (uint256 clearedBits)
    {
        uint256 mask = ~(uint256(2 ** bitSize - 1) << startingPosition); // set all 1s for the length of the bit space (as in a uint24), shift it left x bits to make it the appropriate entry, and then invert it to set those bits to zero
        // ex. mask = 11110001111
        clearedBits = bitObject & mask; // takes the existing bits and overwrites with the new 0 value bits
            // ex. currentBits = 10110110110
            // ex. new value = 10110000110
    }

    /**
     * @dev
     * the _allEntries mapping is treated as an object which contains sequential arrays of 10 numbers each.
     * entries are stored as such: _allEntries[0] = [0,1,2,3,4,5,6,7,8,9], _allEntries[1] = [10,11,12,13,14,15,16,17,18,19], etc.
     * we can use division and modulo on a given entry index to always find the key of the 'array' its in, and its position in that 'array'
     * note that 24 in the following function represents the maximum bit size of an index.
     * @param index the entry index
     * @return userIndex the user index at that entry position
     * @return userAddress the address of the user with that userIndex
     */
    function _getEntrantIdAndAddressAtIndex(uint256 index) private view returns (uint24, address) {
        uint256 key = index / 10;
        uint256 position = index > 9 ? index % (key * 10) : index;
        uint256 bitPosition = position * 24;
        uint256 bitObj = _allEntries[key];

        uint24 userIndex = uint24(bitObj >> bitPosition);
        return (userIndex, _indexUser[userIndex]);
    }

    /**
     * @dev this function finds the existing entry count of a user, and the bit space after their most recently recorded entry
     * @param bitObject the entries bit 'object' of the user
     * @return count the amount of entries the user already has
     * @return nextEntryPosition the bit position where the next entry can be inserted
     */
    function _getCurrentEntryCountAndNextEntryPosition(uint256 bitObject)
        private
        pure
        returns (uint256 count, uint256 nextEntryPosition)
    {
        for (; count < 10;) {
            uint24 entry;
            nextEntryPosition = count * 24;
            entry = uint24(bitObject >> nextEntryPosition);
            if (entry == 0) {
                break;
            }
            unchecked {
                ++count;
            }
        }
    }

    /**
     * @dev returns all of the values in the global data_ value
     * @param data the global data_ value
     * @return checks the CHECKS struct
     * @return fees the FEES struct
     * @return max the MAX struct
     * @return currentUserIndex the next user index to be assigned to a user
     * @return currentEntryIndex the next entry index to be assigned to a user
     */
    function _getAllData(uint256 data)
        private
        pure
        returns (
            CHECKS memory checks,
            FEES memory fees,
            MAX memory max,
            uint256 currentUserIndex,
            uint256 currentEntryIndex
        )
    {
        checks.changeblock = uint256(uint32(data));
        checks.limitsblock = uint256(uint32(data >> 32));
        checks.standardmode = uint256(uint8(data >> 64));
        checks.feesenabled = uint256(uint8(data >> 72));
        checks.cooldown = uint256(uint8(data >> 80));
        checks.eoatransfers = uint256(uint8(data >> 88));
        fees.feebuy = uint256(uint8(data >> 96));
        fees.feesell = uint256(uint8(data >> 104));
        fees.feeliq = uint256(uint8(data >> 112));
        max.maxtx = uint256(uint16(data >> 120));
        max.maxbal = uint256(uint24(data >> 136));
        currentUserIndex = uint256(uint24(data >> 160));
        currentEntryIndex = uint256(uint24(data >> 184));
    }

    function _getUserData(uint256 user) private pure returns (USER memory user_) {
        user_.buy = uint256(uint32(user));
        user_.exemptfee = uint256(uint8(user >> 32));
        user_.exemptlimit = uint256(uint8(user >> 40));
        user_.index = uint256(uint24(user >> 48));
    }

    function _getChecksData(uint256 data) private pure returns (CHECKS memory checks) {
        checks.changeblock = uint256(uint32(data));
        checks.limitsblock = uint256(uint32(data >> 32));
        checks.standardmode = uint256(uint8(data >> 64));
        checks.feesenabled = uint256(uint8(data >> 72));
        checks.cooldown = uint256(uint8(data >> 80));
        checks.eoatransfers = uint256(uint8(data >> 88));
    }

    function _getFeesData(uint256 data) private pure returns (FEES memory fees) {
        fees.feebuy = uint256(uint8(data >> 96));
        fees.feesell = uint256(uint8(data >> 104));
        fees.feeliq = uint256(uint8(data >> 112));
    }

    function _getMaxData(uint256 data) private pure returns (MAX memory max) {
        max.maxtx = uint256(uint16(data >> 120));
        max.maxbal = uint256(uint24(data >> 136));
    }

    function _getCurrentUserIndex(uint256 data) private pure returns (uint256) {
        return uint256(uint24(data >> 160));
    }

    function _getCurrentEntryIndex(uint256 data) private pure returns (uint256) {
        return uint256(uint24(data >> 184));
    }

    function _overflowCheck(uint256 value, uint256 bytecount) private pure {
        //checks if value fits in target uint type

        if (value >= uint256(1 << bytecount)) {
            revert castOverflow(uint256(value), uint256(bytecount));
        }
    }

    function _hasCode(address _address) private view returns (bool) {
        return _address.code.length != 0;
    }

    /*//////////////////////////////////////////////////////////////
                            EXTERNAL VIEW
    //////////////////////////////////////////////////////////////*/

    function getUserData(address user) external view returns (USER memory user_) {
        return _getUserData(_users[user]);
    }

    function getUserEntryCount(address sender) external view returns (uint256) {
        return _getUserEntryCount(sender);
    }

    function getAllUserEntries(address user) external view returns (uint24[] memory) {
        uint256 bitObj = _userEntries[user];
        uint24[] memory entries = new uint24[](10);
        for (uint256 i; i < 10;) {
            uint256 bitPosition = i * 24;
            entries[i] = uint24(bitObj >> bitPosition);
            unchecked {
                ++i;
            }
        }
        return entries;
    }

    function getAllData()
        external
        view
        returns (
            CHECKS memory checks,
            FEES memory fees,
            MAX memory max,
            uint256 currentUserIndex,
            uint256 currentEntryIndex
        )
    {
        return _getAllData(data_);
    }

    function getEntryMinimums() external pure returns (uint256[] memory) {
        uint256[] memory entries = new uint256[](7);
        entries[0] = ONE_ENTRY;
        entries[1] = TWO_ENTRIES;
        entries[2] = THREE_ENTRIES;
        entries[3] = FOUR_ENTRIES;
        entries[4] = FIVE_ENTRIES;
        entries[5] = SEVEN_ENTRIES;
        entries[6] = TEN_ENTRIES;
        return entries;
    }

    function getWETH() external view returns (address) {
        return WETH;
    }

    function getPair() external view returns (address) {
        return _pair;
    }

    function getIndexUser(uint256 index) external view returns (address) {
        return _indexUser[index];
    }

    function getEntrantIdAndAddressAtIndex(uint256 index) external view returns (uint24, address) {
        return _getEntrantIdAndAddressAtIndex(index);
    }

    /*//////////////////////////////////////////////////////////////
                            EXTERNAL WRITE
    //////////////////////////////////////////////////////////////*/

    function deploy(uint48 duration) public payable onlyOwner {
        // can only be deployed once
        if (_pair != address(0)) {
            revert alreadyOpen();
        }

        // close limit must exceed one hour
        if (duration <= 300) {
            // (60 minutes * 60 seconds) / 12 seconds per block = 300
            revert valueTooLow();
        }

        _approve(address(this), address(ROUTER), type(uint256).max);
        ROUTER.addLiquidityETH{value: address(this).balance}(
            address(this), balanceOf(address(this)) - 1, 0, 0, address(this), block.timestamp
        );
        address factory = ROUTER.factory();
        address pair = IUniswapV2Factory(factory).getPair(WETH, address(this));
        _setUserData(pair, 0, 1, 0, 0);
        _pair = pair;
        _closeLimitBlock = uint48(block.number + duration);

        // userIndex must start at 1, as 0 needs to mean 'no user'
        // entryIndex must start at 1 for edge case in which first user adds to existing entries with multiple buys
        uint256[13] memory data = [
            block.number, // launch block
            block.number + 50, // limits window ((~12-second block time * 50) / 60 seconds) = ~10 minutes
            0, // standard mode
            1, // fees enabled
            3, // min blocks for cooldown
            1, // allow EOA to EOA transfers
            4, // buy fee
            4, // sell fee
            1, // liq fee
            6_000, // max tx - (fee + liq fee + amount for ten entries) * 1.2 (120%) to try and account for price action
            10_000, // max balance
            1, // userIndex
            1 // entryIndex
        ];
        _setData(data);
    }

    /**
     * @dev
     * closes trading by setting launch block to 0, performs a final price-impact-limited contract swap,
     * and requests a random number from chainlink VRF
     * this can only be done if trading is open, if it has not already been successfully run, and the specified time has passed (24 hours)
     */
    function closeTradingAndRollDice() external onlyOwner returns (uint256 requestId) {
        CHECKS memory checks = _getChecksData(data_);
        uint256 currentEntryIndex = _getCurrentEntryIndex(data_);
        if (
            checks.changeblock == 0 // not launched, or this has been run already
                || _closedAtTimestamp != 0 // this has been run already
                || block.number < uint256(_closeLimitBlock) // timeframe has not elapsed
                || currentEntryIndex == 1 // no entries have been registered yet
        ) {
            revert closeConditionsUnmet();
        }

        uint256 contractTokenBalance = balanceOf(address(this));
        // only attempt to sell an amount that uniswap shouldnt complain about (INSUFFICIENT_OUTPUT_AMOUNT)
        if (contractTokenBalance > ONE_ENTRY) {
            // perform final fee swap
            uint256 impactSell = (balanceOf(_pair) * 20) / 100;
            if (contractTokenBalance > impactSell) {
                contractTokenBalance = impactSell;
            }
            _nestedSwap(contractTokenBalance - 1);
        }

        uint256 contractETHBalance = address(this).balance;

        // don't require the fee transfer to succeed. dev can collect fees on their own later, if necessary
        if (contractETHBalance != 0) {
            (bool success,) = owner().call{value: address(this).balance}("");
            success;
        }

        // for display purposes
        _closedAtTimestamp = uint48(block.timestamp);

        // reset changeblock to zero, halting trading
        _setChecksDataCloseTrading();

        // exempt router from limits for the liquidity removal
        _setUserData(address(ROUTER), 0, 1, 1, 0);
        requestId = requestRandomness(uint32(_linkFee), uint16(3), uint32(1)); // actual gas cost is roughly 300_000
        _randomResult = uint128(ROLL_IN_PROGRESS);
        emit DiceRolled(requestId);
    }

    /**
     * @dev
     * this function is external as a contingency for the possible scenario in which this function fails when executed in the VRF callback.
     * ideally, this is not needed, but better to be safe than sorry.
     * because this function is used internally, and we are using memory values in order to minimize gas, it must accept parameters.
     * if this function is called externally by owner,
     * whatever parameters they provided are ignored, and correct ones are pulled from existing contract logic
     * this eliminates unnecessary work to retrieve correct values, and prevents exploitation by the owner
     * @param randomResult the random index set in fulfillRandomWords (pass 0 when calling as owner)
     * @param currentEntryIndex the final entry index assigned to a user before trading closed (pass 0 when calling as owner)
     */
    function sendToWinner(uint256 randomResult, uint256 currentEntryIndex) external {
        if (msg.sender != address(this) && msg.sender != address(_wrapper) && msg.sender != owner()) {
            revert notAuthorized();
        }

        if (msg.sender == owner()) {
            // cannot be run if random result was not already requested and received
            if (_closedAtTimestamp == 0 || _randomResult == ROLL_IN_PROGRESS || _randomResult == 0) {
                revert vrfCallbackNotComplete();
            }

            // when owner is the caller, ignore the values they passed and get the correct ones
            // this prevents exploitation by owner to assign winner to whomever they want

            // if owner can successfully call this function, we have already received a random number and set the random winner index
            randomResult = _randomResult;
            currentEntryIndex = _getCurrentEntryIndex(data_);
            unchecked {
                --currentEntryIndex; // last entry index assigned is one less than current value of currentEntryIndex
            }
        }

        // run the actual winner selection and payout logic
        _sendToWinner(randomResult, currentEntryIndex);
    }

    function setUserExempt(address userAddress, bool exemptfee, bool exemptlimit) external onlyOwner {
        // cannot alter significant contracts externally
        if (userAddress == _pair || userAddress == address(ROUTER) || userAddress == address(this)) {
            revert notAuthorized();
        }
        _setUserExempt(userAddress, exemptfee, exemptlimit);
    }

    function updateMax(uint256 maxTx, uint256 maxBalance) external onlyOwner {
        MAX memory currentMax = _getMaxData(data_);
        CHECKS memory currentChecks = _getChecksData(data_);

        if (currentChecks.changeblock != 0) {
            // neither value can be reduced
            if (maxTx < currentMax.maxtx || maxBalance < currentMax.maxbal) {
                revert valueTooLow();
            }
        }

        _setMaxData(maxTx, maxBalance);
        emit MaxUpdated(maxTx, maxBalance);
    }

    function updateFees(uint256 buy, uint256 sell, uint256 liq) external onlyOwner {
        if (((buy + liq) > 10) || ((sell + liq) > 10)) {
            revert valueTooHigh();
        }
        _setFeesData(buy, sell, liq);
        emit FeesUpdated(buy, sell, liq);
    }

    function reduceLimitBlock(uint256 newBlock) external onlyOwner {
        // once this block has passed, max tx, max balance, and buy cooldown are ignored
        CHECKS memory checks = _getChecksData(data_);
        uint256 oldBlock = checks.limitsblock;

        if (newBlock > oldBlock) {
            revert valueTooHigh();
        }
        _setChecksData(
            checks.changeblock, newBlock, checks.standardmode, checks.feesenabled, checks.cooldown, checks.eoatransfers
        );
        emit LimitBlockReduced(newBlock);
    }

    function reduceCooldown(uint256 newCooldown) external onlyOwner {
        // the number of blocks that must pass before user can perform another tx
        CHECKS memory checks = _getChecksData(data_);
        uint256 oldCooldown = checks.cooldown;

        if (newCooldown > oldCooldown) {
            revert valueTooHigh();
        }
        _setChecksData(
            checks.changeblock,
            checks.limitsblock,
            checks.standardmode,
            checks.feesenabled,
            newCooldown,
            checks.eoatransfers
        );
        emit CooldownReduced(newCooldown);
    }

    function toggleStandardMode() external onlyOwner {
        // standard mode eliminates all custom transfer logic
        CHECKS memory checks = _getChecksData(data_);

        uint256 standardmode = checks.standardmode != 0 ? 0 : uint256(1);
        require(standardmode != uint256(checks.standardmode), "same value");
        _setChecksData(
            checks.changeblock,
            checks.limitsblock,
            standardmode,
            checks.feesenabled,
            checks.cooldown,
            checks.eoatransfers
        );

        if (standardmode != 0) {
            emit StandardModeToggled(true);
        } else {
            emit StandardModeToggled(false);
        }
    }

    function toggleFees() external onlyOwner {
        CHECKS memory checks = _getChecksData(data_);

        uint256 feesenabled = checks.feesenabled != 0 ? 0 : uint256(1);
        require(feesenabled != uint256(checks.feesenabled), "same value");
        _setChecksData(
            checks.changeblock,
            checks.limitsblock,
            checks.standardmode,
            feesenabled,
            checks.cooldown,
            checks.eoatransfers
        );

        if (feesenabled != 0) {
            emit FeesToggled(true);
        } else {
            emit FeesToggled(false);
        }
    }

    function toggleEOATransfers() external onlyOwner {
        // enable or disable transferring tokens between user-owned wallets
        // NOTE: this has no effect on buying or selling
        CHECKS memory checks = _getChecksData(data_);

        uint256 eoatransfers = checks.eoatransfers != 0 ? 0 : uint256(1);
        require(eoatransfers != uint256(checks.eoatransfers), "same value");
        _setChecksData(
            checks.changeblock,
            checks.limitsblock,
            checks.standardmode,
            checks.feesenabled,
            checks.cooldown,
            eoatransfers
        );

        if (eoatransfers != 0) {
            emit EOATransfersToggled(true);
        } else {
            emit EOATransfersToggled(false);
        }
    }

    function manualDistribute(address recipient, uint256 amount) external onlyOwner {
        if (recipient == address(0)) {
            revert sendToZero();
        }
        bool sent;
        // send entire ETH balance
        if (amount == 0) {
            (sent,) = recipient.call{value: address(this).balance}("");
            if (!sent) {
                revert failedToSendETH();
            }
        }
        require(_pair != recipient, "Use addToPair instead.");
        uint256 amountInFinney = amount * 1e15;
        (sent,) = recipient.call{value: (amountInFinney)}(""); // sending 1 ETH = '1000', .1 ETH = '100', .01 ETH = '10'
        if (!sent) {
            revert failedToSendETH();
        }
    }

    function addToPair(uint256 amount) external onlyOwner {
        if (_pair == address(0)) {
            revert notOpen();
        }
        uint256 amountInFinney = amount * 1e15;
        IWETH(WETH).deposit{value: amountInFinney}(); // sending 1 ETH = '1000', .1 ETH = '100', .01 ETH = '10'
        bool sent = IWETH(WETH).transfer(_pair, IWETH(WETH).balanceOf(address(this)));
        if (!sent) {
            revert failedToSendETH();
        }
        IUniswapV2Pair(_pair).sync();
        emit LiqBoosted(WETH, amountInFinney);
    }

    /**
     * @dev
     * This value is used by Chainlink to determine how much gas the callback function is allowed to consume.
     * it has no effect on users or swaps.
     */
    function updateLinkFee(uint256 newValue) external onlyOwner {
        // this function is only needed in case the dev needs to increase the gas cost of the callback function
        if (newValue < _linkFee) {
            revert valueTooLow();
        }
        _linkFee = uint32(newValue);
        emit LinkFeeUpdated(newValue);
    }

    function recoverLink() external onlyOwner {
        // can only reclaim unused LINK after winner has received payout
        require(_winner != address(0));
        LINK.transfer(owner(), LINK.balanceOf(address(this)));
    }
}

File 2 of 13 : VRFV2WrapperConsumerBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../interfaces/LinkTokenInterface.sol";
import "../interfaces/VRFV2WrapperInterface.sol";

/** *******************************************************************************
 * @notice Interface for contracts using VRF randomness through the VRF V2 wrapper
 * ********************************************************************************
 * @dev PURPOSE
 *
 * @dev Create VRF V2 requests without the need for subscription management. Rather than creating
 * @dev and funding a VRF V2 subscription, a user can use this wrapper to create one off requests,
 * @dev paying up front rather than at fulfillment.
 *
 * @dev Since the price is determined using the gas price of the request transaction rather than
 * @dev the fulfillment transaction, the wrapper charges an additional premium on callback gas
 * @dev usage, in addition to some extra overhead costs associated with the VRFV2Wrapper contract.
 * *****************************************************************************
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VRFV2WrapperConsumerBase. The consumer must be funded
 * @dev with enough LINK to make the request, otherwise requests will revert. To request randomness,
 * @dev call the 'requestRandomness' function with the desired VRF parameters. This function handles
 * @dev paying for the request based on the current pricing.
 *
 * @dev Consumers must implement the fullfillRandomWords function, which will be called during
 * @dev fulfillment with the randomness result.
 */
abstract contract VRFV2WrapperConsumerBase {
  LinkTokenInterface internal immutable LINK;
  VRFV2WrapperInterface internal immutable VRF_V2_WRAPPER;

  /**
   * @param _link is the address of LinkToken
   * @param _vrfV2Wrapper is the address of the VRFV2Wrapper contract
   */
  constructor(address _link, address _vrfV2Wrapper) {
    LINK = LinkTokenInterface(_link);
    VRF_V2_WRAPPER = VRFV2WrapperInterface(_vrfV2Wrapper);
  }

  /**
   * @dev Requests randomness from the VRF V2 wrapper.
   *
   * @param _callbackGasLimit is the gas limit that should be used when calling the consumer's
   *        fulfillRandomWords function.
   * @param _requestConfirmations is the number of confirmations to wait before fulfilling the
   *        request. A higher number of confirmations increases security by reducing the likelihood
   *        that a chain re-org changes a published randomness outcome.
   * @param _numWords is the number of random words to request.
   *
   * @return requestId is the VRF V2 request ID of the newly created randomness request.
   */
  function requestRandomness(
    uint32 _callbackGasLimit,
    uint16 _requestConfirmations,
    uint32 _numWords
  ) internal returns (uint256 requestId) {
    LINK.transferAndCall(
      address(VRF_V2_WRAPPER),
      VRF_V2_WRAPPER.calculateRequestPrice(_callbackGasLimit),
      abi.encode(_callbackGasLimit, _requestConfirmations, _numWords)
    );
    return VRF_V2_WRAPPER.lastRequestId();
  }

  /**
   * @notice fulfillRandomWords handles the VRF V2 wrapper response. The consuming contract must
   * @notice implement it.
   *
   * @param _requestId is the VRF V2 request ID.
   * @param _randomWords is the randomness result.
   */
  function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal virtual;

  function rawFulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) external {
    require(msg.sender == address(VRF_V2_WRAPPER), "only VRF V2 wrapper can fulfill");
    fulfillRandomWords(_requestId, _randomWords);
  }
}

File 3 of 13 : IUniswapV2Pair.sol
pragma solidity >=0.5.0;

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

File 4 of 13 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

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 5 of 13 : IUniswapV2Factory.sol
pragma solidity >=0.5.0;

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

File 6 of 13 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

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

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

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

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

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

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}

File 8 of 13 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 9 of 13 : LinkTokenInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface LinkTokenInterface {
  function allowance(address owner, address spender) external view returns (uint256 remaining);

  function approve(address spender, uint256 value) external returns (bool success);

  function balanceOf(address owner) external view returns (uint256 balance);

  function decimals() external view returns (uint8 decimalPlaces);

  function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);

  function increaseApproval(address spender, uint256 subtractedValue) external;

  function name() external view returns (string memory tokenName);

  function symbol() external view returns (string memory tokenSymbol);

  function totalSupply() external view returns (uint256 totalTokensIssued);

  function transfer(address to, uint256 value) external returns (bool success);

  function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool success);

  function transferFrom(address from, address to, uint256 value) external returns (bool success);
}

File 10 of 13 : VRFV2WrapperInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface VRFV2WrapperInterface {
  /**
   * @return the request ID of the most recent VRF V2 request made by this wrapper. This should only
   * be relied option within the same transaction that the request was made.
   */
  function lastRequestId() external view returns (uint256);

  /**
   * @notice Calculates the price of a VRF request with the given callbackGasLimit at the current
   * @notice block.
   *
   * @dev This function relies on the transaction gas price which is not automatically set during
   * @dev simulation. To estimate the price at a specific gas price, use the estimatePrice function.
   *
   * @param _callbackGasLimit is the gas limit used to estimate the price.
   */
  function calculateRequestPrice(uint32 _callbackGasLimit) external view returns (uint256);

  /**
   * @notice Estimates the price of a VRF request with a specific gas limit and gas price.
   *
   * @dev This is a convenience function that can be called in simulation to better understand
   * @dev pricing.
   *
   * @param _callbackGasLimit is the gas limit used to estimate the price.
   * @param _requestGasPriceWei is the gas price in wei used for the estimation.
   */
  function estimateRequestPrice(uint32 _callbackGasLimit, uint256 _requestGasPriceWei) external view returns (uint256);
}

File 11 of 13 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

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

File 12 of 13 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 13 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);
}

Settings
{
  "remappings": [
    "@chainlink/=lib/chainlink/contracts/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@permit2/=lib/permit2/src/",
    "@solmate/=lib/solmate/src/",
    "@uniswap-core-local/=lib/v2-core/local-contracts/",
    "@uniswap-core/=lib/v2-core/contracts/",
    "@uniswap-lib-local/=lib/solidity-lib/local-contracts/",
    "@uniswap-periphery-local/=lib/v2-periphery/local-contracts/",
    "@uniswap-periphery/=lib/v2-periphery/contracts/",
    "chainlink/=lib/chainlink/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "permit2/=lib/permit2/",
    "solidity-lib/=lib/solidity-lib/",
    "solmate/=lib/solmate/src/",
    "sstore2/=lib/sstore2/contracts/",
    "v2-core/=lib/v2-core/",
    "v2-periphery/=lib/v2-periphery/",
    "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/",
    "lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/",
    "lib/openzeppelin-contracts:openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "lib/permit2:ds-test/=lib/permit2/lib/forge-std/lib/ds-test/src/",
    "lib/permit2:forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/",
    "lib/permit2:forge-std/=lib/permit2/lib/forge-std/src/",
    "lib/permit2:openzeppelin-contracts/=lib/permit2/lib/openzeppelin-contracts/",
    "lib/permit2:solmate/=lib/permit2/lib/solmate/",
    "lib/solmate:ds-test/=lib/solmate/lib/ds-test/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"router_","type":"address"},{"internalType":"address","name":"linkAddress","type":"address"},{"internalType":"address","name":"wrapperAddress","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"alreadyOpen","type":"error"},{"inputs":[],"name":"belowMinBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"bytecount","type":"uint256"}],"name":"castOverflow","type":"error"},{"inputs":[],"name":"closeConditionsUnmet","type":"error"},{"inputs":[],"name":"exceedMaxBalance","type":"error"},{"inputs":[],"name":"exceedMaxTx","type":"error"},{"inputs":[],"name":"failedToSendETH","type":"error"},{"inputs":[],"name":"noEOAtoEOATransfers","type":"error"},{"inputs":[],"name":"notAuthorized","type":"error"},{"inputs":[],"name":"notOpen","type":"error"},{"inputs":[],"name":"sendToZero","type":"error"},{"inputs":[],"name":"txCooldown","type":"error"},{"inputs":[],"name":"valueTooHigh","type":"error"},{"inputs":[],"name":"valueTooLow","type":"error"},{"inputs":[],"name":"vrfCallbackNotComplete","type":"error"},{"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":false,"internalType":"uint256","name":"newcooldown","type":"uint256"}],"name":"CooldownReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"result","type":"uint256"}],"name":"DiceLanded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"DiceRolled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"eoatransfers","type":"bool"}],"name":"EOATransfersToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EntriesGained","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EntriesLost","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"feesenabled","type":"bool"}],"name":"FeesToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"buy","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sell","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"FeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newblock","type":"uint256"}],"name":"LimitBlockReduced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newfee","type":"uint256"}],"name":"LinkFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiqBoosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxtx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxbal","type":"uint256"}],"name":"MaxUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_holder","type":"address"}],"name":"SentToWinner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"standardmode","type":"bool"}],"name":"StandardModeToggled","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":[],"name":"ROUTER","outputs":[{"internalType":"contract IUniswapV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_closeLimitBlock","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_closedAtTimestamp","outputs":[{"internalType":"uint48","name":"","type":"uint48"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_linkFee","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_pureRandomNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_randomResult","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_winner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addToPair","outputs":[],"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":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"closeTradingAndRollDice","outputs":[{"internalType":"uint256","name":"requestId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"duration","type":"uint48"}],"name":"deploy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAllData","outputs":[{"components":[{"internalType":"uint256","name":"changeblock","type":"uint256"},{"internalType":"uint256","name":"limitsblock","type":"uint256"},{"internalType":"uint256","name":"standardmode","type":"uint256"},{"internalType":"uint256","name":"feesenabled","type":"uint256"},{"internalType":"uint256","name":"cooldown","type":"uint256"},{"internalType":"uint256","name":"eoatransfers","type":"uint256"}],"internalType":"struct IGMI.CHECKS","name":"checks","type":"tuple"},{"components":[{"internalType":"uint256","name":"feebuy","type":"uint256"},{"internalType":"uint256","name":"feesell","type":"uint256"},{"internalType":"uint256","name":"feeliq","type":"uint256"}],"internalType":"struct IGMI.FEES","name":"fees","type":"tuple"},{"components":[{"internalType":"uint256","name":"maxtx","type":"uint256"},{"internalType":"uint256","name":"maxbal","type":"uint256"}],"internalType":"struct IGMI.MAX","name":"max","type":"tuple"},{"internalType":"uint256","name":"currentUserIndex","type":"uint256"},{"internalType":"uint256","name":"currentEntryIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getAllUserEntries","outputs":[{"internalType":"uint24[]","name":"","type":"uint24[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getEntrantIdAndAddressAtIndex","outputs":[{"internalType":"uint24","name":"","type":"uint24"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEntryMinimums","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getIndexUser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserData","outputs":[{"components":[{"internalType":"uint256","name":"buy","type":"uint256"},{"internalType":"uint256","name":"exemptfee","type":"uint256"},{"internalType":"uint256","name":"exemptlimit","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IGMI.USER","name":"user_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"getUserEntryCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"manualDistribute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_requestId","type":"uint256"},{"internalType":"uint256[]","name":"_randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recoverLink","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"reduceCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newBlock","type":"uint256"}],"name":"reduceLimitBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"randomResult","type":"uint256"},{"internalType":"uint256","name":"currentEntryIndex","type":"uint256"}],"name":"sendToWinner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"userAddress","type":"address"},{"internalType":"bool","name":"exemptfee","type":"bool"},{"internalType":"bool","name":"exemptlimit","type":"bool"}],"name":"setUserExempt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleEOATransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleStandardMode","outputs":[],"stateMutability":"nonpayable","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":"amount","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":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"buy","type":"uint256"},{"internalType":"uint256","name":"sell","type":"uint256"},{"internalType":"uint256","name":"liq","type":"uint256"}],"name":"updateFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateLinkFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxTx","type":"uint256"},{"internalType":"uint256","name":"maxBalance","type":"uint256"}],"name":"updateMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61010060405260405162004d0538038062004d0583398101604081905262000027916200037c565b81816040518060400160405280600481526020016349474d4960e01b8152506040518060400160405280600481526020016349474d4960e01b815250816003908162000074919062000462565b50600462000083828262000462565b505050620000a06200009a620001a660201b60201c565b620001aa565b6001600160a01b03918216608052811660a052600e80546001600160a01b031916918316919091179055620000da305f60018082620001fb565b620000ea335f60018082620001fb565b6200010c3062000106670de0b6b3a7640000620f42406200053e565b62000266565b6001600160a01b03831660e0819052604080516315ab88c960e31b8152905163ad5c4648916004808201926020929091908290030181865afa15801562000155573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200017b91906200055e565b6001600160a01b031660c0525050600780546001600160e01b0316613d0960e61b1790555062000597565b3390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b620002088460206200032c565b83620002168460086200032c565b602084901b17620002298360086200032c565b602883901b176200023c8260186200032c565b6001600160a01b039095165f90815260096020526040902060309190911b94909417909355505050565b6001600160a01b038216620002c25760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064015b60405180910390fd5b8060025f828254620002d5919062000581565b90915550506001600160a01b0382165f81815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b5050565b6001811b82106200032857604051638f44d83160e01b81526004810183905260248101829052604401620002b9565b505050565b80516001600160a01b038116811462000377575f80fd5b919050565b5f805f606084860312156200038f575f80fd5b6200039a8462000360565b9250620003aa6020850162000360565b9150620003ba6040850162000360565b90509250925092565b634e487b7160e01b5f52604160045260245ffd5b600181811c90821680620003ec57607f821691505b6020821081036200040b57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200035b575f81815260208120601f850160051c81016020861015620004395750805b601f850160051c820191505b818110156200045a5782815560010162000445565b505050505050565b81516001600160401b038111156200047e576200047e620003c3565b62000496816200048f8454620003d7565b8462000411565b602080601f831160018114620004cc575f8415620004b45750858301515b5f19600386901b1c1916600185901b1785556200045a565b5f85815260208120601f198616915b82811015620004fc57888601518255948401946001909101908401620004db565b50858210156200051a57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176200055857620005586200052a565b92915050565b5f602082840312156200056f575f80fd5b6200057a8262000360565b9392505050565b808201808211156200055857620005586200052a565b60805160a05160c05160e0516146c3620006425f395f8181610477015281816111710152818161119901528181611249015281816116ec01528181611f4801528181612add01528181612b7b01526131a401525f818161078c0152818161098e01528181610a1c01528181610b8f015281816112de015261314d01525f8181610dea0152818161326e015261337201525f818161183e01528181611892015261324401526146c35ff3fe608060405260043610610278575f3560e01c80638d5fcacb1161014a578063cae5f11e116100be578063e461a55e11610078578063e461a55e14610858578063e8891de814610884578063e9cc4edd146108a3578063ef4d5efa146108c2578063f2fde38b146108d6578063ffc9896b146108f5575f80fd5b8063cae5f11e1461077e578063d346b577146107b0578063d7e1a3d9146107ec578063dd62ed3e14610811578063ddf5451214610830578063de9ca28d14610844575f80fd5b8063b2a8116a1161010f578063b2a8116a146106c3578063b4664394146106e2578063beba2126146106f6578063c09d28561461070b578063c1f1b1b514610742578063c1f3c33f1461075f575f80fd5b80638d5fcacb146106125780638da5cb5b1461065457806395d89b4114610671578063a457c2d714610685578063a9059cbb146106a4575f80fd5b806332fe7b26116101ec5780635fd2f823116101a65780635fd2f8231461056e57806367a2b56a1461058257806370a08231146105a1578063715018a6146105c057806377841d59146105d457806382374c13146105f3575f80fd5b806332fe7b261461046657806339509351146104b15780633c3b2a73146104d0578063556d9228146104ef57806355a34e6f146105235780635ac1c61e14610536575f80fd5b80631fe543e31161023d5780631fe543e31461033c578063224290851461035b57806323b872dd1461037a57806325dee0c4146103995780632d10fa28146103b8578063313ce5671461044b575f80fd5b8063051515541461028357806306fdde03146102a4578063095ea7b3146102ce578063128047b5146102fd57806318160ddd1461031e575f80fd5b3661027f57005b5f80fd5b34801561028e575f80fd5b506102a261029d366004613fba565b610947565b005b3480156102af575f80fd5b506102b8610bec565b6040516102c5919061401e565b60405180910390f35b3480156102d9575f80fd5b506102ed6102e8366004614044565b610c7c565b60405190151581526020016102c5565b348015610308575f80fd5b50610311610c95565b6040516102c5919061406e565b348015610329575f80fd5b506002545b6040519081526020016102c5565b348015610347575f80fd5b506102a26103563660046140c5565b610ddf565b348015610366575f80fd5b506102a261037536600461418a565b610e6a565b348015610385575f80fd5b506102ed6103943660046141b3565b610efa565b3480156103a4575f80fd5b506102a26103b3366004613fba565b610f1f565b3480156103c3575f80fd5b506103cc610faa565b6040805186518152602080880151818301528783015182840152606080890151908301526080808901519083015260a09788015197820197909752855160c08201528686015160e0820152940151610100850152825161012085015293909101516101408301526101608201526101808101919091526101a0016102c5565b348015610456575f80fd5b50604051601281526020016102c5565b348015610471575f80fd5b506104997f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102c5565b3480156104bc575f80fd5b506102ed6104cb366004614044565b611004565b3480156104db575f80fd5b506102a26104ea3660046141f1565b611025565b3480156104fa575f80fd5b50610499610509366004613fba565b5f908152600c60205260409020546001600160a01b031690565b6102a2610531366004614211565b61110f565b348015610541575f80fd5b5060075461055990600160e01b900463ffffffff1681565b60405163ffffffff90911681526020016102c5565b348015610579575f80fd5b506102a261143d565b34801561058d575f80fd5b506102a261059c366004614044565b61151d565b3480156105ac575f80fd5b5061032e6105bb366004614236565b61169e565b3480156105cb575f80fd5b506102a26116b8565b3480156105df575f80fd5b506102a26105ee36600461425e565b6116cb565b3480156105fe575f80fd5b50600f54610499906001600160a01b031681565b34801561061d575f80fd5b5061063161062c366004613fba565b611761565b6040805162ffffff90931683526001600160a01b039091166020830152016102c5565b34801561065f575f80fd5b506005546001600160a01b0316610499565b34801561067c575f80fd5b506102b8611775565b348015610690575f80fd5b506102ed61069f366004614044565b611784565b3480156106af575f80fd5b506102ed6106be366004614044565b611809565b3480156106ce575f80fd5b5061032e6106dd366004614236565b611816565b3480156106ed575f80fd5b506102a2611820565b348015610701575f80fd5b5061032e60085481565b348015610716575f80fd5b5060075461072a906001600160801b031681565b6040516001600160801b0390911681526020016102c5565b34801561074d575f80fd5b50600d546001600160a01b0316610499565b34801561076a575f80fd5b506102a2610779366004613fba565b611972565b348015610789575f80fd5b507f0000000000000000000000000000000000000000000000000000000000000000610499565b3480156107bb575f80fd5b506007546107d590600160b01b900465ffffffffffff1681565b60405165ffffffffffff90911681526020016102c5565b3480156107f7575f80fd5b506007546107d590600160801b900465ffffffffffff1681565b34801561081c575f80fd5b5061032e61082b3660046142a6565b611a00565b34801561083b575f80fd5b506102a2611a2a565b34801561084f575f80fd5b506102a2611b02565b348015610863575f80fd5b50610877610872366004614236565b611bda565b6040516102c591906142dd565b34801561088f575f80fd5b506102a261089e366004613fba565b611c6c565b3480156108ae575f80fd5b506102a26108bd3660046141f1565b611cfa565b3480156108cd575f80fd5b5061032e611db9565b3480156108e1575f80fd5b506102a26108f0366004614236565b611fd7565b348015610900575f80fd5b5061091461090f366004614236565b61204d565b6040516102c591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b61094f612095565b600d546001600160a01b0316610978576040516305835fed60e01b815260040160405180910390fd5b5f61098a8266038d7ea4c6800061432d565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156109e5575f80fd5b505af11580156109f7573d5f803e3d5ffd5b5050600d546040516370a0823160e01b81523060048201525f94506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116945063a9059cbb93509091169083906370a08231906024016020604051808303815f875af1158015610a71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a959190614344565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af1158015610add573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b01919061435b565b905080610b215760405163062e4f6360e11b815260040160405180910390fd5b600d5f9054906101000a90046001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610b6d575f80fd5b505af1158015610b7f573d5f803e3d5ffd5b5050604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152602081018690527f5c0eec4199f95cf196fdac30f5458f67ba720232c0fce87b1540c0c7dc0e773f93500190505b60405180910390a1505050565b606060038054610bfb90614376565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2790614376565b8015610c725780601f10610c4957610100808354040283529160200191610c72565b820191905f5260205f20905b815481529060010190602001808311610c5557829003601f168201915b5050505050905090565b5f33610c898185856120ef565b60019150505b92915050565b60408051600780825261010082019092526060915f91906020820160e080368337019050509050681b1ae4d6e2ef500000815f81518110610cd857610cd86143ae565b602002602001018181525050683635c9adc5dea0000081600181518110610d0157610d016143ae565b602002602001018181525050685150ae84a8cdf0000081600281518110610d2a57610d2a6143ae565b602002602001018181525050686c6b935b8bbd40000081600381518110610d5357610d536143ae565b60200260200101818152505068878678326eac90000081600481518110610d7c57610d7c6143ae565b60200260200101818152505068bdbc41e0348b30000081600581518110610da557610da56143ae565b60200260200101818152505069010f0cf064dd5920000081600681518110610dcf57610dcf6143ae565b6020908102919091010152919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e5c5760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792056524620563220777261707065722063616e2066756c66696c6c0060448201526064015b60405180910390fd5b610e668282612212565b5050565b610e72612095565b600a610e7e82856143c2565b1180610e935750600a610e9182846143c2565b115b15610eb157604051633634941560e21b815260040160405180910390fd5b610ebc838383612341565b60408051848152602081018490529081018290527fcf8a1e1d5f09cf3c97dbb653cd9a4d7aace9292fbc1bb8211febf2d400febbdd90606001610bdf565b5f33610f0785828561238e565b610f12858585612400565b60019150505b9392505050565b610f27612095565b600754600160e01b900463ffffffff16811015610f5757604051631c23763d60e01b815260040160405180910390fd5b600780546001600160e01b0316600160e01b63ffffffff8416021790556040518181527f0f7a60a7e1cf3f1b0b1540f0e964947327ad8b2bde2e2ac3e07d922b69e977d99060200160405180910390a150565b610fb2613f8a565b610fd360405180606001604052805f81526020015f81526020015f81525090565b604080518082019091525f80825260208201525f80610ff36006546128ee565b945094509450945094509091929394565b5f33610c898185856110168383611a00565b61102091906143c2565b6120ef565b3330148015906110405750600e546001600160a01b03163314155b801561105757506005546001600160a01b03163314155b1561107557604051636932705760e11b815260040160405180910390fd5b6005546001600160a01b0316330361110557600754600160b01b900465ffffffffffff1615806110b257506007546001600160801b03166298967f145b806110c657506007546001600160801b0316155b156110e4576040516351bf115f60e01b815260040160405180910390fd5b6007546006546001600160801b03909116925060b81c62ffffff165f190190505b610e6682826129c5565b611117612095565b600d546001600160a01b03161561114157604051630cac471160e41b815260040160405180910390fd5b61012c8165ffffffffffff161161116b57604051631c23763d60e01b815260040160405180910390fd5b611197307f00000000000000000000000000000000000000000000000000000000000000005f196120ef565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f305d719473060016111d33061169e565b6111dd91906143d5565b5f8030426040518863ffffffff1660e01b8152600401611202969594939291906143e8565b60606040518083038185885af115801561121e573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906112439190614423565b5050505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c7919061444e565b60405163e6a4390560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301523060248301529192505f9183169063e6a4390590604401602060405180830381865afa158015611336573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135a919061444e565b905061136a815f60015f80612d2d565b600d80546001600160a01b0319166001600160a01b03831617905561139765ffffffffffff8416436143c2565b600760106101000a81548165ffffffffffff021916908365ffffffffffff1602179055505f604051806101a001604052804381526020014360326113db91906143c2565b81526020015f815260200160018152602001600381526020016001815260200160048152602001600481526020016001815260200161177081526020016127108152602001600181526020016001815250905061143781612d90565b50505050565b611445612095565b5f611451600654612e91565b90505f81604001515f03611466576001611468565b5f5b90508160400151810361148d5760405162461bcd60e51b8152600401610e5390614469565b6114ae825f0151836020015183856060015186608001518760a00151612ee5565b80156114ed57604051600181527f0f8293c744b66395bf9a745e7b4d95c3b84f65fd0f4cb60bad74975fa315eb1b906020015b60405180910390a15050565b6040515f81527f0f8293c744b66395bf9a745e7b4d95c3b84f65fd0f4cb60bad74975fa315eb1b906020016114e1565b611525612095565b6001600160a01b03821661154c57604051639ed698f560e01b815260040160405180910390fd5b5f815f036115c3576040516001600160a01b0384169047905f81818185875af1925050503d805f811461159a576040519150601f19603f3d011682016040523d82523d5f602084013e61159f565b606091505b505080915050806115c35760405163062e4f6360e11b815260040160405180910390fd5b600d546001600160a01b038085169116036116195760405162461bcd60e51b81526020600482015260166024820152752ab9b29030b2322a37a830b4b91034b739ba32b0b21760511b6044820152606401610e53565b5f61162b8366038d7ea4c6800061432d565b9050836001600160a01b0316816040515f6040518083038185875af1925050503d805f8114611675576040519150601f19603f3d011682016040523d82523d5f602084013e61167a565b606091505b505080925050816114375760405163062e4f6360e11b815260040160405180910390fd5b6001600160a01b03165f9081526020819052604090205490565b6116c0612095565b6116c95f612f63565b565b6116d3612095565b600d546001600160a01b038481169116148061172057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316145b8061173357506001600160a01b03831630145b1561175157604051636932705760e11b815260040160405180910390fd5b61175c838383612fb4565b505050565b5f8061176c83613015565b91509150915091565b606060048054610bfb90614376565b5f33816117918286611a00565b9050838110156117f15760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610e53565b6117fe82868684036120ef565b506001949350505050565b5f33610c89818585612400565b5f610c8f82613092565b611828612095565b600f546001600160a01b031661183c575f80fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb61187d6005546001600160a01b031690565b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156118df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119039190614344565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af115801561194b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f919061435b565b50565b61197a612095565b5f611986600654612e91565b6020810151909150808311156119af57604051633634941560e21b815260040160405180910390fd5b6119d0825f0151848460400151856060015186608001518760a00151612ee5565b6040518381527fb32eee1f3b022fecf91130907d354359df3234353a0ee169155ac37dbeed75c090602001610bdf565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b611a32612095565b5f611a3e600654612e91565b90505f81606001515f03611a53576001611a55565b5f5b905081606001518103611a7a5760405162461bcd60e51b8152600401610e5390614469565b611a9b825f0151836020015184604001518486608001518760a00151612ee5565b8015611ad257604051600181527fc97260ffb3df6b903cdfd59e3b5b21a896404903a8e8a83bf60ba3fca365fbe5906020016114e1565b6040515f81527fc97260ffb3df6b903cdfd59e3b5b21a896404903a8e8a83bf60ba3fca365fbe5906020016114e1565b611b0a612095565b5f611b16600654612e91565b90505f8160a001515f03611b2b576001611b2d565b5f5b90508160a001518103611b525760405162461bcd60e51b8152600401610e5390614469565b611b73825f0151836020015184604001518560600151866080015186612ee5565b8015611baa57604051600181527fa8392e314504d0b57633e056d62ab8ededff9020da370c77dd137a25324b5c18906020016114e1565b6040515f81527fa8392e314504d0b57633e056d62ab8ededff9020da370c77dd137a25324b5c18906020016114e1565b6001600160a01b0381165f908152600a602081815260408084205481518481526101608101909252606094909390928201610140803683370190505090505f5b600a811015611c64575f611c2f82601861432d565b90508084901c838381518110611c4757611c476143ae565b62ffffff9092166020928302919091019091015250600101611c1a565b509392505050565b611c74612095565b5f611c80600654612e91565b608081015190915080831115611ca957604051633634941560e21b815260040160405180910390fd5b611cca825f0151836020015184604001518560600151878760a00151612ee5565b6040518381527fb3bf54177f07aa628d24efcbd137a401112718a4d9c8c1a8538b24e21029422990602001610bdf565b611d02612095565b60065460408051808201909152607882901c61ffff16815260889190911c62ffffff1660208201525f611d36600654612e91565b805190915015611d70578151841080611d525750816020015183105b15611d7057604051631c23763d60e01b815260040160405180910390fd5b611d7a84846130bd565b60408051858152602081018590527faa6f6b0a509f2b07cf30d89dbd3bb410883aaa429ad4da41fdf36c02398cf1a0910160405180910390a150505050565b5f611dc2612095565b5f611dce600654612e91565b600654815191925060b81c62ffffff16901580611dfb5750600754600160b01b900465ffffffffffff1615155b80611e165750600754600160801b900465ffffffffffff1643105b80611e215750806001145b15611e3f57604051630cc4134b60e11b815260040160405180910390fd5b5f611e493061169e565b9050681b1ae4d6e2ef500000811115611eae57600d545f90606490611e76906001600160a01b031661169e565b611e8190601461432d565b611e8b91906144a1565b905080821115611e99578091505b611eac611ea76001846143d5565b6130f8565b505b478015611f19575f611ec86005546001600160a01b031690565b6001600160a01b0316476040515f6040518083038185875af1925050503d805f8114611f0f576040519150601f19603f3d011682016040523d82523d5f602084013e611f14565b606091505b505050505b6007805465ffffffffffff60b01b1916600160b01b4265ffffffffffff1602179055611f4361320c565b611f717f00000000000000000000000000000000000000000000000000000000000000005f6001805f612d2d565b600754611f8e90600160e01b900463ffffffff166003600161321f565b600780546001600160801b0319166298967f17905560405190955085907f0c720560a539b13f97fb22b6c1ac4393045cedca3bb997fd2ea1f7a3dfb76a58905f90a25050505090565b611fdf612095565b6001600160a01b0381166120445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610e53565b61196f81612f63565b61207460405180608001604052805f81526020015f81526020015f81526020015f81525090565b6001600160a01b0382165f90815260096020526040902054610c8f906133f8565b6005546001600160a01b031633146116c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e53565b6001600160a01b0383166121515760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610e53565b6001600160a01b0382166121b25760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610e53565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6006545f9060b81c62ffffff16905080600190039050815f8151811061223a5761223a6143ae565b60200260200101516008819055505f8160085461225791906144b4565b600780546001600160801b0319166001600160801b0383169081179091556040519192509085907f54d97c1f7e5abad75bd421455cd4dd296852a52e1ea721f2cdb66d06fa2082a9905f90a3604080516001600160801b0383166024820152604480820185905282518083039091018152606490910182526020810180516001600160e01b0316633c3b2a7360e01b17905290515f9130916122f991906144c7565b5f604051808303815f865af19150503d805f8114612332576040519150601f19603f3d011682016040523d82523d5f602084013e612337565b606091505b5050505050505050565b5f61235160065460606018613456565b905061235e84600861347f565b606084901b1761236f83600861347f565b606883901b1761238082600861347f565b60709190911b176006555050565b5f6123998484611a00565b90505f19811461143757818110156123f35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610e53565b61143784848484036120ef565b6006545f61240d82612e91565b6001600160a01b0386165f9081526009602052604081205491925090612432906133f8565b6001600160a01b0386165f9081526009602052604081205491925090612457906133f8565b90506001600160a01b0387163014806124735750604083015115155b8061248f575060208201511580159061248f5750604082015115155b806124ab57506020810151158015906124ab5750604081015115155b156124c0576124bb8787876134ac565b6128e5565b82515f036124e1576040516305835fed60e01b815260040160405180910390fd5b600d5460408051808201909152607886901c61ffff168152608886901c62ffffff1660208201525f916001600160a01b0316905f61251e8861364e565b325f908152600960205260408120549192509061253a906133f8565b90508b6001600160a01b0316846001600160a01b0316036126e35785604001515f036126da5743886020015111156126525787516125799060026143c2565b43101561258b57600a80835260408301525b82516125a090670de0b6b3a76400009061432d565b8a11156125c057604051632d2b153d60e01b815260040160405180910390fd5b670de0b6b3a764000083602001516125d8919061432d565b8a6125e28d61169e565b6125ec91906143c2565b111561260b5760405163cc91297760e01b815260040160405180910390fd5b608088015186514391011180612628575060808801518151439101115b156126465760405163dcafac0960e01b815260040160405180910390fd5b60078252600360408301525b43865260608601511561267b5761267b8b875f0151886020015189604001518a60600151612d2d565b61269d8b878c8c8660018e606001515f03612696575f613697565b6001613697565b326001600160a01b038c16148015906126b95750438860200151115b156126da576126da32875f0151886020015189604001518a60600151612d2d565b600194506127ca565b8a6001600160a01b0316846001600160a01b0316036127ca5760408701511580156127115750608088015115155b1561275157608088015187514391011180612733575060808801518151439101115b156127515760405163dcafac0960e01b815260040160405180910390fd5b61276b8c888c8c865f8e606001515f03612696575f613697565b5f6127753061169e565b9050681b1ae4d6e2ef5000008111156127c8575f60646127948e61169e565b61279f90600561432d565b6127a991906144a1565b90506127c68183116127c057611ea76001846143d5565b816130f8565b505b505b606088015115801590612824575060208601511580156127fb57508b6001600160a01b0316846001600160a01b0316145b806128245750602087015115801561282457508a6001600160a01b0316846001600160a01b0316145b1561283b576128368c8c8c88866139ea565b6128df565b8b6001600160a01b0316846001600160a01b03161415801561286f57508a6001600160a01b0316846001600160a01b031614155b156128d4578760a001515f03612898576040516308090ba360e41b815260040160405180910390fd5b60208601511580156128ab575086518651105b156128b557865186525b6128c48c888c8c865f80613697565b6128d48b878c8c8660015f613697565b6128df8c8c8c6134ac565b50505050505b50505050505050565b6128f6613f8a565b61291760405180606001604052805f81526020015f81526020015f81525090565b60408051808201825263ffffffff8581168552602086811c9091168186015260ff86841c811686850152604887901c8116606080880191909152605088901c82166080880152605888901c821660a0808901919091529088901c82168652606888901c821686840152607088901c9091169385019390935261ffff607887901c16825262ffffff608887901c8116918301919091529395929490939181901c82169260b89190911c90911690565b815f6129d082613015565b9150506001600160a01b038116612aab5782821015612a2b575f6129f483856143d5565b90505f5b81811015612a2857836001019350612a0f84613015565b9350506001600160a01b038316612a28576001016129f8565b50505b6001600160a01b038116158015612a4157508282145b15612a7d578391505f5b84811015612a7b575f1990920191612a6283613015565b9250506001600160a01b038216612a7b57600101612a4b565b505b6001600160a01b038116612a8f575f80fd5b600780546001600160801b0319166001600160801b0384161790555b600f80546001600160a01b0319166001600160a01b0383811691909117909155600d5460405163095ea7b360e01b81527f0000000000000000000000000000000000000000000000000000000000000000831660048201525f19602482015291169063095ea7b3906044016020604051808303815f875af1158015612b32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b56919061435b565b50600d546040516370a0823160e01b815230600482018190525f926001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116936302751cec939291909116906370a0823190602401602060405180830381865afa158015612bcd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bf19190614344565b5f8030426040518763ffffffff1660e01b8152600401612c16969594939291906143e8565b60408051808303815f875af1158015612c31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c5591906144e2565b9150505f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612ca1576040519150601f19603f3d011682016040523d82523d5f602084013e612ca6565b606091505b5050905080612ce95760405162461bcd60e51b815260206004820152600f60248201526e4661696c656420746f2073656e642160881b6044820152606401610e53565b6040516001600160a01b03841681527f0992f42a6118239e571ca390863e9f148a939f9f0470578217d738d6d665116e9060200160405180910390a1505050505050565b612d3884602061347f565b83612d4484600861347f565b602084901b17612d5583600861347f565b602883901b17612d6682601861347f565b6001600160a01b039095165f90815260096020526040902060309190911b94909417909355505050565b604080516101a0810182526020808252808201526008918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091526010610120820152601861014082018190526101608201819052610180820152600d905f9081905f5b84811015612e8757612e428682600d8110612e1e57612e1e6143ae565b60200201518383600d8110612e3557612e356143ae565b602002015160ff1661347f565b838682600d8110612e5557612e556143ae565b6020020151901b831792508181600d8110612e7257612e726143ae565b602002015160ff169390930192600101612e01565b5050600655505050565b612e99613f8a565b63ffffffff8083168252602083811c9091169082015260ff604083811c821690830152604883901c81166060830152605083901c8116608083015260589290921c90911660a082015290565b5f612ef46006545f6060613456565b9050612f0187602061347f565b8617612f0e86602061347f565b602086901b17612f1f85600861347f565b604085901b17612f3084600861347f565b604884901b17612f4183600861347f565b605083901b17612f5282600861347f565b60589190911b176006555050505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0383165f90815260096020526040812054612fd5906133f8565b90505f83612fe3575f612fe6565b60015b90505f83612ff4575f612ff7565b60015b905061300d86845f015184848760600151612d2d565b505050505050565b5f8080613023600a856144a1565b90505f600985116130345784613049565b61303f82600a61432d565b61304990866144b4565b90505f61305782601861432d565b5f938452600b602090815260408086205490921c62ffffff81168652600c90915293205492966001600160a01b039093169550919350505050565b6001600160a01b0381165f908152600a6020526040812054816130b482613af5565b50949350505050565b5f6130cd60065460786028613456565b90506130da83601061347f565b607883901b176130eb82601861347f565b60889190911b1760065550565b6040805160028082526060820183525f9260208301908036833701905050905030815f8151811061312b5761312b6143ae565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160018151811061317f5761317f6143ae565b6001600160a01b03928316602091820292909201015260405163791ac94760e01b81527f00000000000000000000000000000000000000000000000000000000000000009091169063791ac947906131e39085905f90869030904290600401614504565b5f604051808303815f87803b1580156131fa575f80fd5b505af115801561300d573d5f803e3d5ffd5b61321a6006545f6020613456565b600655565b6040516310c1b4d560e21b815263ffffffff841660048201525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811691634000aea0917f00000000000000000000000000000000000000000000000000000000000000009190821690634306d35490602401602060405180830381865afa1580156132b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132da9190614344565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b815260040161332f93929190614573565b6020604051808303815f875af115801561334b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061336f919061435b565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fc2a88c36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133f09190614344565b949350505050565b61341f60405180608001604052805f81526020015f81526020015f81526020015f81525090565b63ffffffff8216815260ff602083811c821690830152602883901c16604082015262ffffff60309290921c91909116606082015290565b5f80836001613466856002614682565b61347091906143d5565b901b1994909416949350505050565b6001811b8210610e6657604051638f44d83160e01b81526004810183905260248101829052604401610e53565b6001600160a01b0383166135105760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610e53565b6001600160a01b0382166135725760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610e53565b6001600160a01b0383165f90815260208190526040902054818110156135e95760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610e53565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611437565b61366f60405180606001604052805f81526020015f81526020015f81525090565b60ff606083901c81168252606883901c8116602083015260709290921c909116604082015290565b5f6136a188613092565b90505f83156138fa5782156137aa578451158015906136c35750604085015115155b156137335761372c60648660400151896136dd919061432d565b6136e791906144a1565b86516064906136f6908b61432d565b61370091906144a1565b61370a908a6143d5565b61371491906143d5565b61371d8b61169e565b61372791906143c2565b613b36565b90506137ba565b84511580159061374557506040850151155b1561377157845161372c9060649061375d908a61432d565b61376791906144a1565b61371490896143d5565b84511580156137835750604085015115155b1561379d5761372c606486604001518961375d919061432d565b61372c8761371d8b61169e565b6137b78761371d8b61169e565b90505b6060880151805f8190036138195760a088901c62ffffff1691508190506137ef8b8b5f01518c602001518d6040015186612d2d565b5f828152600c6020526040902080546001600160a01b0319166001600160a01b038d161790556001015b82158061382557508383145b80156138315750808214155b15613849576138408882613bee565b505050506128e5565b838311156138f35762ffffff60b889901c165f6138708d61386a88886143d5565b84613c11565b90505f61387e858385613c96565b9050838514613897576138928b8583613d41565b6138a1565b6138a18b82613d7c565b7fd4a167f62427a87418c8179efb1099f2da50e01c5374433a1e21db418fd9e4458e6138cd89896143d5565b604080516001600160a01b03909316835260208301919091520160405180910390a15050505b50506139df565b866139048a61169e565b10156139115750506128e5565b6139288761391e8b61169e565b61372791906143d5565b9050818110156139df575f61393d82846143d5565b90505f8167ffffffffffffffff811115613959576139596140b1565b604051908082528060200260200182016040528015613982578160200160208202803683370190505b50905061398f8b83613d9f565b905061399a81613e94565b604080516001600160a01b038d168152602081018490527f0c129863ec4f7070868d0ab05157245e6264ef1004096ec9dd7fbbc67d575253910160405180910390a150505b505050505050505050565b5f8083613a005782602001518360400151613a08565b825160408401515b90925090505f6064613a1a848861432d565b613a2491906144a1565b90505f6064613a33848961432d565b613a3d91906144a1565b90505f81613a4b848a6143d5565b613a5591906143d5565b90508615613a6d57613a688a8a836134ac565b613ad8565b8115613acd57613a7e8a8a846134ac565b886001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613ab6575f80fd5b505af1158015613ac8573d5f803e3d5ffd5b505050505b613ad88a8a836134ac565b8215613ae957613ae98a30856134ac565b50505050505050505050565b5f805b600a821015613b31575f613b0d83601861432d565b91505082811c62ffffff81165f03613b255750915091565b82600101925050613af8565b915091565b5f681b1ae4d6e2ef500000821015613b4f57505f919050565b683635c9adc5dea00000821015613b6857506001919050565b685150ae84a8cdf00000821015613b8157506002919050565b686c6b935b8bbd400000821015613b9a57506003919050565b68878678326eac900000821015613bb357506004919050565b68bdbc41e0348b300000821015613bcc57506005919050565b69010f0cf064dd59200000821015613be657506007919050565b50600a919050565b613bfb8260a06018613456565b9150613c0881601861347f565b60a01b17600655565b6001600160a01b0383165f908152600a602052604081205481613c3382613af5565b9150508060d803613c48578492505050610f18565b5f5b85811015613c7357600180860195831b93909317920160d88214613c7357601882019150613c4a565b50506001600160a01b0385165f908152600a602052604090205550819392505050565b600a81045f818152600b6020526040812054909190825b85811015613d3657600a85045f60098711613cc85786613cdc565b81600a028781613cda57613cda61448d565b065b9050601881028015613cf557808a901b85179450613cfb565b89811b94505b8160091480613d0c57508884600101145b15613d22575f838152600b602052604090208590555b876001019750836001019350505050613cad565b509295945050505050565b613d4e8360a06030613456565b9250613d5b82601861347f565b60a082901b83179250613d6f81601861347f565b60b81b9190911760065550565b613d898260b86018613456565b9150613d9681601861347f565b60b81b17600655565b60605f613dab84613092565b6001600160a01b0385165f908152600a60205260408120549192508467ffffffffffffffff811115613ddf57613ddf6140b1565b604051908082528060200260200182016040528015613e08578160200160208202803683370190505b5090505f613e1784601861432d565b90505f5b86811015613e5b576018820391508184901c838281518110613e3f57613e3f6143ae565b62ffffff90921660209283029190910190910152600101613e1b565b50613e718382613e6c89601861432d565b613456565b6001600160a01b0388165f908152600a6020526040902055509250505092915050565b80515f80805b83811015613f83575f858281518110613eb557613eb56143ae565b602002602001015162ffffff1690505f600a8281613ed557613ed561448d565b049050825f03613ef0575f818152600b602052604090205493505b8215801590613eff5750808514155b15613f20575f858152600b6020526040808220959095558181529390932054925b5f60098311613f2f5782613f43565b81600a028381613f4157613f4161448d565b065b90505f816018029050613f5886826018613456565b9550878560010103613f75575f838152600b602052604090208690555b509094505050600101613e9a565b5050505050565b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f60208284031215613fca575f80fd5b5035919050565b5f5b83811015613feb578181015183820152602001613fd3565b50505f910152565b5f815180845261400a816020860160208601613fd1565b601f01601f19169290920160200192915050565b602081525f610f186020830184613ff3565b6001600160a01b038116811461196f575f80fd5b5f8060408385031215614055575f80fd5b823561406081614030565b946020939093013593505050565b602080825282518282018190525f9190848201906040850190845b818110156140a557835183529284019291840191600101614089565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156140d6575f80fd5b8235915060208084013567ffffffffffffffff808211156140f5575f80fd5b818601915086601f830112614108575f80fd5b81358181111561411a5761411a6140b1565b8060051b604051601f19603f8301168101818110858211171561413f5761413f6140b1565b60405291825284820192508381018501918983111561415c575f80fd5b938501935b8285101561417a57843584529385019392850192614161565b8096505050505050509250929050565b5f805f6060848603121561419c575f80fd5b505081359360208301359350604090920135919050565b5f805f606084860312156141c5575f80fd5b83356141d081614030565b925060208401356141e081614030565b929592945050506040919091013590565b5f8060408385031215614202575f80fd5b50508035926020909101359150565b5f60208284031215614221575f80fd5b813565ffffffffffff81168114610f18575f80fd5b5f60208284031215614246575f80fd5b8135610f1881614030565b801515811461196f575f80fd5b5f805f60608486031215614270575f80fd5b833561427b81614030565b9250602084013561428b81614251565b9150604084013561429b81614251565b809150509250925092565b5f80604083850312156142b7575f80fd5b82356142c281614030565b915060208301356142d281614030565b809150509250929050565b602080825282518282018190525f9190848201906040850190845b818110156140a557835162ffffff16835292840192918401916001016142f8565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610c8f57610c8f614319565b5f60208284031215614354575f80fd5b5051919050565b5f6020828403121561436b575f80fd5b8151610f1881614251565b600181811c9082168061438a57607f821691505b6020821081036143a857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b80820180821115610c8f57610c8f614319565b81810381811115610c8f57610c8f614319565b6001600160a01b039687168152602081019590955260408501939093526060840191909152909216608082015260a081019190915260c00190565b5f805f60608486031215614435575f80fd5b8351925060208401519150604084015190509250925092565b5f6020828403121561445e575f80fd5b8151610f1881614030565b6020808252600a908201526973616d652076616c756560b01b604082015260600190565b634e487b7160e01b5f52601260045260245ffd5b5f826144af576144af61448d565b500490565b5f826144c2576144c261448d565b500690565b5f82516144d8818460208701613fd1565b9190910192915050565b5f80604083850312156144f3575f80fd5b505080516020909101519092909150565b5f60a082018783526020878185015260a0604085015281875180845260c08601915082890193505f5b818110156145525784516001600160a01b03168352938301939183019160010161452d565b50506001600160a01b03969096166060850152505050608001529392505050565b60018060a01b0384168152826020820152606060408201525f6145996060830184613ff3565b95945050505050565b600181815b808511156145dc57815f19048211156145c2576145c2614319565b808516156145cf57918102915b93841c93908002906145a7565b509250929050565b5f826145f257506001610c8f565b816145fe57505f610c8f565b8160018114614614576002811461461e5761463a565b6001915050610c8f565b60ff84111561462f5761462f614319565b50506001821b610c8f565b5060208310610133831016604e8410600b841016171561465d575081810a610c8f565b61466783836145a2565b805f190482111561467a5761467a614319565b029392505050565b5f610f1883836145e456fea264697066735822122071da3b7386b293fee1e1929e49f67a4cef2c5b4570c355088fbfdf8ff32e2d0f64736f6c634300081500330000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca0000000000000000000000005a861794b927983406fce1d062e00b9368d97df6

Deployed Bytecode

0x608060405260043610610278575f3560e01c80638d5fcacb1161014a578063cae5f11e116100be578063e461a55e11610078578063e461a55e14610858578063e8891de814610884578063e9cc4edd146108a3578063ef4d5efa146108c2578063f2fde38b146108d6578063ffc9896b146108f5575f80fd5b8063cae5f11e1461077e578063d346b577146107b0578063d7e1a3d9146107ec578063dd62ed3e14610811578063ddf5451214610830578063de9ca28d14610844575f80fd5b8063b2a8116a1161010f578063b2a8116a146106c3578063b4664394146106e2578063beba2126146106f6578063c09d28561461070b578063c1f1b1b514610742578063c1f3c33f1461075f575f80fd5b80638d5fcacb146106125780638da5cb5b1461065457806395d89b4114610671578063a457c2d714610685578063a9059cbb146106a4575f80fd5b806332fe7b26116101ec5780635fd2f823116101a65780635fd2f8231461056e57806367a2b56a1461058257806370a08231146105a1578063715018a6146105c057806377841d59146105d457806382374c13146105f3575f80fd5b806332fe7b261461046657806339509351146104b15780633c3b2a73146104d0578063556d9228146104ef57806355a34e6f146105235780635ac1c61e14610536575f80fd5b80631fe543e31161023d5780631fe543e31461033c578063224290851461035b57806323b872dd1461037a57806325dee0c4146103995780632d10fa28146103b8578063313ce5671461044b575f80fd5b8063051515541461028357806306fdde03146102a4578063095ea7b3146102ce578063128047b5146102fd57806318160ddd1461031e575f80fd5b3661027f57005b5f80fd5b34801561028e575f80fd5b506102a261029d366004613fba565b610947565b005b3480156102af575f80fd5b506102b8610bec565b6040516102c5919061401e565b60405180910390f35b3480156102d9575f80fd5b506102ed6102e8366004614044565b610c7c565b60405190151581526020016102c5565b348015610308575f80fd5b50610311610c95565b6040516102c5919061406e565b348015610329575f80fd5b506002545b6040519081526020016102c5565b348015610347575f80fd5b506102a26103563660046140c5565b610ddf565b348015610366575f80fd5b506102a261037536600461418a565b610e6a565b348015610385575f80fd5b506102ed6103943660046141b3565b610efa565b3480156103a4575f80fd5b506102a26103b3366004613fba565b610f1f565b3480156103c3575f80fd5b506103cc610faa565b6040805186518152602080880151818301528783015182840152606080890151908301526080808901519083015260a09788015197820197909752855160c08201528686015160e0820152940151610100850152825161012085015293909101516101408301526101608201526101808101919091526101a0016102c5565b348015610456575f80fd5b50604051601281526020016102c5565b348015610471575f80fd5b506104997f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d81565b6040516001600160a01b0390911681526020016102c5565b3480156104bc575f80fd5b506102ed6104cb366004614044565b611004565b3480156104db575f80fd5b506102a26104ea3660046141f1565b611025565b3480156104fa575f80fd5b50610499610509366004613fba565b5f908152600c60205260409020546001600160a01b031690565b6102a2610531366004614211565b61110f565b348015610541575f80fd5b5060075461055990600160e01b900463ffffffff1681565b60405163ffffffff90911681526020016102c5565b348015610579575f80fd5b506102a261143d565b34801561058d575f80fd5b506102a261059c366004614044565b61151d565b3480156105ac575f80fd5b5061032e6105bb366004614236565b61169e565b3480156105cb575f80fd5b506102a26116b8565b3480156105df575f80fd5b506102a26105ee36600461425e565b6116cb565b3480156105fe575f80fd5b50600f54610499906001600160a01b031681565b34801561061d575f80fd5b5061063161062c366004613fba565b611761565b6040805162ffffff90931683526001600160a01b039091166020830152016102c5565b34801561065f575f80fd5b506005546001600160a01b0316610499565b34801561067c575f80fd5b506102b8611775565b348015610690575f80fd5b506102ed61069f366004614044565b611784565b3480156106af575f80fd5b506102ed6106be366004614044565b611809565b3480156106ce575f80fd5b5061032e6106dd366004614236565b611816565b3480156106ed575f80fd5b506102a2611820565b348015610701575f80fd5b5061032e60085481565b348015610716575f80fd5b5060075461072a906001600160801b031681565b6040516001600160801b0390911681526020016102c5565b34801561074d575f80fd5b50600d546001600160a01b0316610499565b34801561076a575f80fd5b506102a2610779366004613fba565b611972565b348015610789575f80fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2610499565b3480156107bb575f80fd5b506007546107d590600160b01b900465ffffffffffff1681565b60405165ffffffffffff90911681526020016102c5565b3480156107f7575f80fd5b506007546107d590600160801b900465ffffffffffff1681565b34801561081c575f80fd5b5061032e61082b3660046142a6565b611a00565b34801561083b575f80fd5b506102a2611a2a565b34801561084f575f80fd5b506102a2611b02565b348015610863575f80fd5b50610877610872366004614236565b611bda565b6040516102c591906142dd565b34801561088f575f80fd5b506102a261089e366004613fba565b611c6c565b3480156108ae575f80fd5b506102a26108bd3660046141f1565b611cfa565b3480156108cd575f80fd5b5061032e611db9565b3480156108e1575f80fd5b506102a26108f0366004614236565b611fd7565b348015610900575f80fd5b5061091461090f366004614236565b61204d565b6040516102c591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b61094f612095565b600d546001600160a01b0316610978576040516305835fed60e01b815260040160405180910390fd5b5f61098a8266038d7ea4c6800061432d565b90507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156109e5575f80fd5b505af11580156109f7573d5f803e3d5ffd5b5050600d546040516370a0823160e01b81523060048201525f94506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116945063a9059cbb93509091169083906370a08231906024016020604051808303815f875af1158015610a71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a959190614344565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af1158015610add573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b01919061435b565b905080610b215760405163062e4f6360e11b815260040160405180910390fd5b600d5f9054906101000a90046001600160a01b03166001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610b6d575f80fd5b505af1158015610b7f573d5f803e3d5ffd5b5050604080516001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2168152602081018690527f5c0eec4199f95cf196fdac30f5458f67ba720232c0fce87b1540c0c7dc0e773f93500190505b60405180910390a1505050565b606060038054610bfb90614376565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2790614376565b8015610c725780601f10610c4957610100808354040283529160200191610c72565b820191905f5260205f20905b815481529060010190602001808311610c5557829003601f168201915b5050505050905090565b5f33610c898185856120ef565b60019150505b92915050565b60408051600780825261010082019092526060915f91906020820160e080368337019050509050681b1ae4d6e2ef500000815f81518110610cd857610cd86143ae565b602002602001018181525050683635c9adc5dea0000081600181518110610d0157610d016143ae565b602002602001018181525050685150ae84a8cdf0000081600281518110610d2a57610d2a6143ae565b602002602001018181525050686c6b935b8bbd40000081600381518110610d5357610d536143ae565b60200260200101818152505068878678326eac90000081600481518110610d7c57610d7c6143ae565b60200260200101818152505068bdbc41e0348b30000081600581518110610da557610da56143ae565b60200260200101818152505069010f0cf064dd5920000081600681518110610dcf57610dcf6143ae565b6020908102919091010152919050565b336001600160a01b037f0000000000000000000000005a861794b927983406fce1d062e00b9368d97df61614610e5c5760405162461bcd60e51b815260206004820152601f60248201527f6f6e6c792056524620563220777261707065722063616e2066756c66696c6c0060448201526064015b60405180910390fd5b610e668282612212565b5050565b610e72612095565b600a610e7e82856143c2565b1180610e935750600a610e9182846143c2565b115b15610eb157604051633634941560e21b815260040160405180910390fd5b610ebc838383612341565b60408051848152602081018490529081018290527fcf8a1e1d5f09cf3c97dbb653cd9a4d7aace9292fbc1bb8211febf2d400febbdd90606001610bdf565b5f33610f0785828561238e565b610f12858585612400565b60019150505b9392505050565b610f27612095565b600754600160e01b900463ffffffff16811015610f5757604051631c23763d60e01b815260040160405180910390fd5b600780546001600160e01b0316600160e01b63ffffffff8416021790556040518181527f0f7a60a7e1cf3f1b0b1540f0e964947327ad8b2bde2e2ac3e07d922b69e977d99060200160405180910390a150565b610fb2613f8a565b610fd360405180606001604052805f81526020015f81526020015f81525090565b604080518082019091525f80825260208201525f80610ff36006546128ee565b945094509450945094509091929394565b5f33610c898185856110168383611a00565b61102091906143c2565b6120ef565b3330148015906110405750600e546001600160a01b03163314155b801561105757506005546001600160a01b03163314155b1561107557604051636932705760e11b815260040160405180910390fd5b6005546001600160a01b0316330361110557600754600160b01b900465ffffffffffff1615806110b257506007546001600160801b03166298967f145b806110c657506007546001600160801b0316155b156110e4576040516351bf115f60e01b815260040160405180910390fd5b6007546006546001600160801b03909116925060b81c62ffffff165f190190505b610e6682826129c5565b611117612095565b600d546001600160a01b03161561114157604051630cac471160e41b815260040160405180910390fd5b61012c8165ffffffffffff161161116b57604051631c23763d60e01b815260040160405180910390fd5b611197307f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d5f196120ef565b7f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663f305d719473060016111d33061169e565b6111dd91906143d5565b5f8030426040518863ffffffff1660e01b8152600401611202969594939291906143e8565b60606040518083038185885af115801561121e573d5f803e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906112439190614423565b5050505f7f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112c7919061444e565b60405163e6a4390560e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811660048301523060248301529192505f9183169063e6a4390590604401602060405180830381865afa158015611336573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135a919061444e565b905061136a815f60015f80612d2d565b600d80546001600160a01b0319166001600160a01b03831617905561139765ffffffffffff8416436143c2565b600760106101000a81548165ffffffffffff021916908365ffffffffffff1602179055505f604051806101a001604052804381526020014360326113db91906143c2565b81526020015f815260200160018152602001600381526020016001815260200160048152602001600481526020016001815260200161177081526020016127108152602001600181526020016001815250905061143781612d90565b50505050565b611445612095565b5f611451600654612e91565b90505f81604001515f03611466576001611468565b5f5b90508160400151810361148d5760405162461bcd60e51b8152600401610e5390614469565b6114ae825f0151836020015183856060015186608001518760a00151612ee5565b80156114ed57604051600181527f0f8293c744b66395bf9a745e7b4d95c3b84f65fd0f4cb60bad74975fa315eb1b906020015b60405180910390a15050565b6040515f81527f0f8293c744b66395bf9a745e7b4d95c3b84f65fd0f4cb60bad74975fa315eb1b906020016114e1565b611525612095565b6001600160a01b03821661154c57604051639ed698f560e01b815260040160405180910390fd5b5f815f036115c3576040516001600160a01b0384169047905f81818185875af1925050503d805f811461159a576040519150601f19603f3d011682016040523d82523d5f602084013e61159f565b606091505b505080915050806115c35760405163062e4f6360e11b815260040160405180910390fd5b600d546001600160a01b038085169116036116195760405162461bcd60e51b81526020600482015260166024820152752ab9b29030b2322a37a830b4b91034b739ba32b0b21760511b6044820152606401610e53565b5f61162b8366038d7ea4c6800061432d565b9050836001600160a01b0316816040515f6040518083038185875af1925050503d805f8114611675576040519150601f19603f3d011682016040523d82523d5f602084013e61167a565b606091505b505080925050816114375760405163062e4f6360e11b815260040160405180910390fd5b6001600160a01b03165f9081526020819052604090205490565b6116c0612095565b6116c95f612f63565b565b6116d3612095565b600d546001600160a01b038481169116148061172057507f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d6001600160a01b0316836001600160a01b0316145b8061173357506001600160a01b03831630145b1561175157604051636932705760e11b815260040160405180910390fd5b61175c838383612fb4565b505050565b5f8061176c83613015565b91509150915091565b606060048054610bfb90614376565b5f33816117918286611a00565b9050838110156117f15760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610e53565b6117fe82868684036120ef565b506001949350505050565b5f33610c89818585612400565b5f610c8f82613092565b611828612095565b600f546001600160a01b031661183c575f80fd5b7f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b031663a9059cbb61187d6005546001600160a01b031690565b6040516370a0823160e01b81523060048201527f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca6001600160a01b0316906370a0823190602401602060405180830381865afa1580156118df573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119039190614344565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303815f875af115801561194b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061196f919061435b565b50565b61197a612095565b5f611986600654612e91565b6020810151909150808311156119af57604051633634941560e21b815260040160405180910390fd5b6119d0825f0151848460400151856060015186608001518760a00151612ee5565b6040518381527fb32eee1f3b022fecf91130907d354359df3234353a0ee169155ac37dbeed75c090602001610bdf565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b611a32612095565b5f611a3e600654612e91565b90505f81606001515f03611a53576001611a55565b5f5b905081606001518103611a7a5760405162461bcd60e51b8152600401610e5390614469565b611a9b825f0151836020015184604001518486608001518760a00151612ee5565b8015611ad257604051600181527fc97260ffb3df6b903cdfd59e3b5b21a896404903a8e8a83bf60ba3fca365fbe5906020016114e1565b6040515f81527fc97260ffb3df6b903cdfd59e3b5b21a896404903a8e8a83bf60ba3fca365fbe5906020016114e1565b611b0a612095565b5f611b16600654612e91565b90505f8160a001515f03611b2b576001611b2d565b5f5b90508160a001518103611b525760405162461bcd60e51b8152600401610e5390614469565b611b73825f0151836020015184604001518560600151866080015186612ee5565b8015611baa57604051600181527fa8392e314504d0b57633e056d62ab8ededff9020da370c77dd137a25324b5c18906020016114e1565b6040515f81527fa8392e314504d0b57633e056d62ab8ededff9020da370c77dd137a25324b5c18906020016114e1565b6001600160a01b0381165f908152600a602081815260408084205481518481526101608101909252606094909390928201610140803683370190505090505f5b600a811015611c64575f611c2f82601861432d565b90508084901c838381518110611c4757611c476143ae565b62ffffff9092166020928302919091019091015250600101611c1a565b509392505050565b611c74612095565b5f611c80600654612e91565b608081015190915080831115611ca957604051633634941560e21b815260040160405180910390fd5b611cca825f0151836020015184604001518560600151878760a00151612ee5565b6040518381527fb3bf54177f07aa628d24efcbd137a401112718a4d9c8c1a8538b24e21029422990602001610bdf565b611d02612095565b60065460408051808201909152607882901c61ffff16815260889190911c62ffffff1660208201525f611d36600654612e91565b805190915015611d70578151841080611d525750816020015183105b15611d7057604051631c23763d60e01b815260040160405180910390fd5b611d7a84846130bd565b60408051858152602081018590527faa6f6b0a509f2b07cf30d89dbd3bb410883aaa429ad4da41fdf36c02398cf1a0910160405180910390a150505050565b5f611dc2612095565b5f611dce600654612e91565b600654815191925060b81c62ffffff16901580611dfb5750600754600160b01b900465ffffffffffff1615155b80611e165750600754600160801b900465ffffffffffff1643105b80611e215750806001145b15611e3f57604051630cc4134b60e11b815260040160405180910390fd5b5f611e493061169e565b9050681b1ae4d6e2ef500000811115611eae57600d545f90606490611e76906001600160a01b031661169e565b611e8190601461432d565b611e8b91906144a1565b905080821115611e99578091505b611eac611ea76001846143d5565b6130f8565b505b478015611f19575f611ec86005546001600160a01b031690565b6001600160a01b0316476040515f6040518083038185875af1925050503d805f8114611f0f576040519150601f19603f3d011682016040523d82523d5f602084013e611f14565b606091505b505050505b6007805465ffffffffffff60b01b1916600160b01b4265ffffffffffff1602179055611f4361320c565b611f717f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d5f6001805f612d2d565b600754611f8e90600160e01b900463ffffffff166003600161321f565b600780546001600160801b0319166298967f17905560405190955085907f0c720560a539b13f97fb22b6c1ac4393045cedca3bb997fd2ea1f7a3dfb76a58905f90a25050505090565b611fdf612095565b6001600160a01b0381166120445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610e53565b61196f81612f63565b61207460405180608001604052805f81526020015f81526020015f81526020015f81525090565b6001600160a01b0382165f90815260096020526040902054610c8f906133f8565b6005546001600160a01b031633146116c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610e53565b6001600160a01b0383166121515760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610e53565b6001600160a01b0382166121b25760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610e53565b6001600160a01b038381165f8181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6006545f9060b81c62ffffff16905080600190039050815f8151811061223a5761223a6143ae565b60200260200101516008819055505f8160085461225791906144b4565b600780546001600160801b0319166001600160801b0383169081179091556040519192509085907f54d97c1f7e5abad75bd421455cd4dd296852a52e1ea721f2cdb66d06fa2082a9905f90a3604080516001600160801b0383166024820152604480820185905282518083039091018152606490910182526020810180516001600160e01b0316633c3b2a7360e01b17905290515f9130916122f991906144c7565b5f604051808303815f865af19150503d805f8114612332576040519150601f19603f3d011682016040523d82523d5f602084013e612337565b606091505b5050505050505050565b5f61235160065460606018613456565b905061235e84600861347f565b606084901b1761236f83600861347f565b606883901b1761238082600861347f565b60709190911b176006555050565b5f6123998484611a00565b90505f19811461143757818110156123f35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610e53565b61143784848484036120ef565b6006545f61240d82612e91565b6001600160a01b0386165f9081526009602052604081205491925090612432906133f8565b6001600160a01b0386165f9081526009602052604081205491925090612457906133f8565b90506001600160a01b0387163014806124735750604083015115155b8061248f575060208201511580159061248f5750604082015115155b806124ab57506020810151158015906124ab5750604081015115155b156124c0576124bb8787876134ac565b6128e5565b82515f036124e1576040516305835fed60e01b815260040160405180910390fd5b600d5460408051808201909152607886901c61ffff168152608886901c62ffffff1660208201525f916001600160a01b0316905f61251e8861364e565b325f908152600960205260408120549192509061253a906133f8565b90508b6001600160a01b0316846001600160a01b0316036126e35785604001515f036126da5743886020015111156126525787516125799060026143c2565b43101561258b57600a80835260408301525b82516125a090670de0b6b3a76400009061432d565b8a11156125c057604051632d2b153d60e01b815260040160405180910390fd5b670de0b6b3a764000083602001516125d8919061432d565b8a6125e28d61169e565b6125ec91906143c2565b111561260b5760405163cc91297760e01b815260040160405180910390fd5b608088015186514391011180612628575060808801518151439101115b156126465760405163dcafac0960e01b815260040160405180910390fd5b60078252600360408301525b43865260608601511561267b5761267b8b875f0151886020015189604001518a60600151612d2d565b61269d8b878c8c8660018e606001515f03612696575f613697565b6001613697565b326001600160a01b038c16148015906126b95750438860200151115b156126da576126da32875f0151886020015189604001518a60600151612d2d565b600194506127ca565b8a6001600160a01b0316846001600160a01b0316036127ca5760408701511580156127115750608088015115155b1561275157608088015187514391011180612733575060808801518151439101115b156127515760405163dcafac0960e01b815260040160405180910390fd5b61276b8c888c8c865f8e606001515f03612696575f613697565b5f6127753061169e565b9050681b1ae4d6e2ef5000008111156127c8575f60646127948e61169e565b61279f90600561432d565b6127a991906144a1565b90506127c68183116127c057611ea76001846143d5565b816130f8565b505b505b606088015115801590612824575060208601511580156127fb57508b6001600160a01b0316846001600160a01b0316145b806128245750602087015115801561282457508a6001600160a01b0316846001600160a01b0316145b1561283b576128368c8c8c88866139ea565b6128df565b8b6001600160a01b0316846001600160a01b03161415801561286f57508a6001600160a01b0316846001600160a01b031614155b156128d4578760a001515f03612898576040516308090ba360e41b815260040160405180910390fd5b60208601511580156128ab575086518651105b156128b557865186525b6128c48c888c8c865f80613697565b6128d48b878c8c8660015f613697565b6128df8c8c8c6134ac565b50505050505b50505050505050565b6128f6613f8a565b61291760405180606001604052805f81526020015f81526020015f81525090565b60408051808201825263ffffffff8581168552602086811c9091168186015260ff86841c811686850152604887901c8116606080880191909152605088901c82166080880152605888901c821660a0808901919091529088901c82168652606888901c821686840152607088901c9091169385019390935261ffff607887901c16825262ffffff608887901c8116918301919091529395929490939181901c82169260b89190911c90911690565b815f6129d082613015565b9150506001600160a01b038116612aab5782821015612a2b575f6129f483856143d5565b90505f5b81811015612a2857836001019350612a0f84613015565b9350506001600160a01b038316612a28576001016129f8565b50505b6001600160a01b038116158015612a4157508282145b15612a7d578391505f5b84811015612a7b575f1990920191612a6283613015565b9250506001600160a01b038216612a7b57600101612a4b565b505b6001600160a01b038116612a8f575f80fd5b600780546001600160801b0319166001600160801b0384161790555b600f80546001600160a01b0319166001600160a01b0383811691909117909155600d5460405163095ea7b360e01b81527f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d831660048201525f19602482015291169063095ea7b3906044016020604051808303815f875af1158015612b32573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b56919061435b565b50600d546040516370a0823160e01b815230600482018190525f926001600160a01b037f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d8116936302751cec939291909116906370a0823190602401602060405180830381865afa158015612bcd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bf19190614344565b5f8030426040518763ffffffff1660e01b8152600401612c16969594939291906143e8565b60408051808303815f875af1158015612c31573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c5591906144e2565b9150505f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114612ca1576040519150601f19603f3d011682016040523d82523d5f602084013e612ca6565b606091505b5050905080612ce95760405162461bcd60e51b815260206004820152600f60248201526e4661696c656420746f2073656e642160881b6044820152606401610e53565b6040516001600160a01b03841681527f0992f42a6118239e571ca390863e9f148a939f9f0470578217d738d6d665116e9060200160405180910390a1505050505050565b612d3884602061347f565b83612d4484600861347f565b602084901b17612d5583600861347f565b602883901b17612d6682601861347f565b6001600160a01b039095165f90815260096020526040902060309190911b94909417909355505050565b604080516101a0810182526020808252808201526008918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091526010610120820152601861014082018190526101608201819052610180820152600d905f9081905f5b84811015612e8757612e428682600d8110612e1e57612e1e6143ae565b60200201518383600d8110612e3557612e356143ae565b602002015160ff1661347f565b838682600d8110612e5557612e556143ae565b6020020151901b831792508181600d8110612e7257612e726143ae565b602002015160ff169390930192600101612e01565b5050600655505050565b612e99613f8a565b63ffffffff8083168252602083811c9091169082015260ff604083811c821690830152604883901c81166060830152605083901c8116608083015260589290921c90911660a082015290565b5f612ef46006545f6060613456565b9050612f0187602061347f565b8617612f0e86602061347f565b602086901b17612f1f85600861347f565b604085901b17612f3084600861347f565b604884901b17612f4183600861347f565b605083901b17612f5282600861347f565b60589190911b176006555050505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0383165f90815260096020526040812054612fd5906133f8565b90505f83612fe3575f612fe6565b60015b90505f83612ff4575f612ff7565b60015b905061300d86845f015184848760600151612d2d565b505050505050565b5f8080613023600a856144a1565b90505f600985116130345784613049565b61303f82600a61432d565b61304990866144b4565b90505f61305782601861432d565b5f938452600b602090815260408086205490921c62ffffff81168652600c90915293205492966001600160a01b039093169550919350505050565b6001600160a01b0381165f908152600a6020526040812054816130b482613af5565b50949350505050565b5f6130cd60065460786028613456565b90506130da83601061347f565b607883901b176130eb82601861347f565b60889190911b1760065550565b6040805160028082526060820183525f9260208301908036833701905050905030815f8151811061312b5761312b6143ae565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160018151811061317f5761317f6143ae565b6001600160a01b03928316602091820292909201015260405163791ac94760e01b81527f0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d9091169063791ac947906131e39085905f90869030904290600401614504565b5f604051808303815f87803b1580156131fa575f80fd5b505af115801561300d573d5f803e3d5ffd5b61321a6006545f6020613456565b600655565b6040516310c1b4d560e21b815263ffffffff841660048201525f906001600160a01b037f000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca811691634000aea0917f0000000000000000000000005a861794b927983406fce1d062e00b9368d97df69190821690634306d35490602401602060405180830381865afa1580156132b6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132da9190614344565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b815260040161332f93929190614573565b6020604051808303815f875af115801561334b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061336f919061435b565b507f0000000000000000000000005a861794b927983406fce1d062e00b9368d97df66001600160a01b031663fc2a88c36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133f09190614344565b949350505050565b61341f60405180608001604052805f81526020015f81526020015f81526020015f81525090565b63ffffffff8216815260ff602083811c821690830152602883901c16604082015262ffffff60309290921c91909116606082015290565b5f80836001613466856002614682565b61347091906143d5565b901b1994909416949350505050565b6001811b8210610e6657604051638f44d83160e01b81526004810183905260248101829052604401610e53565b6001600160a01b0383166135105760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610e53565b6001600160a01b0382166135725760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610e53565b6001600160a01b0383165f90815260208190526040902054818110156135e95760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610e53565b6001600160a01b038481165f81815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611437565b61366f60405180606001604052805f81526020015f81526020015f81525090565b60ff606083901c81168252606883901c8116602083015260709290921c909116604082015290565b5f6136a188613092565b90505f83156138fa5782156137aa578451158015906136c35750604085015115155b156137335761372c60648660400151896136dd919061432d565b6136e791906144a1565b86516064906136f6908b61432d565b61370091906144a1565b61370a908a6143d5565b61371491906143d5565b61371d8b61169e565b61372791906143c2565b613b36565b90506137ba565b84511580159061374557506040850151155b1561377157845161372c9060649061375d908a61432d565b61376791906144a1565b61371490896143d5565b84511580156137835750604085015115155b1561379d5761372c606486604001518961375d919061432d565b61372c8761371d8b61169e565b6137b78761371d8b61169e565b90505b6060880151805f8190036138195760a088901c62ffffff1691508190506137ef8b8b5f01518c602001518d6040015186612d2d565b5f828152600c6020526040902080546001600160a01b0319166001600160a01b038d161790556001015b82158061382557508383145b80156138315750808214155b15613849576138408882613bee565b505050506128e5565b838311156138f35762ffffff60b889901c165f6138708d61386a88886143d5565b84613c11565b90505f61387e858385613c96565b9050838514613897576138928b8583613d41565b6138a1565b6138a18b82613d7c565b7fd4a167f62427a87418c8179efb1099f2da50e01c5374433a1e21db418fd9e4458e6138cd89896143d5565b604080516001600160a01b03909316835260208301919091520160405180910390a15050505b50506139df565b866139048a61169e565b10156139115750506128e5565b6139288761391e8b61169e565b61372791906143d5565b9050818110156139df575f61393d82846143d5565b90505f8167ffffffffffffffff811115613959576139596140b1565b604051908082528060200260200182016040528015613982578160200160208202803683370190505b50905061398f8b83613d9f565b905061399a81613e94565b604080516001600160a01b038d168152602081018490527f0c129863ec4f7070868d0ab05157245e6264ef1004096ec9dd7fbbc67d575253910160405180910390a150505b505050505050505050565b5f8083613a005782602001518360400151613a08565b825160408401515b90925090505f6064613a1a848861432d565b613a2491906144a1565b90505f6064613a33848961432d565b613a3d91906144a1565b90505f81613a4b848a6143d5565b613a5591906143d5565b90508615613a6d57613a688a8a836134ac565b613ad8565b8115613acd57613a7e8a8a846134ac565b886001600160a01b031663fff6cae96040518163ffffffff1660e01b81526004015f604051808303815f87803b158015613ab6575f80fd5b505af1158015613ac8573d5f803e3d5ffd5b505050505b613ad88a8a836134ac565b8215613ae957613ae98a30856134ac565b50505050505050505050565b5f805b600a821015613b31575f613b0d83601861432d565b91505082811c62ffffff81165f03613b255750915091565b82600101925050613af8565b915091565b5f681b1ae4d6e2ef500000821015613b4f57505f919050565b683635c9adc5dea00000821015613b6857506001919050565b685150ae84a8cdf00000821015613b8157506002919050565b686c6b935b8bbd400000821015613b9a57506003919050565b68878678326eac900000821015613bb357506004919050565b68bdbc41e0348b300000821015613bcc57506005919050565b69010f0cf064dd59200000821015613be657506007919050565b50600a919050565b613bfb8260a06018613456565b9150613c0881601861347f565b60a01b17600655565b6001600160a01b0383165f908152600a602052604081205481613c3382613af5565b9150508060d803613c48578492505050610f18565b5f5b85811015613c7357600180860195831b93909317920160d88214613c7357601882019150613c4a565b50506001600160a01b0385165f908152600a602052604090205550819392505050565b600a81045f818152600b6020526040812054909190825b85811015613d3657600a85045f60098711613cc85786613cdc565b81600a028781613cda57613cda61448d565b065b9050601881028015613cf557808a901b85179450613cfb565b89811b94505b8160091480613d0c57508884600101145b15613d22575f838152600b602052604090208590555b876001019750836001019350505050613cad565b509295945050505050565b613d4e8360a06030613456565b9250613d5b82601861347f565b60a082901b83179250613d6f81601861347f565b60b81b9190911760065550565b613d898260b86018613456565b9150613d9681601861347f565b60b81b17600655565b60605f613dab84613092565b6001600160a01b0385165f908152600a60205260408120549192508467ffffffffffffffff811115613ddf57613ddf6140b1565b604051908082528060200260200182016040528015613e08578160200160208202803683370190505b5090505f613e1784601861432d565b90505f5b86811015613e5b576018820391508184901c838281518110613e3f57613e3f6143ae565b62ffffff90921660209283029190910190910152600101613e1b565b50613e718382613e6c89601861432d565b613456565b6001600160a01b0388165f908152600a6020526040902055509250505092915050565b80515f80805b83811015613f83575f858281518110613eb557613eb56143ae565b602002602001015162ffffff1690505f600a8281613ed557613ed561448d565b049050825f03613ef0575f818152600b602052604090205493505b8215801590613eff5750808514155b15613f20575f858152600b6020526040808220959095558181529390932054925b5f60098311613f2f5782613f43565b81600a028381613f4157613f4161448d565b065b90505f816018029050613f5886826018613456565b9550878560010103613f75575f838152600b602052604090208690555b509094505050600101613e9a565b5050505050565b6040518060c001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81525090565b5f60208284031215613fca575f80fd5b5035919050565b5f5b83811015613feb578181015183820152602001613fd3565b50505f910152565b5f815180845261400a816020860160208601613fd1565b601f01601f19169290920160200192915050565b602081525f610f186020830184613ff3565b6001600160a01b038116811461196f575f80fd5b5f8060408385031215614055575f80fd5b823561406081614030565b946020939093013593505050565b602080825282518282018190525f9190848201906040850190845b818110156140a557835183529284019291840191600101614089565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f80604083850312156140d6575f80fd5b8235915060208084013567ffffffffffffffff808211156140f5575f80fd5b818601915086601f830112614108575f80fd5b81358181111561411a5761411a6140b1565b8060051b604051601f19603f8301168101818110858211171561413f5761413f6140b1565b60405291825284820192508381018501918983111561415c575f80fd5b938501935b8285101561417a57843584529385019392850192614161565b8096505050505050509250929050565b5f805f6060848603121561419c575f80fd5b505081359360208301359350604090920135919050565b5f805f606084860312156141c5575f80fd5b83356141d081614030565b925060208401356141e081614030565b929592945050506040919091013590565b5f8060408385031215614202575f80fd5b50508035926020909101359150565b5f60208284031215614221575f80fd5b813565ffffffffffff81168114610f18575f80fd5b5f60208284031215614246575f80fd5b8135610f1881614030565b801515811461196f575f80fd5b5f805f60608486031215614270575f80fd5b833561427b81614030565b9250602084013561428b81614251565b9150604084013561429b81614251565b809150509250925092565b5f80604083850312156142b7575f80fd5b82356142c281614030565b915060208301356142d281614030565b809150509250929050565b602080825282518282018190525f9190848201906040850190845b818110156140a557835162ffffff16835292840192918401916001016142f8565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610c8f57610c8f614319565b5f60208284031215614354575f80fd5b5051919050565b5f6020828403121561436b575f80fd5b8151610f1881614251565b600181811c9082168061438a57607f821691505b6020821081036143a857634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b80820180821115610c8f57610c8f614319565b81810381811115610c8f57610c8f614319565b6001600160a01b039687168152602081019590955260408501939093526060840191909152909216608082015260a081019190915260c00190565b5f805f60608486031215614435575f80fd5b8351925060208401519150604084015190509250925092565b5f6020828403121561445e575f80fd5b8151610f1881614030565b6020808252600a908201526973616d652076616c756560b01b604082015260600190565b634e487b7160e01b5f52601260045260245ffd5b5f826144af576144af61448d565b500490565b5f826144c2576144c261448d565b500690565b5f82516144d8818460208701613fd1565b9190910192915050565b5f80604083850312156144f3575f80fd5b505080516020909101519092909150565b5f60a082018783526020878185015260a0604085015281875180845260c08601915082890193505f5b818110156145525784516001600160a01b03168352938301939183019160010161452d565b50506001600160a01b03969096166060850152505050608001529392505050565b60018060a01b0384168152826020820152606060408201525f6145996060830184613ff3565b95945050505050565b600181815b808511156145dc57815f19048211156145c2576145c2614319565b808516156145cf57918102915b93841c93908002906145a7565b509250929050565b5f826145f257506001610c8f565b816145fe57505f610c8f565b8160018114614614576002811461461e5761463a565b6001915050610c8f565b60ff84111561462f5761462f614319565b50506001821b610c8f565b5060208310610133831016604e8410600b841016171561465d575081810a610c8f565b61466783836145a2565b805f190482111561467a5761467a614319565b029392505050565b5f610f1883836145e456fea264697066735822122071da3b7386b293fee1e1929e49f67a4cef2c5b4570c355088fbfdf8ff32e2d0f64736f6c63430008150033

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

0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca0000000000000000000000005a861794b927983406fce1d062e00b9368d97df6

-----Decoded View---------------
Arg [0] : router_ (address): 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D
Arg [1] : linkAddress (address): 0x514910771AF9Ca656af840dff83E8264EcF986CA
Arg [2] : wrapperAddress (address): 0x5A861794B927983406fCE1D062e00b9368d97Df6

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d
Arg [1] : 000000000000000000000000514910771af9ca656af840dff83e8264ecf986ca
Arg [2] : 0000000000000000000000005a861794b927983406fce1d062e00b9368d97df6


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.