ETH Price: $3,915.52 (+6.69%)

Token

ERC-20: IGMI (IGMI)
 

Overview

Max Total Supply

1,000,000 IGMI

Holders

137

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

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

[{"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


Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.